Skip to content

Commit

Permalink
API v1 (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
dungeon-master-666 authored Mar 14, 2023
1 parent 9b15b9e commit 28b9c27
Show file tree
Hide file tree
Showing 16 changed files with 1,320 additions and 160 deletions.
File renamed without changes.
Empty file added api/api_v0/__init__.py
Empty file.
70 changes: 21 additions & 49 deletions webserver/main.py → api/api_v0/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import List, Optional
from datetime import datetime

from fastapi import FastAPI, Depends, Query, status
from fastapi import FastAPI, APIRouter, Depends, Query, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import HTTPException
from starlette.exceptions import HTTPException as StarletteHTTPException
Expand All @@ -13,47 +13,18 @@

from config import settings

from webserver import schemas
from . import schemas
from indexer.database import SessionMaker
from indexer import crud

logging.basicConfig(format='%(asctime)s %(module)-15s %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
# logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)


description = ''
app = FastAPI(
title="TON Index",
description=description,
version='0.1.0',
root_path=settings.webserver.api_root_path,
docs_url='/',
)
router = APIRouter()

# Dependency
async def get_db():
async with SessionMaker() as db:
yield db

@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
return JSONResponse({'error' : str(exc.detail)}, status_code=exc.status_code)

@app.exception_handler(crud.DataNotFound)
async def tonlib_wront_result_exception_handler(request, exc):
return JSONResponse({'error' : str(exc)}, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)

@app.exception_handler(Exception)
def generic_exception_handler(request, exc):
return JSONResponse({'error' : str(exc)}, status_code=status.HTTP_503_SERVICE_UNAVAILABLE)

@app.on_event("startup")
def startup():
logger.info('Service started successfully')

@app.get('/getTransactionsByMasterchainSeqno', response_model=List[schemas.Transaction])
@router.get('/getTransactionsByMasterchainSeqno', response_model=List[schemas.Transaction])
async def get_transactions_by_masterchain_seqno(
seqno: int = Query(..., description="Masterchain seqno"),
include_msg_body: bool = Query(False, description="Whether return full message body or not"),
Expand All @@ -65,7 +36,7 @@ async def get_transactions_by_masterchain_seqno(
db_transactions = await db.run_sync(crud.get_transactions_by_masterchain_seqno, seqno, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getTransactionsByAddress', response_model=List[schemas.Transaction])
@router.get('/getTransactionsByAddress', response_model=List[schemas.Transaction])
async def get_transactions_by_address(
address: str = Query(..., description="The address to get transactions. Can be sent in any form."),
start_utime: Optional[int] = Query(None, description="UTC timestamp to start searching transactions"),
Expand All @@ -83,7 +54,7 @@ async def get_transactions_by_address(
db_transactions = await db.run_sync(crud.get_transactions_by_address, raw_address, start_utime, end_utime, limit, offset, sort, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getTransactionsInBlock', response_model=List[schemas.Transaction])
@router.get('/getTransactionsInBlock', response_model=List[schemas.Transaction])
async def get_transactions_in_block(
workchain: int = Query(..., description="Block workchain"),
shard: int = Query(..., description="Block shard"),
Expand All @@ -94,7 +65,7 @@ async def get_transactions_in_block(
db_transactions = await db.run_sync(crud.get_transactions_in_block, workchain, shard, seqno, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getChainLastTransactions', response_model=List[schemas.Transaction])
@router.get('/getChainLastTransactions', response_model=List[schemas.Transaction])
async def get_chain_last_transactions(
workchain: Optional[int] = Query(..., description="Transactions workchain"),
start_utime: Optional[int] = Query(None, description="UTC timestamp to start searching transactions"),
Expand All @@ -110,7 +81,7 @@ async def get_chain_last_transactions(
db_transactions = await db.run_sync(crud.get_chain_last_transactions, workchain, start_utime, end_utime, limit, offset, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getInMessageByTxID', response_model=Optional[schemas.Message], deprecated=True)
@router.get('/getInMessageByTxID', response_model=Optional[schemas.Message], deprecated=True)
async def get_in_message_by_transaction(
tx_lt: int = Query(..., description="Logical time of transaction"),
tx_hash: str = Query(..., description="Transaction hash"),
Expand All @@ -120,10 +91,10 @@ async def get_in_message_by_transaction(
"""
Deprecated in favor of `getTransactionByHash`.
"""
db_message = await db.run_sync(crud.get_in_message_by_transaction, tx_lt, tx_hash, include_msg_body)
db_message = await db.run_sync(crud.get_in_message_by_transaction_Deprecated, tx_lt, tx_hash, include_msg_body)
return schemas.Message.message_from_orm(db_message, include_msg_body) if db_message else None

@app.get('/getOutMessagesByTxID', response_model=List[schemas.Message], deprecated=True)
@router.get('/getOutMessagesByTxID', response_model=List[schemas.Message], deprecated=True)
async def get_out_message_by_transaction(
tx_lt: int = Query(..., description="Transaction logical time"),
tx_hash: str = Query(..., description="Transaction hash"),
Expand All @@ -133,10 +104,10 @@ async def get_out_message_by_transaction(
"""
Deprecated in favor of `getTransactionByHash`.
"""
db_messages = await db.run_sync(crud.get_out_messages_by_transaction, tx_lt, tx_hash, include_msg_body)
db_messages = await db.run_sync(crud.get_out_messages_by_transaction_Deprecated, tx_lt, tx_hash, include_msg_body)
return [schemas.Message.message_from_orm(m, include_msg_body) for m in db_messages]

@app.get('/getMessageByHash', response_model=List[schemas.Message])
@router.get('/getMessageByHash', response_model=List[schemas.Message])
async def get_message_by_hash(
msg_hash: str = Query(..., description="Message hash"),
include_msg_body: bool = Query(False, description="Whether return full message body or not"),
Expand All @@ -145,7 +116,7 @@ async def get_message_by_hash(
db_messages = await db.run_sync(crud.get_messages_by_hash, msg_hash, include_msg_body)
return [schemas.Message.message_from_orm(m, include_msg_body) for m in db_messages]

@app.get('/getTransactionByHash', response_model=List[schemas.Transaction])
@router.get('/getTransactionByHash', response_model=List[schemas.Transaction])
async def get_transaction_by_hash(
tx_hash: str = Query(..., description="Transaction hash"),
include_msg_body: bool = Query(False, description="Whether return full message body or not"),
Expand All @@ -154,15 +125,15 @@ async def get_transaction_by_hash(
db_transactions = await db.run_sync(crud.get_transactions_by_hash, tx_hash, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getBlockByTransaction', response_model=schemas.Block)
@router.get('/getBlockByTransaction', response_model=schemas.Block)
async def get_block_by_transaction(
tx_hash: str = Query(..., description="Transaction hash"),
db: Session = Depends(get_db)
):
block = await db.run_sync(crud.get_block_by_transaction, tx_hash)
return schemas.Block.block_from_orm_block_header(block)

@app.get('/lookupMasterchainBlock', response_model=schemas.Block)
@router.get('/lookupMasterchainBlock', response_model=schemas.Block)
async def lookup_masterchain_block(
workchain: int,
shard: int,
Expand All @@ -177,7 +148,7 @@ async def lookup_masterchain_block(
mc_block = await db.run_sync(crud.lookup_masterchain_block, workchain, shard, seqno)
return schemas.Block.block_from_orm_block_header(mc_block)

@app.get('/getTransactionByInMessageHash', response_model=List[schemas.Transaction])
@router.get('/getTransactionByInMessageHash', response_model=List[schemas.Transaction])
async def get_transaction_by_in_message_hash(
msg_hash: str = Query(..., description="Transaction hash"),
include_msg_body: bool = Query(False, description="Whether return full message body or not"),
Expand All @@ -186,7 +157,7 @@ async def get_transaction_by_in_message_hash(
db_transactions = await db.run_sync(crud.get_transactions_by_in_message_hash, msg_hash, include_msg_body)
return [schemas.Transaction.transaction_from_orm(t, include_msg_body) for t in db_transactions]

@app.get('/getSourceTransactionByMessage', response_model=schemas.Transaction)
@router.get('/getSourceTransactionByMessage', response_model=schemas.Transaction)
async def get_source_transaction_by_message(
source: str = Query(..., description="Source address"),
destination: str = Query(..., description="Destination address"),
Expand All @@ -199,7 +170,7 @@ async def get_source_transaction_by_message(
db_transaction = await db.run_sync(crud.get_source_transaction_by_message, source, destination, msg_lt)
return schemas.Transaction.transaction_from_orm(db_transaction, True)

@app.get('/getDestinationTransactionByMessage', response_model=schemas.Transaction)
@router.get('/getDestinationTransactionByMessage', response_model=schemas.Transaction)
async def get_destination_transaction_by_message(
source: str = Query(..., description="Sender address"),
destination: str = Query(..., description="Receiver address"),
Expand All @@ -213,7 +184,7 @@ async def get_destination_transaction_by_message(
return schemas.Transaction.transaction_from_orm(db_transaction, True)


@app.get('/getBlocksByUnixTime', response_model=List[schemas.Block])
@router.get('/getBlocksByUnixTime', response_model=List[schemas.Block])
async def get_blocks_by_unix_time(
start_utime: Optional[int] = Query(None, description="UTC timestamp to start searching blocks"),
end_utime: Optional[int] = Query(None, description="UTC timestamp to stop searching blocks. If not specified latest blocks are returned."),
Expand All @@ -227,7 +198,8 @@ async def get_blocks_by_unix_time(
db_blocks = await db.run_sync(crud.get_blocks_by_unix_time, start_utime, end_utime, workchain, shard, limit, offset, sort)
return [schemas.Block.block_from_orm_block_header(b) for b in db_blocks]

@app.get('/getActiveAccountsCountInPeriod', response_model=schemas.CountResponse)

@router.get('/getActiveAccountsCountInPeriod', response_model=schemas.CountResponse)
async def get_active_accounts_count_in_period(
start_utime: int = Query(..., description="UTC timestamp of period start"),
end_utime: Optional[int] = Query(None, description="UTC timestamp of period end. If not specified now time is used."),
Expand Down
6 changes: 4 additions & 2 deletions webserver/schemas.py → api/api_v0/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from pydantic import BaseModel, Field

from pytonlib.utils.address import detect_address

class Block(BaseModel):
workchain: int
shard: str
Expand Down Expand Up @@ -41,8 +43,8 @@ class Message(BaseModel):
@classmethod
def message_from_orm(cls, obj, include_msg_bodies):
return Message(
source=obj.source,
destination=obj.destination,
source=detect_address(obj.source)["bounceable"]["b64url"] if len(obj.source) else '',
destination=detect_address(obj.destination)["bounceable"]["b64url"] if len(obj.destination) else '',
value=obj.value,
fwd_fee=obj.fwd_fee,
ihr_fee=obj.ihr_fee,
Expand Down
Empty file added api/api_v1/__init__.py
Empty file.
Loading

0 comments on commit 28b9c27

Please sign in to comment.