项目更新

This commit is contained in:
hahwu 2025-12-12 11:40:38 +08:00
parent 82158467f9
commit c72667123f
86 changed files with 26087 additions and 1124 deletions

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "kafka comsumer",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/kafka/main.go"
}
]
}

View File

@ -1,4 +1,4 @@
{
"ansible.python.interpreterPath": "c:\\Users\\U\\AppData\\Local\\Microsoft\\WindowsApps\\python3.12.exe",
"workbench.colorTheme":"Quiet Light"
"workbench.colorTheme":"GitHub Dark Colorblind (Beta)"
}

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# 生成一个新的脚本文件
## 生成步骤
1.脚本语言使用python3
2.脚本文件名为`script.py`
3.备份mysql数据库的数据
4.清空mysql数据库的数据
5.清空redis数据库的数据

1
access_token.txt Normal file
View File

@ -0,0 +1 @@
ya29.a0ARW5m75vC6Xu3uPbWDPkCFnfJ20ppzCFfblGfKlCdBxqWvKnMP1w1TX3GO6ylh7IbRrBqh83mSZyS9-fNxjPmI0eynjAH8Z6O-2rcJtaI_s-pBWRJV3FI5rkLeDiMahq7HAHVhJsnIJAqOKZ1M9zL43zrwjUJPxTrMLxzXNdMgaCgYKAdESARISFQHGX2Mis6ycpB32JnANYYLmP25gxA0177

View File

