developing

This commit is contained in:
wystan_rin 2024-11-11 18:23:57 +08:00
parent fd17cc9c04
commit c31591484c
12 changed files with 255 additions and 127 deletions

7
app.py Normal file
View File

@ -0,0 +1,7 @@
from flask import Flask
from config import get_config
config = get_config()
app = Flask(__name__)

View File

@ -1 +1 @@
import settings
from .utils import get_config

12
config/param.ini Normal file
View File

@ -0,0 +1,12 @@
[APIKey]
tronscan=cc87d361-7cd6-4f69-a57b-f0a77a213355
[PaymentAddresses]
usdt=TB592A5QwHvvcJoCmvALmzT3S9Pux91Gub
[MYSQL]
user: 'your_mysql_username'
password: 'your_mysql_password'
host: 'localhost'
database: 'your_database_name'
autocommit: false

View File

@ -1,113 +0,0 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project payment
@File __init__.py.py
@IDE PyCharm
@Author rengengchen
@Time 2024/11/06 16:11
"""
import argparse
import os
import random
import sys
from argparse import Namespace
from configparser import ConfigParser
import requests
from loguru import logger
random_seed = 20240717
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def setup_seed(seed):
# import torch
# torch.manual_seed(seed)
# torch.cuda.manual_seed_all(seed)
# torch.backends.cudnn.deterministic = True
# import numpy as np
# np.random.seed(seed)
random.seed(seed)
setup_seed(random_seed)
class Config:
def __init__(self,
config_parser: ConfigParser = None,
argument_parser: Namespace = None,
**kwargs):
if argument_parser:
for k in vars(argument_parser):
kwargs[k] = getattr(argument_parser, k)
if config_parser:
kwargs1 = kwargs.copy()
for section in config_parser.sections():
section1 = kwargs.setdefault(section, Config(**kwargs1))
for option in config_parser.options(section):
section1[option] = config_parser.get(section, option)
self.config = {k: Config(**v) if isinstance(v, dict) else v for k, v in kwargs.items()}
def refresh(self, **kwargs):
kwargs = {k: Config(**v) if isinstance(v, dict) else v for k, v in kwargs.items()}
self.config.update(kwargs)
def get(self, item, default=None):
if item in self.config:
return self.config[item]
return default
def get_int(self, item):
v = self.get(item)
if v is not None:
return int(v)
def get_float(self, item):
v = self.get(item)
if v is not None:
return float(v)
def get_bool(self, item):
v = self.get(item)
if v is not None:
return bool(v)
def __getitem__(self, item):
return self.config[item]
def __setitem__(self, key, value):
self.config[key] = value
def __getattr__(self, key):
if key in self.__dict__:
return self.__dict__[key]
try:
return self.config[key]
except KeyError:
raise AttributeError(f"'{self}' object has no attribute '{key}'")
def __str__(self):
return str(self.config)
def log_config(config):
# fmt = '%(asctime)s [%(name)s] %(levelname)s: %(message)s'
# datefmt = "%Y-%m-%d %H:%M:%S"
logger.remove()
logger.add(sys.stdout, level=config.log_level)
logger.add(sys.stderr, level="ERROR")
logger.add(os.path.join(ROOT_DIR, "logs", "{time}.log"), level="DEBUG", encoding='utf8', rotation="100 MB", retention=3)
def get_config() -> Config:
requests.adapters.DEFAULT_RETRIES = 3
configparser = ConfigParser()
configparser.read(fr'{ROOT_DIR}/config_file/param.conf')
parser = argparse.ArgumentParser(description='payment system')
parser.add_argument("--seed", type=int, default=2024)
args = parser.parse_args()
config = Config(configparser, args)
return config

145
config/utils.py Normal file
View File

@ -0,0 +1,145 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project payment
@File __init__.py.py
@IDE PyCharm
@Author rengengchen
@Time 2024/11/06 16:11
"""
import argparse
import os
import random
import sys
from argparse import Namespace
from configparser import ConfigParser
import requests
from loguru import logger
random_seed = 20240717
ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
def setup_seed(seed):
# import torch
# torch.manual_seed(seed)
# torch.cuda.manual_seed_all(seed)
# torch.backends.cudnn.deterministic = True
# import numpy as np
# np.random.seed(seed)
random.seed(seed)
setup_seed(random_seed)
class Setting:
def __init__(self,
config_parser: ConfigParser = None,
argument_parser: Namespace = None,
_visited=None,
_parent=None,
**kwargs):
self._parent = _parent
if config_parser:
for section in config_parser.sections():
section_config = Setting(_parent=self)
for option in config_parser.options(section):
section_config[option] = config_parser.get(section, option)
self.__dict__[section] = section_config
if argument_parser:
for k in vars(argument_parser):
self.__dict__[k] = getattr(argument_parser, k)
if _visited is None:
_visited = set()
self.update(_visited=_visited, **kwargs)
def update(self, _visited=None, **kwargs):
if _visited is None:
_visited = {}
for k, v in kwargs.items():
cls_attr = getattr(self.__class__, k, None)
if callable(cls_attr):
raise KeyError(f"The key '{k}' conflicts with an existing class method. you can use {k}_ instead.")
if isinstance(v, dict):
obj_id = id(v)
if obj_id in _visited:
logger.warning(f"Circular reference detected in key: '{k}'.")
v = _visited[obj_id]
else:
v = Setting(_visited=_visited, _parent=self, **v)
_visited[obj_id] = v
self.__dict__[k] = v
def get(self, item, default=None):
if item not in self.__dict__ and self._parent is not None:
return self._parent.get(item, default)
return default
def get_int(self, item):
return int(self.get(item))
def get_float(self, item):
return float(self.get(item))
def get_bool(self, item):
return bool(self.get(item))
def set(self, item, value):
self.__dict__[item] = value
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __getattr__(self, key):
return self.get(key)
def __str__(self):
def _str_helper(config, indent=0, visited=None):
if visited is None:
visited = set()
lines = []
indent_str = ' ' * indent
for key, value in config.__dict__.items():
if key.startswith('_'):
continue
if isinstance(value, Setting):
if id(value) in visited:
lines.append(f"{indent_str}{key}: <Circular Reference>")
else:
visited.add(id(value))
lines.append(f"{indent_str}{key}:")
lines.append(_str_helper(value, indent + 1, visited))
else:
lines.append(f"{indent_str}{key}: {value}")
return '\n'.join(lines)
return _str_helper(self)
def log_config(config):
# fmt = '%(asctime)s [%(name)s] %(levelname)s: %(message)s'
# datefmt = "%Y-%m-%d %H:%M:%S"
logger.remove()
logger.add(sys.stdout, level=config.log_level)
logger.add(sys.stderr, level="ERROR")
logger.add(os.path.join(ROOT_DIR, "logs", "{time}.log"), level="DEBUG", encoding='utf8', rotation="100 MB",
retention=3)
def get_config(config_file=fr'{ROOT_DIR}/config/param.ini') -> Setting:
requests.adapters.DEFAULT_RETRIES = 3
configparser = ConfigParser()
configparser.read(config_file)
parser = argparse.ArgumentParser(description='payment system')
parser.add_argument("--seed", type=int, default=2024)
args = parser.parse_args()
config = Setting(configparser, args)
return config

