developing

This commit is contained in:
wystan_rin 2024-11-10 18:00:58 +08:00
parent f2d37cb5ca
commit 5c8f1acace
11 changed files with 208 additions and 12 deletions

0
__init__.py Normal file
View File

View File

@ -1,5 +1,7 @@
import requests import requests
from custom_decorators import singleton
trc20token_info = { trc20token_info = {
"usdt": {"tokenId": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "usdt": {"tokenId": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"tokenAbbr": "USDT", "tokenAbbr": "USDT",
@ -9,7 +11,7 @@ trc20token_info = {
"vip": True} "vip": True}
} }
@singleton
class Tronscan: class Tronscan:
def __init__(self, api_key): def __init__(self, api_key):
self.api_key = api_key self.api_key = api_key
@ -25,19 +27,19 @@ class Tronscan:
return response.json() return response.json()
def transactions(self, start=0, limit=10, start_timestamp=None, end_timestamp=None, def transactions(self, start=0, limit=10, start_timestamp=None, end_timestamp=None,
fromAddress=None, toAddress=None, tokens=None, block=None, from_address=None, to_address=None, tokens=None, block=None,
type=None, method=None): type_=None, method=None):
""" """
Get a list of transactions. Get a list of transactions.
:param start: Start number. Default 0 :param start: Start number. Default 0
:param limit: Number of items per page. Default 10 :param limit: Number of items per page. Default 10
:param start_timestamp: Start time :param start_timestamp: Start time
:param end_timestamp: End time :param end_timestamp: End time
:param fromAddress: Sender's address. :param from_address: Sender's address.
:param toAddress: Recipient's address. :param to_address: Recipient's address.
:param tokens: Tokens involved :param tokens: Tokens involved
:param block: Block :param block: Block
:param type: Transaction type :param type_: Transaction type
:param method: Method called in a smart contract signature. Only one value can be specified each time. :param method: Method called in a smart contract signature. Only one value can be specified each time.
:return: Getx a list of transactions. :return: Getx a list of transactions.
""" """
@ -52,16 +54,16 @@ class Tronscan:
params["start_timestamp"] = start_timestamp params["start_timestamp"] = start_timestamp
if end_timestamp is not None: if end_timestamp is not None:
params["end_timestamp"] = end_timestamp params["end_timestamp"] = end_timestamp
if fromAddress is not None: if from_address is not None:
params["fromAddress"] = fromAddress params["fromAddress"] = from_address
if toAddress is not None: if to_address is not None:
params["toAddress"] = toAddress params["toAddress"] = to_address
if tokens is not None: if tokens is not None:
params["tokens"] = tokens params["tokens"] = tokens
if block is not None: if block is not None:
params["block"] = block params["block"] = block
if type is not None: if type_ is not None:
params["type"] = type params["type"] = type_
if method is not None: if method is not None:
params["method"] = method params["method"] = method

7
config/db.py Normal file
View File

@ -0,0 +1,7 @@
config = {
'user': 'your_mysql_username',
'password': 'your_mysql_password',
'host': 'localhost',
'database': 'your_database_name',
'autocommit': False,
}

17
custom_decorators.py Normal file
View File

@ -0,0 +1,17 @@
def singleton(cls):
"""
Decorator for making a class a singleton.
This ensures that only one instance of the class exists.
"""
instances = {} # Dictionary to store the instance of the singleton class
def get_instance(*args, **kwargs):
"""
If an instance of the class does not exist, create one and store it.
If it exists, return the existing instance.
"""
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance

17
repositories/order.py Normal file
View File

@ -0,0 +1,17 @@
from custom_decorators import singleton
@singleton
class OrderRepository:
def __init__(self):
self.db = None
def create(self, order_id, from_address, to_address):
pass
def update_status(self, order_id, status):
# 更新状态和时间
pass
def get_creation_time(self, order_id):
pass

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
loguru==0.7.2
mysql-connector-python==9.1.0
Requests==2.32.3

28
services/order.py Normal file
View File

@ -0,0 +1,28 @@
import uuid
from custom_decorators import singleton
from repositories.order import OrderRepository
from utils.datetime import current, current_timestamp, is_time_difference_greater_than
@singleton
class OrderService:
def __init__(self):
self.order_repo = OrderRepository()
def create_order(self, from_address, to_address, *args, **kwargs):
date_str = current().strftime('%Y%m%d%H%M%S')
unique_id = str(uuid.uuid4()).split('-')[0]
order_id = f"{date_str}-{unique_id}"
self.order_repo.create(order_id, from_address, to_address)
return order_id
def finish_order(self, order_id):
# 判断支付时间是否超过订单存活时间
order_creation_time = self.order_repo.get_creation_time(order_id)
if is_time_difference_greater_than(current_timestamp(), order_creation_time, minutes=15):
status = 2
else:
status = 1
self.order_repo.update_status(order_id, status)
return status

21
services/payment.py Normal file
View File

@ -0,0 +1,21 @@
from api import Tronscan
from custom_decorators import singleton
from utils.datetime import current_timestamp
@singleton
class Payment:
def __init__(self, api_key):
self.tronscan = Tronscan(api_key)
def check_payment(self, quant, from_address, to_address, order_create_timestamp):
result = self.tronscan.token_trc20_transfers(from_address=from_address,
to_address=to_address,
start_timestamp=order_create_timestamp,
end_timestamp=int(current_timestamp() * 1000))
token_transfers = result['token_transfers']
token_transfer = token_transfers[-1]
confirmed = token_transfer['confirmed']
correct_quant = quant == (token_transfer['quant'] / 6)
confirmed = confirmed and correct_quant
return confirmed

0
utils/__init__.py Normal file
View File

35
utils/datetime.py Normal file
View File

@ -0,0 +1,35 @@
import datetime
def current():
return datetime.datetime.now()
def current_timestamp():
datetime.datetime.now().timestamp()
def is_time_difference_greater_than(timestamp1, timestamp2, hours=0, minutes=0, seconds=0):
"""
判断两个时间戳的时间差是否大于指定的小时分钟和秒数
参数:
timestamp1 (int): 第一个时间戳
timestamp2 (int): 第二个时间戳
hours (int): 要比较的小时数默认是0小时
minutes (int): 要比较的分钟数默认是0分钟
seconds (int): 要比较的秒数默认是0秒
返回:
bool: 如果时间差大于指定的小时分钟和秒数返回True否则返回False
"""
# 将时间戳转换为 datetime 对象
time1 = datetime.fromtimestamp(timestamp1)
time2 = datetime.fromtimestamp(timestamp2)
# 计算时间差
time_difference = abs(time2 - time1)
# 计算指定的时间差值
threshold = datetime.timedelta(hours=hours, minutes=minutes, seconds=seconds)
# 判断时间差是否大于指定的时间
return time_difference > threshold

66
utils/db_connection.py Normal file
View File

@ -0,0 +1,66 @@
from loguru import logger
from mysql.connector import connect, Error, OperationalError
from mysql.connector import errors as db_errors
from custom_decorators import singleton
@singleton
class Database:
def __init__(self, config):
self.connection = None
self.config = config
self.connect()
def connect(self):
"""Establish a new database connection."""
try:
self.connection = connect(**self.config)
if self.connection.is_connected():
logger.info("Connected to MySQL database")
except Error as e:
logger.info(f"Error while connecting to MySQL: {e}")
self.connection = None
def get_connection(self):
"""Get the database connection, with reconnection logic."""
if self.connection is None or not self.connection.is_connected():
logger.info("Reconnecting to the database...")
self.connect()
return self.connection
def close_connection(self):
if self.connection and self.connection.is_connected():
self.connection.close()
logger.info("MySQL connection is closed")
def execute_query(self, query, params=None):
"""Execute a query with optional parameters, supports transactions."""
cursor = None
try:
connection = self.get_connection()
cursor = connection.cursor()
cursor.execute(query, params)
return cursor
except OperationalError as e:
logger.info(f"Operational error: {e}. Attempting to reconnect...")
self.connect()
cursor = self.get_connection().cursor()
cursor.execute(query, params)
return cursor
except db_errors.Error as e:
logger.info(f"Database error: {e}")
raise
finally:
if cursor:
cursor.close()
def commit(self):
"""Commit the current transaction."""
if self.connection:
self.connection.commit()
def rollback(self):
"""Rollback the current transaction."""
if self.connection:
self.connection.rollback()