This commit is contained in:
Your Name
2026-02-13 22:59:13 +08:00
parent 984223c720
commit e28338f34d
13925 changed files with 385 additions and 154 deletions

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python3
"""
为 tg_phone_devices_copy1 表添加 tg_web_app_data 列(若不存在)。
解决: Unknown column 't1.tg_web_app_data' in 'field list'
"""
import sys
from pathlib import Path
project_root = Path(__file__).resolve().parent.parent
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from models.tg_models import db
TABLE = "tg_phone_devices_copy1"
COLUMN = "tg_web_app_data"
SPEC = "VARCHAR(2048) NULL COMMENT 'Blum WebApp tgWebAppData token'"
def column_exists(cursor, table, column):
cursor.execute(
"""
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = %s
AND COLUMN_NAME = %s
""",
(table, column),
)
return cursor.fetchone()[0] > 0
def main():
if not db.is_closed():
db.connect()
try:
with db.connection() as conn:
cursor = conn.cursor()
if column_exists(cursor, TABLE, COLUMN):
print(f"{TABLE} 已存在列 {COLUMN},无需添加。")
return
sql = f"ALTER TABLE `{TABLE}` ADD COLUMN `{COLUMN}` {SPEC};"
cursor.execute(sql)
print(f"已在表 {TABLE} 添加列 {COLUMN}")
finally:
if not db.is_closed():
try:
db.close()
except Exception:
pass
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""
为 SQLite haha.db 中 tg_phone_devices_copy1 表添加 tg_web_app_data 列(若不存在)。
解决 踢设备.py 报错: no such column: t1.tg_web_app_data
"""
import sys
from pathlib import Path
project_root = Path(__file__).resolve().parent.parent
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
from models.tg_phone_devices import db
TABLE = "tg_phone_devices_copy1"
COLUMN = "tg_web_app_data"
def column_exists_sqlite(cursor, table, column):
cursor.execute("PRAGMA table_info({})".format(table))
return any(row[1] == column for row in cursor.fetchall())
def main():
db.connect()
try:
with db.connection() as conn:
cursor = conn.cursor()
cursor.execute("PRAGMA table_info({})".format(TABLE))
if any(row[1] == COLUMN for row in cursor.fetchall()):
print(f"{TABLE} 已存在列 {COLUMN},无需添加。")
return
cursor.execute("ALTER TABLE {} ADD COLUMN {} TEXT".format(TABLE, COLUMN))
print(f"已在表 {TABLE}SQLite添加列 {COLUMN}")
finally:
if not db.is_closed():
try:
db.close()
except Exception:
pass
if __name__ == "__main__":
main()

View File

@@ -1,26 +1,136 @@
from peewee import *
from pathlib import Path
from datetime import datetime
import threading
import time
import pymysql
from peewee import MySQLDatabase
from playhouse.pool import PooledMySQLDatabase
# 安装 pymysql 作为 MySQLdb
pymysql.install_as_MySQLdb()
# 断连相关的 MySQL 错误码
_RETRY_ERRORS = (
0, # InterfaceError: (0, '')
2006, # MySQL server has gone away
2013, # Lost connection to MySQL server during query
)
class SingleConnectionMySQLDatabase(MySQLDatabase):
"""
多线程共用一个 MySQL 连接:
- 使用 thread_safe=False 让所有线程共享同一个 _state一个连接
- 用 RLock 串行化所有 connect/close/execute_sql保证同一时刻只有一个线程在用连接
"""
def __init__(self, *args, **kwargs):
# thread_safe=False → _state 为共享的 _ConnectionState不按线程隔离
super().__init__(*args, thread_safe=False, **kwargs)
self._lock = threading.RLock()
def connect(self, reuse_if_open=False):
with self._lock:
if self.deferred:
raise InterfaceError('Error, database must be initialized before opening a connection.')
conn = self._state.conn
if conn is not None and not self._state.closed:
if reuse_if_open:
return False
try:
conn.ping(reconnect=True)
except Exception:
try:
self._close(conn)
except Exception:
pass
self._state.reset()
if self._state.closed:
self._state.reset()
try:
self._state.set_connection(self._connect())
if self.server_version is None:
self._set_server_version(self._state.conn)
self._initialize_connection(self._state.conn)
except Exception:
self._state.reset()
raise
return True
def execute_sql(self, sql, params=None, commit=True):
with self._lock:
try:
return super().execute_sql(sql, params, commit)
except (OperationalError, InterfaceError) as e:
err_code = getattr(e, 'args', (None,))[0]
if err_code in _RETRY_ERRORS or (isinstance(err_code, int) and err_code in _RETRY_ERRORS):
try:
self.close()
except Exception:
pass
return super().execute_sql(sql, params, commit)
raise
def close(self):
with self._lock:
return super().close()
class ReconnectPooledMySQLDatabase(PooledMySQLDatabase):
"""
带自动重连的 MySQL 连接池:
1. 从池中取连接时先 pingping 失败则丢弃并新建连接
2. SQL 执行遇到断连错误时,关闭坏连接并自动重试一次
"""
def _connect(self):
"""新建连接后设置 autocommit避免长事务导致连接被 MySQL 断开。"""
conn = super()._connect()
return conn
def connection(self):
"""取连接时先 ping 探活,不通就关掉让池重新创建。"""
conn = super().connection()
try:
conn.ping(reconnect=True)
except Exception:
# ping 失败,连接已死,关掉让 peewee 重新获取
try:
self.close()
except Exception:
pass
conn = super().connection()
return conn
def execute_sql(self, sql, params=None, commit=True):
"""执行 SQL遇到断连错误自动重试一次。"""
try:
return super().execute_sql(sql, params, commit)
except (OperationalError, InterfaceError) as e:
err_code = getattr(e, 'args', (None,))[0]
if err_code in _RETRY_ERRORS or (isinstance(err_code, int) and err_code in _RETRY_ERRORS):
# 关闭坏连接,下次 connection() 会重新获取
try:
self.close()
except Exception:
pass
# 重试一次
return super().execute_sql(sql, params, commit)
raise
# 数据库配置
db_config = {
'database': 'lm',
'user': 'lm',
'password': 'sAn5MfjKApiTBrx4',
'host': '172.16.197.130',
'port': 3306
'host': '199.168.137.123',
'port': 3309
}
# 全局数据库实例
db = MySQLDatabase(
# 全局数据库实例:多线程共用一个连接(串行化访问,无 MaxConnectionsExceeded
db = SingleConnectionMySQLDatabase(
db_config['database'],
user=db_config['user'],
password=db_config['password'],
@@ -88,6 +198,7 @@ class TgPhoneDevices1(Model):
user = CharField(null=True, ) # 电话号码
pwd = CharField(null=True, ) # 电话号码
device_start = IntegerField(null=True, ) # API ID
tg_web_app_data = CharField(null=True, max_length=2048, help_text='Blum WebApp tgWebAppData token') # Blum token
class Meta:
database = db # 指定数据库