View File

View File

@ -1,20 +1,41 @@
from ruamel_yaml.util import create_timestamp
from custom_decorators import singleton
from database import Database
from utils.datetime import current_timestamp
@singleton
class OrderRepository:
def __init__(self):
self.db = None
def __init__(self, config):
self.db = Database(config['MYSQL'])
def create(self, order_id, from_address, to_address):
create_time = create_timestamp()
pass
cur_time = current_timestamp()
try:
self.db.execute_query(
"INSERT INTO orders (order_id, from_address, to_address, create_timestamp, update_timestamp) "
"VALUES (%s, %s, %s, %s, %s)",
[order_id, from_address, to_address, cur_time, cur_time]
)
self.db.commit()
except Exception:
self.db.rollback()
raise
def update_status(self, order_id, status):
# 更新状态和时间
pass
try:
self.db.execute_query("UPDATE orders "
"SET status = %s, update_timestamp = %s "
"WHERE order_id = %s",
[status, current_timestamp(), order_id])
self.db.commit()
except Exception:
self.db.rollback()
raise
def get_order_info(self, order_id):
pass
self.db.execute_query("SELECT quant, from_address, to_address, create_timestamp "
"FROM orders "
"WHERE order_id = %s",
[order_id])

40
repositories/user.py Normal file
View File

