fastapi/main.py

139 lines
5.8 KiB
Python
Executable File

from typing import Optional, Union
from urllib.parse import urlparse
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import time, socket
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import QueuePool
import uvicorn
#local
from rpcs import RPCHost, RPCXMR
from models import Return
from meta import Queue
from functions import checksumCheck, validDns
import config
class ErrorException(Exception):
def __init__(self, code: str, status: str, status_message: str):
self.status = status
self.code = code
self.status_message = status_message
app = FastAPI()
@app.get("/")
def root():
return
@app.exception_handler(ErrorException)
def unicorn_exception_handler(request: Request, exc: ErrorException):
return JSONResponse(
status_code=exc.code,
content={
"status": f"{exc.status}",
"message": f"{exc.status_message}"
},
)
@app.get("/api/receive")
def receive(method: str, address: str, callback: Union[str, None] = None):
if not method:
raise ErrorException(code=422,status="error",status_message='Empty method used')
if not address:
raise ErrorException(code=422,status="error",status_message='Empty destination address')
if method.lower() not in ['btc', 'btct', 'ltc', 'doge', 'zec', 'bch', 'xmr']:
raise ErrorException(code=422,status="error",status_message='Invalid method used')
if checksumCheck(method.lower(), address) == False:
raise ErrorException(code=422,status="error",status_message='Invalid Destination Address')
if callback:
try:
data = urlparse(callback)
#scheme validation
if data.scheme == 'http' or data.scheme == 'https':
#domain validation
if validDns(data.netloc) != True:
raise ErrorException(code=422,status="error",status_message='Invalid callback: domain name does not resolve')
else:
raise ErrorException(code=422,status="error",status_message='Invalid callback: wrong url scheme, we accept http or https only')
except:
callback = 'None'
callback_req_n = 0
else:
callback = 'None'
callback_req_n = 1
## RPC connection to Demons
match method.upper():
case 'BTC' | 'LTC' | 'ZEC' | 'BCH' | 'BTCT' | 'DOGE':
rpc = RPCHost("http://%s:%s@%s:%s" % (config.rpcs[method.upper()]['user'], config.rpcs[method.upper()]['pass'], config.rpcs[method.upper()]['host'], config.rpcs[method.upper()]['port']))
case 'XMR':
rpc = RPCXMR(config.rpcs[method.upper()]['host'], config.rpcs[method.upper()]['user'], config.rpcs[method.upper()]['pass'])
case _:
raise ErrorException(code=422,status="error",status_message='RPC undergoing maintenance')
## checking if wallet is loaded
# wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False)
try:
match method.upper():
case 'XMR':
wallet = rpc.call('create_address',{"account_index": 0})
wallet = wallet['address']
case 'LTC' | 'ZEC' | 'DOGE':
#wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,False,True)
wallet = rpc.call('getnewaddress')
case 'BTC' | 'BTCT':
#wallet = rpc.call('createwallet','test',False,False,'exdTHnRJ1BxZfBvU',False,True,True,False)
wallet = rpc.call('getnewaddress','', 'p2sh-segwit')
case 'BCH':
wallet = rpc.call('getnewaddress')
wallet = wallet.replace('bitcoincash:', '')
case _:
## notify admin about the error
raise ErrorException(code=422, status="error", status_message='RPC unavailable')
except Exception as error:
## notify admin about the error
# Failed to connect for remote procedure call.
raise ErrorException(code=422, status="error", status_message='Failed to connect for remote procedure call.')
## SQL Connection with SQLAlchemy
engine = create_engine(
"mysql+pymysql://%s:%s@%s:%s/dev" % (config.DB['user'], config.DB['pass'], config.DB['host'], config.DB['port']),
poolclass=QueuePool,
#echo=True, #debug sqlalchemy
pool_size=4,
max_overflow=0,
pool_timeout=15, # Wait 15s for a connection
)
Session = sessionmaker(bind = engine)
session = Session()
if wallet:
try:
q = Queue(txhash = 'None', time = int(time.time()), account = method.upper(), fee = config.fee['REGULAR'][method.upper()], ready = 0, confirmations =0, callbackurl = callback, generated_address = wallet, destination = address, balance_received = '0.00000000', callback_req = callback_req_n, ip = socket.gethostbyname(socket.gethostname()) , hostname = socket.gethostname(), merchantId = 'None', dateTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
session.add(q)
session.commit()
session.close()
except Exception as error:
## notify admin about the error
raise ErrorException(code=422,status="error",status_message='Invalid response from dbServer')
else:
## notify admin about the error
raise ErrorException(code=422,status="error",status_message='Invalid response from rpcServer')
return Return(
address = wallet,
destination = address,
callback_url = callback,
fee = config.fee['REGULAR'][method.upper()],
status = 'success'
)
# Run
if __name__ == '__main__':
uvicorn.run('main:app', host='0.0.0.0')
#workers=4 (doesn't work with reload)