@ -0,0 +1,280 @@
-- MySQL dump 10.13 Distrib 8.0.42, for Linux (x86_64)
--
-- Host: 172.20.0.5 Database: Merge_Pet_1
-- ------------------------------------------------------
-- Server version 8.4.5
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `db_version`
--
DROP TABLE IF EXISTS `db_version`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `db_version` (
`version_2018_02_06_13` int unsigned NOT NULL COMMENT 'version'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='数据库版本号';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `db_version`
--
LOCK TABLES `db_version` WRITE;
/*!40000 ALTER TABLE `db_version` DISABLE KEYS */;
/*!40000 ALTER TABLE `db_version` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `system_mail_info`
--
DROP TABLE IF EXISTS `system_mail_info`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `system_mail_info` (
`mail_id` bigint NOT NULL AUTO_INCREMENT COMMENT '邮件ID',
`title` varchar(128) DEFAULT '' COMMENT '邮件标题',
`content` varchar(2048) DEFAULT '' COMMENT '邮件内容',
`title_en` varchar(128) DEFAULT '' COMMENT '英文邮件标题',
`content_en` varchar(2048) DEFAULT '' COMMENT '英文邮件内容',
`items` varchar(2048) DEFAULT '{}' COMMENT '邮件附件',
`start_time` int unsigned NOT NULL DEFAULT '0' COMMENT '开始时间',
`register_time` int unsigned NOT NULL DEFAULT '0' COMMENT '注册时间',
`end_time` int unsigned NOT NULL DEFAULT '0' COMMENT '结束时间',
`mail_type` int unsigned NOT NULL DEFAULT '0' COMMENT '邮件类型',
`send_type` int unsigned NOT NULL DEFAULT '0' COMMENT '发送类型',
`to_uids` varchar(2048) DEFAULT '' COMMENT '发送者ID',
`create_time` int unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`mail_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统邮件';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `system_mail_info`
--
LOCK TABLES `system_mail_info` WRITE;
/*!40000 ALTER TABLE `system_mail_info` DISABLE KEYS */;
/*!40000 ALTER TABLE `system_mail_info` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_account`
--
DROP TABLE IF EXISTS `t_account`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_account` (
`user_name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
`user_password` varchar(128) COLLATE utf8mb4_general_ci NOT NULL,
`login_time` int unsigned DEFAULT '0' COMMENT '上次登录时间',
`logout_time` int unsigned DEFAULT '0' COMMENT '上次下线时间',
`ip_address` char(24) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '上次登录的ip地址',
`gm_level` int DEFAULT '0' COMMENT 'gm等级',
`platform` varchar(50) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '平台',
`is_online` int unsigned DEFAULT '0' COMMENT '角色是否在线',
`channel` varchar(50) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '渠道号',
`device_id` varchar(256) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '是否为刷榜账号',
`auto_id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增id',
`id_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '""',
`id_num` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '""',
PRIMARY KEY (`auto_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='账号密码对照表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_account`
--
LOCK TABLES `t_account` WRITE;
/*!40000 ALTER TABLE `t_account` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_account` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_gameserver`
--
DROP TABLE IF EXISTS `t_gameserver`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_gameserver` (
`id` int unsigned NOT NULL COMMENT '服务器id',
`start_time` int unsigned DEFAULT NULL COMMENT '开服时间',
`close_time` int unsigned DEFAULT NULL COMMENT '关服时间',
`is_close` int unsigned DEFAULT NULL COMMENT '是否关服',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='服务器设置';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_gameserver`
--
LOCK TABLES `t_gameserver` WRITE;
/*!40000 ALTER TABLE `t_gameserver` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_gameserver` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_player_baseinfo`
--
DROP TABLE IF EXISTS `t_player_baseinfo`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_player_baseinfo` (
`dwUin` bigint unsigned NOT NULL COMMENT '对应玩家account表中的dwUin',
`energy` int unsigned NOT NULL DEFAULT '0' COMMENT '能量',
`star` int unsigned NOT NULL DEFAULT '0' COMMENT '星星',
`recover_time` int unsigned NOT NULL DEFAULT '0' COMMENT '能量开始恢复时间',
`diamond` int unsigned NOT NULL DEFAULT '1' COMMENT '钻石',
`level` int unsigned NOT NULL DEFAULT '0' COMMENT '玩家等级',
`exp` int(10) unsigned zerofill NOT NULL DEFAULT '0000000000' COMMENT '玩家经验',
`start_order_id` varchar(50) DEFAULT NULL COMMENT '配置订单进度',
`music_code` int unsigned NOT NULL DEFAULT '0' COMMENT '音效状态码改为GUID免费改名状态',
`guild` int unsigned NOT NULL DEFAULT '0' COMMENT '引导进度 ',
`pack_unlock_count` int unsigned NOT NULL DEFAULT '0' COMMENT '背包解锁数量',
`last_play_time` int NOT NULL DEFAULT '0' COMMENT '广告能量购买时间',
`EnergyBuyCount` int NOT NULL DEFAULT '0' COMMENT '能量购买次数',
`user_name` varchar(50) NOT NULL DEFAULT '' COMMENT '玩家账号',
`nick_name` varchar(50) NOT NULL DEFAULT '' COMMENT '玩家昵称',
`login_time` int unsigned NOT NULL DEFAULT '0' COMMENT '上次登录时间',
`logout_time` int unsigned NOT NULL DEFAULT '0' COMMENT '上次下线时间',
`todayolinetime` int unsigned NOT NULL DEFAULT '0' COMMENT '当天的累计在线时间',
`rolecreatetime` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`EmitOrderCnt` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`DailyRenewTime` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`NoAd` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`ChampshipsGroupID` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`LastChampGroupID` int unsigned NOT NULL DEFAULT '0' COMMENT '注册帐号时间',
`FaceBookId` varchar(128) DEFAULT '' COMMENT '玩家账号',
PRIMARY KEY (`dwUin`),
KEY `nick_name` (`nick_name`),
KEY `user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='存储玩家基本信息';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_player_baseinfo`
--
LOCK TABLES `t_player_baseinfo` WRITE;
/*!40000 ALTER TABLE `t_player_baseinfo` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_player_baseinfo` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_player_charge`
--
DROP TABLE IF EXISTS `t_player_charge`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_player_charge` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '订单id',
`Uid` bigint unsigned NOT NULL COMMENT '玩家id',
`OrderId` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '订单号',
`ProductId` int unsigned NOT NULL DEFAULT '0' COMMENT '商品id',
`ProductName` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '商品名称',
`ProductDesc` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '商品描述',
`Price` float NOT NULL DEFAULT '0' COMMENT '价格',
`Currency` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '货币',
`CreateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
`PayTime` int unsigned NOT NULL DEFAULT '0' COMMENT '支付时间',
`PayStatus` int unsigned NOT NULL DEFAULT '0' COMMENT '支付状态 0 未支付 1 已支付 2 支付失败 3 已发货',
`PayType` int unsigned NOT NULL DEFAULT '0' COMMENT '支付类型',
`PayPlatform` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '支付平台',
`PayChannel` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '支付渠道',
`PayChannelOrderId` varchar(512) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '支付渠道订单号',
`PayChannelUserId` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '支付渠道用户id',
`PayChannelExtra` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '支付渠道额外信息',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='玩家订单表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_player_charge`
--
LOCK TABLES `t_player_charge` WRITE;
/*!40000 ALTER TABLE `t_player_charge` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_player_charge` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_player_mod`
--
DROP TABLE IF EXISTS `t_player_mod`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_player_mod` (
`dwUin` bigint unsigned NOT NULL COMMENT '玩家uid',
`mData` blob COMMENT '数据',
`updateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`dwUin`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='玩家模块表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_player_mod`
--
LOCK TABLES `t_player_mod` WRITE;
/*!40000 ALTER TABLE `t_player_mod` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_player_mod` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `t_server_mod`
--
DROP TABLE IF EXISTS `t_server_mod`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `t_server_mod` (
`id` int NOT NULL AUTO_INCREMENT,
`key` varchar(128) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '模块key',
`mData` mediumblob COMMENT '数据',
`updateTime` int unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统模块表';
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `t_server_mod`
--
LOCK TABLES `t_server_mod` WRITE;
/*!40000 ALTER TABLE `t_server_mod` DISABLE KEYS */;
/*!40000 ALTER TABLE `t_server_mod` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Dumping routines for database 'Merge_Pet_1'
--
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-07-09 2:47:05

View File

@ -0,0 +1,4 @@
# Redis数据导出
# 导出时间: 2025-07-09 02:47:06.709571
# Redis数据库为空

BIN
dist/verifyOrder vendored Normal file

Binary file not shown.

BIN
dist/verifyOrder.exe vendored Normal file

Binary file not shown.

BIN
dynamicLv_output.xlsx Normal file

Binary file not shown.

59
format_language_csv.py Normal file
View File

@ -0,0 +1,59 @@
import re
import csv
from pathlib import Path
SRC = Path(r"d:\Github\docs\config\LanguageDataTwo.csv")
if not SRC.exists():
print(f"Source not found: {SRC}")
raise SystemExit(1)
# 备份原文件
bak = SRC.with_suffix(SRC.suffix + ".bak")
if not bak.exists():
bak.write_bytes(SRC.read_bytes())
out_rows = []
with SRC.open("r", encoding="utf-8") as f:
for raw in f:
line = raw.rstrip("\n")
if not line.strip():
continue
# 跳过首部注释行(以#开头)
if line.lstrip().startswith("#"):
continue
# 将连续两个或以上空格替换为制表符,便于分割(原文件里有制表或多空格分隔)
norm = re.sub(r"[ \u00A0]{2,}", "\t", line)
# 以制表符分割(如果没有制表符,会退化为按任意空格分割)
parts = [p.strip() for p in re.split(r"\t+", norm)]
# 如果分割后超过4列则把第0,1固定剩下的尽量合并为 English 和 Chinese 两列
if len(parts) >= 4:
id_, key = parts[0], parts[1]
# English 可能包含制表/空格,取中间所有并把最后一列当作中文
eng = " ".join(parts[2:-1]).strip()
chi = parts[-1].strip()
out_rows.append((id_, key, eng, chi))
elif len(parts) == 3:
id_, key, rest = parts
# 无法区分 English / Chinese尝试按中文字符后半部分切分保守策略
m = re.search(r"[\u4e00-\u9fff]+", rest)
if m:
idx = m.start()
eng = rest[:idx].strip()
chi = rest[idx:].strip()
else:
eng = rest
chi = ""
out_rows.append((id_, key, eng, chi))
else:
# 无法解析的行,跳过或记录为备注行
# 记录为空的键以便人工检查
out_rows.append(("", "", line.strip(), ""))
# 写入标准 CSV全部字段用双引号包裹
with SRC.open("w", encoding="utf-8", newline="") as out:
writer = csv.writer(out, quoting=csv.QUOTE_ALL)
writer.writerow(["Id", "key", "English", "ChineseSimplified"])
for r in out_rows:
writer.writerow(r)
print(f"Formatted CSV written to {SRC} (backup at {bak})")

38
getToken.spec Normal file
View File

@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['script\\test.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='getToken',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

View File

@ -53,7 +53,7 @@ func ProcessMsg(SqlDb *sqlx.DB, m kafka.Message) error {
default:
go event(SqlDb, m)
}
offset(SqlDb, m)
// if err != nil {
// tx.Rollback()
// return err
@ -105,3 +105,10 @@ func pay(SqlDb *sqlx.DB, m kafka.Message) error {
}
return err
}
func offset(SqlDb *sqlx.DB, m kafka.Message) error {
sql := " INSERT INTO `log_var` (`Key` , `Value`, `Timestamp`) Values (?,?,?) ON DUPLICATE KEY UPDATE `key` = ? , `Value` = ? ,`Timestamp`=?"
Value := strconv.FormatInt(m.Offset+1, 10)
Timestamp := util.GetNowTime()
_, err := SqlDb.Exec(sql, "offset", Value, Timestamp, "offset", Value, Timestamp)
return err
}

View File

@ -1,57 +1,62 @@
services:
# zoo1:
# image: zookeeper
# hostname: zoo1
# container_name: zoo1
# kafka1:
# image: bitnami/kafka:latest
# hostname: kafka-server-1
# container_name: kafka-server-1
# ports:
# - "2181:2181"
# - "9092:9092"
# - "9093:9093"
# volumes:
# - zoo1_data:/data
# - kafka1_data:/bitnami/kafka
# environment:
# ZOOKEEPER_CLIENT_PORT: 2181
# ZOOKEEPER_SERVER_ID: 1
# ZOOKEEPER_SERVERS: zoo1:2888:3888
kafka1:
# KAFKA_CFG_NODE_ID: 0
# KAFKA_KRAFT_CLUSTER_ID: kafka-cluster
# KAFKA_CFG_BROKER_ID: 0
# KAFKA_CFG_PROCESS_ROLES: controller,broker
# KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
# KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
# KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka-server-1:9093
# KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
kafka2:
image: bitnami/kafka:latest
hostname: kafka-server
container_name: kafka-server
restart: always
hostname: kafka-server-3
container_name: kafka-server-3
ports:
- "9092:9092"
- "9093:9093"
volumes:
- kafka1_data:/bitnami/kafka
- /data/kafka_data:/bitnami/kafka
- /etc/hosts:/etc/hosts:ro # 只读方式挂载 hosts 文件
environment:
KAFKA_CFG_NODE_ID: 0
KAFKA_CFG_PROCESS_ROLES: controller,broker
KAFKA_CFG_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_CFG_NODE_ID: 3
KAFKA_CFG_PROCESS_ROLES: broker
KAFKA_CFG_BROKER_ID: 3
KAFKA_KRAFT_CLUSTER_ID: 5abhbnhATXqNFrXsjiSmKw
KAFKA_CFG_LISTENERS: PLAINTEXT://kafka-server-2:9092
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@kafka-server:9093
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: 0@8.155.14.94:9093
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: CONTROLLER
# KAFKA_CFG_ZOOKEEPER_CONNECT: zoo1:2181
# depends_on:
# - zoo1
kafka-ui:
container_name: kafka-ui
restart: always
image: provectuslabs/kafka-ui:latest
ports:
- 500:8080
depends_on:
- kafka1
environment:
DYNAMIC_CONFIG_ENABLED: "TRUE"
networks:
default:
name: kafka-network
external: true
# - kafka1
# kafka-ui:
# container_name: kafka-ui
# image: provectuslabs/kafka-ui:latest
# ports:
# - "500:8080"
# depends_on:
# - kafka1
# - kafka2
# environment:
# DYNAMIC_CONFIG_ENABLED: "TRUE"
# networks:
# default:
# name: bridage
# external: true
#volumes:
# kafka4_data:
# driver: local
volumes:
zoo1_data:
driver: local
kafka1_data:
driver: local

File diff suppressed because it is too large Load Diff

157
kafka/log/comsume.log Normal file
View File

@ -0,0 +1,157 @@
2025/12/04 14:58:58 comsumer start merge_pet_sdk
2025/12/04 14:58:58 comsumer start pet_home
2025/12/04 14:58:58 comsumer start Merge_Pet_online
2025/12/04 14:58:58 comsumer start merge_pet_london
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":34,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673638}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":107,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673651}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103353,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"187.19.255.171:19132","change_after":14,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673635}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","change_after":25,"change_num":17,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673608}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103353,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"187.19.255.171:19132","change_after":13,"change_num":9,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673632}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103279,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.6.248.68:19583","change_after":100,"change_num":43,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673648}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":38,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673635}
2025/12/04 14:59:13 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673624}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","chess_id":85},"TimeStamp":1764673625}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":167079,"change_num":3,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673622}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","order_id":2,"order_item_id":[7],"order_item_reward":[],"order_star_reward":10,"order_star_value":149,"order_type":13,"preset_order_group":1,"preset_order_step":2},"TimeStamp":1764673617}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":98,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673640}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":98,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673624}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","chess_id":1511},"TimeStamp":1764673644}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":233,"change_num":40,"change_reason":"HandleChess","change_type":"gain","item_id":100001},"TimeStamp":1764673634}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":32,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673646}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":99,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673637}
2025/12/04 14:59:15 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","chess_id":565},"TimeStamp":1764673637}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"collection_add","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","item_id":1,"item_name":"Fish-shaped Treats"},"TimeStamp":1764673637}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":106,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673633}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":35,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673637}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":40,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673623}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"collection_add","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","item_id":21,"item_name":"Cat Snack"},"TimeStamp":1764673636}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","chess_id":125},"TimeStamp":1764673611}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","change_after":5104,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673625}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"preset_order_birth","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","order_id":4,"order_item_id":[5],"preset_order_group":1,"preset_order_step":4},"TimeStamp":1764673642}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","order_id":1,"order_item_id":[3],"order_item_reward":[],"order_star_reward":2,"order_star_value":15,"order_type":13,"preset_order_group":1,"preset_order_step":1},"TimeStamp":1764673643}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"preset_order_birth","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","order_id":2,"order_item_id":[7],"preset_order_group":1,"preset_order_step":2},"TimeStamp":1764673643}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673651}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":2,"change_num":2,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673643}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":54,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673586}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":44,"change_num":10,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673607}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103275,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.33.30.37:36272","change_after":99,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673631}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","order_id":3,"order_item_id":[4],"order_item_reward":[],"order_star_reward":4,"order_star_value":27,"order_type":13,"preset_order_group":1,"preset_order_step":3},"TimeStamp":1764673642}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":193,"change_num":5,"change_reason":"HandleChess","change_type":"gain","item_id":100001},"TimeStamp":1764673633}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":39,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673623}
2025/12/04 14:59:16 comsumer Merge_Pet_online received message: {"Uid":103010,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"186.249.151.60:23262","chess_id":1602},"TimeStamp":1764673652}
2025/12/04 14:59:17 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","chess_id":561},"TimeStamp":1764673613}
2025/12/04 14:59:17 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":56,"change_num":7,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673648}
2025/12/04 14:59:22 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673630}
2025/12/04 14:59:22 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":36,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673635}
2025/12/04 14:59:22 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":63,"change_num":4,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673636}
2025/12/04 14:59:23 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2747,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673639}
2025/12/04 14:59:23 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":37,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673635}
2025/12/04 14:59:49 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":29,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673647}
2025/12/04 14:59:49 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":33,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673638}
2025/12/04 14:59:49 comsumer Merge_Pet_online received message: {"Uid":103105,"AppId":0,"ServerId":1,"EventName":"logout","Param":{"#zone_offset":-5,"after_level":10,"order_list":{"45":{"MergeId":[246],"Diff":0,"Type":13,"Timestamp":1764638272,"Q":0,"S":0,"Items":[{"Id":100002,"Num":60},{"Id":708,"Num":1}]},"49":{"MergeId":[227],"Diff":0,"Type":13,"Timestamp":1764653111,"Q":0,"S":0,"Items":[{"Id":100002,"Num":236},{"Id":1514,"Num":1}]},"55":{"MergeId":[48],"Diff":0,"Type":13,"Timestamp":1764653277,"Q":0,"S":0,"Items":[{"Id":100002,"Num":134},{"Id":1514,"Num":2}]},"59":{"MergeId":[64,65],"Diff":0,"Type":13,"Timestamp":1764653564,"Q":0,"S":0,"Items":[{"Id":100002,"Num":300}]},"65":{"MergeId":[11],"Diff":0,"Type":13,"Timestamp":1764669362,"Q":0,"S":0,"Items":[{"Id":100002,"Num":800},{"Id":1602,"Num":1}]},"70":{"MergeId":[25,25,25],"Diff":0,"Type":13,"Timestamp":1764653411,"Q":0,"S":0,"Items":[{"Id":100002,"Num":700}]}},"tmp_diamond":57,"tmp_energy":197},"TimeStamp":1764673652}
2025/12/04 14:59:50 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","get_star_num":3,"merge_item_id":522,"product_name":"A Few Star"},"TimeStamp":1764673650}
2025/12/04 14:59:50 comsumer pet_home received message: {"Uid":100100013,"AppId":1,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764831582}
2025/12/04 14:59:50 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":5,"change_num":5,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673653}
2025/12/04 14:59:50 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","change_after":26,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673654}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103279,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673648}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2731,"change_num":6,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673655}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103279,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673648}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","get_star_num":3,"merge_item_id":522,"product_name":"A Few Star"},"TimeStamp":1764673655}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103105,"AppId":0,"ServerId":1,"EventName":"Login_Out","Param":null,"TimeStamp":1764673652}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","order_id":6,"order_item_id":[5],"order_item_reward":[],"order_star_reward":5,"order_star_value":48,"order_type":13,"preset_order_group":2,"preset_order_step":1},"TimeStamp":1764673653}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","order_id":23,"order_item_id":[25],"order_item_reward":[],"order_star_reward":6,"order_star_value":50,"order_type":13,"preset_order_group":4,"preset_order_step":6},"TimeStamp":1764673656}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":104,"change_num":3,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673655}
2025/12/04 14:59:58 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":31,"change_num":5,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673656}
2025/12/04 14:59:59 comsumer Merge_Pet_online received message: {"Uid":103353,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"187.19.255.171:19132","change_after":8,"change_num":6,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673653}
2025/12/04 15:00:04 comsumer Merge_Pet_online received message: {"Uid":103358,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"148.222.209.252:38648","change_after":97,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673658}
2025/12/04 15:00:05 comsumer Merge_Pet_online received message: {"Uid":103010,"AppId":0,"ServerId":1,"EventName":"collection_add","Param":{"#zone_offset":-5,"Ip":"186.249.151.60:23262","item_id":1531,"item_name":"one tile"},"TimeStamp":1764673656}
2025/12/04 15:00:05 comsumer Merge_Pet_online received message: {"Uid":103353,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"187.19.255.171:19132","chess_id":85},"TimeStamp":1764673654}
2025/12/04 15:00:05 comsumer Merge_Pet_online received message: {"Uid":102784,"AppId":0,"ServerId":1,"EventName":"Login_Out","Param":null,"TimeStamp":1764673654}
2025/12/04 15:00:05 comsumer Merge_Pet_online received message: {"Uid":103225,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.190.171.13:38620","change_after":39,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673655}
2025/12/04 15:00:08 comsumer Merge_Pet_online received message: {"Uid":103010,"AppId":0,"ServerId":1,"EventName":"collection_add","Param":{"#zone_offset":-5,"Ip":"186.249.151.60:23262","item_id":1533,"item_name":"a pile of tiles"},"TimeStamp":1764673656}
2025/12/04 15:00:08 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673658}
2025/12/04 15:00:08 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673659}
2025/12/04 15:00:13 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","get_star_num":0,"merge_item_id":504,"product_name":"Large Amount Energy"},"TimeStamp":1764673634}
2025/12/04 15:00:15 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"ReqGetChessFromBuff","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","chess_id":1511},"TimeStamp":1764673642}
2025/12/04 15:00:16 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":12,"change_num":10,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673617}
2025/12/04 15:00:19 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":167082,"change_num":3,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673650}
2025/12/04 15:00:20 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","change_after":48,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673653}
2025/12/04 15:00:20 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":36,"change_num":3,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673643}
2025/12/04 15:00:22 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":30,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673647}
2025/12/04 15:00:23 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"playroom_interact","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","interact_id":21,"interact_type":0},"TimeStamp":1764673643}
2025/12/04 15:00:30 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":108,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673654}
2025/12/04 15:00:32 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":94,"change_num":4,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673658}
2025/12/04 15:00:37 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":231,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673663}
2025/12/04 15:00:37 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","get_star_num":7,"merge_item_id":523,"product_name":"Small Star"},"TimeStamp":1764673663}
2025/12/04 15:00:40 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"preset_order_birth","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","order_id":9,"order_item_id":[4],"preset_order_group":2,"preset_order_step":3},"TimeStamp":1764673664}
2025/12/04 15:00:43 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":230,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673663}
2025/12/04 15:00:43 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":7,"change_num":2,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673664}
2025/12/04 15:00:43 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":115,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673659}
2025/12/04 15:00:43 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":100,"change_num":15,"change_reason":"DecorateCost","change_type":"consume","item_id":100002},"TimeStamp":1764673664}
2025/12/04 15:00:45 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"finish_deco","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","deco_step_id":"1_8","material_cost":[]},"TimeStamp":1764673664}
2025/12/04 15:00:45 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"scene_reward","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","deco_step_id":"1_8","item_list":[{"Id":87,"Num":1},{"Id":100001,"Num":2}]},"TimeStamp":1764673664}
2025/12/04 15:00:49 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","change_after":50,"change_num":2,"change_reason":"DecorateAdd","change_type":"gain","item_id":100001},"TimeStamp":1764673667}
2025/12/04 15:00:51 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","change_after":100,"change_num":50,"change_reason":"LevUpReward","change_type":"gain","item_id":100001},"TimeStamp":1764673667}
2025/12/04 15:00:52 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"level_up","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","after_level":12},"TimeStamp":1764673667}
2025/12/04 15:00:55 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":27,"change_num":4,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673667}
2025/12/04 15:00:55 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":31,"change_num":2,"change_reason":"DecorateAdd","change_type":"gain","item_id":100001},"TimeStamp":1764673664}
2025/12/04 15:00:57 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":229,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673668}
2025/12/04 15:01:02 comsumer Merge_Pet_online received message: {"Uid":103359,"AppId":0,"ServerId":1,"EventName":"register_info","Param":{"username":"3703926"},"TimeStamp":1764673669}
2025/12/04 15:01:02 comsumer Merge_Pet_online received message: {"Uid":103359,"AppId":0,"ServerId":1,"EventName":"register","Param":null,"TimeStamp":1764673669}
2025/12/04 15:01:04 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"playerdeco_set","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","playerdeco_id":0,"playerdeco_type":"emoji","set_function":"playroom_game"},"TimeStamp":1764673667}
2025/12/04 15:01:07 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":228,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673670}
2025/12/04 15:01:11 comsumer Merge_Pet_online received message: {"Uid":103359,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673670}
2025/12/04 15:01:12 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2727,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673671}
2025/12/04 15:01:12 comsumer Merge_Pet_online received message: {"Uid":103360,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673670}
2025/12/04 15:01:15 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":25,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673672}
2025/12/04 15:01:17 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2719,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673672}
2025/12/04 15:01:23 comsumer Merge_Pet_online received message: {"Uid":103358,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"148.222.209.252:38648","change_after":99,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673654}
2025/12/04 15:01:23 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2739,"change_num":8,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673640}
2025/12/04 15:01:24 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":84,"change_num":7,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673642}
2025/12/04 15:01:24 comsumer Merge_Pet_online received message: {"Uid":102784,"AppId":0,"ServerId":1,"EventName":"logout","Param":{"#zone_offset":-5,"after_level":16,"order_list":{"10007":{"MergeId":[248,287],"Diff":1,"Type":15,"Timestamp":1764643436,"Q":0,"S":0,"Items":[{"Id":1602,"Num":2}]},"52":{"MergeId":[229],"Diff":0,"Type":13,"Timestamp":1764622727,"Q":0,"S":0,"Items":[{"Id":100002,"Num":800},{"Id":1602,"Num":1}]},"60":{"MergeId":[65,65,65],"Diff":0,"Type":13,"Timestamp":1764593624,"Q":0,"S":0,"Items":[{"Id":100002,"Num":600}]},"66":{"MergeId":[12],"Diff":0,"Type":13,"Timestamp":1764608546,"Q":0,"S":0,"Items":[{"Id":100002,"Num":1300},{"Id":1602,"Num":2}]}},"tmp_diamond":15,"tmp_energy":3},"TimeStamp":1764673654}
2025/12/04 15:01:25 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","get_star_num":0,"merge_item_id":502,"product_name":"Small Amount Energy"},"TimeStamp":1764673633}
2025/12/04 15:01:27 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673654}
2025/12/04 15:01:27 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","change_after":114,"change_num":6,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673656}
2025/12/04 15:01:30 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":232,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673658}
2025/12/04 15:01:33 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","change_after":1557,"change_num":300,"change_reason":"DecorateCost","change_type":"consume","item_id":100002},"TimeStamp":1764673667}
2025/12/04 15:01:37 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"finish_deco","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","deco_step_id":"1_32","material_cost":[]},"TimeStamp":1764673667}
2025/12/04 15:01:37 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"property_level_up","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","pet_level":12,"property_level":12,"property_level_reward":"Pack_2_+1,","story_level":12},"TimeStamp":1764673667}
2025/12/04 15:01:44 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":71,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673669}
2025/12/04 15:01:46 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":70,"change_num":14,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673668}
2025/12/04 15:01:46 comsumer Merge_Pet_online received message: {"Uid":103360,"AppId":0,"ServerId":1,"EventName":"register","Param":null,"TimeStamp":1764673669}
2025/12/04 15:01:50 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":24,"change_num":3,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673668}
2025/12/04 15:01:51 comsumer Merge_Pet_online received message: {"Uid":102286,"AppId":0,"ServerId":1,"EventName":"finish_mini_game","Param":{"#zone_offset":-5,"Ip":"173.40.240.152:38188","is_chip":false,"item_list":[{"Id":100002,"Num":32}],"mini_game_type":1},"TimeStamp":1764673667}
2025/12/04 15:01:52 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","change_after":227,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673671}
2025/12/04 15:01:53 comsumer Merge_Pet_online received message: {"Uid":103360,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673670}
2025/12/04 15:01:54 comsumer Merge_Pet_online received message: {"Uid":103275,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.33.30.37:36272","change_after":84,"change_num":15,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673674}
2025/12/04 15:01:58 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"preset_order_birth","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","order_id":58,"order_item_id":[63,64],"preset_order_group":7,"preset_order_step":3},"TimeStamp":1764673674}
2025/12/04 15:02:03 comsumer Merge_Pet_online received message: {"Uid":103361,"AppId":0,"ServerId":1,"EventName":"register","Param":null,"TimeStamp":1764673676}
2025/12/04 15:02:07 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"preset_order_birth","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","order_id":3,"order_item_id":[4],"preset_order_group":1,"preset_order_step":3},"TimeStamp":1764673676}
2025/12/04 15:02:10 comsumer Merge_Pet_online received message: {"Uid":103279,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"189.6.248.68:19583","change_after":99,"change_num":1,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673676}
2025/12/04 15:02:10 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2721,"change_num":6,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673671}
2025/12/04 15:02:11 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":167091,"change_num":1,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673678}
2025/12/04 15:02:11 comsumer Merge_Pet_online received message: {"Uid":103361,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673676}
2025/12/04 15:02:13 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":12,"change_num":10,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673676}
2025/12/04 15:02:13 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"sell_item","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","get_star_num":1,"merge_item_id":521,"product_name":"A Star"},"TimeStamp":1764673678}
2025/12/04 15:02:14 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":22,"change_num":6,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673681}
2025/12/04 15:02:14 comsumer Merge_Pet_online received message: {"Uid":103010,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"186.249.151.60:23262","change_after":16,"change_num":1,"change_reason":"recover_server","change_type":"gain","item_id":100001},"TimeStamp":1764673678}
2025/12/04 15:02:16 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","order_id":4,"order_item_id":[5],"order_item_reward":[],"order_star_reward":6,"order_star_value":48,"order_type":13,"preset_order_group":1,"preset_order_step":4},"TimeStamp":1764673681}
2025/12/04 15:02:18 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"playroom_interact","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","interact_id":10,"interact_type":1},"TimeStamp":1764673682}
2025/12/04 15:02:19 comsumer Merge_Pet_online received message: {"Uid":103354,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"138.36.7.60:37201","change_after":16,"change_num":4,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673642}
2025/12/04 15:02:25 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2729,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673656}
2025/12/04 15:02:27 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":2737,"change_num":2,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673654}
2025/12/04 15:02:28 comsumer Merge_Pet_online received message: {"Uid":100004,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"120.41.146.28:16858","change_after":167090,"change_num":7,"change_reason":"HandleChess","change_type":"gain","item_id":100002},"TimeStamp":1764673663}
2025/12/04 15:02:28 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"scene_reward","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","deco_step_id":"1_32","item_list":[{"Id":100001,"Num":2}]},"TimeStamp":1764673667}
2025/12/04 15:02:32 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":48,"change_num":4,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673670}
2025/12/04 15:02:43 comsumer Merge_Pet_online received message: {"Uid":102827,"AppId":0,"ServerId":1,"EventName":"Login_log","Param":null,"TimeStamp":1764673675}
2025/12/04 15:02:46 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","order_id":2,"order_item_id":[7],"order_item_reward":[],"order_star_reward":10,"order_star_value":149,"order_type":13,"preset_order_group":1,"preset_order_step":2},"TimeStamp":1764673676}
2025/12/04 15:02:46 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","change_after":130,"change_num":12,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673674}
2025/12/04 15:02:52 comsumer Merge_Pet_online received message: {"Uid":103154,"AppId":0,"ServerId":1,"EventName":"playroom_guide","Param":{"#zone_offset":-5,"Ip":"189.44.63.106:54862","Physiology":5},"TimeStamp":1764673673}
2025/12/04 15:02:52 comsumer Merge_Pet_online received message: {"Uid":103292,"AppId":0,"ServerId":1,"EventName":"logout","Param":{"#zone_offset":-5,"after_level":10,"order_list":{"44":{"MergeId":[227],"Diff":0,"Type":13,"Timestamp":1764653742,"Q":0,"S":0,"Items":[{"Id":100002,"Num":64},{"Id":1501,"Num":2}]},"45":{"MergeId":[246],"Diff":0,"Type":13,"Timestamp":1764653742,"Q":0,"S":0,"Items":[{"Id":100002,"Num":60},{"Id":708,"Num":1}]},"50":{"MergeId":[228],"Diff":0,"Type":13,"Timestamp":1764673204,"Q":0,"S":0,"Items":[{"Id":100002,"Num":500},{"Id":1602,"Num":1}]},"55":{"MergeId":[48],"Diff":0,"Type":13,"Timestamp":1764654764,"Q":0,"S":0,"Items":[{"Id":100002,"Num":134},{"Id":1514,"Num":2}]},"58":{"MergeId":[63,64],"Diff":0,"Type":13,"Timestamp":1764654689,"Q":0,"S":0,"Items":[{"Id":100002,"Num":50},{"Id":1511,"Num":2}]},"64":{"MergeId":[9],"Diff":0,"Type":13,"Timestamp":1764654618,"Q":0,"S":0,"Items":[{"Id":100002,"Num":164},{"Id":1513,"Num":2}]},"69":{"MergeId":[23,24],"Diff":0,"Type":13,"Timestamp":1764654651,"Q":0,"S":0,"Items":[{"Id":100002,"Num":80},{"Id":1511,"Num":2}]}},"tmp_diamond":53,"tmp_energy":242},"TimeStamp":1764673677}
2025/12/04 15:02:57 comsumer Merge_Pet_online received message: {"Uid":103289,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"170.239.38.36:53963","order_id":41,"order_item_id":[46],"order_item_reward":[],"order_star_reward":12,"order_star_value":89,"order_type":13,"preset_order_group":6,"preset_order_step":4},"TimeStamp":1764673674}
2025/12/04 15:02:58 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"order_finish","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","order_id":9,"order_item_id":[4],"order_item_reward":[],"order_star_reward":2,"order_star_value":27,"order_type":13,"preset_order_group":2,"preset_order_step":3},"TimeStamp":1764673683}
2025/12/04 15:02:58 comsumer Merge_Pet_online received message: {"Uid":103355,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"177.173.235.32:29071","change_after":9,"change_num":2,"change_reason":"OrderReward","change_type":"gain","item_id":100002},"TimeStamp":1764673683}
2025/12/04 15:02:59 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"finish_deco","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","deco_step_id":"1_9","material_cost":[]},"TimeStamp":1764673683}
2025/12/04 15:03:02 comsumer Merge_Pet_online received message: {"Uid":103357,"AppId":0,"ServerId":1,"EventName":"asset_change","Param":{"#zone_offset":-5,"Ip":"45.4.57.69:43723","change_after":89,"change_num":5,"change_reason":"HandleChess","change_type":"consume","item_id":100001},"TimeStamp":1764673673}
2025/12/04 15:03:02 comsumer Merge_Pet_online received message: {"Uid":103348,"AppId":0,"ServerId":1,"EventName":"scene_reward","Param":{"#zone_offset":-5,"Ip":"45.172.146.93:53930","deco_step_id":"1_9","item_list":[{"Id":88,"Num":1},{"Id":100001,"Num":2}]},"TimeStamp":1764673683}
2025/12/04 15:03:44 comsumer Merge_Pet_online received message: {"Uid":102974,"AppId":0,"ServerId":1,"EventName":"mail_reward","Param":{"#zone_offset":-5,"Ip":"200.138.90.205:39080","item_list":[{"Id":100003,"Num":10}],"mail_id":2},"TimeStamp":1764673683}

View File

@ -25,7 +25,6 @@ var (
var (
rl *rotatelogs.RotateLogs
logWriter io.Writer
errWriter io.Writer
)
var c = make(chan os.Signal, 1)
var d = make(chan int, 1)
@ -52,14 +51,12 @@ func main() {
// 打开一个普通的最新日志文件(不使用 symlink用于提供固定路径的最新日志
currFile, err := os.OpenFile("./log/comsume.log", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
// 如果打开失败,仍然继续使用轮转器+控制台
// 如果打开失败,仍然继续使用轮转器
log.Printf("warning: failed to open current log file: %v", err)
logWriter = io.MultiWriter(rl, os.Stdout)
errWriter = io.MultiWriter(rl, os.Stderr)
logWriter = io.MultiWriter(rl)
} else {
// 同时输出到轮转日志、固定最新日志文件和控制台
logWriter = io.MultiWriter(rl, currFile, os.Stdout)
errWriter = io.MultiWriter(rl, currFile, os.Stderr)
}
log.SetOutput(logWriter)
@ -102,13 +99,12 @@ func scheduleDailyTask() {
func getKafkaReader(kafkaURL, topic, groupID string) *kafka.Reader {
brokers := strings.Split(kafkaURL, ",")
return kafka.NewReader(kafka.ReaderConfig{
Brokers: brokers,
GroupID: groupID,
Topic: topic,
MinBytes: 1, // 降低最小聚合字节,减少等待
MaxBytes: 10e6, // 10MB
MaxWait: 100 * time.Millisecond, // 缩短等待聚合时间
QueueCapacity: 5000, // 内部预取队列容量(根据流量调整)
Brokers: brokers,
GroupID: groupID,
Topic: topic,
MinBytes: 1, // 降低最小聚合字节,减少等待
MaxBytes: 10e6, // 10MB
MaxWait: 100 * time.Millisecond, // 缩短等待聚合时间
Dialer: &kafka.Dialer{
Timeout: 3 * time.Second, // 减少建立连接超时,避免 ~9s 阻塞
DualStack: true,
@ -145,8 +141,7 @@ func comsumer(Game *config.Game) {
log.Printf("comsumer %s error :%v", Game.Name, err)
continue
}
jsonData := string(m.Value)
log.Printf("comsumer %s received message: %s", Game.Name, jsonData)
log.Printf("comsumer %s received message: %s", Game.Name, m.Value)
r.CommitMessages(ctx, m)
Wait.Add(1)
err = db.ProcessMsg(sqlDb, m)

Binary file not shown.

31
nginx/jenkins.conf Normal file
View File

@ -0,0 +1,31 @@
server {
listen 80;
server_name jenkins.bywaystudios.com;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name jenkins.bywaystudios.com;
ssl_certificate /etc/nginx/ssl/bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://localhost:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/jenkins_access.log;
error_log /var/log/nginx/jenkins_error.log;
}

31
nginx/login.conf.j2 Normal file
View File

@ -0,0 +1,31 @@
server {
listen 80;
server_name {{ login_domain }};
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name {{ login_domain }};
ssl_certificate /etc/nginx/ssl/bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /api {
proxy_pass http://localhost:5240;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/kafka_access.log;
error_log /var/log/nginx/kafka_error.log;
}

33
nginx/policy.conf Normal file
View File

@ -0,0 +1,33 @@
server {
listen 80;
server_name policy.bywaystudios.com;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name policy.bywaystudios.com;
ssl_certificate /etc/nginx/ssl/bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location = /docs {
return 301 /docs/;
}
location /docs/ {
alias /data/policy/;
index index.html;
try_files $uri $uri/ =404;
}
# 可选:配置日志文件
access_log /var/log/nginx/dify_access.log;
error_log /var/log/nginx/dify_error.log;
}

31
nginx/shipping.conf.j2 Normal file
View File

@ -0,0 +1,31 @@
server {
listen 80;
server_name {{ shipping_domain }};
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name {{ shipping_domain }};
ssl_certificate /etc/nginx/ssl/bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location /api {
proxy_pass http://localhost:5250;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/ship_access.log;
error_log /var/log/nginx/ship_error.log;
}

32
nginx/verdaccio.conf Normal file
View File

@ -0,0 +1,32 @@
server {
listen 80;
server_name npm.bywaystudios.com;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name npm.bywaystudios.com;
ssl_certificate /etc/nginx/ssl/bywaystudios.com.pem;
ssl_certificate_key /etc/nginx/ssl/bywaystudios.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
deny all;
proxy_pass http://localhost:4873;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 可选:配置日志文件
access_log /var/log/nginx/jenkins_access.log;
error_log /var/log/nginx/jenkins_error.log;
}

View File

@ -0,0 +1,2 @@
url,title,description,links_count,images_count,html_length,timestamp
https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9,飞书 - 登录,整合即时通讯、智能日历、云端创作等功能于一体,打造高效办公方式,0,3,163481,2025-07-15 11:35:20
1 url title description links_count images_count html_length timestamp
2 https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9 飞书 - 登录 整合即时通讯、智能日历、云端创作等功能于一体,打造高效办公方式 0 3 163481 2025-07-15 11:35:20

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
url,title,description,links_count,images_count,html_length,timestamp
https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9,漏洞跟踪记录Updated - 飞书云文档,,0,2,1151746,2025-07-15 11:42:32
1 url title description links_count images_count html_length timestamp
2 https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9 ‌‌‬​⁢​⁡⁤⁤‬⁢‍‍‌‍⁡⁣⁡‌‬‬‌‍‍⁡⁡⁣‬⁢⁤​⁡⁣‌‬⁤‌​​⁤⁣⁣⁡‬‬⁣‌‍漏洞跟踪记录Updated - 飞书云文档 0 2 1151746 2025-07-15 11:42:32

View File

@ -0,0 +1,24 @@
[
{
"url": "https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9",
"title": "漏洞跟踪记录Updated - 飞书云文档",
"description": "",
"links": [],
"images": [
{
"url": "https://s1-imfile.feishucdn.com/static-resource/v1/v3_00hl_105b235e-bf60-434d-add8-897ecb4fd47g~?image_size=noop&cut_type=&quality=&format=image&sticker_format=.webp",
"alt": "",
"title": ""
},
{
"url": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA2MCA2MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTE2LjI1IDIwVjE4Ljc1QzE2LjI1IDExLjE1NjEgMjIuNDA2MSA1IDMwIDVDMzcuNTkzOSA1IDQzLjc1IDExLjE1NjEgNDMuNzUgMTguNzVWMjBINTBDNTIuNzYxNCAyMCA1NSAyMi4yMzg2IDU1IDI1VjUwQzU1IDUyLjc2MTQgNTIuNzYxNCA1NSA1MCA1NUgxMEM3LjIzODU4IDU1IDUgNTIuNzYxNCA1IDUwVjI1QzUgMjIuMjM4NiA3LjIzODU4IDIwIDEwIDIwSDE2LjI1Wk0zOC43NSAxOC43NUMzOC43NSAxMy45MTc1IDM0LjgzMjUgMTAgMzAgMTBDMjUuMTY3NSAxMCAyMS4yNSAxMy45MTc1IDIxLjI1IDE4Ljc1VjIwSDM4Ljc1VjE4Ljc1Wk0zNi4yNSAzNy41QzM2LjI1IDM0LjA0ODIgMzMuNDUxOCAzMS4yNSAzMCAzMS4yNUMyNi41NDgyIDMxLjI1IDIzLjc1IDM0LjA0ODIgMjMuNzUgMzcuNUMyMy43NSA0MC45NTE4IDI2LjU0ODIgNDMuNzUgMzAgNDMuNzVDMzMuNDUxOCA0My43NSAzNi4yNSA0MC45NTE4IDM2LjI1IDM3LjVaIiBmaWxsPSIjQkJCRkM0Ii8+Cjwvc3ZnPgo=",
"alt": "",
"title": ""
}
],
"text_length": 4386,
"html_length": 1151746,
"script_data": {},
"timestamp": "2025-07-15 11:42:32"
}
]

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAth2OvQ4vKkQnKzfMEW+dBUGjPXpwuzizCa5wAGOyLFTIwv2a
WsRDSnCeAA8NsoYVzuG2+tzHi7hOulAJTWHzr/XgdpNqO7KzFoIkYXGtTjFg3gML
R8ikRZZWMMnSHy0jDvBoeydaf/ff+a2WZjKb2FknRBIUfdmbQdFLauo9Q1/V2mSc
/9MQT4rLk50wpbWf4zzsYClHt09BD4lDoWS1iLKLDi5Do2DELkUUbV2flaElBcqX
D6yw1v/fqmXUM1UpV5gKBrDZp3x9k0cbudUGfYlLulC0+k+UuVhXsVWQPMNUlp0+
s9bfUUm1BQRmSaPUvkgwtzH83EAZmiKuUMTJ0QIDAQABAoIBAAJW+uB+8Cgw2/f4
LY0DzBanMzu0+QHOxq4XKaU3orBjHnky3OrRnrO0IrOJffmPM3SG/dzXPVEUOx61
rIjr+z+Ffy7G0hSWRSrC3UjLNxjMFZyEmX6Am2uxdMYHscVoxQyKFi2O4eDHBH+m
tUn22H29F34OZWkAhLghwkBLZiIZcYBJhptG0uk5mpdN7thAG+3DQXv6VYIYyLT6
3MVFPmaxBmxhQGUzRyyd+YF3Z6DiKPpWVYL7Wk3MT+62aui7X1J9Rwh54yAaFVox
9U6cbwJb23cccSRvYJV19Uq1WzVTc19mex5+a9IY72kV9X50s6K/xpbzHyHhW+1B
Bf4vcIECgYEA+gSjDkK+jKN2Scr61g5eTDd398aQcChvYSjVRTb2hY5pPTTVSy5/
PoeW7XQlWbYZRpB3gVWLh61pSY4M063E/d8IZXHvvOl8UwwktoqCkrS7y5PO7aNM
jF0vfbK9btMm/hjK/1bNPDQjknwVXMOug153wxLuCoRkm5yf7XxZTlkCgYEAunkE
LJgpIcHQdViWwUzdqDuF8croDFRpDi/Nm93142E5w2N6yX9RS07EnRw2HacLQWxp
oS85s3QxukihemU/4yblhtw6PZTkXE4vUPH8OI9hUQi9SwaWfD9qS4CGhYmjbB+d
L917QHKoaaxk0+LvNZHa93RQsPl0yTSOiSCaGDkCgYEApKnHJk5JJ2FFN8aqu65M
5s+lgJfTazsGWCxHgkV3yXCI2VnhnJlsDqfIfG2BZ/tp3DKrso+/zMUmUd5vjj6l
PjrVUdLffUEds6iMyXiiFLNZ9/NKVvK1KMD61UOSRdpllPaJQ/BMTXldcE2u2CC8
4CKop97gziZyCJb4MbYzL0kCgYEAm4klOi0Q4d9PiRGDbWg32oMLjkq4ktA1cGff
EAtrdWU7UQZA/KD9pdrllEZbvRAAC2nqEU/ayRw5/i9mwTiCuW1QNdSrn4H5mCR+
wv2Ua3jsqzKm8VVlX+1lM+TYT7omXaFg8vPCQldgsgPhdfrrm7s08QJL69Gm38y+
txJCdcECgYBd6HDypjiuswd6fTmdNYMZBQJ+M1ouuyoylv4m6hEp3iHhmWyGvE30
+VLfzPDMXwjAvbk6PLIKJw6R2fA/Lh3GOjb0heAcwuGpgqe0OM0+PRo4mxlbovcx
K0RpSiac5cgpEdO4Og+cgKzCg3g35wVLfvUYDAaZrsP26I/Xru5lUw==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,127 @@
-----BEGIN CERTIFICATE-----
MIIGNzCCBR+gAwIBAgIQVqPp7OLoPM3oQ1nibTAApzANBgkqhkiG9w0BAQsFADBc
MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29UcnVzIENBIExpbWl0ZWQxMTAvBgNV
BAMMKFdvVHJ1cyBEViBTZXJ2ZXIgQ0EgIFtSdW4gYnkgdGhlIElzc3Vlcl0wHhcN
MjUxMjA5MDAwMDAwWhcNMjcwMTA5MjM1OTU5WjAdMRswGQYDVQQDDBIqLmJ5d2F5
c3R1ZGlvcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2HY69
Di8qRCcrN8wRb50FQaM9enC7OLMJrnAAY7IsVMjC/ZpaxENKcJ4ADw2yhhXO4bb6
3MeLuE66UAlNYfOv9eB2k2o7srMWgiRhca1OMWDeAwtHyKRFllYwydIfLSMO8Gh7
J1p/99/5rZZmMpvYWSdEEhR92ZtB0Utq6j1DX9XaZJz/0xBPisuTnTCltZ/jPOxg
KUe3T0EPiUOhZLWIsosOLkOjYMQuRRRtXZ+VoSUFypcPrLDW/9+qZdQzVSlXmAoG
sNmnfH2TRxu51QZ9iUu6ULT6T5S5WFexVZA8w1SWnT6z1t9RSbUFBGZJo9S+SDC3
MfzcQBmaIq5QxMnRAgMBAAGjggMyMIIDLjAfBgNVHSMEGDAWgBSZmy32i/Cj24nU
nvvldC9o0pBP5DAdBgNVHQ4EFgQUCFKCjmFS7bzr/gxZGuYPNTLwwwYwDgYDVR0P
AQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwSQYD
VR0gBEIwQDA0BgsrBgEEAbIxAQICFjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3Nl
Y3RpZ28uY29tL0NQUzAIBgZngQwBAgEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov
L2NybC5jcmxvY3NwLmNuL1dvVHJ1c0RWU2VydmVyQ0FfMi5jcmwwbAYIKwYBBQUH
AQEEYDBeMDgGCCsGAQUFBzAChixodHRwOi8vYWlhLmNybG9jc3AuY24vV29UcnVz
RFZTZXJ2ZXJDQV8yLmNydDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuY3Jsb2Nz
cC5jbjAvBgNVHREEKDAmghIqLmJ5d2F5c3R1ZGlvcy5jb22CEGJ5d2F5c3R1ZGlv
cy5jb20wggGOBgorBgEEAdZ5AgQCBIIBfgSCAXoBeAB3AGBMmq96f3dfAdQG/JIN
yJnrCxx9+MlSG/r6F3c7l4vJAAABmwG3KuMAAAQDAEgwRgIhAOApwbyVueun3xhC
mTSOgscM+EfoyMnm4lrNEcEly4ANAiEAqkqI93x0tYyXyanzewv1mVqWt5n9jKzs
rOVBbn89QRwAfQCOykcLrN5q86IGsKR6hLdG/h/Gv5U+JeabTuQCSPPG6AAAAZsB
tyvaAAgAAAUAAGfcEAQDAEYwRAIgIITO+svcTRkjPRrFpuvPT0yBDrxI0to55ivE
amsxY+ACIGyR3rLWtmunFaVO4SIFzwg8cIl9Dv3C8+gEIE+YmhNwAH4AWW5sM4aU
sllyolbIoOjdkEp26Ag92oc7AQg4KBQ87lkAAAGbAbcsGQAIAAAFAAAA590EAwBH
MEUCIQDa9BiAFvEFRyS2VXo1RD6NL+1LycCQfe8lwaRgANltYAIgQwclGCysMlcz
dB0OfBnmP5yskdWL4raEoxLX5+y9OPQwDQYJKoZIhvcNAQELBQADggEBAFULS/wz
GEE6rqG1Pdd8in6JthtVgVwwTbLsOt09RAWRs0VS/qeVEYxrqYCcuO5FIjoX6ENk
Hf6FAnqZp65/iTv9YtSoZFbghvD8ys8kjCB8bZOcs0FROehtCzLZb02ceozYjPoz
1S1SEsvy4TM3pkW2OCPdNqTm1+dSPHZKlfZeeMuZxYv7a3rONry/JE3kN6tQ0Wfe
HTRjO+H7trxie+e92SQ4vCcbooHvS6A5TAgtBC4cGNWWaMga+3GJyp2kcdjPzzpI
yuOJLZKbRba+sWY1EDZVZ8pMwYMOYbf+4/ThLHVpzignsjSMgvcnq9CnMA4MPeIW
bUtCaexj/Mif4ww=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF4jCCA8qgAwIBAgIRANVuJGyU7WOrsUbvwZa2T7AwDQYJKoZIhvcNAQEMBQAw
gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK
ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD
VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw
MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowXDELMAkGA1UEBhMCQ04xGjAYBgNV
BAoTEVdvVHJ1cyBDQSBMaW1pdGVkMTEwLwYDVQQDDChXb1RydXMgRFYgU2VydmVy
IENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA7IE0rmVTVdRdNOzK1jsR/VppyukZ/XbQgakJHOhg6XGDsiHe/l5B
3PxyXw18jEdN+7YxP0qsGz+HlQbsQh6XlwIyjpz/2gFMiqa7y1v+dHOgj6xNOF5a
oaPm/Qhb0N+JYQidgaC+1Zp6W+YeC736rzCMr9vL1Usa3QLzRoQEo0DzbG4sPeP1
US0Ia/i8o6szArH+DAcvrzCZ2kkpTScQ9QfOsvkMBP1W2otICdKUyZHaBc+ztTAd
ovSlOR+GPf29dYfGQkZAp0tffIRw/na3WB86WGZPpNFfo2QxxsHYoL3oSWKfSWTY
FgW22J8eA03TFHYowm/NqYuJ7GW553HppQIDAQABo4IBcDCCAWwwHwYDVR0jBBgw
FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFJmbLfaL8KPbidSe++V0
L2jSkE/kMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB
AgIWMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0
cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww
cQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVz
dC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v
b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQB5t8v3uYzHa4EL
0rOb9g/YAmptUbILcBMKk1x188ucsGVPaG1DG9bpVamxbmCtFA1MlrA7iUC8SGop
KBnuWFsNKiC7jCbRoahT1/FSwFsSuDlDmOjr1MqDXE+or08UkXsJB57XxXxdVOPl
DcZHII4qHi1XKK4iurMqb+kbdpAWadyfidRRCGPopYCVYLLYhRJgpFGtfr6Gk8N0
j81jq/7QbN0dRSDzMNdadKTc7c3+i9fIrXj79lV5Wvva+OL7nh8MxQhG1Ekek7Rv
en++jSZvaEhCrMsSedFTA/aIy7oJg85tfglF2ybK61HsobjYzdDNICKJlIm4chlA
XIDDqw2mw0Kz2snrkp9dpvMBqahF/Uy1kHzPcrq1/w5OqZWAuDKxZ68PuZ/ME2hI
YbIDG9dWT6Y7eqtjQ2TmAQbOqdAG2LeikPMl2DMrPEa4lcKJzsFbHfHAW3hVgPSQ
hRfS4TtbNnxijbsp8GguMHxP2R7dpAAYybwfZdXP7WYAnwEr1mzIf0Y3J0m7GDyX
JhaflN3G2wIm2HzRd39NvnDRmFEraqui/YYO9ym0pwq1d0S+bGG6876QCto0u3Cg
ItFh3Za2ZeIY+g5mWrejSaDs9LT7eu44iCyebfgekdMRqFeCuGAsJdsun3LOHHJo
tCVPRjyFg9NDeJeMa4Z8QuXAXLd9cw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI
s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG
vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ
Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb
IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0
tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E
xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV
icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5
D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ
WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ
5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG
KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg
EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID
ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG
BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr
BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+
rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+
/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA
CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F
zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA
vGp4z7h/jnZymQyd/teRCBaho1+V
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----

View File

@ -1,58 +1,28 @@
---
- name: Deploy GoLeaf release
hosts: london
hosts: test
gather_facts: no
remote_user: root
vars:
goleaf_src: /data/devops/source/main
goleaf_dest: /data/devops/MergePet/main
goleaf_dest: /usr/local/games/MergePet
config_src: /data/docs/tool/config/
config_dest: /data/devops/MergePet/config/
config_dest: /usr/local/games/MergePet/gamedata/config/
pack_script: /data/devops/pack.sh
tar_file: /usr/local/MergePet.tar
tar_dest: /usr/local/game
branch: develop
tasks:
- name: sh pack.sh
shell: sh /data/devops/pack_local.sh
delegate_to: localhost
# - name: copy
# copy:
# src: /data/devops/Goleaf.tar
# dest: /usr/local
# - name: tar
# command: tar -xvf /usr/local/Goleaf.tar -C /usr/local/
# - name: 切换分支 {{branch}}
# shell: cd /codes/pet_home_server && git checkout {{branch}} && git pull
# delegate_to: localhost
# register: git_result
# - name: sh pack.sh
# shell: sh /data/devops/pack.sh
# delegate_to: localhost
- name: backup goleaf
shell: mv "{{goleaf_dest}}"/main "{{goleaf_dest}}"/main.bak
ignore_errors: yes
# - name: copy goleaf
# copy:
# src: /data/devops/source/main
# dest: /usr/local/MergePet/main
- name: copy goleaf
copy:
src: /data/devops/script/dist/verifyOrder
dest: /usr/local/MergePet/script
mode: '0777'
src: "{{ goleaf_src }}"
dest: "{{goleaf_dest}}"
mode: 0755
# - name: copy config
# copy:
# src: /data/docs/tool/out/
# dest: /usr/local/Goleaf/gamedata/config/
# mode: '0777'
# - name: restart goleaf
# command: sh /usr/local/Goleaf/Restart.sh restart
# register: restart_result
# - name: show restart result
# debug:
# var: restart_result.stdout_lines

View File

@ -1,11 +1,10 @@
# @format
---
- name: Deploy GoLeaf release
hosts: test
hosts: google
remote_user: root
tasks:
# - name: copy config
# copy:
# src: /data/docs/tool/out/
@ -13,20 +12,17 @@
# mode: '0777'
- name: pack tool
shell: cd /data/devops/tool && GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/tool/tool main.go
shell: cd /data/devops/tools && GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/tool/tool main.go
delegate_to: localhost
- name: reload tool
copy:
src: /data/devops/MergePet/tool/tool
dest: /usr/local/Goleaf/tool/tool
- name: pack main
shell: cd /data/pet_home_server/src/server && GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/main main.go
delegate_to: localhost
- name: reload main
copy:
src: /data/devops/MergePet/main
dest: /usr/local/Goleaf/main
dest: /usr/local/game/tool
# - name: pack main
# shell: cd /data/pet_home_server/src/server && GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/main main.go
# delegate_to: localhost
# - name: reload main
# copy:
# src: /data/devops/MergePet/main
# dest: /usr/local/Goleaf/main

View File

@ -13,19 +13,12 @@
tar_dest: /usr/local/Goleaf
tasks:
- name: stop goleaf
command: "{{ goleaf_dest }}/tool/tool stop node 3"
register: stop_result
# - name: stop goleaf
# command: "{{ goleaf_dest }}/tool/tool stop node 3"
# register: stop_result
- name: show stop_result
debug:
var: stop_result.stdout_lines
- name: change git branch
shell: cd /codes/pet_home_server && git checkout develop && git pull
delegate_to: localhost
register: git_result
- name: sh pack.sh
shell: sh /data/devops/pack.sh
shell: sh /data/devops/pack_local.sh
delegate_to: localhost
- name: copy goleaf
@ -33,19 +26,19 @@
src: "{{ goleaf_src }}"
dest: "{{goleaf_dest}}"
- name: copy goleaf
command: tar -cvf /usr/local/conf.tar -C /data/docs/tool/out .
delegate_to: localhost
- name: copy tar
copy:
src: /usr/local/conf.tar
dest: /usr/local/Goleaf
- name : untar
command: tar -xvf /usr/local/Goleaf/conf.tar -C /usr/local/Goleaf/config/
# - name: copy goleaf
# command: tar -cvf /usr/local/conf.tar -C /data/docs/tool/out .
# delegate_to: localhost
# - name: copy tar
# copy:
# src: /usr/local/conf.tar
# dest: /usr/local/Goleaf
# - name : untar
# command: tar -xvf /usr/local/Goleaf/conf.tar -C /usr/local/Goleaf/config/
- name: start goleaf
shell: nohup /usr/local/Goleaf/tool/tool start node 3 &
shell: nohup /usr/local/Goleaf/tool/tool restart node 5 &
register: restart_result
- name: show restart result

View File

@ -13,19 +13,8 @@
tar_dest: /usr/local/Goleaf
tasks:
- name: stop goleaf
command: "{{ goleaf_dest }}/tool/tool stop node 4"
register: stop_result
- name: show stop_result
debug:
var: stop_result.stdout_lines
- name: change git branch
shell: cd /codes/pet_home_server && git checkout develop && git pull
delegate_to: localhost
register: git_result
- name: sh pack.sh
shell: sh /data/devops/pack.sh
shell: sh /data/devops/pack_local.sh
delegate_to: localhost
- name: copy goleaf
@ -33,19 +22,19 @@
src: "{{ goleaf_src }}"
dest: "{{goleaf_dest}}"
- name: copy goleaf
command: tar -cvf /usr/local/conf.tar -C /data/docs/tool/out .
delegate_to: localhost
- name: copy tar
copy:
src: /usr/local/conf.tar
dest: /usr/local/Goleaf
- name : untar
command: tar -xvf /usr/local/Goleaf/conf.tar -C /usr/local/Goleaf/config/
# - name: copy goleaf
# command: tar -cvf /usr/local/conf.tar -C /data/docs/tool/out .
# delegate_to: localhost
# - name: copy tar
# copy:
# src: /usr/local/conf.tar
# dest: /usr/local/Goleaf
# - name : untar
# command: tar -xvf /usr/local/Goleaf/conf.tar -C /usr/local/Goleaf/config/
- name: start goleaf
shell: nohup /usr/local/Goleaf/tool/tool start node 4 &
shell: nohup /usr/local/Goleaf/tool/tool restart node 4 &
register: restart_result
- name: show restart result

View File

@ -11,7 +11,8 @@ a2 ansible_ssh_host=172.20.0.3 ansible_ssh_user="root" ansible_ssh_port=22
[google]
g1 ansible_ssh_host=47.254.83.25 ansible_ssh_user="root" ansible_ssh_port=22
[google-sdk]
gs1 ansible_ssh_host=47.88.106.149 ansible_ssh_user="root" ansible_ssh_port=22
[gitea]
gitea1 ansible_ssh_host=8.155.14.94 ansible_ssh_user="root" ansible_ssh_port=22
@ -21,4 +22,10 @@ g1 ansible_ssh_host=47.254.83.25 ansible_ssh_user="root" ansible_ssh_port=22
[london]
london_1 ansible_ssh_host=8.208.47.208 ansible_ssh_user="root" ansible_ssh_port=22
london_1 ansible_ssh_host=8.208.47.208 ansible_ssh_user="root" ansible_ssh_port=22
[nginxservice]
w1 ansible_ssh_host=1.15.182.107 ansible_ssh_user="root" ansible_ssh_port=22
w2 ansible_ssh_host=47.254.83.25 ansible_ssh_user="root" ansible_ssh_port=22
w3 ansible_ssh_host=47.88.106.149 ansible_ssh_user="root" ansible_ssh_port=22
w4 ansible_ssh_host=8.155.14.94 ansible_ssh_user="root" ansible_ssh_port=22

View File

@ -0,0 +1,27 @@
---
- name: Deploy GoLeaf release
hosts: gitea:google-sdk
remote_user: root
tasks:
- name: pack.sh
shell: sh /data/admin_backend/release/login_service/login_pack.sh
delegate_to: localhost
- name: copy main
copy:
src: /data/admin_backend/release/login_service/login_service
dest: /data/meow/login_service/login_service
mode: 0755
- name: copy start script
copy:
src: /data/admin_backend/release/login_service/start.sh
dest: /data/meow/login_service/start.sh
mode: 0755
# - name: copy config
# copy:
# src: /data/admin_backend/release/login_service/conf
# dest: /data/meow/login_service/
# mode: 0644
- name: restart web
shell: sh /data/meow/login_service/start.sh restart

View File

@ -0,0 +1,79 @@
---
- name: Move Docker data-root to /data/docker
hosts: google-sdk
become: true
vars:
new_docker_root: /data/docker
old_docker_root: /var/lib/docker
tasks:
- name: Ensure rsync installed
package:
name: rsync
state: present
- name: Stop Docker service
service:
name: docker
state: stopped
ignore_errors: true
- name: Create new data root
file:
path: "{{ new_docker_root }}"
state: directory
mode: '0755'
- name: Check old docker root exists
stat:
path: "{{ old_docker_root }}"
register: old_docker_root_stat
- name: Sync old data to new root (if old exists)
command: rsync -aHAX --numeric-ids --delete {{ old_docker_root }}/ {{ new_docker_root }}/
when: old_docker_root_stat.stat.exists
args:
warn: false
- name: Backup old directory
command: mv {{ old_docker_root }} {{ old_docker_root }}.bak
args:
creates: "{{ old_docker_root }}.bak"
when: old_docker_root_stat.stat.exists
- name: Ensure /etc/docker exists
file:
path: /etc/docker
state: directory
mode: '0755'
- name: Write daemon.json
copy:
dest: /etc/docker/daemon.json
mode: '0644'
content: |
{
"data-root": "{{ new_docker_root }}",
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
- name: Start Docker
service:
name: docker
state: started
enabled: true
- name: Verify root dir
command: docker info --format '{% raw %}{{json .DockerRootDir}}{% endraw %}'
register: docker_root
changed_when: false
- name: Show result
debug:
msg: "DockerRootDir = {{ docker_root.stdout }}"
- name: Fail if not moved
fail:
msg: "迁移失败,当前仍是旧目录"
when: docker_root.stdout.find(new_docker_root) == -1

41
playbook/nginx.yml Normal file
View File

@ -0,0 +1,41 @@
---
- name: 安装 nginx 并同步本地 ssl 证书到远端 /etc/nginx/ssl
hosts: google-sdk
become: yes
vars:
remote_ssl_dir: /etc/nginx/ssl
tasks:
- name: 安装 nginx 包
package:
name: nginx
state: present
- name: 确保远端 ssl 目录存在
file:
path: "{{ remote_ssl_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: 将本地 ssl/ 目录同步到远端 /etc/nginx/ssl
synchronize:
src: "../ssl/"
dest: "{{ remote_ssl_dir }}/"
recursive: yes
delete: no
rsync_opts:
- "--chmod=D0755,F0644"
delegate_to: localhost
- name: 限制私钥文件权限为 0600匹配 *.key
shell: "find {{ remote_ssl_dir }} -type f -name '*.key' -exec chmod 0600 {} \\;"
args:
warn: false
- name: 确保 nginx 已启用并运行
service:
name: nginx
state: restarted
enabled: yes

33
playbook/sdk/init.yml Normal file
View File

@ -0,0 +1,33 @@
---
- name: 同步 nginx 配置并重启 nginx
hosts: google-sdk
become: yes
vars:
login_domain: login-us.bywaystudios.com
shipping_domain: ship-us.bywaystudios.com
tasks:
- name: Render login.conf from template
template:
src: ../../nginx/login.conf.j2
dest: /etc/nginx/conf.d/login.conf
owner: root
group: root
mode: '0644'
notify: Restart nginx
- name: Render shipping.conf from template
template:
src: ../../nginx/shipping.conf.j2
dest: /etc/nginx/conf.d/shipping.conf
owner: root
group: root
mode: '0644'
notify: Restart nginx
handlers:
- name: Restart nginx
shell: nginx -t && systemctl restart nginx
args:
warn: false
- import_playbook: ../login_service.yml

View File

@ -0,0 +1,32 @@
---
- name: Deploy SDK Shipping Service release
hosts: gitea:google-sdk
remote_user: root
tasks:
- name: remove previous build output
file:
path: /data/admin_backend/release/shipping_service/shipping_service
state: absent
delegate_to: localhost
- name: pack.sh
shell: sh /data/admin_backend/release/shipping_service/pack.sh
delegate_to: localhost
- name: copy main
copy:
src: /data/admin_backend/release/shipping_service/shipping_service
dest: /data/meow/shipping_service/shipping_service
mode: 0755
- name: copy start script
copy:
src: /data/admin_backend/release/shipping_service/start.sh
dest: /data/meow/shipping_service
mode: 0755
# - name: copy config
# copy:
# src: /data/admin_backend/release/shipping_service/conf
# dest: /data/meow/shipping_service/
# mode: 0644
# - name: restart web
# shell: sh /data/meow/shipping_service/start.sh restart

53
playbook/ssl.yml Normal file
View File

@ -0,0 +1,53 @@
---
- name: Update Nginx SSL Configuration
hosts: nginxservice
become: yes
vars:
nginx_ssl_cert_path: /etc/nginx/ssl/bywaystudios.com.pem
nginx_ssl_key_path: /etc/nginx/ssl/bywaystudios.com.key
nginx_config_path: /etc/nginx/sites-available/default
nginx_ssl_cert_src: ssl/bywaystudios.com.pem # 新增:证书源文件,可通过 vars/inventory/extra_vars 覆盖
nginx_ssl_key_src: ssl/bywaystudios.com.key # 新增:私钥源文件,可通过 vars/inventory/extra_vars 覆盖
tasks:
- name: Create SSL directory
file:
path: /etc/nginx/ssl
state: directory
mode: '0755'
- name: Copy SSL certificate
copy:
src: "{{ nginx_ssl_cert_src }}"
dest: "{{ nginx_ssl_cert_path }}"
mode: '0644'
notify: Reload Nginx
- name: Copy SSL private key
copy:
src: "{{ nginx_ssl_key_src }}"
dest: "{{ nginx_ssl_key_path }}"
mode: '0600'
notify: Reload Nginx
# - name: Update Nginx SSL configuration
# template:
# src: templates/nginx-ssl.conf.j2
# dest: "{{ nginx_config_path }}"
# mode: '0644'
# notify: Reload Nginx
- name: Test Nginx configuration
command: nginx -t
register: nginx_test
changed_when: false
- name: Display Nginx test result
debug:
msg: "{{ nginx_test.stderr }}"
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded

View File

@ -37,5 +37,5 @@
src: /data/admin_backend/release/backend
dest: /usr/local/admin/backend
# - name: untar
# shell: tar -xvf /usr/local/admin/backend.tar -C /usr/local/admin/backend/
# - name: restart web
# shell: nohup sh /usr/local/admin/backend/start.sh restart

162
script.log Normal file
View File

@ -0,0 +1,162 @@
2025-07-09 10:16:50,830 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:16:53,033 - INFO - MySQL连接成功
2025-07-09 10:16:53,823 - INFO - Redis连接成功
2025-07-09 10:16:53,824 - INFO - 开始备份MySQL数据库...
2025-07-09 10:16:59,823 - ERROR - 备份数据库 Merge_Pet_1 时发生错误: [WinError 2] 系统找不到指定的文件。
2025-07-09 10:16:59,824 - WARNING - MySQL备份失败或没有数据库需要备份
2025-07-09 10:16:59,824 - INFO - 开始备份Redis数据库...
2025-07-09 10:17:00,440 - INFO - Redis后台保存已启动
2025-07-09 10:21:24,549 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:21:24,843 - INFO - MySQL连接成功
2025-07-09 10:21:24,881 - INFO - Redis连接成功
2025-07-09 10:21:24,882 - INFO - 开始备份MySQL数据库...
2025-07-09 10:21:25,203 - ERROR - 备份数据库 Merge_Pet_1 时发生错误: [WinError 2] 系统找不到指定的文件。
2025-07-09 10:21:25,205 - WARNING - MySQL备份失败或没有数据库需要备份
2025-07-09 10:21:25,205 - INFO - 开始备份Redis数据库...
2025-07-09 10:21:25,207 - INFO - Redis后台保存已启动
2025-07-09 10:21:25,207 - ERROR - 备份Redis数据失败: 'DatabaseManager' object has no attribute 'redis'
2025-07-09 10:21:43,686 - INFO - 开始清空MySQL数据库...
2025-07-09 10:21:47,306 - INFO - 用户中断了脚本执行
2025-07-09 10:21:47,306 - INFO - MySQL连接已关闭
2025-07-09 10:21:47,307 - INFO - Redis连接已关闭
2025-07-09 10:22:26,089 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:22:26,276 - INFO - MySQL连接成功
2025-07-09 10:22:26,301 - INFO - Redis连接成功
2025-07-09 10:22:26,301 - INFO - 开始备份MySQL数据库...
2025-07-09 10:26:55,757 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:26:55,871 - INFO - MySQL连接成功
2025-07-09 10:26:55,924 - INFO - Redis连接成功
2025-07-09 10:26:55,925 - INFO - 开始备份MySQL数据库...
2025-07-09 10:26:56,192 - INFO - 准备备份数据库 Merge_Pet_1 到文件: sql\Merge_Pet_1_20250709_102656.sql
2025-07-09 10:26:56,230 - ERROR - 备份数据库 Merge_Pet_1 时发生错误: [WinError 2] 系统找不到指定的文件。
2025-07-09 10:26:56,230 - WARNING - MySQL备份失败或没有数据库需要备份
2025-07-09 10:26:56,230 - INFO - 开始备份Redis数据库...
2025-07-09 10:26:56,233 - INFO - Redis后台保存已启动
2025-07-09 10:26:56,235 - INFO - 等待Redis数据保存完成...
2025-07-09 10:26:57,237 - INFO - Redis数据保存完成
2025-07-09 10:26:57,360 - INFO - Redis RDB文件路径: /data\dump.rdb
2025-07-09 10:26:57,361 - WARNING - 找不到Redis RDB文件: /data\dump.rdb
2025-07-09 10:26:57,362 - INFO - 创建Redis文本格式备份: sql\redis_20250709_102656.txt
2025-07-09 10:26:57,409 - INFO - 正在导出 114 个Redis键...
2025-07-09 10:26:57,548 - INFO - Redis文本备份创建成功: sql\redis_20250709_102656.txt
2025-07-09 10:26:57,548 - INFO - Redis备份完成
2025-07-09 10:27:13,328 - INFO - 用户取消清空操作
2025-07-09 10:27:13,328 - INFO - MySQL连接已关闭
2025-07-09 10:27:13,329 - INFO - Redis连接已关闭
2025-07-09 10:28:18,999 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:28:19,067 - INFO - MySQL连接成功
2025-07-09 10:28:19,114 - INFO - Redis连接成功
2025-07-09 10:28:19,115 - INFO - 开始备份MySQL数据库...
2025-07-09 10:28:19,403 - INFO - 准备备份数据库 Merge_Pet_1 到文件: sql\Merge_Pet_1_20250709_102819.sql
2025-07-09 10:28:19,435 - ERROR - 备份数据库 Merge_Pet_1 时发生错误: [WinError 2] 系统找不到指定的文件。
2025-07-09 10:28:19,436 - WARNING - MySQL备份失败或没有数据库需要备份
2025-07-09 10:28:19,436 - INFO - 开始备份Redis数据库...
2025-07-09 10:28:19,443 - INFO - Redis后台保存已启动
2025-07-09 10:28:19,444 - INFO - 等待Redis数据保存完成...
2025-07-09 10:28:20,446 - INFO - Redis数据保存完成
2025-07-09 10:28:20,449 - INFO - Redis RDB文件路径: /data\dump.rdb
2025-07-09 10:28:20,449 - WARNING - 找不到Redis RDB文件: /data\dump.rdb
2025-07-09 10:28:20,450 - INFO - 创建Redis文本格式备份: sql\redis_20250709_102819.txt
2025-07-09 10:28:20,465 - INFO - 正在导出 114 个Redis键...
2025-07-09 10:28:20,618 - INFO - Redis文本备份创建成功: sql\redis_20250709_102819.txt
2025-07-09 10:28:20,618 - INFO - Redis备份完成
2025-07-09 10:28:40,414 - INFO - 开始执行数据库备份和清空脚本
2025-07-09 10:28:40,473 - INFO - MySQL连接成功
2025-07-09 10:28:40,504 - INFO - Redis连接成功
2025-07-09 10:28:40,504 - INFO - 开始备份MySQL数据库...
2025-07-09 10:28:40,759 - INFO - 准备备份数据库 Merge_Pet_1 到文件: sql\Merge_Pet_1_20250709_102840.sql
2025-07-09 02:35:56,610 - INFO - 寮€濮嬫墽琛屾暟鎹<E69A9F>簱澶囦唤鍜屾竻绌鸿剼鏈<E589BC>
2025-07-09 02:35:56,637 - ERROR - MySQL杩炴帴澶辫触: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")
2025-07-09 02:35:56,639 - ERROR - Redis杩炴帴澶辫触: Error 111 connecting to localhost:6379. Connection refused.
2025-07-09 02:35:56,639 - ERROR - 鏃犳硶杩炴帴鍒颁换浣曟暟鎹<E69A9F>簱锛岃剼鏈<E589BC>€€鍑<E282AC>
2025-07-09 02:35:56,640 - INFO - Redis杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:37:14,841 - INFO - 寮€濮嬫墽琛屾暟鎹<E69A9F>簱澶囦唤鍜屾竻绌鸿剼鏈<E589BC>
2025-07-09 02:37:15,110 - INFO - MySQL杩炴帴鎴愬姛
2025-07-09 02:37:15,112 - INFO - Redis杩炴帴鎴愬姛
2025-07-09 02:37:15,112 - INFO - 寮€濮嬪<E6BFAE>浠組ySQL鏁版嵁搴<E5B581>...
2025-07-09 02:37:15,395 - INFO - 鍑嗗<E98D91>澶囦唤鏁版嵁搴<E5B581> Merge_Pet_1 鍒版枃浠<E69E83>: sql/Merge_Pet_1_20250709_023715.sql
2025-07-09 02:37:21,737 - INFO - 鏁版嵁搴<E5B581> Merge_Pet_1 澶囦唤鎴愬姛: sql/Merge_Pet_1_20250709_023715.sql (澶у皬: 2378614 瀛楄妭)
2025-07-09 02:37:21,738 - INFO - MySQL澶囦唤瀹屾垚锛屽叡澶囦唤 1 涓<>暟鎹<E69A9F>
2025-07-09 02:37:21,738 - INFO - 寮€濮嬪<E6BFAE>浠絉edis鏁版嵁搴<E5B581>...
2025-07-09 02:37:21,741 - INFO - Redis鍚庡彴淇濆瓨宸插惎鍔<E6838E>
2025-07-09 02:37:21,742 - INFO - 绛夊緟Redis鏁版嵁淇濆瓨瀹屾垚...
2025-07-09 02:37:22,743 - INFO - Redis鏁版嵁淇濆瓨瀹屾垚
2025-07-09 02:37:22,744 - INFO - Redis RDB鏂囦欢璺<E6ACA2>緞: /data/dump.rdb
2025-07-09 02:37:22,745 - WARNING - 鎵句笉鍒癛edis RDB鏂囦欢: /data/dump.rdb
2025-07-09 02:37:22,747 - INFO - 鍒涘缓Redis鏂囨湰鏍煎紡澶囦唤: sql/redis_20250709_023721.txt
2025-07-09 02:37:22,751 - INFO - 姝e湪瀵煎嚭 114 涓猂edis閿<73>...
2025-07-09 02:37:22,804 - INFO - Redis鏂囨湰澶囦唤鍒涘缓鎴愬姛: sql/redis_20250709_023721.txt
2025-07-09 02:37:22,804 - INFO - Redis澶囦唤瀹屾垚
2025-07-09 02:37:35,300 - INFO - 鐢ㄦ埛鍙栨秷娓呯┖鎿嶄綔
2025-07-09 02:37:35,301 - INFO - MySQL杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:37:35,301 - INFO - Redis杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:43:39,640 - INFO - 寮€濮嬫墽琛屾暟鎹<E69A9F>簱澶囦唤鍜屾竻绌鸿剼鏈<E589BC>
2025-07-09 02:43:39,677 - INFO - MySQL杩炴帴鎴愬姛
2025-07-09 02:43:39,679 - INFO - Redis杩炴帴鎴愬姛
2025-07-09 02:43:39,680 - INFO - 寮€濮嬪<E6BFAE>浠組ySQL鏁版嵁搴<E5B581>...
2025-07-09 02:43:39,744 - INFO - 鍑嗗<E98D91>澶囦唤鏁版嵁搴<E5B581> Merge_Pet_1 鍒版枃浠<E69E83>: sql/Merge_Pet_1_20250709_024339.sql
2025-07-09 02:43:40,424 - INFO - 鏁版嵁搴<E5B581> Merge_Pet_1 澶囦唤鎴愬姛: sql/Merge_Pet_1_20250709_024339.sql (澶у皬: 2378612 瀛楄妭)
2025-07-09 02:43:40,424 - INFO - MySQL澶囦唤瀹屾垚锛屽叡澶囦唤 1 涓<>暟鎹<E69A9F>
2025-07-09 02:43:40,424 - INFO - 寮€濮嬪<E6BFAE>浠絉edis鏁版嵁搴<E5B581>...
2025-07-09 02:43:40,427 - INFO - Redis鍚庡彴淇濆瓨宸插惎鍔<E6838E>
2025-07-09 02:43:40,428 - INFO - 绛夊緟Redis鏁版嵁淇濆瓨瀹屾垚...
2025-07-09 02:43:41,428 - INFO - Redis鏁版嵁淇濆瓨瀹屾垚
2025-07-09 02:43:41,429 - INFO - Redis RDB鏂囦欢璺<E6ACA2>緞: /data/dump.rdb
2025-07-09 02:43:41,430 - WARNING - 鎵句笉鍒癛edis RDB鏂囦欢: /data/dump.rdb
2025-07-09 02:43:41,433 - INFO - 鍒涘缓Redis鏂囨湰鏍煎紡澶囦唤: sql/redis_20250709_024340.txt
2025-07-09 02:43:41,436 - INFO - 姝e湪瀵煎嚭 114 涓猂edis閿<73>...
2025-07-09 02:43:41,487 - INFO - Redis鏂囨湰澶囦唤鍒涘缓鎴愬姛: sql/redis_20250709_024340.txt
2025-07-09 02:43:41,487 - INFO - Redis澶囦唤瀹屾垚
2025-07-09 02:43:42,891 - INFO - 寮€濮嬫竻绌篗ySQL鏁版嵁搴<E5B581>...
2025-07-09 02:43:44,155 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.db_version
2025-07-09 02:43:45,240 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.system_mail_info
2025-07-09 02:43:46,625 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_account
2025-07-09 02:43:47,674 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_gameserver
2025-07-09 02:43:49,208 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_baseinfo
2025-07-09 02:43:50,275 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_charge
2025-07-09 02:43:51,196 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_mod
2025-07-09 02:43:52,310 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_server_mod
2025-07-09 02:43:52,311 - INFO - 鏁版嵁搴<E5B581> Merge_Pet_1 鎵€鏈夎〃宸叉竻绌<E7ABBB>
2025-07-09 02:43:52,312 - INFO - MySQL鏁版嵁搴撴竻绌哄畬鎴<E795AC>
2025-07-09 02:43:52,312 - INFO - 寮€濮嬫竻绌篟edis鏁版嵁搴<E5B581>...
2025-07-09 02:43:52,313 - INFO - Redis鏁版嵁搴撳綋鍓嶆湁 114 涓猭ey
2025-07-09 02:43:52,512 - INFO - Redis鏁版嵁搴撳凡娓呯┖
2025-07-09 02:43:52,513 - INFO - Redis鏁版嵁搴撴竻绌哄畬鎴<E795AC>
2025-07-09 02:43:52,513 - INFO - 鎵€鏈夋搷浣滃畬鎴<E795AC>
2025-07-09 02:43:52,513 - INFO - MySQL杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:43:52,514 - INFO - Redis杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:47:05,098 - INFO - 寮€濮嬫墽琛屾暟鎹<E69A9F>簱澶囦唤鍜屾竻绌鸿剼鏈<E589BC>
2025-07-09 02:47:05,168 - INFO - MySQL杩炴帴鎴愬姛
2025-07-09 02:47:05,180 - INFO - Redis杩炴帴鎴愬姛
2025-07-09 02:47:05,180 - INFO - 寮€濮嬪<E6BFAE>浠組ySQL鏁版嵁搴<E5B581>...
2025-07-09 02:47:05,250 - INFO - 鍑嗗<E98D91>澶囦唤鏁版嵁搴<E5B581> Merge_Pet_1 鍒版枃浠<E69E83>: backups/Merge_Pet_1_20250709_024705.sql
2025-07-09 02:47:05,698 - INFO - 鏁版嵁搴<E5B581> Merge_Pet_1 澶囦唤鎴愬姛: backups/Merge_Pet_1_20250709_024705.sql (澶у皬: 12226 瀛楄妭)
2025-07-09 02:47:05,699 - INFO - MySQL澶囦唤瀹屾垚锛屽叡澶囦唤 1 涓<>暟鎹<E69A9F>
2025-07-09 02:47:05,699 - INFO - 寮€濮嬪<E6BFAE>浠絉edis鏁版嵁搴<E5B581>...
2025-07-09 02:47:05,702 - INFO - Redis鍚庡彴淇濆瓨宸插惎鍔<E6838E>
2025-07-09 02:47:05,703 - INFO - 绛夊緟Redis鏁版嵁淇濆瓨瀹屾垚...
2025-07-09 02:47:06,704 - INFO - Redis鏁版嵁淇濆瓨瀹屾垚
2025-07-09 02:47:06,705 - INFO - Redis RDB鏂囦欢璺<E6ACA2>緞: /data/dump.rdb
2025-07-09 02:47:06,706 - WARNING - 鎵句笉鍒癛edis RDB鏂囦欢: /data/dump.rdb
2025-07-09 02:47:06,707 - INFO - 鍒涘缓Redis鏂囨湰鏍煎紡澶囦唤: backups/redis_20250709_024705.txt
2025-07-09 02:47:06,709 - INFO - Redis鏁版嵁搴撲负绌猴紝鍒涘缓绌哄<E7BB8C>浠芥枃浠<E69E83>
2025-07-09 02:47:06,712 - INFO - Redis鏂囨湰澶囦唤鍒涘缓鎴愬姛: backups/redis_20250709_024705.txt
2025-07-09 02:47:06,712 - INFO - Redis澶囦唤瀹屾垚
2025-07-09 02:47:10,331 - INFO - 寮€濮嬫竻绌篗ySQL鏁版嵁搴<E5B581>...
2025-07-09 02:47:11,425 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.db_version
2025-07-09 02:47:12,500 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.system_mail_info
2025-07-09 02:47:13,638 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_account
2025-07-09 02:47:14,467 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_gameserver
2025-07-09 02:47:15,614 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_baseinfo
2025-07-09 02:47:16,548 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_charge
2025-07-09 02:47:17,448 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_player_mod
2025-07-09 02:47:18,290 - INFO - 宸叉竻绌鸿〃: Merge_Pet_1.t_server_mod
2025-07-09 02:47:18,291 - INFO - 鏁版嵁搴<E5B581> Merge_Pet_1 鎵€鏈夎〃宸叉竻绌<E7ABBB>
2025-07-09 02:47:18,291 - INFO - MySQL鏁版嵁搴撴竻绌哄畬鎴<E795AC>
2025-07-09 02:47:18,291 - INFO - 寮€濮嬫竻绌篟edis鏁版嵁搴<E5B581>...
2025-07-09 02:47:18,292 - INFO - Redis鏁版嵁搴撳綋鍓嶆湁 0 涓猭ey
2025-07-09 02:47:18,292 - INFO - Redis鏁版嵁搴撳凡缁忔槸绌虹殑
2025-07-09 02:47:18,293 - INFO - Redis鏁版嵁搴撴竻绌哄畬鎴<E795AC>
2025-07-09 02:47:18,293 - INFO - 鎵€鏈夋搷浣滃畬鎴<E795AC>
2025-07-09 02:47:18,294 - INFO - MySQL杩炴帴宸插叧闂<E58FA7>
2025-07-09 02:47:18,294 - INFO - Redis杩炴帴宸插叧闂<E58FA7>

217
script.py
View File

@ -3,8 +3,8 @@
"""
数据库备份和清空脚本
功能
1. 备份MySQL数据库
2. 清空MySQL数据库
1. 备份MySQL数据库支持指定特定数据库
2. 清空MySQL数据库支持指定特定数据库
3. 清空Redis数据库
"""
@ -30,15 +30,15 @@ logger = logging.getLogger(__name__)
# 数据库配置
MYSQL_CONFIG = {
'host': '172.20.0.5',
'host': '127.0.0.1',
'port': 3306,
'user': 'root',
'password': 'root',
'password': 'Xijing1!',
'charset': 'utf8mb4'
}
REDIS_CONFIG = {
'host': '172.20.0.6',
'host': '127.0.0.1',
'port': 6379,
'password': None, # 如果有密码请设置
'db': 0
@ -47,12 +47,16 @@ REDIS_CONFIG = {
# 备份目录
BACKUP_DIR = './backups'
# 指定要操作的数据库列表(为空表示操作所有用户数据库)
TARGET_DATABASES = ["merge_pet_1"] # 例如: ['database1', 'database2']
class DatabaseManager:
def __init__(self):
def __init__(self, target_databases=None):
self.mysql_conn = None
self.redis_conn = None
self.backup_dir = Path(BACKUP_DIR)
self.backup_dir.mkdir(exist_ok=True)
self.target_databases = target_databases or []
def connect_mysql(self):
"""连接MySQL数据库"""
@ -115,7 +119,7 @@ class DatabaseManager:
# 创建备份文件(如果不存在会自动创建)
logger.info(f"准备备份数据库 {database_name} 到文件: {backup_file}")
with open(backup_file, 'w', encoding='utf-8') as f:
result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True)
result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, start_new_session=True)
if result.returncode == 0:
# 检查备份文件是否创建成功并且有内容
@ -151,6 +155,86 @@ class DatabaseManager:
return backup_files
def get_target_databases(self):
"""获取要操作的数据库列表"""
all_databases = self.get_mysql_databases()
if not all_databases:
logger.warning("没有找到用户数据库")
return []
if self.target_databases:
# 验证指定的数据库是否存在
valid_databases = []
for db in self.target_databases:
if db in all_databases:
valid_databases.append(db)
else:
logger.warning(f"指定的数据库 '{db}' 不存在")
return valid_databases
else:
# 如果没有指定,让用户选择
return self.select_databases_interactively(all_databases)
def select_databases_interactively(self, all_databases):
"""交互式选择数据库"""
print("\n可用的数据库列表:")
for i, db in enumerate(all_databases, 1):
print(f"{i}. {db}")
print(f"{len(all_databases) + 1}. 所有数据库")
print("0. 退出")
while True:
try:
choice = input("\n请选择要操作的数据库(输入数字,多个数字用逗号分隔): ").strip()
if choice == '0':
logger.info("用户选择退出")
return []
if choice == str(len(all_databases) + 1):
logger.info("用户选择操作所有数据库")
return all_databases
# 解析用户输入的数字
selected_indices = [int(x.strip()) for x in choice.split(',') if x.strip()]
selected_databases = []
for index in selected_indices:
if 1 <= index <= len(all_databases):
selected_databases.append(all_databases[index - 1])
else:
print(f"无效的选择: {index}")
continue
if selected_databases:
logger.info(f"用户选择的数据库: {', '.join(selected_databases)}")
return selected_databases
else:
print("没有有效的选择,请重新输入")
except ValueError:
print("输入格式错误,请输入数字")
except KeyboardInterrupt:
logger.info("用户中断操作")
return []
def backup_selected_mysql_databases(self):
"""备份选定的MySQL数据库"""
databases = self.get_target_databases()
if not databases:
logger.warning("没有选择要备份的数据库")
return []
backup_files = []
for db in databases:
logger.info(f"正在备份数据库: {db}")
backup_file = self.backup_mysql_database(db)
if backup_file:
backup_files.append(backup_file)
return backup_files
def clear_mysql_database(self, database_name):
"""清空指定MySQL数据库的所有表"""
try:
@ -193,6 +277,24 @@ class DatabaseManager:
for db in databases:
self.clear_mysql_database(db)
def clear_selected_mysql_databases(self):
"""清空选定的MySQL数据库"""
databases = self.get_target_databases()
if not databases:
logger.warning("没有选择要清空的数据库")
return
# 确认清空操作
print(f"\n即将清空以下数据库: {', '.join(databases)}")
confirm = input("确认要清空这些数据库吗?(y/N): ")
if confirm.lower() != 'y':
logger.info("用户取消清空操作")
return
for db in databases:
logger.info(f"正在清空数据库: {db}")
self.clear_mysql_database(db)
def backup_redis_database(self):
"""备份Redis数据库"""
try:
@ -351,54 +453,101 @@ class DatabaseManager:
self.redis_conn.close()
logger.info("Redis连接已关闭")
def select_operation_mode():
"""选择操作模式"""
print("\n请选择操作模式:")
print("1. 仅备份数据库")
print("2. 仅清空数据库")
print("3. 备份后清空数据库")
print("4. 备份和清空Redis")
print("0. 退出")
while True:
try:
choice = input("\n请输入选择 (0-4): ").strip()
if choice in ['0', '1', '2', '3', '4']:
return choice
else:
print("无效选择,请输入 0-4")
except KeyboardInterrupt:
return '0'
def main():
"""主函数"""
logger.info("开始执行数据库备份和清空脚本")
db_manager = DatabaseManager()
# 选择操作模式
mode = select_operation_mode()
if mode == '0':
logger.info("用户选择退出")
return True
# 从配置或用户交互获取目标数据库
target_dbs = TARGET_DATABASES if TARGET_DATABASES else None
db_manager = DatabaseManager(target_databases=target_dbs)
try:
# 连接数据库
mysql_connected = db_manager.connect_mysql()
redis_connected = db_manager.connect_redis()
redis_connected = db_manager.connect_redis() if mode == '4' else True
if not mysql_connected and not redis_connected:
logger.error("无法连接到任何数据库,脚本退出")
if mode in ['1', '2', '3'] and not mysql_connected:
logger.error("无法连接到MySQL数据库,脚本退出")
return False
# 1. 备份MySQL数据库
if mysql_connected:
if mode == '4' and not redis_connected:
logger.error("无法连接到Redis数据库脚本退出")
return False
# 执行相应操作
if mode == '1': # 仅备份
logger.info("开始备份MySQL数据库...")
backup_files = db_manager.backup_all_mysql_databases()
backup_files = db_manager.backup_selected_mysql_databases()
if backup_files:
logger.info(f"MySQL备份完成共备份 {len(backup_files)} 个数据库")
else:
logger.warning("MySQL备份失败或没有数据库需要备份")
# 2. 备份Redis数据库
if redis_connected:
elif mode == '2': # 仅清空
logger.info("开始清空MySQL数据库...")
db_manager.clear_selected_mysql_databases()
logger.info("MySQL数据库清空完成")
elif mode == '3': # 备份后清空
# 1. 备份MySQL数据库
logger.info("开始备份MySQL数据库...")
backup_files = db_manager.backup_selected_mysql_databases()
if backup_files:
logger.info(f"MySQL备份完成共备份 {len(backup_files)} 个数据库")
# 确认是否继续清空数据库
confirm = input("备份完成,是否继续清空数据库?(y/N): ")
if confirm.lower() == 'y':
logger.info("开始清空MySQL数据库...")
# 重新使用相同的数据库选择
db_manager.target_databases = [os.path.basename(f).split('_')[0] for f in backup_files]
db_manager.clear_selected_mysql_databases()
logger.info("MySQL数据库清空完成")
else:
logger.info("用户取消清空操作")
else:
logger.warning("MySQL备份失败跳过清空操作")
elif mode == '4': # Redis操作
# 备份Redis
logger.info("开始备份Redis数据库...")
redis_backup = db_manager.backup_redis_database()
if redis_backup:
logger.info("Redis备份完成")
# 确认是否继续清空数据库
confirm = input("备份完成,是否继续清空数据库?(y/N): ")
if confirm.lower() != 'y':
logger.info("用户取消清空操作")
return True
# 3. 清空MySQL数据库
if mysql_connected:
logger.info("开始清空MySQL数据库...")
db_manager.clear_all_mysql_databases()
logger.info("MySQL数据库清空完成")
# 4. 清空Redis数据库
if redis_connected:
logger.info("开始清空Redis数据库...")
if db_manager.clear_redis_database():
logger.info("Redis数据库清空完成")
# 确认是否清空Redis
confirm = input("Redis备份完成是否清空Redis数据库(y/N): ")
if confirm.lower() == 'y':
logger.info("开始清空Redis数据库...")
if db_manager.clear_redis_database():
logger.info("Redis数据库清空完成")
else:
logger.info("用户取消Redis清空操作")
logger.info("所有操作完成")
return True

BIN
script/Item.xlsx Normal file

Binary file not shown.

Binary file not shown.

BIN
script/OrderData.xlsx Normal file

Binary file not shown.

531
script/automate.py Normal file
View File

@ -0,0 +1,531 @@
import requests
from bs4 import BeautifulSoup
import time
import json
import csv
import os
from urllib.parse import urljoin, urlparse
import logging
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
import asyncio
class WebScraper:
def __init__(self, delay=1, timeout=30000, headless=True):
"""
初始化爬虫
:param delay: 请求间隔时间
:param timeout: 页面加载超时时间毫秒
:param headless: 是否无头模式运行浏览器
"""
self.delay = delay
self.timeout = timeout
self.headless = headless
self.playwright = None
self.browser = None
self.context = None
# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
self.logger = logging.getLogger(__name__)
def start_browser(self):
"""启动浏览器"""
try:
self.playwright = sync_playwright().start()
self.browser = self.playwright.chromium.launch(
headless=self.headless,
args=[
'--disable-blink-features=AutomationControlled',
'--no-sandbox',
'--disable-dev-shm-usage'
]
)
self.context = self.browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
viewport={'width': 1920, 'height': 1080}
)
self.logger.info("浏览器启动成功")
except Exception as e:
self.logger.error(f"启动浏览器失败: {e}")
raise
def stop_browser(self):
"""关闭浏览器"""
if self.context:
self.context.close()
if self.browser:
self.browser.close()
if self.playwright:
self.playwright.stop()
self.logger.info("浏览器已关闭")
def get_page_with_playwright(self, url, max_retries=3, wait_for_load=True):
"""
使用Playwright获取网页内容
:param url: 目标URL
:param max_retries: 最大重试次数
:param wait_for_load: 是否等待页面完全加载
:return: HTML内容或None
"""
if not self.context:
self.start_browser()
for attempt in range(max_retries):
page = None
try:
page = self.context.new_page()
# 设置额外的请求头
page.set_extra_http_headers({
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
})
# 访问页面
response = page.goto(url, timeout=self.timeout, wait_until='domcontentloaded')
if response and response.status == 200:
# 等待页面加载完成
if wait_for_load:
try:
# 等待网络空闲
page.wait_for_load_state('networkidle', timeout=10000)
# 额外等待JavaScript执行
page.wait_for_timeout(2000)
except PlaywrightTimeoutError:
self.logger.warning(f"页面加载超时,但继续处理: {url}")
# 获取页面内容
html_content = page.content()
page.close()
self.logger.info(f"成功获取页面: {url}")
time.sleep(self.delay)
return html_content
else:
self.logger.warning(f"页面响应状态异常: {response.status if response else 'None'}")
except PlaywrightTimeoutError:
self.logger.warning(f"页面加载超时 (尝试 {attempt + 1}/{max_retries}): {url}")
except Exception as e:
self.logger.warning(f"获取页面失败 (尝试 {attempt + 1}/{max_retries}): {e}")
finally:
if page:
page.close()
if attempt < max_retries - 1:
time.sleep(2 ** attempt) # 指数退避
self.logger.error(f"无法获取页面: {url}")
return None
def get_page(self, url, max_retries=3):
"""
获取网页内容兼容方法使用Playwright
:param url: 目标URL
:param max_retries: 最大重试次数
:return: HTML内容或None
"""
return self.get_page_with_playwright(url, max_retries)
def parse_html(self, html_content, parser='html.parser'):
"""
解析HTML内容
:param html_content: HTML字符串
:param parser: 解析器类型
:return: BeautifulSoup对象
"""
return BeautifulSoup(html_content, parser)
def extract_links(self, soup, base_url):
"""
提取页面中的所有链接
:param soup: BeautifulSoup对象
:param base_url: 基础URL
:return: 链接列表
"""
links = []
for link in soup.find_all('a', href=True):
full_url = urljoin(base_url, link['href'])
links.append({
'url': full_url,
'text': link.get_text(strip=True),
'title': link.get('title', '')
})
return links
def extract_images(self, soup, base_url):
"""
提取页面中的所有图片
:param soup: BeautifulSoup对象
:param base_url: 基础URL
:return: 图片信息列表
"""
images = []
for img in soup.find_all('img'):
src = img.get('src')
if src:
full_url = urljoin(base_url, src)
images.append({
'url': full_url,
'alt': img.get('alt', ''),
'title': img.get('title', '')
})
return images
def save_to_json(self, data, filename):
"""
保存数据为JSON格式
:param data: 要保存的数据
:param filename: 文件名
"""
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
self.logger.info(f"数据已保存到: {filename}")
def save_to_csv(self, data, filename, fieldnames):
"""
保存数据为CSV格式
:param data: 要保存的数据列表
:param filename: 文件名
:param fieldnames: CSV字段名
"""
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(data)
self.logger.info(f"数据已保存到: {filename}")
def save_to_html(self, html_content, filename):
"""
保存HTML内容到文件
:param html_content: HTML内容
:param filename: 文件名
"""
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, 'w', encoding='utf-8') as f:
f.write(html_content)
self.logger.info(f"HTML已保存到: {filename}")
def scrape_page(self, url):
"""
爬取单个页面的完整信息
:param url: 目标URL
:return: 页面数据字典
"""
html_content = self.get_page_with_playwright(url)
if not html_content:
return None
# 保存原始HTML内容
soup = self.parse_html(html_content)
# 提取基本信息
title = soup.find('title')
title_text = title.get_text(strip=True) if title else ''
# 提取meta信息
meta_description = soup.find('meta', attrs={'name': 'description'})
description = meta_description.get('content', '') if meta_description else ''
# 提取链接和图片
links = self.extract_links(soup, url)
images = self.extract_images(soup, url)
# 提取文本内容
text_content = soup.get_text(strip=True)
# 提取JavaScript变量特别针对飞书等SPA应用
script_data = self.extract_script_data(soup)
return {
'url': url,
'title': title_text,
'description': description,
'links': links,
'images': images,
'text_length': len(text_content),
'html_content': html_content,
'html_length': len(html_content),
'script_data': script_data,
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
}
def extract_script_data(self, soup):
"""
提取页面中的JavaScript数据
:param soup: BeautifulSoup对象
:return: 提取的数据字典
"""
script_data = {}
# 查找包含JSON数据的script标签
for script in soup.find_all('script'):
script_text = script.get_text()
# 查找常见的数据模式
patterns = [
'window.__pageStartTime',
'window.serverInjectRes',
'window.ENV',
'window.locales',
'window.deviceInfoBySSO'
]
for pattern in patterns:
if pattern in script_text:
try:
# 提取变量赋值
lines = script_text.split('\n')
for line in lines:
if pattern in line and '=' in line:
script_data[pattern] = line.strip()
except Exception as e:
self.logger.warning(f"提取脚本数据失败: {e}")
return script_data
def create_safe_filename(self, url, max_length=100):
"""
创建安全的文件名
:param url: 原始URL
:param max_length: 最大文件名长度
:return: 安全的文件名
"""
# 移除协议
safe_name = url.replace('https://', '').replace('http://', '')
# 替换或移除无效字符
invalid_chars = ['<', '>', ':', '"', '|', '?', '*', '/', '\\', '&', '=', '#']
for char in invalid_chars:
safe_name = safe_name.replace(char, '_')
# 移除连续的下划线
while '__' in safe_name:
safe_name = safe_name.replace('__', '_')
# 移除开头和结尾的下划线
safe_name = safe_name.strip('_')
# 限制长度
if len(safe_name) > max_length:
safe_name = safe_name[:max_length]
# 确保文件名不为空
if not safe_name:
safe_name = 'scraped_page'
return safe_name
def manual_login_and_scrape(self, login_url, target_urls):
"""
手动登录并爬取页面
:param login_url: 登录页面URL
:param target_urls: 需要爬取的目标URL列表
:return: 爬取结果列表
"""
if not self.context:
self.start_browser()
page = self.context.new_page()
try:
# 打开登录页面
self.logger.info(f"正在打开登录页面: {login_url}")
page.goto(login_url, timeout=self.timeout)
# 等待用户手动登录
print("=" * 60)
print("浏览器已打开,请在浏览器中完成登录操作")
print("登录完成后,请在此控制台按回车键继续...")
print("=" * 60)
input()
# 确认登录状态
current_url = page.url
self.logger.info(f"当前页面URL: {current_url}")
# 获取cookies用于后续请求
cookies = self.context.cookies()
self.logger.info(f"获取到 {len(cookies)} 个cookies")
# 开始爬取目标页面
results = []
for url in target_urls:
print(f"正在爬取: {url}")
data = self.scrape_page_with_session(page, url)
if data:
results.append(data)
return results
except Exception as e:
self.logger.error(f"手动登录过程中发生错误: {e}")
return []
finally:
if page:
page.close()
def scrape_page_with_session(self, page, url):
"""
使用已有session爬取页面
:param page: Playwright页面对象
:param url: 目标URL
:return: 页面数据字典
"""
try:
# 导航到目标页面
response = page.goto(url, timeout=self.timeout, wait_until='domcontentloaded')
if response and response.status == 200:
# 等待页面加载完成
try:
page.wait_for_load_state('networkidle', timeout=15000)
page.wait_for_timeout(3000) # 额外等待时间确保内容加载
except PlaywrightTimeoutError:
self.logger.warning(f"页面加载超时,但继续处理: {url}")
# 获取页面内容
html_content = page.content()
# 解析页面内容
soup = self.parse_html(html_content)
# 提取基本信息
title = soup.find('title')
title_text = title.get_text(strip=True) if title else ''
# 提取meta信息
meta_description = soup.find('meta', attrs={'name': 'description'})
description = meta_description.get('content', '') if meta_description else ''
# 提取链接和图片
links = self.extract_links(soup, url)
images = self.extract_images(soup, url)
# 提取文本内容
text_content = soup.get_text(strip=True)
# 提取JavaScript变量
script_data = self.extract_script_data(soup)
self.logger.info(f"成功获取页面: {url}")
time.sleep(self.delay)
return {
'url': url,
'title': title_text,
'description': description,
'links': links,
'images': images,
'text_length': len(text_content),
'html_content': html_content,
'html_length': len(html_content),
'script_data': script_data,
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S')
}
else:
self.logger.warning(f"页面响应状态异常: {response.status if response else 'None'}")
return None
except Exception as e:
self.logger.error(f"爬取页面失败: {e}")
return None
def wait_for_manual_action(self, page, message="请完成操作后按回车继续..."):
"""
等待用户手动操作
:param page: Playwright页面对象
:param message: 提示信息
"""
print("=" * 60)
print(f"当前页面: {page.url}")
print(message)
print("=" * 60)
input()
def main():
"""
示例使用方法 - 手动登录模式
"""
# 创建爬虫实例(非无头模式,便于手动登录)
scraper = WebScraper(delay=2, timeout=30000, headless=False)
try:
# 启动浏览器
scraper.start_browser()
# 定义输出目录
output_dir = 'd:/Github/devops/output'
# 登录页面和目标页面
login_url = 'https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9'
target_urls = [
'https://yixj5m42od.feishu.cn/sheets/VlAIsKxYchNABztr3RGcBnrEnYM?table=tblNs3625a9MAc89&view=vewkRuPWCL&sheet=y1FRE9',
# 可以添加更多需要爬取的页面
]
# 手动登录并爬取
print("开始手动登录流程...")
results = scraper.manual_login_and_scrape(login_url, target_urls)
# 保存结果
if results:
# 保存HTML文件
for result in results:
safe_filename = scraper.create_safe_filename(result['url'])
html_filename = f'{output_dir}/html/{safe_filename}_logged_in.html'
scraper.save_to_html(result['html_content'], html_filename)
# 保存完整数据包含HTML到JSON
scraper.save_to_json(results, f'{output_dir}/scrape_results_full_logged_in.json')
# 保存不含HTML的精简版本到JSON
simplified_results = []
for result in results:
simplified_result = result.copy()
simplified_result.pop('html_content', None)
simplified_results.append(simplified_result)
scraper.save_to_json(simplified_results, f'{output_dir}/scrape_results_logged_in.json')
# 保存CSV
csv_data = []
for result in results:
csv_data.append({
'url': result['url'],
'title': result['title'],
'description': result['description'],
'links_count': len(result['links']),
'images_count': len(result['images']),
'html_length': result['html_length'],
'timestamp': result['timestamp']
})
fieldnames = ['url', 'title', 'description', 'links_count', 'images_count', 'html_length', 'timestamp']
scraper.save_to_csv(csv_data, f'{output_dir}/scrape_results_logged_in.csv', fieldnames)
print(f"爬取完成,共处理 {len(results)} 个页面")
print(f"HTML文件保存在: {output_dir}/html/")
print(f"完整数据保存在: {output_dir}/scrape_results_full_logged_in.json")
else:
print("未获取到任何数据")
except KeyboardInterrupt:
print("\n用户中断操作")
except Exception as e:
print(f"发生错误: {e}")
finally:
# 确保浏览器被关闭
print("正在关闭浏览器...")
scraper.stop_browser()
if __name__ == "__main__":
main()

582
script/backup.py Normal file
View File

@ -0,0 +1,582 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库备份和清空脚本
功能
1. 备份MySQL数据库支持指定特定数据库
2. 清空MySQL数据库支持指定特定数据库
3. 清空Redis数据库
"""
import os
import sys
import subprocess
import datetime
import logging
import redis
import pymysql
from pathlib import Path
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('script.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# 数据库配置
MYSQL_CONFIG = {
'host': '127.0.0.1',
'port': 3306,
'user': 'root',
'password': 'Xijing1!',
'charset': 'utf8mb4'
}
REDIS_CONFIG = {
'host': '127.0.0.1',
'port': 6379,
'password': None, # 如果有密码请设置
'db': 0
}
# 备份目录
BACKUP_DIR = './backups'
# 指定要操作的数据库列表(为空表示操作所有用户数据库)
TARGET_DATABASES = ["merge_pet_1"] # 例如: ['database1', 'database2']
class DatabaseManager:
def __init__(self, target_databases=None):
self.mysql_conn = None
self.redis_conn = None
self.backup_dir = Path(BACKUP_DIR)
self.backup_dir.mkdir(exist_ok=True)
self.target_databases = target_databases or []
def connect_mysql(self):
"""连接MySQL数据库"""
try:
self.mysql_conn = pymysql.connect(**MYSQL_CONFIG)
logger.info("MySQL连接成功")
return True
except Exception as e:
logger.error(f"MySQL连接失败: {e}")
return False
def connect_redis(self):
"""连接Redis数据库"""
try:
self.redis_conn = redis.Redis(**REDIS_CONFIG)
self.redis_conn.ping()
logger.info("Redis连接成功")
return True
except Exception as e:
logger.error(f"Redis连接失败: {e}")
return False
def get_mysql_databases(self):
"""获取所有MySQL数据库列表排除系统数据库"""
try:
cursor = self.mysql_conn.cursor()
cursor.execute("SHOW DATABASES")
databases = [db[0] for db in cursor.fetchall()]
# 排除系统数据库
system_dbs = ['information_schema', 'performance_schema', 'mysql', 'sys']
user_dbs = [db for db in databases if db not in system_dbs]
cursor.close()
return user_dbs
except Exception as e:
logger.error(f"获取数据库列表失败: {e}")
return []
def backup_mysql_database(self, database_name):
"""备份指定的MySQL数据库"""
try:
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = self.backup_dir / f"{database_name}_{timestamp}.sql"
# 确保备份目录存在
backup_file.parent.mkdir(parents=True, exist_ok=True)
# 使用mysqldump命令备份
cmd = [
'mysqldump',
f'--host={MYSQL_CONFIG["host"]}',
f'--port={MYSQL_CONFIG["port"]}',
f'--user={MYSQL_CONFIG["user"]}',
f'--password={MYSQL_CONFIG["password"]}',
'--single-transaction',
'--routines',
'--triggers',
database_name
]
# 创建备份文件(如果不存在会自动创建)
logger.info(f"准备备份数据库 {database_name} 到文件: {backup_file}")
with open(backup_file, 'w', encoding='utf-8') as f:
result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE)
if result.returncode == 0:
# 检查备份文件是否创建成功并且有内容
if backup_file.exists() and backup_file.stat().st_size > 0:
logger.info(f"数据库 {database_name} 备份成功: {backup_file} (大小: {backup_file.stat().st_size} 字节)")
return str(backup_file)
else:
logger.error(f"数据库 {database_name} 备份文件创建失败或为空")
return None
else:
logger.error(f"数据库 {database_name} 备份失败: {result.stderr}")
# 如果备份失败,删除可能创建的空文件
if backup_file.exists():
backup_file.unlink()
return None
except Exception as e:
logger.error(f"备份数据库 {database_name} 时发生错误: {e}")
return None
def backup_all_mysql_databases(self):
"""备份所有用户数据库"""
databases = self.get_mysql_databases()
if not databases:
logger.warning("没有找到用户数据库")
return []
backup_files = []
for db in databases:
backup_file = self.backup_mysql_database(db)
if backup_file:
backup_files.append(backup_file)
return backup_files
def get_target_databases(self):
"""获取要操作的数据库列表"""
all_databases = self.get_mysql_databases()
if not all_databases:
logger.warning("没有找到用户数据库")
return []
if self.target_databases:
# 验证指定的数据库是否存在
valid_databases = []
for db in self.target_databases:
if db in all_databases:
valid_databases.append(db)
else:
logger.warning(f"指定的数据库 '{db}' 不存在")
return valid_databases
else:
# 如果没有指定,让用户选择
return self.select_databases_interactively(all_databases)
def select_databases_interactively(self, all_databases):
"""交互式选择数据库"""
print("\n可用的数据库列表:")
for i, db in enumerate(all_databases, 1):
print(f"{i}. {db}")
print(f"{len(all_databases) + 1}. 所有数据库")
print("0. 退出")
while True:
try:
choice = input("\n请选择要操作的数据库(输入数字,多个数字用逗号分隔): ").strip()
if choice == '0':
logger.info("用户选择退出")
return []
if choice == str(len(all_databases) + 1):
logger.info("用户选择操作所有数据库")
return all_databases
# 解析用户输入的数字
selected_indices = [int(x.strip()) for x in choice.split(',') if x.strip()]
selected_databases = []
for index in selected_indices:
if 1 <= index <= len(all_databases):
selected_databases.append(all_databases[index - 1])
else:
print(f"无效的选择: {index}")
continue
if selected_databases:
logger.info(f"用户选择的数据库: {', '.join(selected_databases)}")
return selected_databases
else:
print("没有有效的选择,请重新输入")
except ValueError:
print("输入格式错误,请输入数字")
except KeyboardInterrupt:
logger.info("用户中断操作")
return []
def backup_selected_mysql_databases(self):
"""备份选定的MySQL数据库"""
databases = self.get_target_databases()
if not databases:
logger.warning("没有选择要备份的数据库")
return []
backup_files = []
for db in databases:
logger.info(f"正在备份数据库: {db}")
backup_file = self.backup_mysql_database(db)
if backup_file:
backup_files.append(backup_file)
return backup_files
def clear_mysql_database(self, database_name):
"""清空指定MySQL数据库的所有表"""
try:
cursor = self.mysql_conn.cursor()
# 使用数据库
cursor.execute(f"USE `{database_name}`")
# 禁用外键检查
cursor.execute("SET FOREIGN_KEY_CHECKS = 0")
# 获取所有表
cursor.execute("SHOW TABLES")
tables = [table[0] for table in cursor.fetchall()]
# 清空所有表
for table in tables:
cursor.execute(f"TRUNCATE TABLE `{table}`")
logger.info(f"已清空表: {database_name}.{table}")
# 重新启用外键检查
cursor.execute("SET FOREIGN_KEY_CHECKS = 1")
self.mysql_conn.commit()
cursor.close()
logger.info(f"数据库 {database_name} 所有表已清空")
return True
except Exception as e:
logger.error(f"清空数据库 {database_name} 失败: {e}")
return False
def clear_all_mysql_databases(self):
"""清空所有用户数据库"""
databases = self.get_mysql_databases()
if not databases:
logger.warning("没有找到用户数据库")
return
for db in databases:
self.clear_mysql_database(db)
def clear_selected_mysql_databases(self):
"""清空选定的MySQL数据库"""
databases = self.get_target_databases()
if not databases:
logger.warning("没有选择要清空的数据库")
return
# 确认清空操作
print(f"\n即将清空以下数据库: {', '.join(databases)}")
confirm = input("确认要清空这些数据库吗?(y/N): ")
if confirm.lower() != 'y':
logger.info("用户取消清空操作")
return
for db in databases:
logger.info(f"正在清空数据库: {db}")
self.clear_mysql_database(db)
def backup_redis_database(self):
"""备份Redis数据库"""
try:
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_file = self.backup_dir / f"redis_{timestamp}.rdb"
# 确保备份目录存在
backup_file.parent.mkdir(parents=True, exist_ok=True)
# 执行BGSAVE命令
self.redis_conn.bgsave()
logger.info("Redis后台保存已启动")
# 等待保存完成
import time
initial_lastsave = self.redis_conn.lastsave()
logger.info("等待Redis数据保存完成...")
# 等待BGSAVE完成最多等待30秒
timeout = 30
start_time = time.time()
while time.time() - start_time < timeout:
current_lastsave = self.redis_conn.lastsave()
if current_lastsave > initial_lastsave:
logger.info("Redis数据保存完成")
break
time.sleep(1)
else:
logger.warning("Redis保存超时但继续尝试备份")
# 尝试获取Redis RDB文件路径
try:
config_info = self.redis_conn.config_get('dir')
redis_dir = config_info.get('dir', './') if config_info else './'
dbfilename_info = self.redis_conn.config_get('dbfilename')
dbfilename = dbfilename_info.get('dbfilename', 'dump.rdb') if dbfilename_info else 'dump.rdb'
redis_rdb_path = os.path.join(redis_dir, dbfilename)
logger.info(f"Redis RDB文件路径: {redis_rdb_path}")
except:
# 如果无法获取配置,使用默认路径
redis_rdb_path = "./dump.rdb"
logger.warning(f"无法获取Redis配置使用默认路径: {redis_rdb_path}")
# 复制RDB文件
if os.path.exists(redis_rdb_path):
import shutil
# 确保目标文件目录存在
backup_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(redis_rdb_path, backup_file)
if backup_file.exists() and backup_file.stat().st_size > 0:
logger.info(f"Redis数据备份成功: {backup_file} (大小: {backup_file.stat().st_size} 字节)")
return str(backup_file)
else:
logger.error("Redis备份文件创建失败或为空")
return None
else:
logger.warning(f"找不到Redis RDB文件: {redis_rdb_path}")
# 尝试创建一个简单的Redis数据导出
return self._create_redis_text_backup(backup_file)
except Exception as e:
logger.error(f"备份Redis数据失败: {e}")
return None
def _create_redis_text_backup(self, backup_file):
"""创建Redis文本格式备份"""
try:
text_backup_file = backup_file.with_suffix('.txt')
# 确保目录存在
text_backup_file.parent.mkdir(parents=True, exist_ok=True)
logger.info(f"创建Redis文本格式备份: {text_backup_file}")
with open(text_backup_file, 'w', encoding='utf-8') as f:
f.write("# Redis数据导出\n")
f.write(f"# 导出时间: {datetime.datetime.now()}\n\n")
# 获取所有key
keys = self.redis_conn.keys('*')
total_keys = len(keys)
if total_keys == 0:
f.write("# Redis数据库为空\n")
logger.info("Redis数据库为空创建空备份文件")
else:
f.write(f"# 总共 {total_keys} 个键\n\n")
logger.info(f"正在导出 {total_keys} 个Redis键...")
for i, key in enumerate(keys, 1):
try:
key_str = key.decode('utf-8') if isinstance(key, bytes) else str(key)
key_type = self.redis_conn.type(key).decode('utf-8')
f.write(f"# Key {i}/{total_keys}: {key_str} (类型: {key_type})\n")
if key_type == 'string':
value = self.redis_conn.get(key)
if isinstance(value, bytes):
try:
value = value.decode('utf-8')
except:
value = str(value)
f.write(f"SET \"{key_str}\" \"{value}\"\n")
elif key_type == 'hash':
hash_data = self.redis_conn.hgetall(key)
for field, value in hash_data.items():
if isinstance(field, bytes):
field = field.decode('utf-8')
if isinstance(value, bytes):
value = value.decode('utf-8')
f.write(f"HSET \"{key_str}\" \"{field}\" \"{value}\"\n")
f.write("\n")
except Exception as key_error:
f.write(f"# 错误处理键 {key}: {key_error}\n\n")
continue
if text_backup_file.exists():
logger.info(f"Redis文本备份创建成功: {text_backup_file}")
return str(text_backup_file)
else:
logger.error("Redis文本备份文件创建失败")
return None
except Exception as e:
logger.error(f"创建Redis文本备份失败: {e}")
return None
def clear_redis_database(self):
"""清空Redis数据库"""
try:
# 获取当前数据库的key数量
key_count = self.redis_conn.dbsize()
logger.info(f"Redis数据库当前有 {key_count} 个key")
if key_count > 0:
# 清空当前数据库
self.redis_conn.flushdb()
logger.info("Redis数据库已清空")
else:
logger.info("Redis数据库已经是空的")
return True
except Exception as e:
logger.error(f"清空Redis数据库失败: {e}")
return False
def close_connections(self):
"""关闭数据库连接"""
if self.mysql_conn:
self.mysql_conn.close()
logger.info("MySQL连接已关闭")
if self.redis_conn:
self.redis_conn.close()
logger.info("Redis连接已关闭")
def select_operation_mode():
"""选择操作模式"""
print("\n请选择操作模式:")
print("1. 仅备份数据库")
print("2. 仅清空数据库")
print("3. 备份后清空数据库")
print("4. 备份和清空Redis")
print("0. 退出")
while True:
try:
choice = input("\n请输入选择 (0-4): ").strip()
if choice in ['0', '1', '2', '3', '4']:
return choice
else:
print("无效选择,请输入 0-4")
except KeyboardInterrupt:
return '0'
def main():
"""主函数"""
logger.info("开始执行数据库备份和清空脚本")
# 选择操作模式
mode = select_operation_mode()
if mode == '0':
logger.info("用户选择退出")
return True
# 从配置或用户交互获取目标数据库
target_dbs = TARGET_DATABASES if TARGET_DATABASES else None
db_manager = DatabaseManager(target_databases=target_dbs)
try:
# 连接数据库
mysql_connected = db_manager.connect_mysql()
redis_connected = db_manager.connect_redis() if mode == '4' else True
if mode in ['1', '2', '3'] and not mysql_connected:
logger.error("无法连接到MySQL数据库脚本退出")
return False
if mode == '4' and not redis_connected:
logger.error("无法连接到Redis数据库脚本退出")
return False
# 执行相应操作
if mode == '1': # 仅备份
logger.info("开始备份MySQL数据库...")
backup_files = db_manager.backup_selected_mysql_databases()
if backup_files:
logger.info(f"MySQL备份完成共备份 {len(backup_files)} 个数据库")
else:
logger.warning("MySQL备份失败或没有数据库需要备份")
elif mode == '2': # 仅清空
logger.info("开始清空MySQL数据库...")
db_manager.clear_selected_mysql_databases()
logger.info("MySQL数据库清空完成")
elif mode == '3': # 备份后清空
# 1. 备份MySQL数据库
logger.info("开始备份MySQL数据库...")
backup_files = db_manager.backup_selected_mysql_databases()
if backup_files:
logger.info(f"MySQL备份完成共备份 {len(backup_files)} 个数据库")
# 确认是否继续清空数据库
confirm = input("备份完成,是否继续清空数据库?(y/N): ")
if confirm.lower() == 'y':
logger.info("开始清空MySQL数据库...")
# 重新使用相同的数据库选择
db_manager.target_databases = [os.path.basename(f).split('_')[0] for f in backup_files]
db_manager.clear_selected_mysql_databases()
logger.info("MySQL数据库清空完成")
else:
logger.info("用户取消清空操作")
else:
logger.warning("MySQL备份失败跳过清空操作")
elif mode == '4': # Redis操作
# 备份Redis
logger.info("开始备份Redis数据库...")
redis_backup = db_manager.backup_redis_database()
if redis_backup:
logger.info("Redis备份完成")
# 确认是否清空Redis
confirm = input("Redis备份完成是否清空Redis数据库(y/N): ")
if confirm.lower() == 'y':
logger.info("开始清空Redis数据库...")
if db_manager.clear_redis_database():
logger.info("Redis数据库清空完成")
else:
logger.info("用户取消Redis清空操作")
logger.info("所有操作完成")
return True
except KeyboardInterrupt:
logger.info("用户中断了脚本执行")
return False
except Exception as e:
logger.error(f"脚本执行过程中发生错误: {e}")
return False
finally:
db_manager.close_connections()
if __name__ == "__main__":
# 检查依赖包
required_packages = ['pymysql', 'redis']
missing_packages = []
for package in required_packages:
try:
__import__(package)
except ImportError:
missing_packages.append(package)
if missing_packages:
print(f"缺少依赖包: {', '.join(missing_packages)}")
print(f"请运行: pip install {' '.join(missing_packages)}")
sys.exit(1)
success = main()
sys.exit(0 if success else 1)

View File

@ -2,47 +2,26 @@ import pandas as pd
import math
subEmitColor = ["Wood", "Clothes storage bag"]
file_path = './script/MergeData.xlsx'
file_path = 'D:/Github/docs/config/MergeData.xlsx'
df = pd.read_excel(file_path, engine='openpyxl')
df = df.drop(index=0)
df_emitter = df[(df['Type'] == 'Emitter') & (df['Emit_Product'].notnull())]
df_emitter = df_emitter.assign(Dynamic=df_emitter['Emit_Product'])
def limitLv(x):
if x == 0:
return 5
if x == 1:
return 3
if x == 2:
return 2
if x == 3:
return 1
# for index, row in df_emitter.iterrows():
# print(f"Index: {index}")
# print(row['Emit_List'])
# a1 = row['Emit_List'].split(',')
# Product = row['Emit_Product'].split(',')
# main = row['Emit_Product'].split(',')[0]
# if len(a1) == 1:
# a2 = a1[0].split('=')
# color_values = df[df["Id"] == int(a2[0])]["Color"].values[0]
# if color_values in subEmitColor:
# print(f"Main: {main} - Sub: {color_values}")
# else:
# df_emitter.loc[index, 'Dynamic'] = f"{color_values}=0"
# continue
# d = {}
# for i in Product:
# d[i] = 0.0
# for i in a1 :
# a2 = i.split('=')
# color = df[df["Id"] == int(a2[0])]["Color"].values[0]
# d[color] += float(a2[1])*(int(a2[0])%10)
# c = {}
# mainNum = d[main]
# for k, i in d.items():
# if k == main:
# c[k] = 0
# else:
# x = round(mainNum/i)
# c[k] = round(math.log(x, 2))
# print(df_emitter.head())
def minLv(x):
return min(x, lv)
def getDynamicValue1(df, index):
row = df.loc[index]
d = {}
@ -55,79 +34,199 @@ def getDynamicValue1(df, index):
d[color_values] = 0
return d
else:
sumN = 0
for i in Product:
d[i] = 0.0
for i in Emit_List :
a2 = i.split('=')
color = df[df["Id"] == int(a2[0])]["Color"].values[0]
d[color] += float(a2[1])*(int(a2[0])%10)
d[color] += float(a2[1])*(minLv(int(a2[0])%10))
sumN += float(a2[1])*(minLv(int(a2[0])%10))
c = {}
mainNum = d[main]
# mainNum = d[main]
for k, i in d.items():
if k == main:
c[k] = 0
else:
x = mainNum/i
c[k] = math.floor(math.log(x, 2))
x = sumN/i
c[k] = math.floor(math.log(x, 2))
return c
def getDynamicValueG(df, index):
def getDynamicValueJ(df, index):
row = df.loc[index]
d = {}
Emit_List = row['Emit_List'].split(',')
Product = row['Emit_Product'].split(',')
main = row['Emit_Product'].split(',')[0]
x1 = 30
y = 16
c = {}
if len(Emit_List) == 1:
a2 = Emit_List[0].split('=')
color_values = df[df["Id"] == int(a2[0])]["Color"].values[0]
d[color_values] = 0
return d
c["Detective Tools"] = round(math.floor(math.log((x1+y)/y, 2)))
return c
else:
for i in Product:
d[i] = 0.0
for i in Emit_List :
a2 = i.split('=')
color = df[df["Id"] == int(a2[0])]["Color"].values[0]
if color == "Clothes storage bag":
d["Dress"] += float(a2[1])*(int(a2[0])%10)
if color == "Detective Bag":
d["Detective Tools"] += float(a2[1])*(minLv(int(a2[0])%10))
else:
d[color] += float(a2[1])*(int(a2[0])%10)
c = {}
mainNum = d[main]
for k, i in d.items():
if k == main:
c[k] = 0
else:
x = mainNum/i
c[k] = math.floor(math.log(x, 2))
d[color] += float(a2[1])*(minLv(int(a2[0])%10))
x2 = x1*(d["Detective Tools"]/d["Detective Outfit"])
c["Detective Tools"] = round(math.ceil(math.log((x1+x2+y)/y, 2)))
c["Detective Outfit"] = round(math.floor(math.log((x1+x2)/x2, 2)))
return c
def getDynamicValueM(df, index):
row = df.loc[index]
d = {}
Emit_List = row['Emit_List'].split(',')
Product = row['Emit_Product'].split(',')
x1 = 112
y = 16
c = {}
if len(Emit_List) == 1:
c["Dye"] = round(math.floor(math.log((x1+y)/y, 2)))
return c
else:
for i in Product:
d[i] = 0.0
for i in Emit_List :
a2 = i.split('=')
color = df[df["Id"] == int(a2[0])]["Color"].values[0]
if color == "Flower":
d["Dye"] += float(a2[1])*(minLv(int(a2[0])%10))
else:
d[color] += float(a2[1])*(minLv(int(a2[0])%10))
x2 = x1*(d["Dye"]/d["Aromatherapy"])
c["Dye"] = round(math.ceil(math.log((x1+x2+y)/y, 2)))
c["Aromatherapy"] = round(math.floor(math.log((x1+x2)/x2, 2)))
return c
def getDynamicValueR(df, index):
row = df.loc[index]
d = {}
Emit_List = row['Emit_List'].split(',')
Product = row['Emit_Product'].split(',')
x1 = 112
y = 15
c = {}
if len(Emit_List) == 1:
c["Outdoor Toys"] = round(math.floor(math.log((x1+y)/y, 2)))
return c
else:
for i in Product:
d[i] = 0.0
for i in Emit_List :
a2 = i.split('=')
color = df[df["Id"] == int(a2[0])]["Color"].values[0]
if color == "Tent":
d["Outdoor Toys"] += float(a2[1])*(minLv(int(a2[0])%10))
else:
d[color] += float(a2[1])*(minLv(int(a2[0])%10))
x2 = x1*(d["Bird Watching"]/d["Outdoor Toys"])
c["Outdoor Toys"] = round(math.ceil(math.log((x1+x2+y)/y, 2)))
c["Bird Watching"] = round(math.floor(math.log((x1+x2)/x2, 2)))
return c
def getDynamicValueW(df, index):
row = df.loc[index]
d = {}
Emit_List = row['Emit_List'].split(',')
Product = row['Emit_Product'].split(',')
x1 = 31
y = 16
c = {}
if len(Emit_List) == 1:
c["Curtains"] = 1
return c
else:
for i in Product:
d[i] = 0.0
for i in Emit_List :
a2 = i.split('=')
color = df[df["Id"] == int(a2[0])]["Color"].values[0]
if color == "Handmade Fabric Art":
d["Cushion"] += float(a2[1])*(minLv(int(a2[0])%10))
else:
d[color] += float(a2[1])*(minLv(int(a2[0])%10))
x2 = x1*(d["Cushion"]/d["Curtains"])
c["Cushion"] = round(math.ceil(math.log((x1+x2+y)/y, 2)))
c["Curtains"] = round(math.floor(math.log((x1+x2)/x2, 2)))
return c
def getDynamicValueC(df, index):
x1 = 16
y = 16
c = {}
c["Pet House"] = round(math.ceil(math.log((x1+y)/y, 2)))
return c
def getDynamicValueH(df, index):
x1 = 112
y = 16
c = {}
c["Jewelry Accessories"] = round(math.ceil(math.log((x1+y)/y, 2)))
return c
def getDynamicValue3(df, id):
return df[df['Id'] == id]['Dynamic'].values[0]
for i in range(0,4):
lv = limitLv(i)
for index, row in df_emitter.iterrows():
if row['Emit_ID'] == 'A':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'B':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'C':
d = getDynamicValueC(df, index)
if row['Emit_ID'] == 'D':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'E':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'F':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'G':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'H':
d = getDynamicValueH(df, index)
if row['Emit_ID'] == 'I':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'J':
d = getDynamicValueJ(df, index)
if row['Emit_ID'] == 'K':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'L':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'M':
d = getDynamicValueM(df, index)
if row['Emit_ID'] == 'N':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'O':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'P':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'Q':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'R':
d = getDynamicValueR(df, index)
if row['Emit_ID'] == 'S':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'T':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'U':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'V':
d = getDynamicValue1(df, index)
if row['Emit_ID'] == 'W':
d = getDynamicValueW(df, index)
if row['Emit_ID'] == 'X':
d = getDynamicValue1(df, index)
# 将字典格式化为 "key=value,..." 并写入原 DataFrame 的 'X' 列,然后打印验证
dynamic_str = ",".join(f"{k}={v}" for k, v in d.items())
# 构造列名,避免将 int 直接与 str 拼接导致 TypeError
col_name = 'Dynamic' if i == 0 else f'Dynamic{i}'
df.at[index, col_name] = dynamic_str
print(dynamic_str)
for index, row in df_emitter.iterrows():
if row['Emit_ID'] == 'I':
d = getDynamicValueG(df, index)
else:
continue
# if row['Emit_ID'] == 'B':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'C':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'D':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'E':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'F':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'G':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'H':
# d = getDynamicValue1(df, index)
# if row['Emit_ID'] == 'I':
# d = getDynamicValue1(df, index)
str = ""
for i,j in d.items():
str += f"{i}={j},"
str = str[:-1]
print(str)
# 保存回 Excel会覆盖原文件已在脚本开始处有备份逻辑可扩展
save_file_path = './dynamicLv_output.xlsx'
df.to_excel(save_file_path, index=False, engine='openpyxl')
print(f"Saved updated file to {save_file_path}")

61
script/insertRegister.py Normal file
View File

@ -0,0 +1,61 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder(
ssh_address_or_host=("1.15.182.107", 22),
ssh_username="root",
ssh_password="`NS?VGg@7]~F3}p",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5143)
)
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Z4rf7eZZe500dxa",
database="pet_home_5"
)
cursor = conn.cursor()
cursor.execute("select `dwUin`, `rolecreatetime` from t_player_baseinfo")
result = cursor.fetchall()
server2 = SSHTunnelForwarder(
ssh_address_or_host=("8.155.14.94", 22),
ssh_username="root",
ssh_password="-xLX]p!PQ1@SHm`A",
remote_bind_address=("rm-f8zd2030feam53n43.mysql.rds.aliyuncs.com",3306),
local_bind_address=('127.0.0.1',5144)
)
server2.start()
db_host2 = server2.local_bind_host
db_port2 = server2.local_bind_port
conn2 = pymysql.connect(
host=db_host2,
port=db_port2,
user="root",
password="Z4rf7eZZe500dxa",
database="pet_home"
)
cursor2 = conn2.cursor()
for i in result:
cursor2.execute("INSERT INTO log_login (`Uid`, `Event`, Timestamp) VALUES (%s, 'register', %s)", (i[0], i[1]))
print(i)
conn2.commit()
cursor2.close()
conn2.close()
server2.stop()
cursor.close()
conn.close()
server.stop()

1923
script/merged.csv Normal file

File diff suppressed because it is too large Load Diff

BIN
script/merged.xlsx Normal file

Binary file not shown.

View File

@ -23,8 +23,8 @@ server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
print(db_host, db_port)
RID = 100184
MYRID = 100004
RID = 105372
MYRID = 100100042
conn = pymysql.connect(
host=db_host,
@ -37,20 +37,32 @@ cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))
result1 = cursor.fetchone()
conn1 = pymysql.connect(
host="127.0.0.1",
port=3306,
user="root",
password="root",
database='Merge_Pet'
server2 = SSHTunnelForwarder(
ssh_address_or_host=("1.15.182.107", 22),
ssh_username="root",
ssh_password="`NS?VGg@7]~F3}p",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5144)
)
cursor1 = conn1.cursor()
server2.start()
db_host2 = server2.local_bind_host
db_port2 = server2.local_bind_port
conn2 = pymysql.connect(
host=db_host2,
port=db_port2,
user="root",
password="Z4rf7eZZe500dxa",
database=f"pet_home_1"
)
cursor2 = conn2.cursor()
sql = "UPDATE t_player_mod SET mData = %s WHERE dwUin = %s"
cursor1.execute(sql, (result1[1], MYRID))
conn1.commit()
cursor2.execute(sql, (result1[1], MYRID))
conn2.commit()
cursor.close()
conn.close()
cursor1.close()
conn1.close()
cursor2.close()
conn2.close()
exit()

View File

@ -0,0 +1,56 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
from pymysql.converters import escape_string
from ruamel.yaml import YAML
import math
UUID = 600000500823
# ===================config===================
server = SSHTunnelForwarder(
ssh_address_or_host=("47.254.83.25", 22),
ssh_username="root",
ssh_password="ByWayStudios01!",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5143)
)
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
print(db_host, db_port)
RID = 104214
MYRID = 100100017
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Xijing1!",
database="Merge_Pet_1"
)
cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))
result1 = cursor.fetchone()
conn1 = pymysql.connect(
host="127.0.0.1",
port=3306,
user="root",
password="root",
database='Merge_Pet_1'
)
cursor1 = conn1.cursor()
sql = "UPDATE t_player_mod SET mData = %s WHERE dwUin = %s"
cursor1.execute(sql, (result1[1], MYRID))
conn1.commit()
cursor.close()
conn.close()
cursor1.close()
conn1.close()
exit()

View File

@ -0,0 +1,68 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
from pymysql.converters import escape_string
from ruamel.yaml import YAML
import math
UUID = 600000500823
# ===================config===================
server = SSHTunnelForwarder(
ssh_address_or_host=("47.254.83.25", 22),
ssh_username="root",
ssh_password="ByWayStudios01!",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5143)
)
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
print(db_host, db_port)
RID = 102931
MYRID = 200100030
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Xijing1!",
database="Merge_Pet_1"
)
cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))
result1 = cursor.fetchone()
server2 = SSHTunnelForwarder(
ssh_address_or_host=("1.15.182.107", 22),
ssh_username="root",
ssh_password="`NS?VGg@7]~F3}p",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5144)
)
server2.start()
db_host2 = server2.local_bind_host
db_port2 = server2.local_bind_port
conn2 = pymysql.connect(
host=db_host2,
port=db_port2,
user="root",
password="Z4rf7eZZe500dxa",
database=f"Merge_Pet_sdk"
)
cursor2 = conn2.cursor()
sql = "UPDATE t_player_mod SET mData = %s WHERE dwUin = %s"
cursor2.execute(sql, (result1[1], MYRID))
conn2.commit()
cursor.close()
conn.close()
cursor2.close()
conn2.close()
exit()

View File

@ -1,8 +1,5 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
from pymysql.converters import escape_string
from ruamel.yaml import YAML
import math
UUID = 600000500823
@ -23,8 +20,8 @@ server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
print(db_host, db_port)
RID = 200200121
MYRID = 100004
RID = 200100004
MYRID = 100100001
conn = pymysql.connect(
host=db_host,

50
script/mysql_sdk.py Normal file
View File

@ -0,0 +1,50 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
from pymysql.converters import escape_string
from ruamel.yaml import YAML
import math
# ===================config===================
server = SSHTunnelForwarder(
ssh_address_or_host=("1.15.182.107", 22),
ssh_username="root",
ssh_password="`NS?VGg@7]~F3}p",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5143)
)
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
RID = 200100030
MYRID = 100100017
ServerId = int((RID % 100000000) / 100000)
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Z4rf7eZZe500dxa",
database=f"Merge_Pet_sdk"
)
cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))
result1 = cursor.fetchone()
conn1 = pymysql.connect(
host="127.0.0.1",
port=3306,
user="root",
password="root",
database='Merge_Pet_1'
)
cursor1 = conn1.cursor()
sql = "UPDATE t_player_mod SET mData = %s WHERE dwUin = %s"
cursor1.execute(sql, (result1[1], MYRID))
conn1.commit()
cursor.close()
conn.close()
cursor1.close()
conn1.close()
exit()

51
script/mysql_test.py Normal file
View File

@ -0,0 +1,51 @@
import pymysql
from sshtunnel import SSHTunnelForwarder
from pymysql.converters import escape_string
from ruamel.yaml import YAML
import math
# ===================config===================
server = SSHTunnelForwarder(
ssh_address_or_host=("1.15.182.107", 22),
ssh_username="root",
ssh_password="`NS?VGg@7]~F3}p",
remote_bind_address=("127.0.0.1",3306),
local_bind_address=('127.0.0.1',5143)
)
server.start()
db_host = server.local_bind_host
db_port = server.local_bind_port
print(db_host, db_port)
RID = 100100006
MYRID = 100100017
ServerId = int((RID % 100000000) / 100000)
conn = pymysql.connect(
host=db_host,
port=db_port,
user="root",
password="Z4rf7eZZe500dxa",
database=f"pet_home_{ServerId}"
)
cursor = conn.cursor()
cursor.execute(("select * from t_player_mod where dwUin = {rid}").format(rid = RID))
result1 = cursor.fetchone()
conn1 = pymysql.connect(
host="127.0.0.1",
port=3306,
user="root",
password="root",
database='Merge_Pet_1'
)
cursor1 = conn1.cursor()
sql = "UPDATE t_player_mod SET mData = %s WHERE dwUin = %s"
cursor1.execute(sql, (result1[1], MYRID))
conn1.commit()
cursor.close()
conn.close()
cursor1.close()
conn1.close()
exit()

1
script/output.ts Normal file

File diff suppressed because one or more lines are too long

22
script/test.py Normal file
View File

@ -0,0 +1,22 @@
import requests
def get_location_by_ip(ip):
url = f"http://ip-api.com/json/{ip}?lang=zh-CN"
response = requests.get(url)
data = response.json()
if data['status'] == 'success':
return {
'国家': data['country'],
'省份': data['regionName'],
'城市': data['city'],
'运营商': data['isp'],
'经度': data['lon'],
'纬度': data['lat']
}
else:
return None
# 示例
ip = '8.8.8.8'
location = get_location_by_ip(ip)
print(location)

40
script/test.spec Normal file
View File

@ -0,0 +1,40 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['test.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='test',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )

View File

@ -9,17 +9,32 @@
"name": "stdout",
"output_type": "stream",
"text": [
"42\n",
"46\n",
"[2, 4, 6, 23, 23, 26, 26, 42, 43, 45, 47, 48, 61, 65, 85, 105, 127, 143, 145, 145, 165, 183, 222, 225, 242, 248, 262, 264, 265, 265, 266, 267, 284, 288, 289, 303, 304, 306, 523, 563, 564, 702]\n",
"[2, 4, 6, 22, 22, 23, 26, 26, 42, 43, 45, 47, 48, 61, 64, 64, 85, 105, 127, 143, 145, 145, 165, 183, 222, 225, 242, 248, 262, 264, 265, 265, 266, 267, 284, 288, 289, 303, 304, 306, 521, 521, 522, 563, 564, 702]\n"
"60\n",
"59\n"
]
},
{
"ename": "ValueError",
"evalue": "invalid literal for int() with base 10: '22\\n04'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[1;32mIn[1], line 18\u001b[0m\n\u001b[0;32m 16\u001b[0m l2 \u001b[38;5;241m=\u001b[39m []\n\u001b[0;32m 17\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m a1:\n\u001b[1;32m---> 18\u001b[0m l1\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mi\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msplit\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m:\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[0;32m 19\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m a2:\n\u001b[0;32m 20\u001b[0m l2\u001b[38;5;241m.\u001b[39mappend(\u001b[38;5;28mint\u001b[39m(i))\n",
"\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: '22\\n04'"
]
}
],
"source": [
"str = \"\"\"0@0@0@26:702 0@1@0@-1:26 0@2@0@-1:23 0@3@0@-1:303 0@4@0@-1:284 0@5@0@-1:43 0@6@0@-1:2 0@7@0@-1:65 0@8@0@2:85 1@0@0@-1:288 1@1@0@-1:61 1@2@0@-1:242 1@5@0@-1:6 1@6@0@-1:45 1@7@0@-1:47 1@8@0@21:183 2@0@0@-1:26 2@1@0@24:564 2@7@0@-1:42 2@8@0@4:105 3@0@0@16:563 3@1@0@-1:4 3@2@0@-1:265 3@6@0@-1:304 3@7@0@-1:222 3@8@0@-1:23 4@0@1@-1:289 4@1@0@-1:266 4@2@0@-1:265 4@7@0@-1:143 4@8@1@-1:306 5@0@0@-1:48 5@1@0@-1:248 5@2@0@-1:262 5@7@0@27:145 5@8@0@28:145 6@0@0@15:165 6@1@0@-1:264 6@2@0@-1:523 6@6@0@-1:225 6@7@0@22:127 6@8@1@-1:267\"\"\"\n",
"str = \"\"\"0@0@0@165@0:1807 0@1@0@167@0:1803 0@2@0@-1@0:1531 0\n",
"@3@0@155@0:1806 0@4@0@-1@0:1224 0@5@0@77@0:1207 0@6@0@-1@0:1222 0@7@0@-1@0:1523 0@8@0@-1@0:1521 1@0@0@147@0:1802 1@1@0@146@0:1801 1@2@0@205@0:2328 1@3@0@-1@0:2026 1@4@0@-1@0:1221 1@5@0@189@0:2302 1@6@0@187@0:22\n",
"04 1@7@0@-1@0:1511 1@8@0@137@0:1408 2@0@0@152@0:1805 2@1@0@206@0:1602 2@3@0@204@0:2506 2@5@0@-1@0:2422 2@6@0@201@0:2403 2@7@0@-1@0:1866 2@8@0@198@0:2305 3@0@0@86@0:1107 3@1@0@-1@0:1512 3@2@0@186@0:2301 3@3@0@-1\n",
"@0:1531 3@4@0@-1@0:1531 3@5@0@-1@0:2424 3@6@0@-1@0:1532 3@7@0@148@0:1804 3@8@0@168@0:2003 4@0@0@191@0:2007 4@1@0@-1@0:1535 4@3@0@185@0:2107 4@4@0@-1@0:2426 4@5@0@200@0:2401 4@6@0@199@0:2402 4@7@0@166@0:2002 4@8\n",
"@0@160@0:2001 5@0@0@139@0:1705 5@1@0@-1@0:2524 5@2@0@181@0:2202 5@3@0@177@0:2105 5@4@0@203@0:563 5@5@0@183@0:2203 5@6@0@182@0:2201 5@7@0@176@0:2101 5@8@0@112@0:1704 6@0@0@104@0:1701 6@1@0@130@0:1703 6@2@0@151@0\n",
":1901 6@3@0@159@0:1905 6@4@0@142@0:1706 6@5@0@154@0:1903 6@6@0@157@0:1904 6@7@0@158@0:1902 6@8@0@188@0:1906\"\"\"\n",
"\n",
"str2 = \"\"\"289 61 105 165 48 85 26 183 306 127 288 266 64 563 26 145 145 143 303 304 284 702 23 6 42 43 45 47 222 225 265 267 22 22 2 4 522 264 265 521 262 242 248 64 521 564\"\"\"\n",
"str2 = \"\"\"1107 1701 1207 1704 1703 1705 1706 1801 1802 1804 1901 1805 1806 1904 1902 1903 2001 2002 1803 2003 2101 1807 2105 2202 2201 2203 2107 2204 2301 1866 1905 1906 2302 2007 1408 2305 563 2506 25\n",
"24 2026 2328 1523 1511 1224 2401 1222 2402 2403 2424 2426 2422 1512 1221 1531 1535 1531 1521 1533 1522\"\"\"\n",
"\n",
"a1 = str.split(\" \")\n",
"a2 = str2.split(\" \")\n",
@ -39,14 +54,161 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3/Qr-g]ljJ&9@bM&\n"
"user_name=13100024182, auto_id=89 已更新\n",
"user_name=13100024183, auto_id=90 已更新\n",
"user_name=13100024011, auto_id=106 已更新\n",
"user_name=13100024012, auto_id=107 已更新\n",
"user_name=13100024081, auto_id=108 已更新\n",
"user_name=13100024082, auto_id=109 已更新\n",
"user_name=13100024161, auto_id=110 已更新\n",
"user_name=13100024162, auto_id=111 已更新\n"
]
},
{
"ename": "",
"evalue": "",
"output_type": "error",
"traceback": [
"\u001b[1;31m在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。\n",
"\u001b[1;31m请查看单元格中的代码以确定故障的可能原因。\n",
"\u001b[1;31m单击<a href='https://aka.ms/vscodeJupyterKernelCrash'>此处</a>了解详细信息。\n",
"\u001b[1;31m有关更多详细信息请查看 Jupyter <a href='command:jupyter.viewOutput'>log</a>。"
]
}
],
"source": [
"import pymysql\n",
"from sshtunnel import SSHTunnelForwarder\n",
"server = SSHTunnelForwarder(\n",
" ssh_address_or_host=(\"1.15.182.107\", 22),\n",
" ssh_username=\"root\",\n",
" ssh_password=\"`NS?VGg@7]~F3}p\",\n",
" remote_bind_address=(\"127.0.0.1\",3306),\n",
" local_bind_address=('127.0.0.1',5143)\n",
")\n",
"server.start()\n",
"db_host = server.local_bind_host\n",
"db_port = server.local_bind_port\n",
"conn = pymysql.connect(\n",
" host=db_host,\n",
" port=db_port,\n",
" user=\"root\",\n",
" password=\"Z4rf7eZZe500dxa\",\n",
" database=f\"merge_pet_audit_1\"\n",
")\n",
"cursor = conn.cursor()\n",
"# 获取dwUid=400100082的数据\n",
"user_names = [\n",
" \"13100024182\",\n",
" \"13100024183\",\n",
" \"13100024011\",\n",
" \"13100024012\",\n",
" \"13100024081\",\n",
" \"13100024082\",\n",
" \"13100024161\",\n",
" \"13100024162\"\n",
"]\n",
"\n",
"# 先获取dwUin=400100088的原始mData和updateTime\n",
"cursor.execute(\"SELECT mData, updateTime FROM t_player_mod WHERE dwUin=400100088\")\n",
"row = cursor.fetchone()\n",
"if not row:\n",
" print(\"未找到dwUin=400100088的数据\")\n",
"else:\n",
" mData, updateTime = row\n",
" for user_name in user_names:\n",
" # 查找auto_id\n",
" cursor.execute(\"SELECT auto_id FROM t_account WHERE user_name=%s\", (user_name,))\n",
" result = cursor.fetchone()\n",
" if result:\n",
" auto_id = result[0]\n",
" # 更新t_player_mod表\n",
" cursor.execute(\n",
" \"UPDATE t_player_mod SET mData=%s, updateTime=%s WHERE dwUin=%s\",\n",
" (mData, updateTime, auto_id + 400100000)\n",
" )\n",
" print(f\"user_name={user_name}, auto_id={auto_id} 已更新\")\n",
" else:\n",
" print(f\"user_name={user_name} 未找到auto_id\")\n",
" conn.commit()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"\n",
"# 读取CSV文件\n",
"df = pd.read_excel('item.xlsx')\n",
"\n",
"# 将数据转换为TS的字典格式\n",
"df = df.fillna('')\n",
"ts_dict = df.to_dict(orient='records')\n",
"\n",
"# 写入新的TS文件\n",
"with open('output.ts', 'w', encoding='utf-8') as f:\n",
" f.write('export const data = ')\n",
" f.write(str(ts_dict))\n",
" f.write(';')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"\n",
"def get_location_by_ip(ip):\n",
" url = f\"http://ip-api.com/json/{ip}?lang=zh-CN\"\n",
" response = requests.get(url)\n",
" data = response.json()\n",
" if data['status'] == 'success':\n",
" return {\n",
" '国家': data['country'],\n",
" '省份': data['regionName'],\n",
" '城市': data['city'],\n",
" '运营商': data['isp'],\n",
" '经度': data['lon'],\n",
" '纬度': data['lat']\n",
" }\n",
" else:\n",
" return None\n",
"\n",
"# 示例\n",
"ip = '8.8.8.8'\n",
"location = get_location_by_ip(ip)\n",
"print(location)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"`g.v=aE|-S}[Uk\"^\n"
]
}
],
@ -68,14 +230,14 @@
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"日期时间: 2025-01-11 17:38:45\n"
"日期时间: 2025-02-23 08:00:00\n"
]
}
],
@ -83,7 +245,7 @@
"from datetime import datetime\n",
"\n",
"# 示例时间戳\n",
"timestamp = 1736588325\n",
"timestamp = 1740268800\n",
"\n",
"# 将时间戳转换为日期时间\n",
"dt_object = datetime.fromtimestamp(timestamp)\n",
@ -92,12 +254,432 @@
"print(\"日期时间:\", dt_object)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1739428748\n"
]
}
],
"source": [
"import time\n",
"\n",
"timestamp = int(time.time())\n",
"print(timestamp)\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2025-04-28 10:59:46 BST\n"
]
}
],
"source": [
"from datetime import datetime\n",
"import pytz\n",
"\n",
"date = datetime.now()\n",
"timezone = pytz.timezone('Europe/London')\n",
"aware_date = timezone.localize(date)\n",
"formatted_date = aware_date.strftime(\"%Y-%m-%d %H:%M:%S %Z\")\n",
"print(formatted_date)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
"source": [
"import os\n",
"import chardet\n",
"\n",
"# 获取当前目录下的所有文件\n",
"files = [f for f in os.listdir('F:\\Github\\aplus-b_-pet_-c_nation') if os.path.isfile(f)]\n",
"\n",
"# 检测每个文件的编码\n",
"for file in files:\n",
" with open(file, 'rb') as f:\n",
" raw_data = f.read()\n",
" result = chardet.detect(raw_data)\n",
" print(f\"文件: {file}, 编码: {result['encoding']}, 置信度: {result['confidence']}\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"状态码: 404\n",
"返回文本: 404 page not found\n"
]
}
],
"source": [
"import requests\n",
"# 使用已在其它单元导入的 requests 发起 POST 请求\n",
"url = \"http://ship.bywaystudios.com/api/tuyou/charge\"\n",
"\n",
"payload = {\n",
" \"amount\": 100, # 示例字段,根据接口规范调整\n",
" \"currency\": \"USD\",\n",
" \"description\": \"test charge\",\n",
" \"metadata\": {\"order_id\": \"test123\"}\n",
"}\n",
"\n",
"headers = {\n",
" \"Content-Type\": \"application/json\",\n",
" # 如果接口需要认证,加入相应头,例如:\n",
" # \"Authorization\": \"Bearer YOUR_TOKEN\"\n",
"}\n",
"\n",
"try:\n",
" resp = requests.post(url, json=payload, headers=headers, timeout=10)\n",
" print(\"状态码:\", resp.status_code)\n",
" # 尝试解析为 JSON否则打印文本\n",
" try:\n",
" print(\"返回 JSON:\", resp.json())\n",
" except ValueError:\n",
" print(\"返回文本:\", resp.text)\n",
"except requests.RequestException as e:\n",
" print(\"请求失败:\", e)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"C:\\Users\\U\\AppData\\Roaming\\Python\\Python313\\site-packages\\openpyxl\\styles\\stylesheet.py:237: UserWarning: Workbook contains no default style, apply openpyxl's default\n",
" warn(\"Workbook contains no default style, apply openpyxl's default\")\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"已输出 Excel: merged.xlsx\n",
"已输出 CSV: merged.csv\n"
]
}
],
"source": [
"import os\n",
"import glob\n",
"import pandas as pd\n",
"import string\n",
"\n",
"# 合并当前目录下所有 .xlsx 文件中名为 sheet0..sheet38 的子表到一个表\n",
"\n",
"sheet_names = [f\"Sheet{i}\" for i in range(39)] # sheet0..sheet38\n",
"\n",
"def merge_sheets_in_dir(path=\".\", pattern=\"*.xlsx\", out_excel=\"merged.xlsx\", out_csv=\"merged.csv\", custom_columns=None):\n",
" \"\"\"\n",
" 合并多个Excel文件的指定sheet\n",
" \n",
" Args:\n",
" custom_columns: dict, 列名映射,例如 {\"A\": \"姓名\", \"B\": \"年龄\"}\n",
" \"\"\"\n",
" files = [f for f in glob.glob(os.path.join(path, pattern)) if not os.path.basename(f).startswith(\"~$\")]\n",
" dfs = []\n",
" for file in files:\n",
" try:\n",
" # 读取时不使用第一行作为列名自动生成A,B,C...列名\n",
" xls = pd.read_excel(file, sheet_name=None, header=None)\n",
" except Exception as e:\n",
" print(f\"跳过文件 {file},读取失败: {e}\")\n",
" continue\n",
"\n",
" for s in sheet_names:\n",
" if s in xls and isinstance(xls[s], pd.DataFrame):\n",
" df = xls[s].copy()\n",
" \n",
" # 生成A,B,C...列名\n",
" num_cols = len(df.columns)\n",
" col_letters = [string.ascii_uppercase[i] if i < 26 else f\"{string.ascii_uppercase[i//26-1]}{string.ascii_uppercase[i%26]}\" for i in range(num_cols)]\n",
" df.columns = col_letters\n",
" \n",
" # 应用自定义列名\n",
" if custom_columns:\n",
" df = df.rename(columns=custom_columns)\n",
" \n",
" # 添加来源信息,便于追溯\n",
" df[\"_source_file\"] = os.path.basename(file)\n",
" df[\"_sheet_name\"] = s\n",
" dfs.append(df)\n",
" # 如果不存在则跳过\n",
"\n",
" if not dfs:\n",
" print(\"未找到任何匹配的 sheet未生成合并文件。\")\n",
" return None\n",
"\n",
" # 合并,保留所有列(列并集)\n",
" merged = pd.concat(dfs, ignore_index=True, sort=False)\n",
"\n",
" # 写出文件\n",
" try:\n",
" merged.to_excel(out_excel, index=False)\n",
" print(f\"已输出 Excel: {out_excel}\")\n",
" except Exception as e:\n",
" print(f\"写 Excel 失败: {e}\")\n",
"\n",
" try:\n",
" merged.to_csv(out_csv, index=False)\n",
" print(f\"已输出 CSV: {out_csv}\")\n",
" except Exception as e:\n",
" print(f\"写 CSV 失败: {e}\")\n",
"\n",
" return merged\n",
"\n",
"# 执行合并(可修改 path 或 输出文件名)\n",
"# 示例自定义列名现在A,B,C对应实际的列位置\n",
"column_mapping = {\n",
" \"A\": \"用户ID\",\n",
" \"B\": \"用户名\", \n",
" \"C\": \"积分\"\n",
"}\n",
"merged_df = merge_sheets_in_dir(\n",
" path=r\"D:\\Github\\devops\\source\",\n",
" custom_columns=column_mapping # 传入None则不重命名\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"连接哨兵或 Redis 时出错: No master found for 'mymaster' : <redis.client.Redis(<redis.connection.ConnectionPool(<redis.connection.Connection(host=127.0.0.1,port=26379,db=0)>)>)> - TimeoutError('Timeout connecting to server')\n"
]
}
],
"source": [
"from redis.sentinel import Sentinel\n",
"\n",
"# 连接 Redis 哨兵并获取主节点的示例\n",
"# 若未安装 redis 库,请先在终端运行: pip install redis\n",
"\n",
"\n",
"# 修改为你的哨兵地址列表和 master 名称(若只有一个哨兵地址,仍以列表形式传入)\n",
"SENTINELS = [('127.0.0.1', 26379)]\n",
"MASTER_NAME = 'mymaster' # 根据你的配置修改(常见默认为 'mymaster'\n",
"\n",
"# 如果哨兵或 Redis 需要密码,按需设置以下两个变量\n",
"SENTINEL_PASSWORD = None # 如果 sentinel 自身需要认证,设置该值或保持 None\n",
"REDIS_PASSWORD = None # 如果 redis 主从需要认证,设置该值或保持 None\n",
"\n",
"try:\n",
" sentinel = Sentinel(\n",
" SENTINELS,\n",
" socket_timeout=1,\n",
" sentinel_kwargs={'password': SENTINEL_PASSWORD} if SENTINEL_PASSWORD else None\n",
" )\n",
"\n",
" # 获取主节点客户端(写操作走主节点)\n",
" master = sentinel.master_for(MASTER_NAME, socket_timeout=1, password=REDIS_PASSWORD)\n",
" # 获取主节点的 IP 地址和端口\n",
" master_info = sentinel.discover_master(MASTER_NAME)\n",
" print(f\"主节点地址: {master_info[0]}:{master_info[1]}\")\n",
" # 获取从节点客户端(读操作走从节点)\n",
" slave = sentinel.slave_for(MASTER_NAME, socket_timeout=1, password=REDIS_PASSWORD)\n",
"\n",
" # 简单读写测试\n",
" master.set('sentinel_test_key', 'hello')\n",
" val = slave.get('sentinel_test_key') # 视复制延迟,可能需要短暂等待\n",
" if val is not None:\n",
" print(\"从节点读取值:\", val.decode() if isinstance(val, bytes) else val)\n",
" else:\n",
" print(\"从节点未读到值(可能有复制延迟),主节点值:\", master.get('sentinel_test_key'))\n",
"\n",
"except Exception as e:\n",
" print(\"连接哨兵或 Redis 时出错:\", e)"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"原始主节点: 172.22.0.2:6379\n",
"映射后地址: 172.22.0.2:6379\n",
"连接失败: Timeout connecting to server\n",
"直接端口映射连接成功\n",
"使用直接端口映射连接\n",
"连接失败: Timeout connecting to server\n",
"直接端口映射连接成功\n",
"使用直接端口映射连接\n"
]
}
],
"source": [
"from redis.sentinel import Sentinel\n",
"import redis\n",
"\n",
"# 解决容器内IP映射问题的几种方案\n",
"\n",
"# 方案1: 地址映射 - 将容器内部IP映射到外部可访问地址\n",
"IP_MAPPING = {\n",
" '172.17.0.2': '127.0.0.1', # 容器内IP -> 外部IP\n",
" '172.17.0.3': '127.0.0.1', # 根据实际情况修改\n",
" # 添加更多映射...\n",
"}\n",
"\n",
"# 方案2: 自定义连接类处理IP映射\n",
"class MappedSentinel(Sentinel):\n",
" def __init__(self, sentinels, ip_mapping=None, **kwargs):\n",
" super().__init__(sentinels, **kwargs)\n",
" self.ip_mapping = ip_mapping or {}\n",
" \n",
" def master_for(self, service_name, **kwargs):\n",
" # 获取原始主节点信息\n",
" master_info = self.discover_master(service_name)\n",
" original_host = master_info[0]\n",
" port = master_info[1]\n",
" \n",
" # 应用IP映射\n",
" mapped_host = self.ip_mapping.get(original_host, original_host)\n",
" print(f\"原始主节点: {original_host}:{port}\")\n",
" print(f\"映射后地址: {mapped_host}:{port}\")\n",
" \n",
" # 直接创建Redis连接到映射后的地址\n",
" return redis.Redis(host=mapped_host, port=port, **kwargs)\n",
"\n",
"# 使用示例\n",
"SENTINELS = [('127.0.0.1', 6381)]\n",
"MASTER_NAME = 'mymaster'\n",
"\n",
"try:\n",
" # 方案1: 使用自定义Sentinel类\n",
" sentinel = MappedSentinel(\n",
" SENTINELS,\n",
" ip_mapping=IP_MAPPING,\n",
" socket_timeout=1\n",
" )\n",
" \n",
" master = sentinel.master_for(MASTER_NAME, socket_timeout=1, password=None)\n",
" \n",
" # 测试连接\n",
" master.set('test_key', 'test_value')\n",
" result = master.get('test_key')\n",
" print(f\"连接测试成功: {result}\")\n",
" \n",
"except Exception as e:\n",
" print(\"连接失败:\", e)\n",
"\n",
"# 方案3: 直接指定端口映射如果使用Docker端口映射\n",
"def connect_with_port_mapping():\n",
" \"\"\"\n",
" 如果Redis容器使用了端口映射如 -p 6379:6379\n",
" 可以直接连接到映射的端口\n",
" \"\"\"\n",
" try:\n",
" # 假设容器映射到本地端口6379\n",
" direct_redis = redis.Redis(host='127.0.0.1', port=6379, socket_timeout=1, password='change_me_redis_pass')\n",
" direct_redis.ping()\n",
" print(\"直接端口映射连接成功\")\n",
" return direct_redis\n",
" except Exception as e:\n",
" print(f\"直接连接失败: {e}\")\n",
" return None\n",
"\n",
"# 方案4: 环境变量配置\n",
"import os\n",
"def get_redis_config():\n",
" \"\"\"\n",
" 从环境变量获取Redis配置\n",
" \"\"\"\n",
" return {\n",
" 'host': os.getenv('REDIS_HOST', '127.0.0.1'),\n",
" 'port': int(os.getenv('REDIS_PORT', '6379')),\n",
" 'password': os.getenv('REDIS_PASSWORD', None)\n",
" }\n",
"\n",
"# 测试直接连接\n",
"direct_connection = connect_with_port_mapping()\n",
"if direct_connection:\n",
" print(\"使用直接端口映射连接\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 补充Docker网络配置建议\n",
"\n",
"docker_tips = \"\"\"\n",
"解决容器IP问题的Docker配置建议\n",
"\n",
"1. 端口映射方式:\n",
" docker run -p 6379:6379 redis:latest\n",
"\n",
"2. 自定义网络:\n",
" docker network create redis-net\n",
" docker run --network redis-net --name redis-master redis:latest\n",
"\n",
"3. Host网络模式:\n",
" docker run --network host redis:latest\n",
"\n",
"4. 环境变量配置:\n",
" docker run -e REDIS_HOST=127.0.0.1 -e REDIS_PORT=6379 your-app\n",
"\n",
"5. Docker Compose示例:\n",
" version: '3'\n",
" services:\n",
" redis:\n",
" image: redis:latest\n",
" ports:\n",
" - \"6379:6379\"\n",
" app:\n",
" build: .\n",
" environment:\n",
" - REDIS_HOST=redis\n",
" - REDIS_PORT=6379\n",
" depends_on:\n",
" - redis\n",
"\"\"\"\n",
"\n",
"print(docker_tips)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"/usr/local/game/logs/ga_log/.log"
]
}
],
"metadata": {

View File

@ -47,10 +47,10 @@ def verify_order(product_id, token, access_token):
parser = argparse.ArgumentParser(description="Verify Google Play order")
parser.add_argument("product_id", help="Product ID")
parser.add_argument("token", help="Purchase token")
# args = parser.parse_args()
args = parser.parse_args()
accessToken = getAccessToken()
order = verify_order("diamond_001_1.99", "ipdmanofmimckinooopehnnm.AO-J1OyP6x7gWu-hzaGlGJAeWEQMoqPC0TgQDCXeqz6QGMy4J8ZlDgZllTqSuAIX6uWJJ9QHS5KYnY-4Y6dr6B3T_td7n9ohLqm26WxNw4oBS0dL3GSYKYM", accessToken)
order = verify_order(args.product_id, args.token, accessToken)
print(order)
# python script/verifyOrder.py diamond_001_1.99 ipdmanofmimckinooopehnnm.AO-J1OyP6x7gWu-hzaGlGJAeWEQMoqPC0TgQDCXeqz6QGMy4J8ZlDgZllTqSuAIX6uWJJ9QHS5KYnY-4Y6dr6B3T_td7n9ohLqm26WxNw4oBS0dL3GSYKYM
# ./verifyOrder shopspecialtwonew_001_0.99 dipjdchagdecheahmfmmhoep.AO-J1Ozl2Fmx55383f8zimKDr2vsBpu-86KjOYzCa2KjBt10u-G2-S-L9SOG0aokMMfwpiVsFDkxx87nLIhVl4jQPKO7cISj5ZLjLlI11MFQP_w6QQ4tEqo
# newplayer_001_0.49 ojiimdalhjimomakjmmikjeo.AO-J1OyrzyVwOmTB1g27m5IDCegRilBl67Z36fOgtnqxJCXg0lXahFIAAzCc-BE_1jx01f2FWI9RgukVu6MDY6SbCs23S6TNHXq219h2hczovSm7Ae9nuMc
# python script/verifyOrder.py shopspecialtwonew_001_0.99 lkdkopelbankljnfjfcgaflp.AO-J1OxLyAueQLDYIU3OysbqL-OOlPJvQktggsmurub3-oMDSX0qKcyBcBZA4yQWKnGa-r_cllfTrisHSNt4xFalk0YZg6FhNPeWTdJDjBaHi96isH7ML-c
# ./verifyOrder newplayer_001_0.49 ojiimdalhjimomakjmmikjeo.AO-J1OyrzyVwOmTB1g27m5IDCegRilBl67Z36fOgtnqxJCXg0lXahFIAAzCc-BE_1jx01f2FWI9RgukVu6MDY6SbCs23S6TNHXq219h2hczovSm7Ae9nuMc

40
script/verifyOrder.spec Normal file
View File

@ -0,0 +1,40 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['verifyOrder.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='verifyOrder',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )

BIN
source/20251112.xlsx Normal file

Binary file not shown.

View File

@ -1,62 +1,62 @@
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/$basearch/stable
baseurl=https://download.docker.com/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-stable-debuginfo]
name=Docker CE Stable - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/debug-$basearch/stable
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/stable
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-stable-source]
name=Docker CE Stable - Sources
baseurl=https://download.docker.com/linux/centos/$releasever/source/stable
baseurl=https://download.docker.com/linux/centos/7/source/stable
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-test]
name=Docker CE Test - $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/$basearch/test
baseurl=https://download.docker.com/linux/centos/7/$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-test-debuginfo]
name=Docker CE Test - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/debug-$basearch/test
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-test-source]
name=Docker CE Test - Sources
baseurl=https://download.docker.com/linux/centos/$releasever/source/test
baseurl=https://download.docker.com/linux/centos/7/source/test
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-nightly]
name=Docker CE Nightly - $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/$basearch/nightly
baseurl=https://download.docker.com/linux/centos/7/$basearch/nightly
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-nightly-debuginfo]
name=Docker CE Nightly - Debuginfo $basearch
baseurl=https://download.docker.com/linux/centos/$releasever/debug-$basearch/nightly
baseurl=https://download.docker.com/linux/centos/7/debug-$basearch/nightly
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg
[docker-ce-nightly-source]
name=Docker CE Nightly - Sources
baseurl=https://download.docker.com/linux/centos/$releasever/source/nightly
baseurl=https://download.docker.com/linux/centos/7/source/nightly
enabled=0
gpgcheck=1
gpgkey=https://download.docker.com/linux/centos/gpg

Binary file not shown.

View File

@ -0,0 +1,5 @@
-- filepath: sql/add_title_en_content_en.sql
-- 在 system_mail_info 表中增加 title_en 和 content_en 列
ALTER TABLE system_mail_info
ADD COLUMN title_en VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'English title',
ADD COLUMN content_en TEXT NOT NULL COMMENT 'English content';

27
ssl/bywaystudios.com.key Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAth2OvQ4vKkQnKzfMEW+dBUGjPXpwuzizCa5wAGOyLFTIwv2a
WsRDSnCeAA8NsoYVzuG2+tzHi7hOulAJTWHzr/XgdpNqO7KzFoIkYXGtTjFg3gML
R8ikRZZWMMnSHy0jDvBoeydaf/ff+a2WZjKb2FknRBIUfdmbQdFLauo9Q1/V2mSc
/9MQT4rLk50wpbWf4zzsYClHt09BD4lDoWS1iLKLDi5Do2DELkUUbV2flaElBcqX
D6yw1v/fqmXUM1UpV5gKBrDZp3x9k0cbudUGfYlLulC0+k+UuVhXsVWQPMNUlp0+
s9bfUUm1BQRmSaPUvkgwtzH83EAZmiKuUMTJ0QIDAQABAoIBAAJW+uB+8Cgw2/f4
LY0DzBanMzu0+QHOxq4XKaU3orBjHnky3OrRnrO0IrOJffmPM3SG/dzXPVEUOx61
rIjr+z+Ffy7G0hSWRSrC3UjLNxjMFZyEmX6Am2uxdMYHscVoxQyKFi2O4eDHBH+m
tUn22H29F34OZWkAhLghwkBLZiIZcYBJhptG0uk5mpdN7thAG+3DQXv6VYIYyLT6
3MVFPmaxBmxhQGUzRyyd+YF3Z6DiKPpWVYL7Wk3MT+62aui7X1J9Rwh54yAaFVox
9U6cbwJb23cccSRvYJV19Uq1WzVTc19mex5+a9IY72kV9X50s6K/xpbzHyHhW+1B
Bf4vcIECgYEA+gSjDkK+jKN2Scr61g5eTDd398aQcChvYSjVRTb2hY5pPTTVSy5/
PoeW7XQlWbYZRpB3gVWLh61pSY4M063E/d8IZXHvvOl8UwwktoqCkrS7y5PO7aNM
jF0vfbK9btMm/hjK/1bNPDQjknwVXMOug153wxLuCoRkm5yf7XxZTlkCgYEAunkE
LJgpIcHQdViWwUzdqDuF8croDFRpDi/Nm93142E5w2N6yX9RS07EnRw2HacLQWxp
oS85s3QxukihemU/4yblhtw6PZTkXE4vUPH8OI9hUQi9SwaWfD9qS4CGhYmjbB+d
L917QHKoaaxk0+LvNZHa93RQsPl0yTSOiSCaGDkCgYEApKnHJk5JJ2FFN8aqu65M
5s+lgJfTazsGWCxHgkV3yXCI2VnhnJlsDqfIfG2BZ/tp3DKrso+/zMUmUd5vjj6l
PjrVUdLffUEds6iMyXiiFLNZ9/NKVvK1KMD61UOSRdpllPaJQ/BMTXldcE2u2CC8
4CKop97gziZyCJb4MbYzL0kCgYEAm4klOi0Q4d9PiRGDbWg32oMLjkq4ktA1cGff
EAtrdWU7UQZA/KD9pdrllEZbvRAAC2nqEU/ayRw5/i9mwTiCuW1QNdSrn4H5mCR+
wv2Ua3jsqzKm8VVlX+1lM+TYT7omXaFg8vPCQldgsgPhdfrrm7s08QJL69Gm38y+
txJCdcECgYBd6HDypjiuswd6fTmdNYMZBQJ+M1ouuyoylv4m6hEp3iHhmWyGvE30
+VLfzPDMXwjAvbk6PLIKJw6R2fA/Lh3GOjb0heAcwuGpgqe0OM0+PRo4mxlbovcx
K0RpSiac5cgpEdO4Og+cgKzCg3g35wVLfvUYDAaZrsP26I/Xru5lUw==
-----END RSA PRIVATE KEY-----

127
ssl/bywaystudios.com.pem Normal file
View File

@ -0,0 +1,127 @@
-----BEGIN CERTIFICATE-----
MIIGNzCCBR+gAwIBAgIQVqPp7OLoPM3oQ1nibTAApzANBgkqhkiG9w0BAQsFADBc
MQswCQYDVQQGEwJDTjEaMBgGA1UEChMRV29UcnVzIENBIExpbWl0ZWQxMTAvBgNV
BAMMKFdvVHJ1cyBEViBTZXJ2ZXIgQ0EgIFtSdW4gYnkgdGhlIElzc3Vlcl0wHhcN
MjUxMjA5MDAwMDAwWhcNMjcwMTA5MjM1OTU5WjAdMRswGQYDVQQDDBIqLmJ5d2F5
c3R1ZGlvcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2HY69
Di8qRCcrN8wRb50FQaM9enC7OLMJrnAAY7IsVMjC/ZpaxENKcJ4ADw2yhhXO4bb6
3MeLuE66UAlNYfOv9eB2k2o7srMWgiRhca1OMWDeAwtHyKRFllYwydIfLSMO8Gh7
J1p/99/5rZZmMpvYWSdEEhR92ZtB0Utq6j1DX9XaZJz/0xBPisuTnTCltZ/jPOxg
KUe3T0EPiUOhZLWIsosOLkOjYMQuRRRtXZ+VoSUFypcPrLDW/9+qZdQzVSlXmAoG
sNmnfH2TRxu51QZ9iUu6ULT6T5S5WFexVZA8w1SWnT6z1t9RSbUFBGZJo9S+SDC3
MfzcQBmaIq5QxMnRAgMBAAGjggMyMIIDLjAfBgNVHSMEGDAWgBSZmy32i/Cj24nU
nvvldC9o0pBP5DAdBgNVHQ4EFgQUCFKCjmFS7bzr/gxZGuYPNTLwwwYwDgYDVR0P
AQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwSQYD
VR0gBEIwQDA0BgsrBgEEAbIxAQICFjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3Nl
Y3RpZ28uY29tL0NQUzAIBgZngQwBAgEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov
L2NybC5jcmxvY3NwLmNuL1dvVHJ1c0RWU2VydmVyQ0FfMi5jcmwwbAYIKwYBBQUH
AQEEYDBeMDgGCCsGAQUFBzAChixodHRwOi8vYWlhLmNybG9jc3AuY24vV29UcnVz
RFZTZXJ2ZXJDQV8yLmNydDAiBggrBgEFBQcwAYYWaHR0cDovL29jc3AuY3Jsb2Nz
cC5jbjAvBgNVHREEKDAmghIqLmJ5d2F5c3R1ZGlvcy5jb22CEGJ5d2F5c3R1ZGlv
cy5jb20wggGOBgorBgEEAdZ5AgQCBIIBfgSCAXoBeAB3AGBMmq96f3dfAdQG/JIN
yJnrCxx9+MlSG/r6F3c7l4vJAAABmwG3KuMAAAQDAEgwRgIhAOApwbyVueun3xhC
mTSOgscM+EfoyMnm4lrNEcEly4ANAiEAqkqI93x0tYyXyanzewv1mVqWt5n9jKzs
rOVBbn89QRwAfQCOykcLrN5q86IGsKR6hLdG/h/Gv5U+JeabTuQCSPPG6AAAAZsB
tyvaAAgAAAUAAGfcEAQDAEYwRAIgIITO+svcTRkjPRrFpuvPT0yBDrxI0to55ivE
amsxY+ACIGyR3rLWtmunFaVO4SIFzwg8cIl9Dv3C8+gEIE+YmhNwAH4AWW5sM4aU
sllyolbIoOjdkEp26Ag92oc7AQg4KBQ87lkAAAGbAbcsGQAIAAAFAAAA590EAwBH
MEUCIQDa9BiAFvEFRyS2VXo1RD6NL+1LycCQfe8lwaRgANltYAIgQwclGCysMlcz
dB0OfBnmP5yskdWL4raEoxLX5+y9OPQwDQYJKoZIhvcNAQELBQADggEBAFULS/wz
GEE6rqG1Pdd8in6JthtVgVwwTbLsOt09RAWRs0VS/qeVEYxrqYCcuO5FIjoX6ENk
Hf6FAnqZp65/iTv9YtSoZFbghvD8ys8kjCB8bZOcs0FROehtCzLZb02ceozYjPoz
1S1SEsvy4TM3pkW2OCPdNqTm1+dSPHZKlfZeeMuZxYv7a3rONry/JE3kN6tQ0Wfe
HTRjO+H7trxie+e92SQ4vCcbooHvS6A5TAgtBC4cGNWWaMga+3GJyp2kcdjPzzpI
yuOJLZKbRba+sWY1EDZVZ8pMwYMOYbf+4/ThLHVpzignsjSMgvcnq9CnMA4MPeIW
bUtCaexj/Mif4ww=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIF4jCCA8qgAwIBAgIRANVuJGyU7WOrsUbvwZa2T7AwDQYJKoZIhvcNAQEMBQAw
gYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtK
ZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYD
VQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIw
MDEwODAwMDAwMFoXDTMwMDEwNzIzNTk1OVowXDELMAkGA1UEBhMCQ04xGjAYBgNV
BAoTEVdvVHJ1cyBDQSBMaW1pdGVkMTEwLwYDVQQDDChXb1RydXMgRFYgU2VydmVy
IENBICBbUnVuIGJ5IHRoZSBJc3N1ZXJdMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA7IE0rmVTVdRdNOzK1jsR/VppyukZ/XbQgakJHOhg6XGDsiHe/l5B
3PxyXw18jEdN+7YxP0qsGz+HlQbsQh6XlwIyjpz/2gFMiqa7y1v+dHOgj6xNOF5a
oaPm/Qhb0N+JYQidgaC+1Zp6W+YeC736rzCMr9vL1Usa3QLzRoQEo0DzbG4sPeP1
US0Ia/i8o6szArH+DAcvrzCZ2kkpTScQ9QfOsvkMBP1W2otICdKUyZHaBc+ztTAd
ovSlOR+GPf29dYfGQkZAp0tffIRw/na3WB86WGZPpNFfo2QxxsHYoL3oSWKfSWTY
FgW22J8eA03TFHYowm/NqYuJ7GW553HppQIDAQABo4IBcDCCAWwwHwYDVR0jBBgw
FoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFJmbLfaL8KPbidSe++V0
L2jSkE/kMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAEGzAZMA0GCysGAQQBsjEB
AgIWMAgGBmeBDAECATBQBgNVHR8ESTBHMEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0
cnVzdC5jb20vVVNFUlRydXN0UlNBQ2VydGlmaWNhdGlvbkF1dGhvcml0eS5jcmww
cQYIKwYBBQUHAQEEZTBjMDoGCCsGAQUFBzAChi5odHRwOi8vY3J0LnVzZXJ0cnVz
dC5jb20vVVNFUlRydXN0UlNBQUFBQ0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v
b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQB5t8v3uYzHa4EL
0rOb9g/YAmptUbILcBMKk1x188ucsGVPaG1DG9bpVamxbmCtFA1MlrA7iUC8SGop
KBnuWFsNKiC7jCbRoahT1/FSwFsSuDlDmOjr1MqDXE+or08UkXsJB57XxXxdVOPl
DcZHII4qHi1XKK4iurMqb+kbdpAWadyfidRRCGPopYCVYLLYhRJgpFGtfr6Gk8N0
j81jq/7QbN0dRSDzMNdadKTc7c3+i9fIrXj79lV5Wvva+OL7nh8MxQhG1Ekek7Rv
en++jSZvaEhCrMsSedFTA/aIy7oJg85tfglF2ybK61HsobjYzdDNICKJlIm4chlA
XIDDqw2mw0Kz2snrkp9dpvMBqahF/Uy1kHzPcrq1/w5OqZWAuDKxZ68PuZ/ME2hI
YbIDG9dWT6Y7eqtjQ2TmAQbOqdAG2LeikPMl2DMrPEa4lcKJzsFbHfHAW3hVgPSQ
hRfS4TtbNnxijbsp8GguMHxP2R7dpAAYybwfZdXP7WYAnwEr1mzIf0Y3J0m7GDyX
JhaflN3G2wIm2HzRd39NvnDRmFEraqui/YYO9ym0pwq1d0S+bGG6876QCto0u3Cg
ItFh3Za2ZeIY+g5mWrejSaDs9LT7eu44iCyebfgekdMRqFeCuGAsJdsun3LOHHJo
tCVPRjyFg9NDeJeMa4Z8QuXAXLd9cw==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFgTCCBGmgAwIBAgIQOXJEOvkit1HX02wQ3TE1lTANBgkqhkiG9w0BAQwFADB7
MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
VQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UE
AwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTE5MDMxMjAwMDAwMFoXDTI4
MTIzMTIzNTk1OVowgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5
MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBO
ZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0
aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgBJlFzYOw9sI
s9CsVw127c0n00ytUINh4qogTQktZAnczomfzD2p7PbPwdzx07HWezcoEStH2jnG
vDoZtF+mvX2do2NCtnbyqTsrkfjib9DsFiCQCT7i6HTJGLSR1GJk23+jBvGIGGqQ
Ijy8/hPwhxR79uQfjtTkUcYRZ0YIUcuGFFQ/vDP+fmyc/xadGL1RjjWmp2bIcmfb
IWax1Jt4A8BQOujM8Ny8nkz+rwWWNR9XWrf/zvk9tyy29lTdyOcSOk2uTIq3XJq0
tyA9yn8iNK5+O2hmAUTnAU5GU5szYPeUvlM3kHND8zLDU+/bqv50TmnHa4xgk97E
xwzf4TKuzJM7UXiVZ4vuPVb+DNBpDxsP8yUmazNt925H+nND5X4OpWaxKXwyhGNV
icQNwZNUMBkTrNN9N6frXTpsNVzbQdcS2qlJC9/YgIoJk2KOtWbPJYjNhLixP6Q5
D9kCnusSTJV882sFqV4Wg8y4Z+LoE53MW4LTTLPtW//e5XOsIzstAL81VXQJSdhJ
WBp/kjbmUZIO8yZ9HE0XvMnsQybQv0FfQKlERPSZ51eHnlAfV1SoPv10Yy+xUGUJ
5lhCLkMaTLTwJUdZ+gQek9QmRkpQgbLevni3/GcV4clXhB4PY9bpYrrWX1Uu6lzG
KAgEJTm4Diup8kyXHAc/DVL17e8vgg8CAwEAAaOB8jCB7zAfBgNVHSMEGDAWgBSg
EQojPpbxB+zirynvgqV/0DCktDAdBgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rID
ZsswDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAG
BgRVHSAAMEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29t
L0FBQUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggr
BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
A4IBAQAYh1HcdCE9nIrgJ7cz0C7M7PDmy14R3iJvm3WOnnL+5Nb+qh+cli3vA0p+
rvSNb3I8QzvAP+u431yqqcau8vzY7qN7Q/aGNnwU4M309z/+3ri0ivCRlv79Q2R+
/czSAaF9ffgZGclCKxO/WIu6pKJmBHaIkU4MiRTOok3JMrO66BQavHHxW/BBC5gA
CiIDEOUMsfnNkjcZ7Tvx5Dq2+UUTJnWvu6rvP3t3O9LEApE9GQDTF1w52z97GA1F
zZOFli9d31kWTz9RvdVFGD/tSo7oBmF0Ixa1DVBzJ0RHfxBdiSprhTEUxOipakyA
vGp4z7h/jnZymQyd/teRCBaho1+V
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAo6z7cPVcCIu+rT6ywB5dhhpZfCiKQu155+XPR1kmMFwiFVQe
XnzcT5kmdHLJVEZOgV+LM76SeiGi7haF3wH9N9uYUMmp91b4H2IAiybaKGl/Xc7M
WWpn5YJcttCdd3ZfzYqRQoysucmi4qTzSwf3vJqijo+JFmDvolVWO0KtDsRmU6DL
nocygaKROyyCh5HbWZnikb0bUTLYu58zhYvc1eFwrfwjRSPsGDcTbFHWCl1UNnfZ
mWO0ydMnbfzUSQTGJmOVwqFkhMVRGFFjrTRUAeDNQpkr9YN8tGc+111Igq+uAfMc
yrIIlfEy2ltSnu8hxjNb4sk5v9Fv7APkrjGVsQIDAQABAoIBAALK+8Fm/NDyg+iH
fNv1YknDBYrhhpzZjSGtYYOWQr+pgTViKZOzYSKeLbKBl1J8uDzR6T/fsFBgMykJ
flnnU6+Fa9k/dhe2RrNplzIvEaLsTFP79UjptwGK320ixl6yL04d337f6qSci07l
wXcJMquBUf78j22WOt1gxAEGRFcccNj4yTxLOAFUqwegBy9MuH02VCW4z9QEwiWU
MmQHbFIpHreJaIh+CaBWx9CUEzL4iCYqRnmSNgfw5AE0snvXid1tlQT4IBRvcPE4
I2bRKUcxvckXHpVKbNPv2A43DoWjF+vlGjU6utMfZ5DRJWyn03s4HOAtrUGY48Sj
0kNDbOECgYEAzSZYgqJuNXEzuZ9dYeXwvCdmU+krOUGaRu1gAymkRdSu+KFDxaTs
xnbhbC0uUzSL0idqeUt3DpeV5rGJf8InbCVwTjmV8hKGS9zTMvBWAH4TavZswAJz
/MNKXZ96UR9xRZFU4988pMF/yqliCLUgN8FI0KvAdIiMgJt4XWa0UUkCgYEAzD7s
n9F7vo7ZHYt/L81lviw4+BBk1934LIvZsXadxmUE8S46ZgbqRZHbrErQ4GJGpCsc
tGAsJpubDapGHv8iL5e6eUphHsM1wR18ciCSNjkxcvSiQJcCpzXLgDY8Tg7KxIOF
c+HKH5O+awCIJcRBBZIXgTC6Gxy6IFee/GXNCSkCgYA0h4YQZSENJCBXflv97k/X
Dcug3sqHjanAUZXNGYOLserflQNyf0l1hAkyltsOyRyoQhl8V3tzzBLBEGKhyQgp
I+j+zrX7Vwz2LeQSXgHXfHDiaZjtDXO/nA3VrTk3vnJVmuH+uzGfCkD7lqWYjzBh
tmc7r07HSBOZ9rU6TUsMqQKBgQCEoPPNEB4X7vDj85rCstE3vcW8qACkALrQSnwx
dgIcO6sK5mb7q8/jH0UTy315x7dxkaFRLAZfh7oXFJP2Oty7JP7tFjSc4kx8u6X9
AlOPrHIE4QCfirApXpBoEE/2rDpVg8ZcKqmy+aC0ISNHyvoiIOzscnTXeD8RE3Tl
F0IeiQKBgAMSt0sbXy7jgBSUgK8GU5Ox2YcstNMJfeXu5F7WjbtuAlwMNJgBLVYd
gM2lEE8xBUx/5wPkbvzJq4tRPzNO5T7AjOnYH1Ul2iz+kEDOZfPVL0OL/VUYFBYg
4SZnnt1jC9aHLHVqVIIJK//9cEfOJZ6mz3DtyX2wDm/tdoFOr4cG
-----END RSA PRIVATE KEY-----

View File

@ -1,62 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIGCDCCBPCgAwIBAgIQA0IfJS+AMdxZgd8L1fUl/TANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzIwHhcNMjQxMjA5MDAwMDAwWhcNMjUwMzA5MjM1OTU5WjAj
MSEwHwYDVQQDExhwZXRob21lLmJ5d2F5c3R1ZGlvcy5jb20wggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCjrPtw9VwIi76tPrLAHl2GGll8KIpC7Xnn5c9H
WSYwXCIVVB5efNxPmSZ0cslURk6BX4szvpJ6IaLuFoXfAf0325hQyan3VvgfYgCL
JtooaX9dzsxZamflgly20J13dl/NipFCjKy5yaLipPNLB/e8mqKOj4kWYO+iVVY7
Qq0OxGZToMuehzKBopE7LIKHkdtZmeKRvRtRMti7nzOFi9zV4XCt/CNFI+wYNxNs
UdYKXVQ2d9mZY7TJ0ydt/NRJBMYmY5XCoWSExVEYUWOtNFQB4M1CmSv1g3y0Zz7X
XUiCr64B8xzKsgiV8TLaW1Ke7yHGM1viyTm/0W/sA+SuMZWxAgMBAAGjggLrMIIC
5zAfBgNVHSMEGDAWgBR435GQX+7erPbFdevVTFVT7yRKtjAdBgNVHQ4EFgQUKDRG
tBU/MaYUiXNhjO+s2+fcgs0wIwYDVR0RBBwwGoIYcGV0aG9tZS5ieXdheXN0dWRp
b3MuY29tMD4GA1UdIAQ3MDUwMwYGZ4EMAQIBMCkwJwYIKwYBBQUHAgEWG2h0dHA6
Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMIGABggrBgEFBQcBAQR0MHIwJAYIKwYBBQUH
MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcwAoY+aHR0cDov
L2NhY2VydHMuZGlnaWNlcnQuY29tL0VuY3J5cHRpb25FdmVyeXdoZXJlRFZUTFND
QS1HMi5jcnQwDAYDVR0TAQH/BAIwADCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFo
AHYATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGTqSjTewAABAMA
RzBFAiBZVs4LrOREOEnv8tQKb5UNFkPVfV2nNqCy24bKLAVr/gIhAMg2KsKQ9a6q
8Wc64AKJx3DjFqLFpCytkTVKtrBp0tUzAHUAcyAiDwgWivnzxKaLCrJqmkoA7vV3
hYoITQUA1KVCRFkAAAGTqSjTHwAABAMARjBEAiAiy4Xqcy0oqGMDDBRManyt6VmT
jCZRVA+mHBzoQT0NAgIgOCW5513LuInmKGlKi5jxRkIM0xh6te0uIQvt4ze9EekA
dwDm0jFjQHeMwRBBBtdxuc7B0kD2loSG+7qHMh39HjeOUAAAAZOpKNMvAAAEAwBI
MEYCIQDFKi06ApokpmIizAxE+175uD3bIYO9P3+otQg1ZjSiUQIhAJ0SThOlYjU6
1nvXCCVCrj96Jsb1KuKUdtPAelusunAHMA0GCSqGSIb3DQEBCwUAA4IBAQCoWphr
4DagcE2yZJkgbhtJ05HLnFBqaQQ5+7X6SR/MRAPY65nCKzgntzXvBcpexiF04I2u
ivtR0sH28Riuu+VDL4ltjZQsW20hd0QNeKia4caUaOaX0hEG1EO0sGLfHQI0G+oq
jtEuSQnnzy2El3gs0kORAFqhGkL2q56rscPpandzdF1H5v2CeM54Q9EmCFzwGW7e
NbLm7MSbn0enWs9q/Zjs6+t9n4VYFZw2c8BXDXtrim35ZcJpJZ7D91ve5SaMH5yg
5at5un2nAdDe3D3V1aATz5ebq3M0JHoqkmPE1a3CkzMdfA8CQArmClBn8gquxm/+
dq4rSsSh89wAz+lO
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
-----END CERTIFICATE-----

View File

@ -1,31 +0,0 @@
[app]
app_name = pet_home
app_id = 1001
app_path = /data/devops/Goleaf
conf_path = /etc/pet_home
[server]
tcp_addr = 3600
ws_addr = 3700
listen_addr = 3800
max_conn = 1000
remote = pethome.bywaystudios.com
[mysql]
mysql_user = root
mysql_password = root
mysql_host = 172.20.0.5
mysql_port = 3306
[redis]
redis_host = 172.20.0.6
redis_port = 6379
[cluster]
center_id = 0
center_host = pethome.bywaystudios.com
center_port = 3800
[log]
log_level = debug
te_log_path = /var/log/pet_home/te

View File

@ -1,15 +0,0 @@
module tool
go 1.23.1
require gopkg.in/ini.v1 v1.67.0
require (
github.com/fatih/color v1.18.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/sys v0.25.0 // indirect
)

View File

@ -1,549 +0,0 @@
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"github.com/gookit/color"
"gopkg.in/ini.v1"
)
const (
SECRET_KEY = ")VQbB(vpy=U(wcp)"
)
// GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/tool/tool main.go
var help = `
Usage: app.ini [options]
start start the server
stop stop the server
restart restart the server
status get the server status
install install the server
uninstall uninstall the server
kill kill the server
`
var cfg *ini.File
var FuncMap map[string]func() error
var dirPath string
var app_path string
var (
infoColor = color.New(color.FgGreen)
warn = color.New(color.FgYellow)
err = color.New(color.FgRed)
)
func info(format string, a ...interface{}) {
time := time.Now().Format("2006-01-02 15:04:05")
format = fmt.Sprintf("[%s] %s\n", time, format)
infoColor.Printf(format, a...)
}
func main() {
defer func() {
if err := recover(); err != nil {
info("%s", help)
}
}()
FuncMap = make(map[string]func() error)
// 检查是否提供了命令行参数
if len(os.Args) < 2 {
log.Fatal(help)
}
var err error
// 获取当前文件的绝对路径
execPath, err := os.Executable()
if err != nil {
log.Fatal(err)
}
absPath, err := filepath.Abs(execPath)
if err != nil {
log.Fatal(err)
}
// 获取当前文件的绝对路径的文件夹路径
dirPath = filepath.Dir(absPath)
// 加载 app.ini 文件
cfg, err = ini.Load(dirPath + "/app.ini")
if err != nil {
log.Fatal(err)
}
app_path = cfg.Section("app").Key("app_path").String()
register("start", start)
register("stop", stop)
register("install", install)
register("status", status)
register("restart", restart)
register("uninstall", uninstall)
register("reload", reload)
register("kill", kill)
funcName := os.Args[1]
if f, ok := FuncMap[funcName]; ok {
e := f()
if e != nil {
log.Fatal(e)
}
} else {
log.Fatal(help)
}
}
func register(name string, f func() error) {
FuncMap[name] = f
}
func kill() error {
if len(os.Args) < 4 {
log.Fatal("请输入要停止的服务类型和区号 kill [center|node] 区号")
}
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
log.Fatal(err)
}
// 使用命令行命令 kill -9 杀死进程
cmd := exec.Command("kill", "-9", strconv.Itoa(pid))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
info("server %s_%s 已被 kill -9 杀死, 进程号:%d", NodeType, Zone, pid)
return nil
}
func install() error {
// log.Println("install")
if len(os.Args) < 4 {
err.Println("请输入要安装的服务类型和区号 install [center|node] 区号")
}
serverType := os.Args[2]
zone := os.Args[3]
if serverType != "center" && serverType != "node" {
err.Println("请输入正确的服务类型 center|node")
}
AppName := cfg.Section("app").Key("app_name").String()
// 生成服务名
serviceName := fmt.Sprintf("%s_%s_%s", AppName, serverType, zone)
// 判断文件夹是否存在
folderPath := fmt.Sprintf("%s/zone/%s", app_path, serviceName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
err := os.MkdirAll(folderPath, os.ModePerm)
if err != nil {
log.Fatal(err)
}
info("文件夹 %s 创建成功\n", folderPath)
} else {
info("文件夹 %s 已存在\n", folderPath)
}
// 生成配置文件
configPath := fmt.Sprintf("%s/server.json", folderPath)
file, err := os.Create(configPath)
if err != nil {
log.Fatal(err)
}
defer file.Close()
zoneId, _ := strconv.Atoi(zone)
cf, confs := createConfigFile(zoneId, serverType)
file.WriteString(confs)
// 读取 SQL 文件内容并替换 %database% 字符串
sqlFilePath := fmt.Sprintf("%s/tool/Merge_Pet.sql", app_path)
sqlContent, err := os.ReadFile(sqlFilePath)
if err != nil {
log.Fatal(err)
}
dbName := cf["DbName"].(string)
modifiedSQL := strings.ReplaceAll(string(sqlContent), "%database%", dbName)
// 将修改后的内容写入临时文件
tempSQLFile, err := os.CreateTemp("", "modified_*.sql")
if err != nil {
log.Fatal(err)
}
_, err = tempSQLFile.WriteString(modifiedSQL)
if err != nil {
log.Fatal(err)
}
tempSQLFile.Close()
// 创建数据库
dbUser := cfg.Section("mysql").Key("mysql_user").String()
dbPassword, _ := Decrypt(cfg.Section("mysql").Key("mysql_password").String())
dbHost := cfg.Section("mysql").Key("mysql_host").String()
dbPort := cfg.Section("mysql").Key("mysql_port").String()
// log.Println("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, "-e", fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
createDBCmd := exec.Command("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, "-e", fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", dbName))
createDBCmd.Stdout = os.Stdout
createDBCmd.Stderr = os.Stderr
err = createDBCmd.Run()
if err != nil {
log.Fatal(err)
}
// log.Println("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, dbName, "-e", fmt.Sprintf("source %s", tempSQLFile.Name()))
// 执行修改后的 SQL 文件
cmd := exec.Command("mysql", "-u"+dbUser, "-p"+dbPassword, "-h"+dbHost, "-P"+dbPort, dbName, "-e", fmt.Sprintf("source %s", tempSQLFile.Name()))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
cmd = exec.Command("mkdir", cf["LogPath"].(string))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
}
info("SQL 文件 %s 执行成功\n", sqlFilePath)
info("配置文件 %s 创建成功\n", configPath)
return nil
}
func uninstall() error {
stop()
if len(os.Args) < 4 {
log.Fatal("请输入要卸载的服务类型和区号 uninstall [center|node] 区号")
}
serverType := os.Args[2]
zone := os.Args[3]
if serverType != "center" && serverType != "node" {
log.Fatal("请输入正确的服务类型 center|node")
}
AppName := cfg.Section("app").Key("app_name").String()
// 生成服务名
serviceName := fmt.Sprintf("%s_%s_%s", AppName, serverType, zone)
// 判断文件夹是否存在
folderPath := fmt.Sprintf("%s/zone/%s", app_path, serviceName)
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
info("文件夹 %s 不存在\n", folderPath)
return nil
} else {
info("文件夹 %s 存在\n", folderPath)
}
// 删除文件夹
err := os.RemoveAll(folderPath)
if err != nil {
log.Fatal(err)
}
info("文件夹 %s 删除成功\n", folderPath)
return nil
}
func createConfigFile(Id int, Type string) (map[string]interface{}, string) {
conf := make(map[string]interface{})
conf["LogLevel"] = cfg.Section("log").Key("log_level").String()
TcpStartAddr, _ := cfg.Section("server").Key("tcp_addr").Int()
conf["TcpAddr"] = fmt.Sprintf(":%d", TcpStartAddr+Id)
WsStartAddr, _ := cfg.Section("server").Key("ws_addr").Int()
conf["WsAddr"] = fmt.Sprintf(":%d", WsStartAddr+Id)
ListenAddr, _ := cfg.Section("server").Key("listen_addr").Int()
conf["MySqlAddr"] = cfg.Section("mysql").Key("mysql_host").String()
conf["MySqlUsr"] = cfg.Section("mysql").Key("mysql_user").String()
conf["MySqlPwd"] = cfg.Section("mysql").Key("mysql_password").String()
conf["MySqlPort"] = cfg.Section("mysql").Key("mysql_port").String()
MaxConnNum, _ := cfg.Section("server").Key("max_conn").Int()
conf["MaxConnNum"] = MaxConnNum
app_name := cfg.Section("app").Key("app_name").String()
conf["LogPath"] = fmt.Sprintf("%s/zone/%s_%s_%d/log", app_path, app_name, Type, Id)
conf["DbName"] = fmt.Sprintf("%s_%d", app_name, Id)
conf["TELOGDIR"] = cfg.Section("log").Key("te_log_path").String()
conf["GameName"] = app_name
AppId, _ := cfg.Section("app").Key("app_id").Int()
conf["AppID"] = AppId
conf["AppPath"] = app_path
conf["ServerType"] = Type
conf["ServerID"] = Id
conf["ServerOpenTime"] = "2028-01-01 00:00:00"
conf["ServerName"] = fmt.Sprintf("%s_%d", app_name, Id)
conf["ServerStatus"] = 1
CenterId, _ := cfg.Section("app").Key("center_id").Int()
conf["ServerCenter"] = CenterId
conf["RedisAddr"] = cfg.Section("redis").Key("redis_host").String()
conf["RedisPort"] = cfg.Section("redis").Key("redis_port").String()
conf["GameConfPath"] = app_path + "/config/"
conf["RemoteAddr"] = fmt.Sprintf("%s:%d", cfg.Section("server").Key("remote").String(), ListenAddr+Id) // 服务器地址
conf["ListenAddr"] = fmt.Sprintf(":%d", ListenAddr+Id)
conf["CenterAddr"] = fmt.Sprintf("%s:%s", cfg.Section("cluster").Key("center_host").String(), cfg.Section("cluster").Key("center_port").String()) // 服务器地址
b, _ := json.MarshalIndent(conf, "", " ")
return conf, string(b)
}
func start() error {
// log.Println("start")
if len(os.Args) < 4 {
log.Fatal("请输入要启动的服务类型和区号 start [center|node] 区号")
}
err := status()
if err == nil {
return err
}
info("正在启动服务server %s_%s ...", os.Args[2], os.Args[3])
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
cmdName := app_path + "/main"
cmdArgs := []string{fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)}
// 创建命令
cmd := exec.Command(cmdName, cmdArgs...)
cmd.SysProcAttr = &syscall.SysProcAttr{}
// 创建管道
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
cmd.Env = os.Environ()
// 打开输出文件
outfile, err := os.OpenFile(fmt.Sprintf("%s/zone/%s_%s_%s/output.log", app_path, app_name, NodeType, Zone), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
log.Fatal(err)
}
defer outfile.Close()
// 重定向标准输出和标准错误到文件
cmd.Stdout = outfile
cmd.Stderr = outfile
err = cmd.Start()
if err != nil {
log.Fatal(err)
}
// 打印进程号
info("server %s_%s已启动, 进程号:%d", os.Args[2], os.Args[3], cmd.Process.Pid)
// 发送命令到子进程
go func() {
time.Sleep(2 * time.Second) // 等待子进程启动
_, err := stdin.Write([]byte("your_command\n"))
if err != nil {
log.Fatal(err)
}
stdin.Close()
}()
// 释放与子进程相关的资源
err = cmd.Process.Release()
if err != nil {
log.Fatal(err)
}
return nil
}
func reload() error {
if len(os.Args) < 4 {
log.Fatal("请输入要重启的服务类型和区号 reload [center|node] 区号")
}
app_name := cfg.Section("app").Key("app_name").String()
NodeType := os.Args[2]
Zone := os.Args[3]
args := fmt.Sprintf("%s_%s_%s", app_name, NodeType, Zone)
pid, err := getPidByArgs(args)
if err != nil {
log.Fatal(err)
}
// 向进程发送SIGTERM信号
process, err := os.FindProcess(pid)
if err != nil {
log.Fatal(err)
}
err = process.Signal(syscall.SIGINT)
if err != nil {
log.Fatal(err)
}
fmt.Printf("server %s_%s 已发送SIGINT信号, 进程号: %d\n", NodeType, Zone, pid)
return nil
}
func stop() error {
if len(os.Args) < 4 {
log.Fatal("请输入要停止的服务类型和区号 stop [center|node] 区号")
}
err := statusInfo()
if err != nil {
return err
}
info("正在关闭服务server %s_%s ...", os.Args[2], os.Args[3])
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
log.Fatal(err)
}
// 查找进程
process, err := os.FindProcess(pid)
if err != nil {
log.Fatal(err)
}
// 关闭进程
err = process.Signal(syscall.SIGTERM)
if err != nil {
log.Fatal(err)
}
info("server %s_%s 已关闭,进程号:%d", NodeType, Zone, pid)
return nil
}
func getPidByArgs(args string) (int, error) {
cmd := exec.Command("pgrep", "-f", args)
output, err := cmd.Output()
if err != nil {
return 0, err
}
// 解析输出,获取第一个匹配的进程号
outputStr := strings.TrimSpace(string(output))
pidStr := strings.Split(outputStr, "\n")[0]
pid, err := strconv.Atoi(pidStr)
if err != nil {
return 0, err
}
return pid, nil
}
func status() error {
if len(os.Args) < 4 {
log.Fatal("请输入要查询的服务类型和区号 status [center|node] 区号")
}
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
// 查找进程
_, err = os.FindProcess(pid)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
info("节点 %s_%s 启动中, 进程号 %d\n", NodeType, Zone, pid)
return nil
}
func statusInfo() error {
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
processName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
// 示例进程名称
// 获取进程号
pid, err := getPidByArgs(processName)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
// 查找进程
_, err = os.FindProcess(pid)
if err != nil {
return fmt.Errorf("进程 %s_%s 未启动", NodeType, Zone)
}
// info.Println("节点 %s_%s 启动中, 进程号 %d\n", NodeType, Zone, pid)
return nil
}
func restart() error {
if len(os.Args) < 4 {
log.Fatal("请输入要重启的服务类型和区号 restart [center|node] 区号")
}
err := stop()
if err != nil {
log.Println(err)
}
for statusInfo() == nil {
time.Sleep(1 * time.Second)
}
err = start()
if err != nil {
return err
}
return nil
}
// 解密字符串
func Decrypt(cipherText string) (string, error) {
cipherTextBytes, err := base64.URLEncoding.DecodeString(cipherText)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(SECRET_KEY))
if err != nil {
return "", err
}
if len(cipherTextBytes) < aes.BlockSize {
return "", fmt.Errorf("cipherText too short")
}
iv := cipherTextBytes[:aes.BlockSize]
cipherTextBytes = cipherTextBytes[aes.BlockSize:]
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherTextBytes, cipherTextBytes)
return string(cipherTextBytes), nil
}

BIN
tool/tool

Binary file not shown.

View File

@ -1,102 +0,0 @@
import os
import sys
import subprocess
import configparser
help_message = """
Usage: app.ini [options]
start start the server
stop stop the server
restart restart the server
status get the server status
"""
cfg = None
FuncMap = {}
dir_path = ""
app_path = ""
def main():
global cfg, dir_path, app_path
if len(sys.argv) < 2:
print(help_message)
sys.exit(1)
# 获取当前文件的绝对路径
exec_path = os.path.abspath(sys.argv[0])
dir_path = os.path.dirname(exec_path)
# print(f"当前文件的绝对路径的文件夹路径: {dir_path}")
# 加载 app.ini 文件
cfg = configparser.ConfigParser()
cfg.read(os.path.join(dir_path, "app.ini"))
app_path = cfg.get("app", "app_path")
register("start", start)
register("stop", stop)
func_name = sys.argv[1]
if func_name in FuncMap:
FuncMap[func_name]()
else:
print(help_message)
sys.exit(1)
def register(name, func):
FuncMap[name] = func
def start():
print("start")
NodeType = sys.argv[2]
Zone = sys.argv[3]
app_name = cfg.get("app", "app_name")
cmd_name = app_path + "/main"
cmd_args = [f"{app_path}/zone/{app_name}_{NodeType}_{Zone}/server.json"]
# 创建命令
cmd = [cmd_name] + cmd_args
print(cmd)
# 启动命令
process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True)
print(f"p {process.pid} s")
# 获取命令输出
stdout, stderr = process.communicate()
print("e:", stdout.decode('utf-8', errors='ignore'))
print("e2:", stderr.decode('utf-8', errors='ignore'))
def stop():
print("stop")
NodeType = sys.argv[2]
Zone = sys.argv[3]
app_name = cfg.get("app", "app_name")
process_args = f"{app_path}/zone/{app_name}_{NodeType}_{Zone}/server.json"
# 获取进程号
pid = get_pid_by_args(process_args)
if pid is None:
print("未找到进程")
sys.exit(1)
# 关闭进程
try:
os.kill(pid, 9)
print(f"进程 {pid} 已关闭")
except OSError as e:
print(f"关闭进程失败: {e}")
sys.exit(1)
def get_pid_by_args(args):
try:
output = subprocess.check_output(["pgrep", "-f", args])
pid_str = output.decode().strip().split("\n")[0]
return int(pid_str)
except subprocess.CalledProcessError:
return None
if __name__ == "__main__":
main()

14
tools/go.mod Normal file
View File

@ -0,0 +1,14 @@
module merge
go 1.23.1
require (
github.com/gookit/color v1.5.4
gopkg.in/ini.v1 v1.67.0
)
require (
github.com/stretchr/testify v1.10.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/sys v0.25.0 // indirect
)

View File

@ -1,22 +1,13 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=

View File

@ -21,6 +21,7 @@ import (
const (
SECRET_KEY = ")VQbB(vpy=U(wcp)"
CLEAN_KEY = "MergePet2024!"
)
// GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/tool/tool main.go
@ -30,10 +31,13 @@ Usage: app.ini [options]
start start the server
stop stop the server
restart restart the server
reload reload the config
status get the server status
install install the server
uninstall uninstall the server
kill kill the server
backup backup the database
clean clean the database
`
var cfg *ini.File
var FuncMap map[string]func() error
@ -90,6 +94,8 @@ func main() {
register("uninstall", uninstall)
register("reload", reload)
register("kill", kill)
register("backup", backup)
register("clean", clean)
funcName := os.Args[1]
if f, ok := FuncMap[funcName]; ok {
e := f()
@ -305,6 +311,146 @@ func createConfigFile(Id int, Type string) (map[string]interface{}, string) {
return conf, string(b)
}
func backup() error {
if len(os.Args) < 4 {
log.Fatal("请输入要启动的服务类型和区号 start [center|node] 区号")
}
err := status()
if err == nil {
log.Fatal("节点启动中,请先关闭节点")
}
info("开始备份server %s_%s ...", os.Args[2], os.Args[3])
NodeType := os.Args[2]
Zone := os.Args[3]
// 示例命令
app_name := cfg.Section("app").Key("app_name").String()
configName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
jsonData, err := os.ReadFile(configName)
if err != nil {
log.Fatal(err)
}
var config map[string]interface{}
if err := json.Unmarshal(jsonData, &config); err != nil {
log.Fatal(err)
}
info("读取配置文件 %s 成功", configName)
dbUser := cfg.Section("mysql").Key("mysql_user").String()
dbPassword, _ := Decrypt(cfg.Section("mysql").Key("mysql_password").String())
dbHost := cfg.Section("mysql").Key("mysql_host").String()
dbPort := cfg.Section("mysql").Key("mysql_port").String()
dbName := config["DbName"].(string)
// 生成备份文件名
backupFile := fmt.Sprintf("%s/zone/%s_%s_%s/%s_backup_%s.sql",
app_path, app_name, NodeType, Zone, dbName, time.Now().Format("20060102_150405"))
// 执行 mysqldump 命令
cmd := exec.Command("mysqldump",
"-u"+dbUser,
"-p"+dbPassword,
"-h"+dbHost,
"-P"+dbPort,
dbName,
)
outFile, err := os.Create(backupFile)
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
cmd.Stdout = outFile
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
info("数据库 %s 备份成功,文件:%s", dbName, backupFile)
return nil
}
func clean() error {
if len(os.Args) < 4 {
log.Fatal("请输入要清空的服务类型和区号 clean [center|node] 区号")
}
err := status()
if err == nil {
log.Fatal("节点启动中,请先关闭节点")
}
fmt.Print("请输入操作密钥: ")
var inputKey string
fmt.Scanln(&inputKey)
if inputKey != CLEAN_KEY {
log.Fatal("密钥错误,操作终止")
}
info("开始清空数据库server %s_%s ...", os.Args[2], os.Args[3])
NodeType := os.Args[2]
Zone := os.Args[3]
app_name := cfg.Section("app").Key("app_name").String()
configName := fmt.Sprintf("%s/zone/%s_%s_%s/server.json", app_path, app_name, NodeType, Zone)
jsonData, err := os.ReadFile(configName)
if err != nil {
log.Fatal(err)
}
var config map[string]interface{}
if err := json.Unmarshal(jsonData, &config); err != nil {
log.Fatal(err)
}
dbUser := cfg.Section("mysql").Key("mysql_user").String()
dbPassword, _ := Decrypt(cfg.Section("mysql").Key("mysql_password").String())
dbHost := cfg.Section("mysql").Key("mysql_host").String()
dbPort := cfg.Section("mysql").Key("mysql_port").String()
dbName := config["DbName"].(string)
// 获取所有表名
showTablesCmd := exec.Command("mysql",
"-u"+dbUser,
"-p"+dbPassword,
"-h"+dbHost,
"-P"+dbPort,
"-N", "-e", "SHOW TABLES IN "+dbName)
output, err := showTablesCmd.Output()
if err != nil {
log.Fatal(err)
}
tables := strings.Fields(string(output))
if len(tables) == 0 {
info("数据库 %s 无表,无需清空", dbName)
return nil
}
// 拼接 TRUNCATE 语句
var stmts []string
for _, t := range tables {
stmts = append(stmts, fmt.Sprintf("TRUNCATE TABLE `%s`;", t))
}
truncateSQL := strings.Join(stmts, " ")
// 执行清空
truncateCmd := exec.Command("mysql",
"-u"+dbUser,
"-p"+dbPassword,
"-h"+dbHost,
"-P"+dbPort,
dbName,
"-e", truncateSQL)
truncateCmd.Stdout = os.Stdout
truncateCmd.Stderr = os.Stderr
if err := truncateCmd.Run(); err != nil {
log.Fatal(err)
}
info("数据库 %s 所有表已清空", dbName)
redisHost := cfg.Section("redis").Key("redis_host").String()
redisPort := cfg.Section("redis").Key("redis_port").String()
cmd := exec.Command("redis-cli", "-h", redisHost, "-p", redisPort, "FLUSHALL")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal("清空 Redis 失败: ", err)
}
info("Redis 所有数据已清空")
return nil
}
func start() error {
// log.Println("start")
if len(os.Args) < 4 {
@ -312,7 +458,7 @@ func start() error {
}
err := status()
if err == nil {
return err
log.Fatal("节点启动中")
}
info("正在启动服务server %s_%s ...", os.Args[2], os.Args[3])

View File

@ -1,3 +1,3 @@
# !/bin/bash
cd /data/devops/tool
cd /data/devops/tools
GOOS=linux GOARCH=amd64 go build -o /data/devops/MergePet/tool/tool main.go

38
verifyOrder.spec Normal file
View File

@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['script/verifyOrder.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='verifyOrder',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)