@ -0,0 +1,40 @@
from custom_decorators import singleton
from database import Database
from utils.database import pack_params
@singleton
class UserRepository:
def __init__(self, config):
self.db = Database(config['MYSQL'])
def get_user(self, phone=None, email=None, address=None):
params_sql, params = pack_params(phone=phone, email=email, address=address)
sql = f"SELECT name, phone, email, address FROM user WHERE {params_sql}"
cursor = self.db.execute_query(sql, params)
users = cursor.fetchall()
return users
def create_user(self, phone=None, email=None, address=None):
_, params = pack_params(phone=phone, email=email, address=address)
sql = f"INSERT INTO user (phone, email, address) VALUES (%s, %s, %s)"
self.db.execute_query(sql, params)
self.db.commit()
def record_exists(self, phone=None, email=None, address=None):
params_sql, params = pack_params(phone=phone, email=email, address=address)
sql = f"SELECT EXISTS(SELECT 1 FROM user WHERE {params_sql} LIMIT 1)"
cursor = self.db.execute_query(sql, params)
result = cursor.fetchone()
return bool(result[0])
def create_if_not_exists(self, phone=None, email=None, address=None):
if not self.record_exists(phone=phone, email=email, address=address):
self.create_user(phone=phone, email=email, address=address)
def get_and_create_if_not_exists(self, phone=None, email=None, address=None):
users = self.get_user(phone=phone, email=email, address=address)
if len(users) == 0:
self.create_user(phone=phone, email=email, address=address)
else:
return users

View File

@ -8,11 +8,11 @@ from utils.datetime import current, current_timestamp, is_time_difference_greate
@singleton
class OrderService:
def __init__(self):
self.order_repo = OrderRepository()
def __init__(self, config):
self.order_repo = OrderRepository(config)
self.payment_service = PaymentService()
def create_order(self, from_address, to_address, *args, **kwargs):
def create_order(self, from_address, to_address):
date_str = current().strftime('%Y%m%d%H%M%S')
unique_id = str(uuid.uuid4()).split('-')[0]
order_id = f"{date_str}-{unique_id}"
@ -21,14 +21,14 @@ class OrderService:
def finish_order(self, order_id):
# 判断支付时间是否超过订单存活时间
quant, from_address, to_address, creation_timestamp = self.order_repo.get_order_info(order_id)
quant, from_address, to_address, create_timestamp = self.order_repo.get_order_info(order_id)
current = current_timestamp()
status = 0
if is_time_difference_greater_than(creation_timestamp, current, minutes=15):
if is_time_difference_greater_than(create_timestamp, current, minutes=15):
# 订单超时
status = 4
else:
correct_quant, confirmed = self.payment_service.check_payment(quant, from_address, to_address, creation_timestamp, current)
correct_quant, confirmed = self.payment_service.check_payment(quant, from_address, to_address, create_timestamp, current)
if correct_quant and confirmed:
# 支付成功
status = 1

6
services/user.py Normal file
View File

@ -0,0 +1,6 @@
from custom_decorators import singleton
@singleton
class UserService:
pass

10
utils/database.py Normal file
View File

@ -0,0 +1,10 @@
def pack_params(**kwargs):
params = []
param_sqls = []
flag = False
for k, v in kwargs.items():
flag = True
params.append(v)
param_sqls.append(f"{k}=%s")
if flag:
return " AND ".join(param_sqls), params