commit e9361b4c8739b344d0433a2b6fe54b2585114ebc Author: jjz <3082705704@qq.com> Date: Fri Sep 12 20:42:00 2025 +0800 拼多多集成 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7ccd75 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# 排除虚拟环境目录 +.venv/ + +# 排除test.py文件 +test.py + +# 排除test1.py文件 +test1.py + +# 排除.idea文件 +.idea + +Utils/PythonNew32/ diff --git a/.projectroot b/.projectroot new file mode 100644 index 0000000..21580f0 Binary files /dev/null and b/.projectroot differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec88b98 --- /dev/null +++ b/README.md @@ -0,0 +1,217 @@ +# GUI 单连接多店铺 WebSocket 通信协议 + +--- + +## 1. 连接地址与认证 + +``` +ws:///ws/gui// +``` + +- `exe_token`:用户侧令牌,用于鉴权。连接成功后,后端会立即下发一次连接成功消息(不包含店铺 ID)。 + +### 1.1 连接成功(初次,仅鉴权) +```json +{ + "type": "success", + "content": "connected" +} +``` +说明:该消息仅表示“用户级连接成功”,不包含店铺上下文。后续业务消息按店铺维度进行(见下)。 + +--- + +## 2. 总体约定(多店铺) + +- 单条 WS 连接可处理 N 个店铺消息。除心跳 `ping` 外,GUI → 后端的业务消息必须携带 `store_id`(UUID)。 +- 后端在收到带有 `store_id` 的首条消息时,会按需初始化该店铺上下文并进行处理、转发与存储。 +- 当后台需要为某店铺下发平台连接所需 cookie 时,会通过该用户的这条 WS 连接发送携带 `store_id` 的 `connect_success`。 + +--- + +## 3. 字段规范 + +### 3.1 GUI → 后端(必填) + +| 字段 | 类型 | 说明 | +|---------------|---------|----------------------------------------------------------| +| `type` | string | "message" \| "staff_list" \| "ping" \| "transfer" 等 | +| `content` | string | 消息内容(文本/链接/卡片文本等)。`ping` 无需此字段。 | +| `sender.id` | string | 平台用户 pin。`ping` 无需此字段。 | +| `store_id` | string | 店铺 UUID。`ping` 无需此字段。 | +| `msg_type` | string | 消息类型:text/image/video/product_card/order_card。 | + +说明: +- 文本/卡片可自动识别,但建议显式传 `msg_type`,图片与视频必须传。 +- 可选字段:`pin_image`(头像 URL),`timestamp`(毫秒),`message_id` 等。 + +### 3.2 后端 → GUI(通用) + +| 字段 | 类型 | 说明 | +|---------------|---------|---------------------------------------------------------------------------| +| `type` | string | 消息类型:connect_success/message/transfer/error/pong 等 | +| `content` | string | 具体内容:cookie 文本、AI 回复、错误说明等 | +| `msg_type` | string | 当 `type=message` 时需要,如 text/image/video/product_card/order_card | +| `receiver.id` | string | 当后端主动发消息/AI 回复/转接时指定接收用户 pin | +| `store_id` | string | 关联店铺 UUID(初次连接成功不带;店铺级 cookie 下发时必须携带) | + +--- + +## 4. GUI → 后端:消息格式示例 + +### 4.1 文本消息 +```json +{ + "type": "message", + "content": "你好,请问在吗?", + "msg_type": "text", + "sender": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.2 图片消息 +```json +{ + "type": "message", + "content": "https://example.com/a.jpg", + "msg_type": "image", + "sender": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.3 视频消息 +```json +{ + "type": "message", + "content": "https://example.com/a.mp4", + "msg_type": "video", + "sender": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.4 商品卡片(链接) +```json +{ + "type": "message", + "content": "https://item.jd.com/100123456789.html", + "msg_type": "product_card", + "sender": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.5 订单卡片 +```json +{ + "type": "message", + "content": "商品id:100123456789 订单号:250904-518080458310434", + "msg_type": "order_card", + "sender": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.6 客服列表(staff_list) +```json +{ + "type": "staff_list", + "content": "客服列表更新", + "data": { + "staff_list": [ + { "staff_id": "7545667615256944155", "name": "售后客服01", "status": 1, "department": "", "online": true }, + { "staff_id": "1216524360102748", "name": "水滴智能优品", "status": 1, "department": "", "online": true } + ] + }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 4.7 心跳(ping) +```json +{ "type": "ping", "uuid": "connection_test_123" } +``` + +--- + +## 5. 后端 → GUI:消息格式示例 + +### 5.1 后台点击登录后下发cookies给gui进行连接平台 +```json +{ + "type": "connect_success", + "content": "", + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31", + "platform_name": "京东" +} +``` +说明:当后台触发店铺登录后由后端推送,GUI 收到后使用该 cookie 连接对应平台。 + +### 5.2 错误消息 +```json +{ + "type": "error", + "content": "图形验证码校验失败,请刷新重试!", + "receiver": { "id": "gui_12345678" }, + "data": { "verify_link": "https://safe.jd.com/verify.html?xxx" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 5.3 AI 回复 +```json +{ + "type": "message", + "content": "您好!我是智能客服,很高兴为您服务。", + "msg_type": "text", + "receiver": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 5.4 后台客服消息转发 +```json +{ + "type": "message", + "content": "好的,我来为您查询订单状态", + "msg_type": "text", + "receiver": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 5.5 客服转接 +```json +{ + "type": "transfer", + "content": "客服小王", + "receiver": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 5.6 自动催单(示例) +```json +{ + "type": "message", + "content": "亲,您的订单还在等待您的确认哦~如有任何疑问请及时联系我们!", + "msg_type": "text", + "receiver": { "id": "jd_user_001" }, + "store_id": "93a5c3d2-efe1-4ab5-ada3-d8c1d1212b31" +} +``` + +### 5.7 心跳回复(pong) +```json +{ "type": "pong", "uuid": "connection_test_123" } +``` + +--- + +## 6. Cookie 下发策略 + +- 抖音、拼多多:直接使用后台请求携带的 cookie(pass-through)。 +- 京东、淘宝:由后端插件生成或获取(plugin),后台在店铺登录时通过本 WS 下发店铺级 `connect_success`(带 `store_id`)给 GUI。 + diff --git a/Utils/Dy/DyUtils.py b/Utils/Dy/DyUtils.py new file mode 100644 index 0000000..2e1c8d6 --- /dev/null +++ b/Utils/Dy/DyUtils.py @@ -0,0 +1,1946 @@ +# -*- coding: utf-8 -*- +import json +import traceback +import uuid +import requests +import time +import asyncio +import websockets +import blackboxprotobuf +from websocket import WebSocketApp +import threading +from datetime import datetime +from dataclasses import dataclass, asdict +from urllib.parse import urlencode + +import config +# 导入 message_arg 中的方法 +from Utils.Dy.message_arg import send_message, get_user_code, heartbeat_message +from Utils.message_models import PlatformMessage + + +# 抖音WebSocket管理器类 +class DouYinWebsocketManager: + _instance = None + _lock = threading.Lock() + + def __new__(cls): + if cls._instance is None: + with cls._lock: + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._store = {} + cls._instance._lock = threading.RLock() + return cls._instance + + def on_connect(self, shop_key, douyin_bot, **kwargs): + """存储抖音机器人连接信息""" + with self._lock: + entry = self._store.setdefault(shop_key, { + 'platform': None, + 'customers': [], + 'user_assignments': {} + }) + entry['platform'] = { + 'douyin_bot': douyin_bot, + 'message_handler': douyin_bot.message_handler if douyin_bot else None, + 'last_heartbeat': datetime.now(), + **kwargs + } + return entry + + def get_connection(self, shop_key): + """获取抖音连接信息""" + with self._lock: + return self._store.get(shop_key) + + def remove_connection(self, shop_key): + """移除抖音连接""" + with self._lock: + if shop_key in self._store: + del self._store[shop_key] + + def get_all_connections(self): + """获取所有抖音连接""" + with self._lock: + return dict(self._store) + + +@dataclass +class StaffInfo: + """客服信息结构体""" + staff_id: str + name: str + status: str + department: str = None + online: bool = True + + def to_dict(self): + return { + "staff_id": self.staff_id, + "name": self.name, + "status": self.status, + "department": self.department or "", + "online": self.online + } + + +class DouYinBackendService: + """抖音后端服务调用类(新版:使用统一后端连接 BackendClient)""" + + def __init__(self, *args, **kwargs): + self.current_store_id = "" + + async def connect(self, store_id, *args, **kwargs): + """连接后端服务(使用统一连接,无需独立连接)""" + try: + self.current_store_id = str(store_id or "") + except Exception: + self.current_store_id = "" + return True + + async def send_message_to_backend(self, platform_message): + """改为通过单后端连接发送,需携带store_id""" + try: + from WebSocket.backend_singleton import get_backend_client + backend = get_backend_client() + if not backend: + return None + + # 从platform_message中构造统一上行结构,并附加store_id + body = platform_message.get('body', {}) if isinstance(platform_message, dict) else {} + sender_id = platform_message.get('sender', {}).get('id', '') if isinstance(platform_message, dict) else '' + + # 优先取消息内的store_id,其次取body内,再次退回当前会话store_id + store_id = (platform_message.get('store_id') + or body.get('store_id') + or self.current_store_id + or '') + + msg_type = platform_message.get('msg_type', 'text') + content_for_backend = platform_message.get('content', '') + + # 构造标准消息格式 + msg = { + 'type': 'message', + 'content': content_for_backend, + 'msg_type': msg_type, + 'sender': {'id': sender_id}, + 'store_id': store_id + } + + backend.send_message(msg) + return None + except Exception: + return None + + async def close(self): + """关闭连接(统一连接模式下无需特殊处理)""" + pass + + +class DouYinMessageHandler: + """抖音消息处理器""" + + def __init__(self, cookie: dict, ai_service: DouYinBackendService, + store_id: str): + import uuid + self.instance_id = str(uuid.uuid4())[:8] # 添加实例ID用于调试 + self.cookie = cookie + self.ai_service = ai_service + self.store_id = store_id + self.user_tokens = {} + self.config = None + self.wss_url = None + self.ws = None + self.is_running = True + + self._loop = None # 添加事件循环 + # asyncio.set_event_loop(self._loop) # 设置事件循环 + self._thread = None # 添加事件循环线程 + + # 设置 AI 服务器的消息处理器引用(统一连接模式下无需设置) + # self.ai_service.set_message_handler(self) + + # 添加视频解析相关的headers + self.video_headers = { + "authority": "pigeon.jinritemai.com", + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "cache-control": "no-cache", + "origin": "https://im.jinritemai.com", + "pragma": "no-cache", + "referer": "https://im.jinritemai.com/", + "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-site", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "x-secsdk-csrf-token": "0001000000017e890e18651b2ef5f6d36d0485a64cae6b0bfc36d69e27fdc20fe7d423670eba1861a5bcb5baaf40,a25cfb6098b498c33ee5f0a5dcafe47b" + } + + # 打印实例创建信息 + print(f"[DY Handler] 创建实例 {self.instance_id} for store {store_id}") + + def get_casl(self): + """获取可分配客服列表""" + headers = { + "authority": "pigeon.jinritemai.com", + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "cache-control": "no-cache", + "origin": "https://im.jinritemai.com", + "pragma": "no-cache", + "referer": "https://im.jinritemai.com/", + "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-site", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "x-secsdk-csrf-token": "000100000001fbdad828f64ea30cad11ae4188140964c4e321a7f711791309da962ec586d0471861a72a472781fb,a25cfb6098b498c33ee5f0a5dcafe47b" + } + url = "https://pigeon.jinritemai.com/backstage/getCanAssignStaffList" + params = { + "biz_type": "4", + "PIGEON_BIZ_TYPE": "2", + "_ts": int(time.time() * 1000), + "_pms": "1", + "FUSION": "true", + "verifyFp": "", + "_v": "1.0.1.3585" + } + try: + response = requests.get(url, headers=headers, cookies=self.cookie, params=params).json() + if response.get('code') == 0: + return response.get('data', []) + return None + except Exception as e: + self._log(f"❌ 获取客服列表失败: {e}", "ERROR") + return None + + def transfer_conversation(self, receiver_id, shop_id, staff_id): + """转接对话""" + headers = { + "authority": "pigeon.jinritemai.com", + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "cache-control": "no-cache", + "origin": "https://im.jinritemai.com", + "pragma": "no-cache", + "referer": "https://im.jinritemai.com/", + "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-site", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "x-secsdk-csrf-token": "000100000001fbdad828f64ea30cad11ae4188140964c4e321a7f711791309da962ec586d0471861a72a472781fb,a25cfb6098b498c33ee5f0a5dcafe47b" + } + url = "https://pigeon.jinritemai.com/chat/api/backstage/conversation/transfer_conversation?PIGEON_BIZ_TYPE=2" + params = { + "bizConversationId": f"{receiver_id}:{shop_id}::2:1:pigeon", + "toCid": f"{staff_id}", + "extParams": "{}" + } + try: + response = requests.post(url, headers=headers, cookies=self.cookie, json=params) + if response.status_code == 200: + result = response.json() + if result.get('code') == 0: + self._log(f"✅ 成功转接对话到客服 {staff_id}", "SUCCESS") + return True + self._log(f"❌ 转接对话失败: {response.text}", "ERROR") + return False + except Exception as e: + self._log(f"❌ 转接对话异常: {e}", "ERROR") + return False + + # 新增: 发送客服列表消息到后端 + async def send_staff_list_to_backend(self): + """发送客服列表到后端""" + try: + # 获取客服列表 + staff_list = self.get_casl() + if not staff_list: + self._log("⚠️ 获取客服列表失败", "WARNING") + return False + + # 转换客服数据格式 + staff_infos = [] + for staff in staff_list: + staff_info = StaffInfo( + staff_id=str(staff.get('staffId', '')), + name=staff.get('staffName', ''), + status=staff.get('status', 0), + department=staff.get('department', ''), + online=staff.get('online', True) + ) + staff_infos.append(staff_info.to_dict()) + + # 创建消息模板 + message_template = PlatformMessage( + type="staff_list", + content="客服列表更新", + data={ + "staff_list": staff_infos, + "total_count": len(staff_infos) + }, + store_id=self.store_id + ) + + # 发送到后端 + await self.ai_service.send_message_to_backend(message_template.to_dict()) + self._log(f"发送客服列表消息的结构体为: {message_template.to_json()}") + self._log(f"✅ 成功发送客服列表到后端,共 {len(staff_infos)} 个客服", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 发送客服列表到后端异常: {e}", "ERROR") + return False + + def start_event_loop(self): + """启动事件循环线程""" + if self._loop is not None and not self._loop.is_closed(): + self._loop.close() + + self._loop = asyncio.new_event_loop() + + def run_loop(): + asyncio.set_event_loop(self._loop) + try: + self._loop.run_forever() + except Exception as e: + self._log(f"事件循环异常: {e}", "ERROR") + finally: + # 清理资源 + tasks = asyncio.all_tasks(self._loop) + for task in tasks: + task.cancel() + self._loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True)) + self._loop.close() + + self._thread = threading.Thread(target=run_loop, daemon=True) + self._thread.start() + + def _log(self, message, level="INFO"): + """日志记录""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + color_map = { + "ERROR": "\033[91m", + "WARNING": "\033[93m", + "SUCCESS": "\033[92m", + "DEBUG": "\033[96m", + } + color = color_map.get(level, "") + reset = "\033[0m" + print(f"{color}[{timestamp}] [{level}] {message}{reset}") + + def get_config(self): + """获取配置信息""" + headers = { + 'accept': 'application/json, text/plain, */*', + 'accept-language': 'zh-CN,zh;q=0.9', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', + } + params = [ + ('PIGEON_BIZ_TYPE', '2'), + ('biz_type', '4'), + ('_ts', int(time.time() * 1000)), + ('_pms', '1'), + ('FUSION', 'true'), + ] + + try: + self._log("正在请求配置信息...", "DEBUG") + response = requests.get( + 'https://pigeon.jinritemai.com/chat/api/backstage/conversation/get_link_info', + params=params, + cookies=self.cookie, + headers=headers, + timeout=30 + ) + + self._log(f"响应状态码: {response.status_code}", "DEBUG") + self._log(f"响应内容: {response.text}", "DEBUG") + + if response.status_code != 200: + raise Exception(f"HTTP请求失败: {response.status_code}") + + data = response.json() + self._log(f"解析后的JSON数据: {data}", "DEBUG") + + if data.get('code') != 0: + error_msg = data.get('message', '未知错误') + raise Exception(f"获取配置失败: {error_msg}") + + if 'data' not in data: + raise Exception("响应数据中缺少data字段") + + config_data = data['data'] + required_fields = ['token', 'appId', 'frontierConfig', 'websocketUrl', 'pigeon_sign'] + for field in required_fields: + if field not in config_data: + raise Exception(f"配置数据中缺少必要字段: {field}") + + params = { + 'token': config_data['token'], + 'aid': config_data['appId'], + 'fpid': str(config_data['frontierConfig']['fpId']), + 'device_id': '1216524360102748', + 'access_key': 'd4ececcc8a27b1fb63389380b8007fb0', + 'device_platform': 'web', + 'version_code': '10000', + 'pigeon_source': 'web', + 'PIGEON_BIZ_TYPE': '2', + 'pigeon_sign': config_data['pigeon_sign'] + } + + websocket_url = f"{config_data['websocketUrl']}?{urlencode(params)}" + self._log(f"生成的WebSocket URL: {websocket_url}", "DEBUG") + + return data, websocket_url + + except requests.exceptions.RequestException as e: + self._log(f"请求异常: {e}", "ERROR") + raise Exception(f"网络请求失败: {e}") + except json.JSONDecodeError as e: + self._log(f"JSON解析失败: {e}", "ERROR") + raise Exception(f"响应解析失败: {e}") + except Exception as e: + self._log(f"配置获取失败: {e}", "ERROR") + raise + + def on_error(self, ws, error): + """WebSocket错误处理""" + self._log(f"❌ WebSocket错误: {error}", "ERROR") + self.is_running = False + + def on_close(self, ws, close_status_code, close_msg): + """WebSocket关闭处理""" + self._log(f"🔌 连接关闭: {close_status_code}, {close_msg}", "WARNING") + self.is_running = False + + def heartbeat_wss(self): + """心跳线程""" + while self.is_running: + try: + if self.ws and hasattr(self.ws, 'sock') and self.ws.sock and self.ws.sock.connected: + self.send_heartbeat() + time.sleep(3) + except Exception as e: + self._log(f"❌ 心跳发送失败: {e}", "ERROR") + time.sleep(5) + + def send_heartbeat(self): + """发送心跳包 - 使用 message_arg 中的方法""" + try: + # 使用 message_arg 中的 heartbeat_message 方法 + value, message_type = heartbeat_message( + pigeon_sign=self.config["data"]["pigeon_sign"], + token=self.config["data"]["token"], + session_did=self.cookie["PIGEON_CID"] + ) + form_data = blackboxprotobuf.encode_message(value=value, message_type=message_type) + self.ws.send_bytes(form_data) + self._log("💓 发送心跳包", "DEBUG") + except Exception as e: + self._log(f"❌ 发送心跳包失败: {e}", "ERROR") + + def decode_binary_data(self, obj): + """ + 递归解码字典中的二进制数据 + """ + if isinstance(obj, dict): + # 如果是字典,递归处理每个值 + return {k: self.decode_binary_data(v) for k, v in obj.items()} + elif isinstance(obj, list): + # 如果是列表,递归处理每个元素 + return [self.decode_binary_data(item) for item in obj] + elif isinstance(obj, tuple): + # 如果是元组,递归处理每个元素 + return tuple(self.decode_binary_data(item) for item in obj) + elif isinstance(obj, bytes): + # 如果是二进制数据,尝试解码 + try: + return obj.decode('utf-8') + except UnicodeDecodeError: + # 如果UTF-8解码失败,可以尝试其他编码或返回原始数据 + try: + return obj.decode('latin-1') + except UnicodeDecodeError: + return obj # 或者返回原始二进制数据 + else: + # 其他类型直接返回 + return obj + + def on_open(self, ws): + """WebSocket连接打开""" + self._log(f"✅ WebSocket连接已打开", "SUCCESS") + threading.Thread(target=self.heartbeat_wss, daemon=True).start() + + def code_parse(self, message: dict): + try: + user = (message.get("8").get("6").get("610").get("1").get("1")).decode() + token = (message.get("8").get("6").get("610").get("1").get("4")).decode() + except: + user = None + token = None + return user, token + + def _init_user_info(self, receiver_id, token=None): + """初始化用户信息""" + if receiver_id not in self.user_tokens: + self.user_tokens[receiver_id] = { + "token": token, + "last_sent": 0, + "session_initialized": False, + "talk_id": 7543146114111898922, # 添加默认值 + "p_id": 7542727339747116329, # 添加默认值 + "pending_messages": [] + } + elif token: + self.user_tokens[receiver_id]["token"] = token + self._log(f"✅ 更新用户 {receiver_id} 的Token", "DEBUG") + + def on_message(self, ws, content): + """处理收到的消息""" + try: + message = blackboxprotobuf.decode_message(content)[0] + + # 解析二进制数据 + decoded_message_readable = self.decode_binary_data(message) + print(f"\n📨 收到消息: {decoded_message_readable}") + + user, token = self.code_parse(message=message) + if user and token: + receiver_id = int(user.split(":")[0]) + self._init_user_info(receiver_id, token) + + print(f"✅ 获取到用户Token: 用户ID={receiver_id}") + + # 获取消息类型 + msg_type = message.get('1') + print(f"📋 消息类型: {msg_type}") + + # 获取内部消息结构 + inner_msg = message.get('8', {}) + + # 处理inner_msg为bytes的情况 + if isinstance(inner_msg, bytes): + try: + inner_msg = blackboxprotobuf.decode_message(inner_msg)[0] + print(f"🔄 解析内部消息字节成功") + except Exception as e: + print(f"⚠️ 无法解析内部消息字节: {e}") + return + + if not inner_msg or not isinstance(inner_msg, dict): + print("⚠️ 消息结构不完整") + return + + # 获取内部消息类型 + inner_type = inner_msg.get('1') + inner_data = inner_msg.get('6', {}) + + # 首先检查是否是心跳响应 + if "5" in message: + kv_pairs = message["5"] + if isinstance(kv_pairs, list): + for pair in kv_pairs: + if isinstance(pair, dict) and pair.get("1") == b"code" and pair.get("2") == b"0": + self._log("💓 心跳响应正常", "DEBUG") + return + print(f"📋 内部消息类型: {inner_type}") + print(f"📋 内部消息数据键: {list(inner_data.keys()) if isinstance(inner_data, dict) else type(inner_data)}") + + # 处理不同类型的消息 + if inner_type == 610: # Token消息 + print("🔑 处理Token消息") + self._handle_token_message(inner_data) + + elif inner_type == 500: # 聊天消息 + print("💬 处理聊天消息") + self._handle_chat_message(inner_data, message) + + elif inner_type == 200: # 心跳消息 + print("💓 收到心跳消息") + + else: + print(f"❓ 未知内部消息类型: {inner_type}") + + except Exception as e: + print(f"❌ 解析消息时出错: {e}") + traceback.print_exc() + + async def _process_pending_message(self, sender_id, message_content): + """处理待发送的消息""" + try: + # 获取用户信息 + user_info = self.user_tokens[sender_id] + talk_id = user_info.get("talk_id", 0) + p_id = user_info.get("p_id", 0) + + # 准备发送者和接收者信息 + sender_info = { + "id": str(sender_id), + "name": f"用户_{sender_id}", + "is_customer": True + } + receiver_info = { + "id": self.store_id, + "name": "店铺客服", + "is_merchant": True + } + + # 创建消息模板 + message_template = PlatformMessage( + type="message", + content=message_content, + msg_type="text", + sender={"id": sender_info.get("id", "")}, + store_id=self.store_id + ) + + # 发送消息到后端(使用统一连接) + await self.ai_service.send_message_to_backend(message_template.to_dict()) + self._log(f"✅ 待发送消息已发送到后端", "INFO") + + except Exception as e: + self._log(f"❌ 处理待发送消息失败: {e}", "ERROR") + + def _handle_token_message(self, message): + """处理Token消息""" + try: + # 直接从消息中获取token数据 + token_data = message.get('610', {}).get('1', {}) + if not token_data: + self._log("❌ 未找到token数据", "ERROR") + return + + user_bytes = token_data.get('1') + token_bytes = token_data.get('4') + + if not (isinstance(user_bytes, bytes) and isinstance(token_bytes, bytes)): + self._log("❌ token数据格式错误", "ERROR") + return + + # 解码用户信息和token + user = user_bytes.decode('utf-8') + token = token_bytes.decode('utf-8') + + # 解析用户ID + try: + receiver_id = int(user.split(":")[0]) + except (ValueError, IndexError): + self._log(f"❌ 无法解析用户ID: {user}", "ERROR") + return + + self._log(f"✅ 成功解析Token - 用户: {receiver_id}", "SUCCESS") + + # 确保用户信息存在并保存token + if receiver_id not in self.user_tokens: + self._log(f"🆕 创建用户信息: {receiver_id}", "DEBUG") + self.user_tokens[receiver_id] = { + "token": None, + "last_sent": 0, + "session_initialized": False, + "talk_id": 0, + "p_id": 0, + "pending_messages": [] + } + + # 保存token + self.user_tokens[receiver_id]["token"] = token + self._log(f"✅ 已保存用户 {receiver_id} 的Token", "DEBUG") + + # 处理待发送的消息 + if "pending_messages" in self.user_tokens[receiver_id]: + pending_msgs = self.user_tokens[receiver_id]["pending_messages"] + if pending_msgs: + self._log(f"📤 处理 {len(pending_msgs)} 条待发送消息", "INFO") + for msg in pending_msgs: + asyncio.run_coroutine_threadsafe( + self._process_pending_message(receiver_id, msg), + self._loop + ) + # 清空待发送消息列表 + self.user_tokens[receiver_id]["pending_messages"] = [] + + except Exception as e: + self._log(f"❌ 处理Token消息失败: {e}", "ERROR") + self._log(f"❌ 错误详情: {traceback.format_exc()}", "DEBUG") + + def parse_video(self, vid): + """解析视频获取播放地址""" + try: + self._log(f"🎥 开始解析视频,VID: {vid}", "INFO") + + url = "https://pigeon.jinritemai.com/backstage/video/getPlayToken" + params = { + "vid": vid, + "_pms": "1" + } + + response = requests.get( + url, + headers=self.video_headers, + cookies=self.cookie, + params=params, + timeout=36 + ).json() + + self._log(f"视频解析响应: {response}", "DEBUG") + + if response.get("code") != 0: + self._log(f"❌ 获取视频token失败: {response.get('message')}", "ERROR") + return None + + token = response.get("data", {}).get("token") + if not token: + self._log("❌ 未获取到视频token", "ERROR") + return None + + # 解析token获取播放地址 + token_url = "https://open.bytedanceapi.com/?" + token + video_response = requests.get( + token_url, + headers=self.video_headers, + cookies=self.cookie, + timeout=38 + ).json() + + self._log(f"视频播放信息: {video_response}", "DEBUG") + + result = video_response.get("Result", {}).get("Data", {}).get("PlayInfoList") + if result and len(result) > 0: + play_url = result[0].get("MainPlayUrl") + if play_url: + self._log(f"✅ 成功获取视频播放地址: {play_url[:50]}...", "SUCCESS") + return play_url + else: + self._log("❌ 未找到MainPlayUrl", "ERROR") + else: + self._log("❌ 获取播放地址失败", "ERROR") + + return None + + except requests.exceptions.RequestException as e: + self._log(f"❌ 网络请求失败: {e}", "ERROR") + return None + except json.JSONDecodeError as e: + self._log(f"❌ JSON解析失败: {e}", "ERROR") + return None + except Exception as e: + self._log(f"❌ 视频解析失败: {e}", "ERROR") + return None + + # 获取商品id + def get_goods_id(self, order_id): + headers = { + "authority": "fxg.jinritemai.com", + "accept": "application/json, text/plain, */*", + "accept-language": "zh-CN,zh;q=0.9", + "cache-control": "no-cache", + "pragma": "no-cache", + "referer": "https://fxg.jinritemai.com/ffa/morder/order/detail?id=6921052297377971987", + "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + } + url = "https://fxg.jinritemai.com/api/order/orderDetail" + params = { + "order_id": order_id, + "appid": "1", + "__token": "d83b1e7b9e05390304167f02c95f1a74", + "_bid": "ffa_order", + "aid": "4272", + "_lid": "720383572871", + "verifyFp": "verify_mf3dk1nv_kbxjZXA8_9XBV_4Rvb_B3iI_XDueP5U4SoQx", + "fp": "verify_mf3dk1nv_kbxjZXA8_9XBV_4Rvb_B3iI_XDueP5U4SoQx", + "msToken": "OJcYEsXGO2a1822s3kkoFuk3zwOyj5nhjzxhynXWCz7b4Q4oDuxmbFf85-2C05VezCpYsbhaZ8ZtXs6hl_rrU2Akb5K3kOQQimXOVshe_7yCNW52NA8sAR3nOp_y6N99nQN8VxscYQJ6xLcvQN6CzpsjC7y0gxo6VpfHAVs=", + } + response = requests.get(url, headers=headers, cookies=self.cookie, params=params).json() + # print(response) + if response.get('code') == 0 and response.get('data').get('order_id') == order_id: + # 表示成功展示了对应这个订单内部的信息 + product_data = response.get('data').get('product') + product_id = product_data.get('sku')[0].get('product_id') + return product_id + else: + # 没有找到默认返回None + print("没有根据订单信息找到内部的商品ID 请核对方法get_product_id") + return None + + def _extract_message_text(self, msg_content): + """从消息内容中提取文本和图片URL""" + try: + print("🔍 开始提取消息内容...") + + # 初始化返回结果 + result = { + 'text': None, + 'avatar': None, + 'image_url': None, + 'thumbnail_url': None, + 'goods_id': None, + 'video_url': None, + 'order_id': None + } + + # 方法1: 处理文本消息(从'8'字段获取) + text_content = msg_content.get('8') + if text_content: + print(f"📄 检测到文本内容") + if isinstance(text_content, bytes): + try: + decoded = text_content.decode('utf-8') + result['text'] = decoded + self._log(f"✅ UTF-8解码成功: {decoded}", "SUCCESS") + except UnicodeDecodeError: + try: + decoded = text_content.decode('gbk') + result['text'] = decoded + self._log(f"✅ GBK解码成功: {decoded}", "SUCCESS") + except: + self._log("⚠️ 无法解码文本内容", "DEBUG") + elif isinstance(text_content, str): + result['text'] = text_content + self._log(f"✅ 直接使用文本内容: {text_content}") + + # 方法2: 统一处理'9'字段中的数据(包括文本和图片、消息、视频 + meta_data = msg_content.get('9', []) + if meta_data: + print(f"🔍 检测到消息元数据") + for item in meta_data: + if not isinstance(item, dict): + continue + + key = item.get('1', b'').decode('utf-8') if isinstance(item.get('1'), bytes) else str( + item.get('1', '')) + value = item.get('2', b'').decode('utf-8') if isinstance(item.get('2'), bytes) else str( + item.get('2', '')) + + # 处理所有类型的URL + if key == 'avatar_uri': + result['avatar'] = value + self._log(f"✅ 找到头像URL: {value}", "SUCCESS") + elif key == 'imageUrl': + result['image_url'] = value + self._log(f"✅ 找到图片URL: {value}", "SUCCESS") + elif key == 'thumbnailUrl': + result['thumbnail_url'] = value + self._log(f"✅ 找到缩略图URL: {value}", "SUCCESS") + elif key == 'goods_id': + goods_id = value + result['goods_id'] = goods_id + self._log(f"✅ 找到商品ID: {goods_id}", "SUCCESS") + elif key == 'msg_render_model': + try: + video_info = json.loads(value) + render_body = video_info.get('render_body', {}) + + # 提取视频URL + viedo_url = render_body.get('coverURL') + viedo_vid = render_body.get('vid') + if viedo_vid and viedo_url: + self._log(f"✅ 找到视频原始vid: {viedo_vid}", "SUCCESS") + + # 解析获取视频播放地址 + play_url = self.parse_video(viedo_vid) + if play_url: + result['video_url'] = play_url + else: + # 如果解析失败 在打印对应的日志后 使用备用封面图片作为地址 + if '\\u0026' in viedo_url: + viedo_url = viedo_url.replace('\\u0026', '&') + result['video_url'] = viedo_url + self._log("⚠️ 使用视频封面作为备选", "WARNING") + else: + self._log("⚠️ 未找到视频核心id 可能出现新的数据存放地址", "DEBUG") + except json.JSONDecodeError as e: + self._log(f"解析视频信息失败: {e}", "ERROR") + elif key == 'sku_order_id': + # 取到了对应的订单号 id + order_id = value + result['order_id'] = order_id + + # 如果已经找到所有需要的URL,提前退出循环 + if all([result['avatar'], result['image_url'], result['thumbnail_url']]): + break + + # 方法3: 兼容处理旧的'9-1'字段(如果存在) + image_data = msg_content.get('9-1', []) # 如果没有拿到这个arrayList那么就不需要在对里面的数据进行解析了 + if image_data != []: + print(f"📸 检测到旧的图片数据格式", "DEBUG") + for item in image_data: + if not isinstance(item, dict): + continue + + key = item.get('1', b'').decode('utf-8') if isinstance(item.get('1'), bytes) else str( + item.get('1', '')) + value = item.get('2', b'').decode('utf-8') if isinstance(item.get('2'), bytes) else str( + item.get('2', '')) + + if key == 'avatar_uri' and not result['avatar']: + result['avatar'] = value + self._log(f"✅ 找到头像URL: {value}", "SUCCESS") + elif key == 'imageUrl' and not result['image_url']: + result['image_url'] = value + self._log(f"✅ 找到图片URL: {value}", "SUCCESS") + elif key == 'thumbnailUrl' and not result['thumbnail_url']: + result['thumbnail_url'] = value + self._log(f"✅ 找到缩略图URL: {value}", "SUCCESS") + elif key == 'goods_id': + goods_id = value + result['goods_id'] = goods_id + self._log(f"✅ 找到商品ID: {goods_id}", "SUCCESS") + elif key == 'msg_render_model': + try: + video_info = json.loads(value) + render_body = video_info.get('render_body', {}) + + # 提取视频URL + viedo_url = render_body.get('coverURL') + viedo_vid = render_body.get('vid') + if viedo_vid and viedo_url: + self._log(f"✅ 找到视频原始vid: {viedo_vid}", "SUCCESS") + + # 解析获取视频播放地址 + play_url = self.parse_video(viedo_vid) + if play_url: + result['video_url'] = play_url + else: + # 如果解析失败 在打印对应的日志后 使用备用封面图片作为地址 + if '\\u0026' in viedo_url: + viedo_url = viedo_url.replace('\\u0026', '&') + result['video_url'] = viedo_url + self._log("⚠️ 使用视频封面作为备选", "WARNING") + else: + self._log("⚠️ 未找到视频核心id 可能出现新的数据存放地址", "DEBUG") + except json.JSONDecodeError as e: + self._log(f"解析视频信息失败: {e}", "ERROR") + elif key == 'sku_order_id': + # 取到了对应的订单号 id + order_id = value + result['order_id'] = order_id + + # 如果都没找到内容,打印调试信息 + if not any(result.values()): + print("🔍 未找到有效内容,打印所有字段:") + for key, value in msg_content.items(): + if isinstance(value, bytes): + try: + decoded = value.decode('utf-8', errors='ignore') + print(f" {key}: {decoded[:100]}...") + except: + print(f" {key}: [无法解码的字节数据,长度: {len(value)}]") + elif isinstance(value, list): + print(f" {key}: [列表数据,长度: {len(value)}]") + else: + print(f" {key}: {value}") + + return result + + except Exception as e: + self._log(f"❌ 提取消息内容时出错: {e}", "ERROR") + traceback.print_exc() + return { + 'text': None, + 'avatar': None, + 'image_url': None, + 'thumbnail_url': None, + 'goods_id': None, + 'viedo_url': None, + 'order_id': None + } + + def _handle_chat_message(self, message, msg_type): + """处理聊天消息 - 修改版本,支持多种消息类型""" + try: + self._log(f"🔍 开始解析{message} 消息结构", "DEBUG") + + msg_500 = message.get('500', {}) + if not msg_500: + return + + msg_content = msg_500.get('5', {}) + if not msg_content: + return + + # 从消息内容中获取类型和发送者ID + inner_msg_type = msg_content.get("6", 0) + sender_id = msg_content.get("7", 0) + + self._log(f"📊 内部消息类型: {inner_msg_type}, 发送者ID: {sender_id}", "DEBUG") + + print("会不会到这里来呢") + + # 处理不同类型的消息 + if inner_msg_type == 1000 and sender_id and sender_id != int(self.cookie['PIGEON_CID']): + # 用户文本消息 - 处理AI回复 + self._log("✅ 检测到1000状态的有效消息", "INFO") + self._handle_user_text_message(msg_content, sender_id) + + elif inner_msg_type == 50002 and sender_id and sender_id != int(self.cookie['PIGEON_CID']): + # 系统消息 - 触发token请求 + self._log("✅ 检测到50002类型的系统消息", "INFO") + self._handle_system_message(msg_content, sender_id) + + else: + # 忽略其他消息 + self._log(f"🔍 忽略消息类型: {inner_msg_type}", "DEBUG") + + except Exception as e: + self._log(f"❌ 处理聊天消息失败: {e}", "ERROR") + self._log(f"❌ 错误详情: {traceback.format_exc()}", "DEBUG") + + def _handle_user_text_message(self, msg_content, sender_id): + """处理用户文本消息""" + try: + # 解析消息内容 + + # 使用引入的新的解析全详情代码(包括图片与头像信息) + message_dict = self._extract_message_text(msg_content) + + message_content = None + if "8" in msg_content: + content_data = msg_content["8"] + self._log(f"📄 原始内容数据: {content_data}", "DEBUG") + + + if message_dict and message_dict.get('text') != "客服水滴智能优品接入": + self._log(f"💬 成功解析用户消息: '{message_dict}'", "SUCCESS") + + # 提取会话信息 + talk_id = msg_content.get("20", 0) + p_id = msg_content.get("5", 0) + + self._log(f"📝 会话信息 - TalkID: {talk_id}, PID: {p_id}", "DEBUG") + + # 存储会话信息 + if sender_id not in self.user_tokens: + self.user_tokens[sender_id] = { + "token": None, + "last_sent": 0, + "session_initialized": False, + "talk_id": talk_id, + "p_id": p_id, + "pending_messages": [] + } + else: + # 更新会话信息 + self.user_tokens[sender_id]["talk_id"] = talk_id + self.user_tokens[sender_id]["p_id"] = p_id + + # 使用事件循环提交异步任务 + asyncio.run_coroutine_threadsafe( + self._get_and_send_ai_reply(sender_id, message_dict, talk_id, p_id), + self._loop + ) + else: + self._log("⚠️ 无法解析消息内容", "WARNING") + + except Exception as e: + self._log(f"❌ 处理用户文本消息失败: {e}", "ERROR") + + def _handle_system_message(self, msg_content, sender_id): + """处理系统消息 - 触发token请求""" + try: + # 提取会话信息 + talk_id = msg_content.get("20", 0) + p_id = msg_content.get("5", 0) + + self._log(f"📝 系统消息会话信息 - TalkID: {talk_id}, PID: {p_id}", "DEBUG") + + # 检查是否已经有该用户的token + if sender_id not in self.user_tokens or not self.user_tokens[sender_id].get("token"): + self._log(f"🆕 用户 {sender_id} 无token,请求token", "INFO") + + # 存储会话信息 + if sender_id not in self.user_tokens: + self.user_tokens[sender_id] = { + "token": None, + "last_sent": 0, + "session_initialized": False, + "talk_id": talk_id, + "p_id": p_id, + "pending_messages": [] + } + else: + # 更新会话信息 + self.user_tokens[sender_id]["talk_id"] = talk_id + self.user_tokens[sender_id]["p_id"] = p_id + + # 请求token + self._request_user_token(sender_id, p_id) + else: + self._log(f"✅ 用户 {sender_id} 已有token", "DEBUG") + + except Exception as e: + self._log(f"❌ 处理系统消息失败: {e}", "ERROR") + + def _parse_message_content(self, msg_data): + """解析消息内容""" + try: + # 尝试从不同字段解析内容 + content_fields = ['4', '8', '14'] + for field in content_fields: + content = msg_data.get(field) + if content: + if isinstance(content, bytes): + try: + return content.decode('utf-8') + except UnicodeDecodeError: + try: + return content.decode('gbk') + except: + continue + elif isinstance(content, str): + return content + return None + except Exception as e: + self._log(f"❌ 解析消息内容失败: {e}", "ERROR") + return None + + def _determine_message_type(self, message_dict): + """确定消息类型""" + if message_dict.get('video_url'): # 如果确认收到了video_url类型的数据 那么不可能是其它类型 + return 'video' + elif message_dict.get('image_url'): # 如果确认收到了image_url类型的数据 那么不可能是其它类型 + return 'image' + elif message_dict.get('order_id'): # 如果确认收到了order_id类型的数据 那么不可能是其它类型 只能是发送询问订单 + return 'order' + elif message_dict.get('goods_id'): # 如果确认收到了goods_id类型的数据 那么不可能是其它类型 只能是发送询问商品 + return 'goods' + else: + return 'text' # 最普遍的类型 + + async def _get_and_send_ai_reply(self, sender_id, message_dict, talk_id, p_id): + """获取并发送AI回复 - 修改版本,确保有token""" + try: + self._log(f"🚀 AI回复流程开始,用户: {sender_id}", "INFO") + self._log(f"📋 用户消息内容: '{message_dict}'", "INFO") + + # 检查是否已有token,如果没有则先请求 + if sender_id not in self.user_tokens or not self.user_tokens[sender_id].get("token"): + self._log(f"🆕 用户 {sender_id} 无token,先请求token", "INFO") + self.user_tokens[sender_id] = { + "token": None, + "last_sent": 0, + "session_initialized": False, + "talk_id": talk_id, + "p_id": p_id, + "pending_messages": [] # 存储等待发送的消息 + } + self._request_user_token(sender_id, p_id) + + # 将当前消息加入待处理队列 + self.user_tokens[sender_id]["pending_messages"].append(message_dict) + return + + # 预先定义默认值 (避免后续因为没有成功走到对应分支里产生的错误) + # msg_type = "text" + message_text = message_dict.get('text', '') + avatar_url = message_dict.get('avatar', '') + + # 确定消息类型 (调用确认方法类型) + msg_type = self._determine_message_type(message_dict) + + if msg_type == 'video' and avatar_url or message_dict['text'] == "[视频]": + # 视频类型 + message_text = message_dict['video_url'] + avatar_url = avatar_url + elif msg_type == 'image' and avatar_url: + message_text = message_dict['image_url'] + avatar_url = avatar_url + elif msg_type == 'order': + msg_type = 'order_card' + order_id = message_dict['order_id'] + goods_id = self.get_goods_id(order_id) + if goods_id: + message_text = f"订单号: {order_id}, 商品ID: {goods_id}" + else: + message_text = f"订单号: {order_id}" + elif msg_type == 'goods' or message_dict.get("text", None) == "[商品]": + # 商品类型 + msg_type = 'product_card' + message_text = f"商品卡片ID: {message_dict['goods_id']}" + elif msg_type == 'text' and avatar_url: + message_text = message_dict['text'] + + # 准备发送者和接收者信息 + sender_info = { + "id": str(sender_id), + "name": f"用户_{sender_id}", + "is_customer": True + } + + # 创建消息模板 + message_template = PlatformMessage( + type="message", + content=message_text, + pin_image=avatar_url, + msg_type=msg_type, + sender={"id": sender_info.get("id", "")}, + store_id=self.store_id + ) + + self._log("📤 准备发送消息到AI服务...", "INFO") + self._log(f"📋 消息内容: {message_template.to_json()}", "DEBUG") + + # 发送消息到后端(使用统一连接,不等待回复) + start_time = time.time() + await self.ai_service.send_message_to_backend(message_template.to_dict()) + response_time = time.time() - start_time + + self._log(f"✅ 消息已发送到后端,耗时: {response_time:.2f}s", "SUCCESS") + self._log("🔄 等待后端AI处理并通过GUI转发回复", "INFO") + + except Exception as e: + self._log(f"❌ 获取AI回复失败: {e}", "ERROR") + self._log(f"❌ 错误详情: {traceback.format_exc()}", "DEBUG") + + async def _check_and_send_reply(self, sender_id, talk_id, p_id, reply_text): + """检查并发送回复""" + try: + self._log(f"🔍 检查发送条件,用户: {sender_id}", "DEBUG") + + # 确保用户信息存在 + if sender_id not in self.user_tokens: + self._log(f"❌ 用户 {sender_id} 信息不存在", "ERROR") + return + + user_token = self.user_tokens[sender_id].get("token") + if not user_token: + self._log(f"⚠️ 用户 {sender_id} token为空,将消息加入待发送队列", "WARNING") + # 将消息加入待发送队列 + if "pending_messages" not in self.user_tokens[sender_id]: + self.user_tokens[sender_id]["pending_messages"] = [] + self.user_tokens[sender_id]["pending_messages"].append(reply_text) + return + + # 检查发送频率 + current_time = int(time.time() * 1000) + last_sent = self.user_tokens[sender_id].get("last_sent", 0) + + if current_time - last_sent < 4000: + self._log("⏳ 发送太频繁,跳过", "DEBUG") + return + + self._log(f"📤 准备发送回复给用户 {sender_id}", "INFO") + self._log(f"📝 回复内容: '{reply_text}'", "DEBUG") + + # 发送回复 + success = await self._send_message_to_user(sender_id, talk_id, p_id, user_token, reply_text) + if success: + self.user_tokens[sender_id]["last_sent"] = current_time + self._log(f"✅ 回复发送完成", "SUCCESS") + else: + self._log(f"❌ 回复发送失败", "ERROR") + + except Exception as e: + self._log(f"❌ 检查并发送回复失败: {e}", "ERROR") + + async def _send_message_to_user(self, receiver_id, talk_id, p_id, user_token, content): + """发送消息给用户 - 核心发送方法""" + try: + self._log(f"📤 正在发送消息给用户 {receiver_id}", "DEBUG") + self._log(f"📝 消息内容: {content}", "DEBUG") + + # 检查必要的参数 + if not all([receiver_id, talk_id, p_id, user_token, content]): + self._log("❌ 发送消息参数不全", "ERROR") + print(f"{receiver_id}--{talk_id}--{p_id}--{user_token}--{content}") + return False + + # 使用 message_arg 中的 send_message 方法创建消息 + value, message_type = send_message( + pigeon_sign=self.config["data"]["pigeon_sign"], + token=self.config["data"]["token"], + receiver_id=receiver_id, + shop_id=self.cookie["SHOP_ID"], + talk_id=talk_id, + session_did=self.cookie["PIGEON_CID"], + p_id=p_id, + user_code=user_token, + text=content + ) + + # 编码消息 + form_data = blackboxprotobuf.encode_message(value=value, message_type=message_type) + + # 发送消息 + self.ws.send_bytes(form_data) + self._log(f"✅ 消息已发送给用户 {receiver_id}", "SUCCESS") + + return True + + except Exception as e: + self._log(f"❌ 发送消息给用户失败: {e}", "ERROR") + return False + + def _request_user_token(self, receiver_id, p_id): + """请求用户token - 使用 message_arg 中的方法""" + try: + # 使用 message_arg 中的 get_user_code 方法 + + value, message_type = get_user_code( + pigeon_sign=self.config["data"]["pigeon_sign"], + token=self.config["data"]["token"], + receiver_id=receiver_id, + shop_id=self.cookie["SHOP_ID"], + session_did=self.cookie["PIGEON_CID"], + p_id=p_id + ) + form_data = blackboxprotobuf.encode_message(value=value, message_type=message_type) + self.ws.send_bytes(form_data) + self._log(f"📤 已请求用户 {receiver_id} 的token", "INFO") + except Exception as e: + self._log(f"❌ 请求token失败: {e}", "ERROR") + + def _log_user_tokens_state(self): + """记录当前 user_tokens 状态(用于调试)""" + self._log("🔍 当前 user_tokens 状态:", "DEBUG") + for user_id, info in self.user_tokens.items(): + token_status = "有" if info.get("token") else "无" + self._log( + f" 用户 {user_id}: token={token_status}, talk_id={info.get('talk_id')}, p_id={info.get('p_id')}", + "DEBUG") + + async def _handle_customer_message(self, message_data): + """处理来自后端的客服消息""" + try: + self._log(f"🔍 _handle_customer_message 被调用,当前实例: {self}", "DEBUG") + self._log_user_tokens_state() + + content = message_data.get("content", "") + if not content: + self._log("⚠️ 客服消息内容为空", "WARNING") + return + self._log(f"后端客服传输的消息为:{content}") + + receiver_info = message_data.get("receiver", {}) + receiver_id = receiver_info.get("id") + + if receiver_id and content: + self._log(f"📤 收到客服消息,准备发送给用户 {receiver_id}", "INFO") + + # 确保 receiver_id 是整数类型 + try: + receiver_id = int(receiver_id) + except (ValueError, TypeError): + self._log(f"❌ 无法转换用户ID为整数: {receiver_id}", "ERROR") + return + + # 检查用户信息是否存在,如果不存在则初始化 + if receiver_id not in self.user_tokens: + self._log(f"🆕 用户 {receiver_id} 信息不存在,初始化用户信息", "INFO") + self.user_tokens[receiver_id] = { + "token": None, + "last_sent": 0, + "session_initialized": False, + "talk_id": 7543146114111898922, # 使用默认值 + "p_id": 7542727339747116329, # 使用默认值 + "pending_messages": [content] # 直接将消息加入待发送队列 + } + + # 如果没有token,尝试获取token + if not self.user_tokens[receiver_id]["token"]: + self._log(f"🔄 用户 {receiver_id} 无token,尝试获取", "INFO") + # 触发token获取 + self._request_user_token( + receiver_id, + self.user_tokens[receiver_id]["p_id"] + ) + # 注意:这里不返回,让消息已经在队列中等待处理 + return + + user_info = self.user_tokens[receiver_id] + + # 如果有token,直接发送消息 + if user_info.get("token"): + self._log(f"✅ 用户 {receiver_id} 有token,直接发送消息", "INFO") + # 检查必要的字段是否存在 + required_fields = ["talk_id", "p_id", "token"] + for field in required_fields: + if field not in user_info or not user_info[field]: + self._log(f"❌ 用户 {receiver_id} 缺少必要字段: {field}", "ERROR") + return + + # 发送消息 + await self._send_message_to_user( + receiver_id, + user_info["talk_id"], + user_info["p_id"], + user_info["token"], + content + ) + else: + # 没有token,将消息加入队列并请求token + self._log(f"⚠️ 用户 {receiver_id} 无token,将消息加入队列", "INFO") + if "pending_messages" not in user_info: + user_info["pending_messages"] = [] + user_info["pending_messages"].append(content) + # 请求token + self._request_user_token( + receiver_id, + user_info["p_id"] + ) + + except Exception as e: + self._log(f"❌ 处理客服消息失败: {e}", "ERROR") + self._log(f"❌ 错误详情: {traceback.format_exc()}", "DEBUG") + + async def start_async(self): + """异步启动消息处理器(不阻塞调用线程)""" + try: + self._log("🚀 异步启动消息处理器...", "INFO") + + # 启动事件循环 + self.start_event_loop() + + # 获取配置 + self.config, self.wss_url = self.get_config() + self._log("✅ 配置获取成功", "SUCCESS") + + # 连接后端服务(使用统一连接,无需独立连接) + await self.ai_service.connect(self.store_id) + self._log("✅ 后端服务连接成功(使用统一连接)", "SUCCESS") + + # 创建WebSocket连接 + self.ws = WebSocketApp( + self.wss_url, + header={ + 'Origin': 'https://im.jinritemai.com', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', + }, + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close + ) + + # 添加重连机制 + def run_with_reconnect(): + while self.is_running: + try: + self.ws.run_forever() + except Exception as e: + self._log(f"WebSocket连接异常: {e}, 5秒后重连...", "WARNING") + time.sleep(5) + continue + + # 注册消息处理器(统一连接模式下无需注册) + + # 在新线程中运行WebSocket + ws_thread = threading.Thread(target=run_with_reconnect, daemon=True) + ws_thread.start() + + self._log("🟢 消息处理器异步启动完成", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 异步启动失败: {e}", "ERROR") + return False + + def start(self): + """启动消息处理器""" + try: + self._log("🚀 启动消息处理器...", "INFO") + + # 启动事件循环 + self.start_event_loop() + + # 获取配置 + self.config, self.wss_url = self.get_config() + self._log("✅ 配置获取成功", "SUCCESS") + + # 连接后端服务(使用统一连接,无需独立连接) + async def connect_backend_service(): + await self.ai_service.connect(self.store_id) + self._log("✅ 后端服务连接成功(使用统一连接)", "SUCCESS") + + # 在事件循环中执行连接 + asyncio.run_coroutine_threadsafe(connect_backend_service(), self._loop) + + # 创建WebSocket连接 + self.ws = WebSocketApp( + self.wss_url, + header={ + 'Origin': 'https://im.jinritemai.com', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36', + }, + on_open=self.on_open, + on_message=self.on_message, + on_error=self.on_error, + on_close=self.on_close + ) + + # 添加重连机制 + def run_with_reconnect(): + while self.is_running: + try: + self.ws.run_forever() + except Exception as e: + self._log(f"WebSocket连接异常: {e}, 5秒后重连...", "WARNING") + time.sleep(5) + continue + + # 注册消息处理器(统一连接模式下无需注册) + + # 在新线程中运行WebSocket + ws_thread = threading.Thread(target=run_with_reconnect, daemon=True) + ws_thread.start() + + self._log("🟢 开始运行消息处理器...", "INFO") + + # !!!关键修改:保持主线程运行!!! + while self.is_running: + time.sleep(1) # 主线程保持运行,防止进程退出 + + except Exception as e: + self._log(f"❌ 启动失败: {e}", "ERROR") + finally: + self._log("🛑 消息处理器已停止", "INFO") + + async def close(self): + """关闭连接""" + self.is_running = False + if self.ws: + self.ws.close() + if self.ai_service: + await self.ai_service.close() + + # 关闭事件循环 + if self._loop: + self._loop.call_soon_threadsafe(self._loop.stop) + if self._thread: + self._thread.join(timeout=1.0) + + self._log("🛑 消息处理器已停止", "INFO") + + async def send_message_external(self, receiver_id: str, content: str) -> bool: + """外部调用的发送消息方法 - 用于后端消息转发""" + try: + self._log(f"🔄 [External-{self.instance_id}] 收到转发请求: receiver_id={receiver_id}, content={content}", "INFO") + + # 修复数据类型不匹配问题:将字符串转换为整数 + try: + receiver_id_int = int(receiver_id) + self._log(f"🔧 [External-{self.instance_id}] 转换 receiver_id: '{receiver_id}' -> {receiver_id_int}", "DEBUG") + except ValueError: + self._log(f"❌ [External-{self.instance_id}] receiver_id 无法转换为整数: {receiver_id}", "ERROR") + return False + + # 调试信息:显示当前活跃用户 + active_users = list(self.user_tokens.keys()) + self._log(f"🔍 [External-{self.instance_id}] 当前活跃用户列表: {active_users}", "DEBUG") + self._log(f"🔍 [External-{self.instance_id}] 活跃用户数量: {len(active_users)}", "DEBUG") + + # 检查用户是否存在于user_tokens中(使用整数类型) + self._log(f"🔍 [External-{self.instance_id}] 调试信息:", "DEBUG") + self._log(f"🔍 [External-{self.instance_id}] receiver_id_int: {receiver_id_int} (类型: {type(receiver_id_int)})", "DEBUG") + self._log(f"🔍 [External-{self.instance_id}] user_tokens keys: {list(self.user_tokens.keys())}", "DEBUG") + if self.user_tokens: + first_key = list(self.user_tokens.keys())[0] + self._log(f"🔍 [External-{self.instance_id}] 第一个key: {first_key} (类型: {type(first_key)})", "DEBUG") + self._log(f"🔍 [External-{self.instance_id}] 直接比较: {receiver_id_int == first_key}", "DEBUG") + + if receiver_id_int not in self.user_tokens: + self._log(f"❌ [External-{self.instance_id}] 用户 {receiver_id_int} 不在活跃会话中", "WARNING") + self._log(f"💡 [External-{self.instance_id}] 提示:用户需要先在抖音平台发送消息建立会话", "INFO") + + # 显示当前活跃用户的调试信息 + self.print_active_users_debug() + + return False + + user_info = self.user_tokens[receiver_id_int] + talk_id = user_info.get("talk_id") + p_id = user_info.get("p_id") + user_token = user_info.get("token") + + self._log(f"🔍 [External-{self.instance_id}] 用户会话信息: talk_id={talk_id}, p_id={p_id}, has_token={bool(user_token)}", "DEBUG") + + # 检查必要参数 + if not talk_id or not p_id: + self._log(f"❌ [External-{self.instance_id}] 用户 {receiver_id_int} 缺少必要的会话信息 (talk_id: {talk_id}, p_id: {p_id})", "ERROR") + return False + + if not user_token: + self._log(f"⚠️ [External-{self.instance_id}] 用户 {receiver_id_int} token为空,尝试请求token", "WARNING") + # 请求用户token + self._request_user_token(receiver_id_int, p_id) + # 将消息加入待发送队列 + if "pending_messages" not in user_info: + user_info["pending_messages"] = [] + user_info["pending_messages"].append(content) + self._log(f"📝 [External-{self.instance_id}] 消息已加入待发送队列,队列长度: {len(user_info['pending_messages'])}", "INFO") + return True + + # 发送消息 (注意:_send_message_to_user 可能期望字符串类型的receiver_id) + success = await self._send_message_to_user(receiver_id_int, talk_id, p_id, user_token, content) + if success: + # 更新最后发送时间 + user_info["last_sent"] = int(time.time() * 1000) + self._log(f"✅ [External-{self.instance_id}] 消息转发成功", "SUCCESS") + else: + self._log(f"❌ [External-{self.instance_id}] 消息转发失败", "ERROR") + + return success + + except Exception as e: + self._log(f"❌ [External-{self.instance_id}] 外部消息发送异常: {e}", "ERROR") + self._log(f"❌ [External-{self.instance_id}] 错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def get_active_users_info(self) -> dict: + """获取当前活跃用户的详细信息""" + try: + active_users = {} + for user_id, info in self.user_tokens.items(): + active_users[user_id] = { + "has_token": bool(info.get("token")), + "talk_id": info.get("talk_id"), + "p_id": info.get("p_id"), + "last_sent": info.get("last_sent", 0), + "pending_messages_count": len(info.get("pending_messages", [])), + "session_initialized": info.get("session_initialized", False) + } + return active_users + except Exception as e: + self._log(f"获取活跃用户信息失败: {e}", "ERROR") + return {} + + def print_active_users_debug(self): + """打印当前活跃用户的调试信息""" + try: + active_users = self.get_active_users_info() + self._log(f"🔍 [Debug-{self.instance_id}] 当前活跃用户总数: {len(active_users)}", "INFO") + + if not active_users: + self._log(f"📝 [Debug-{self.instance_id}] 没有活跃用户。用户需要先在抖音平台发送消息建立会话。", "INFO") + return + + for user_id, info in active_users.items(): + self._log(f"👤 [Debug-{self.instance_id}] 用户 {user_id}:", "INFO") + self._log(f" - Token: {'✅' if info['has_token'] else '❌'}", "INFO") + self._log(f" - Talk ID: {info['talk_id']}", "INFO") + self._log(f" - P ID: {info['p_id']}", "INFO") + self._log(f" - 待发送消息: {info['pending_messages_count']}", "INFO") + self._log(f" - 会话已初始化: {'✅' if info['session_initialized'] else '❌'}", "INFO") + + except Exception as e: + self._log(f"打印调试信息失败: {e}", "ERROR") + + +class DouYinChatBot: + """抖音聊天机器人主类""" + + def __init__(self, cookie: dict, store_id: str = None): + self.cookie = cookie + self.store_id = store_id + if not self.store_id: + self.store_id = "68c16836-abac-4307-b763-ea1154823356" + self.ai_service = DouYinBackendService() + self.message_handler = None + self.loop = asyncio.new_event_loop() # 统一的事件循环 + self._stop_event = asyncio.Event() # 添加停止事件 + + async def initialize(self): + """初始化聊天机器人""" + try: + # 创建消息处理器 + self.message_handler = DouYinMessageHandler( + cookie=self.cookie, + ai_service=self.ai_service, + store_id=self.store_id + ) + + return True + + except Exception as e: + print(f"❌ 初始化失败: {e}") + return False + + def start(self): + """启动聊天机器人""" + try: + # 运行初始化 + asyncio.set_event_loop(self.loop) + success = self.loop.run_until_complete(self.initialize()) + + if success: + # 启动消息处理器 + self.message_handler.start() + + # !!!关键修改:简化主循环!!! + # 保持主线程运行,等待停止信号 + while not self._stop_event.is_set(): + time.sleep(1) + + else: + print("❌ 聊天机器人启动失败") + + except Exception as e: + print(f"❌ 启动失败: {e}") + traceback.print_exc() + finally: + if not self._stop_event.is_set(): + self.loop.close() + + async def close(self): + """关闭聊天机器人""" + self._stop_event.set() # 设置停止信号 + + if self.message_handler: + await self.message_handler.close() + if self.ai_service: + await self.ai_service.close() + + +class DouYinListenerForGUI: + """用于GUI集成的抖音监听包装器""" + + def __init__(self, log_callback=None): + self.douyin_bot = None + self.log_callback = log_callback + self.running = False + self.stop_event = None + self.loop = None + + def _log(self, message, log_type="INFO"): + """处理日志输出""" + if self.log_callback: + self.log_callback(message, log_type) + else: + print(f"[{log_type}] {message}") + + async def start_listening(self, cookie_dict, text="您好,感谢您的咨询,我们会尽快回复您!"): + """启动监听的主方法""" + try: + self._log("🔵 开始抖音平台连接流程", "INFO") + + # 验证cookie + if not cookie_dict: + self._log("❌ Cookie信息不能为空", "ERROR") + return False + + required_fields = ['SHOP_ID', 'PIGEON_CID', 'sessionid'] + missing_fields = [field for field in required_fields if field not in cookie_dict] + if missing_fields: + self._log(f"❌ 缺少必需的Cookie字段: {', '.join(missing_fields)}", "ERROR") + return False + + self._log(f"✅ Cookie验证通过,店铺ID: {cookie_dict['SHOP_ID']}", "SUCCESS") + + # 创建抖音聊天机器人实例 + self.douyin_bot = DouYinChatBot(cookie=cookie_dict) + self.running = True + self.stop_event = asyncio.Event() + + self._log("🎉 开始监听抖音平台消息...", "SUCCESS") + + # 初始化并启动机器人 + success = await self.douyin_bot.initialize() + if success: + # 在新的事件循环中运行机器人 + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + # 启动机器人 + def run_bot(): + self.douyin_bot.start() + + # 在新线程中运行机器人 + bot_thread = threading.Thread(target=run_bot, daemon=True) + bot_thread.start() + + return True + else: + self._log("❌ 抖音机器人初始化失败", "ERROR") + return False + + except Exception as e: + self._log(f"❌ 监听过程中出现严重错误: {str(e)}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + async def start_with_cookies(self, store_id, cookie_dict): + """使用下发的cookies与store_id直接建立抖音平台WS并开始监听""" + try: + self._log("🔵 [DY] 收到后端登录指令,开始使用cookies连接平台", "INFO") + + # 验证cookie + if not cookie_dict: + self._log("❌ Cookie信息不能为空", "ERROR") + return False + + required_fields = ['SHOP_ID', 'PIGEON_CID', 'sessionid'] + missing_fields = [field for field in required_fields if field not in cookie_dict] + if missing_fields: + self._log(f"❌ 缺少必需的Cookie字段: {', '.join(missing_fields)}", "ERROR") + return False + + self._log(f"✅ Cookie验证通过,店铺ID: {cookie_dict['SHOP_ID']}", "SUCCESS") + + # 建立与后端的统一连接(确保使用GUI的store_id) + backend_service = DouYinBackendService() + await backend_service.connect(store_id) + self._log("✅ 后端服务连接成功(使用统一连接)", "SUCCESS") + + # 创建抖音聊天机器人实例 + self.douyin_bot = DouYinChatBot(cookie=cookie_dict, store_id=store_id) + # 设置后端服务 + self.douyin_bot.ai_service = backend_service + self.running = True + self.stop_event = asyncio.Event() + + self._log("🎉 开始监听抖音平台消息...", "SUCCESS") + + # 异步初始化机器人 + success = await self.douyin_bot.initialize() + if success: + # 异步启动消息处理器 + if self.douyin_bot.message_handler: + message_handler_success = await self.douyin_bot.message_handler.start_async() + if not message_handler_success: + self._log("❌ 消息处理器启动失败", "ERROR") + return False + + # 注册到全局管理器 + dy_manager = DouYinWebsocketManager() + shop_key = f"抖音:{store_id}" + dy_manager.on_connect(shop_key, self.douyin_bot, store_id=store_id, cookie=cookie_dict) + self._log(f"✅ 已注册抖音连接: {shop_key}", "SUCCESS") + + # 创建一个长期运行的任务来保持监听状态 + async def keep_running(): + try: + while not self.stop_event.is_set(): + await asyncio.sleep(1) + except asyncio.CancelledError: + pass + + # 在后台启动监听任务 + asyncio.create_task(keep_running()) + + self._log("✅ [DY] 抖音平台连接成功,开始监听消息", "SUCCESS") + return True + else: + self._log("❌ 抖音机器人初始化失败", "ERROR") + return False + + except Exception as e: + self._log(f"❌ [DY] 监听过程中出现严重错误: {str(e)}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def stop_listening(self): + """停止监听""" + if self.stop_event: + self.stop_event.set() + self.running = False + if self.douyin_bot: + # 创建新的事件循环来关闭机器人 + async def cleanup(): + await self.douyin_bot.close() + + if self.loop and not self.loop.is_closed(): + self.loop.run_until_complete(cleanup()) + self.loop.close() + self._log("抖音监听已停止", "INFO") + + +# 使用示例 +if __name__ == '__main__': + cookies = { + "passport_csrf_token": "9984fc5ad93abebf1a7bceb157fc4560", + "passport_csrf_token_default": "9984fc5ad93abebf1a7bceb157fc4560", + "qc_tt_tag": "0", + "is_staff_user": "false", + "SHOP_ID": "217051461", + "PIGEON_CID": "1216524360102748", + "passport_mfa_token": "CjeTQsM%2B1gYNk6uL6EBAHaZQqQ0qvxul3Up08WBuQeEr%2BGfitdRk91WzrSVG46q2ldU%2BOnVc%2BmPtGkoKPAAAAAAAAAAAAABPbMkgpgfbZwhLZyjNjTZUm1l5GH%2BAasL%2BonVECzLkUmLgj262JLsX2eLMDc2bxcEFUxCogvsNGPax0WwgAiIBA3PySKw%3D", + "__security_mc_1_s_sdk_crypt_sdk": "da6a1b67-4e38-b24e", + "bd_ticket_guard_client_data": "eyJiZC10aWNrZXQtZ3VhcmQtdmVyc2lvbiI6MiwiYmQtdGlja2V0LWd1YXJkLWl0ZXJhdGlvbi12ZXJzaW9uIjoxLCJiZC10aWNrZXQtZ3VhcmQtcmVlLXB1YmxpYy1rZXkiOiJCTWQ4eGpKMUY2THJEUDRwc283ald6T0ZzTWhCaXhLc3dla3BIQ1JleFNENFRWNmNOK09uOVdKQnIwNWFkNmgvRnM2N0hpQzUxSXJFTGZTSFVWakVtODQ9IiwiYmQtdGlja2V0LWd1YXJkLXdlYi12ZXJzaW9uIjoyfQ%3D%3D", + "bd_ticket_guard_client_web_domain": "2", + "ttwid": "1%7C85xTuedO1rj3zvv-kDVjAu2b0hgRS8wVjCPgOEaCaxo%7C1757499627%7Cb7216cdc62420b85602b4a810e31be759b7a184da042bf2a9a21629f081dd2d9", + "odin_tt": "2b28de94dbb7a08d45168f8f138dda7defd529f717ce89d3148b3151488b33248f176c0c52b58cdca420cfb950e13ecd6dac26d6762394725087280441ac91c5", + "passport_auth_status": "d96aa2b690a33e007d157cf4204b1078%2C62594da316130803f733a79b6a6774df", + "passport_auth_status_ss": "d96aa2b690a33e007d157cf4204b1078%2C62594da316130803f733a79b6a6774df", + "uid_tt": "d1dbdd6e4cebff9fbb496f8735b11c9d", + "uid_tt_ss": "d1dbdd6e4cebff9fbb496f8735b11c9d", + "sid_tt": "784e3e2545c5666529fa3ac9451ed016", + "sessionid": "784e3e2545c5666529fa3ac9451ed016", + "sessionid_ss": "784e3e2545c5666529fa3ac9451ed016", + "ucas_c0": "CkEKBTEuMC4wELKIjrqrodTgaBjmJiDjhaCz682rASiwITDc5uCyws2UAkCRooXGBkiR1sHIBlCmvJOipunJ9WdYbhIU08vxfhaj0eG4pjCi5loa1uv2XEY", + "ucas_c0_ss": "CkEKBTEuMC4wELKIjrqrodTgaBjmJiDjhaCz682rASiwITDc5uCyws2UAkCRooXGBkiR1sHIBlCmvJOipunJ9WdYbhIU08vxfhaj0eG4pjCi5loa1uv2XEY", + "sid_guard": "784e3e2545c5666529fa3ac9451ed016%7C1757499665%7C5184000%7CSun%2C+09-Nov-2025+10%3A21%3A05+GMT", + "session_tlb_tag": "sttt%7C17%7CeE4-JUXFZmUp-jrJRR7QFv_________3dxW8aRfOoXXRgtkArn2rBGBZ8E0_061PH30G5EzcU-M%3D", + "sid_ucp_v1": "1.0.0-KDIwMjIxOWE0MzY1NzA1YTZmNzY3NTRmZGJkMTU1OTg1ODc0MWI0MjkKGwjc5uCyws2UAhCRooXGBhiwISAMOAZA9AdIBBoCbGYiIDc4NGUzZTI1NDVjNTY2NjUyOWZhM2FjOTQ1MWVkMDE2", + "ssid_ucp_v1": "1.0.0-KDIwMjIxOWE0MzY1NzA1YTZmNzY3NTRmZGJkMTU1OTg1ODc0MWI0MjkKGwjc5uCyws2UAhCRooXGBhiwISAMOAZA9AdIBBoCbGYiIDc4NGUzZTI1NDVjNTY2NjUyOWZhM2FjOTQ1MWVkMDE2", + "PHPSESSID": "a72b9c2977908a281d086061f7281046", + "PHPSESSID_SS": "a72b9c2977908a281d086061f7281046", + "csrf_session_id": "623da6c2834082a9036c812d995f39cc" + } + + # # !!!关键修改:使用同步方式启动!!! + # listener = DouYinListenerForGUI() + # + # # 创建新的事件循环来运行异步方法 + # loop = asyncio.new_event_loop() + # asyncio.set_event_loop(loop) + # + # try: + # # 运行启动方法 + # success = loop.run_until_complete(listener.start_with_cookies(store_id=None, cookie_dict=cookies)) + # if success: + # print("✅ 监听器启动成功,按 Ctrl+C 停止...") + # # 保持主线程运行 + # while listener.running: + # time.sleep(1) + # else: + # print("❌ 监听器启动失败") + # except KeyboardInterrupt: + # print("\n🛑 正在停止监听器...") + # listener.stop_listening() + # except Exception as e: + # print(f"❌ 程序异常: {e}") + # traceback.print_exc() + # finally: + # loop.close() + + # 创建聊天机器人实例 + bot = DouYinChatBot(cookie=cookies) + + try: + # 启动机器人 + bot.start() + + except KeyboardInterrupt: + print("\n🛑 正在关闭机器人...") + + + # 清理资源 + async def cleanup(): + await bot.close() + + + # 创建临时事件循环进行清理 + cleanup_loop = asyncio.new_event_loop() + asyncio.set_event_loop(cleanup_loop) + cleanup_loop.run_until_complete(cleanup()) + cleanup_loop.close() + print("✅ 机器人已关闭") diff --git a/Utils/Dy/__init__.py b/Utils/Dy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utils/Dy/message_arg.py b/Utils/Dy/message_arg.py new file mode 100644 index 0000000..8275870 --- /dev/null +++ b/Utils/Dy/message_arg.py @@ -0,0 +1,375 @@ +# -*- coding: utf-8 -*- +# python let's go +# 编辑人:kris思成 + +# coding=utf-8 +import time +import uuid +import json + + +# 发送消息 +def send_message(pigeon_sign: str, token: str, receiver_id: str, shop_id: str, talk_id: int, session_did: str, p_id: int, user_code: str, text: str): + """ + 构造发送消息消息体 + :param pigeon_sign: 接口返回 + :param token: 接口返回 + :param receiver_id: wss消息返回 对方用户id + :param shop_id: cookie自带 + :param talk_id: wss消息返回 激活窗口id + :param session_did: cookie自带 + :param p_id: wss消息返回 + :param user_code: 用户token + :param text: 文本内容 + :return: + """ + value = { + '1': 11778, + '2': int(time.time() * 1000), + '3': 10001, + '4': 1, + '5': [ + {'1': b'pigeon_source', '2': b'web'}, + {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'pigeon_sign', '2': pigeon_sign.encode()}, + ], + '7': {'14': 98}, + '8': { + '1': 100, + '2': 11778, + '3': b'1.0.4-beta.2', + '4': token.encode(), + '5': 3, + '6': 3, + '7': b'2d97ea6:feat/add_init_callback', + '8': { + '100': { + '1': f"{receiver_id}:{shop_id}::2:1:pigeon".encode(), + '2': 11, + '3': p_id, + '4': text.encode(), + '5': [ + {'1': b'type', '2': b'text'}, + {'1': b'shop_id', '2': shop_id.encode()}, + {'1': b'sender_role', '2': b'2'}, + {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'src', '2': b'pc'}, + {'1': b'srcType', '2': b'1'}, + {'1': b'source', '2': b'pc-web'}, + {'1': b'receiver_id', '2': str(receiver_id).encode()}, + {'1': b'hierarchical_dimension', '2': b'{"dynamic_dimension":"4541_1131_9042_6599_9420_6832_4050_3823_3994_8564_1528_0388_8667_2179_7948_1870_1949_0989_8012_6240_7898_7548_8852_6245_9393_3650_8570_4026_4034_4057_6537_8632_2068_8958_0363_2387_9033_3425_2238_0982_1935_8188_3817_8557_7931_3278_4065_1893_6049_6961_3814_4883_4401_6637_7282_3652_9354_0437_4769_4815_9572_7230_5054_3951_4852_2188_3505_6813_2570_5394_0729","goofy_id":"1.0.1.1508","desk_version":"0.0.0","open_stores":"0","memL":"","cpuL":"","session_throughput":0,"message_throughput_send":0,"message_throughput_revice":0}'}, + {'1': b'p:check_Send', '2': str(uuid.uuid4()).encode()}, + {'1': b'track_info','2': json.dumps({"send_time": int(time.time() * 1000), "_send_delta": "77","_send_delta_2": "216"}).encode()}, + {'1': b'user_agent', '2': b'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'sender_id', '2': b''}, + {'1': b'biz_ext', '2': b'{}'}, + {'1': b'p:from_source', '2': b'web'}, + {'1': b's:mentioned_users', '2': b''}, + {'1': b's:client_message_id', '2': str(uuid.uuid4()).encode()} + ], + '6': 1000, + '7': user_code.encode(), + '8': str(uuid.uuid4()).encode(), + '14': talk_id # 激活聊天窗口id + } + }, + '9': session_did.encode(), + '11': b'web', + '15': [ + {'1': b'pigeon_source', '2': b'web'}, + {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'pigeon_sign', '2': b'MIG6BAz2BNUON43WdlOBuGYEgZcsIho9ZjVP4yyExLShzXgAZtsvUMj2e3jZWeMZv+6+TNVQQMq3xSLrqiwcs2cCaOVBDuS6zGsWm5gBlGtlvOOLM5td2/9OS8P37t1sdkjN4BSH2mB7FlGItioZIsTh1sodn6pYCGj+45mtId3Itenufgai3Mnkpt573uoWJmagF8J3jVPHMFtdwd25Qf5vsWC2kB30glpQBBCbk2VO2ubMqctqQSzhI6uD'}, + {'1': b'session_aid', '2': b'1383'}, + {'1': b'session_did', '2': session_did.encode()}, + {'1': b'app_name', '2': b'im'}, + {'1': b'priority_region', '2': b'cn'}, + {'1': b'user_agent','2': b'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'cookie_enabled', '2': b'true'}, + {'1': b'browser_language', '2': b'zh-CN'}, + {'1': b'browser_platform', '2': b'Win32'}, + {'1': b'browser_name', '2': b'Mozilla'}, + {'1': b'browser_version', '2': b'5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'browser_online', '2': b'true'}, + {'1': b'screen_width', '2': b'1707'}, + {'1': b'screen_height', '2': b'1067'}, + {'1': b'referer', '2': b''}, + {'1': b'timezone_name', '2': b'Asia/Shanghai'} + ], + '18': 2} + } + message_type = { + "1": { + "type": "int", + "name": "" + }, + "2": { + "type": "int", + "name": "" + }, + "3": { + "type": "int", + "name": "" + }, + "4": { + "type": "int", + "name": "" + }, + "5": { + "type": "message", + "message_typedef": { + "1": { + "type": "bytes", + "name": "" + }, + "2": { + "type": "bytes", + "name": "" + } + }, + "name": "" + }, + "7": { + "type": "message", + "message_typedef": { + "14": { + "type": "int", + "name": "" + } + }, + "name": "" + }, + "8": { + "type": "message", + "message_typedef": { + "1": { + "type": "int", + "name": "" + }, + "2": { + "type": "int", + "name": "" + }, + "3": { + "type": "bytes", + "name": "" + }, + "4": { + "type": "bytes", + "name": "" + }, + "5": { + "type": "int", + "name": "" + }, + "6": { + "type": "int", + "name": "" + }, + "7": { + "type": "bytes", + "name": "" + }, + "8": { + "type": "message", + "message_typedef": { + "100": { + "type": "message", + "message_typedef": { + "1": { + "type": "bytes", + "name": "" + }, + "2": { + "type": "int", + "name": "" + }, + "3": { + "type": "int", + "name": "" + }, + "4": { + "type": "bytes", + "name": "" + }, + "5": { + "type": "message", + "message_typedef": { + "1": { + "type": "bytes", + "name": "" + }, + "2": { + "type": "bytes", + "name": "" + } + }, + "name": "" + }, + "6": { + "type": "int", + "name": "" + }, + "7": { + "type": "bytes", + "name": "" + }, + "8": { + "type": "bytes", + "name": "" + }, + "14": { + "type": "int", + "name": "" + } + }, + "name": "" + } + }, + "name": "" + }, + "9": { + "type": "bytes", + "name": "" + }, + "11": { + "type": "bytes", + "name": "" + }, + "15": { + "type": "message", + "message_typedef": { + "1": { + "type": "bytes", + "name": "" + }, + "2": { + "type": "bytes", + "name": "" + } + }, + "name": "" + }, + "18": { + "type": "int", + "name": "" + } + }, + "name": "" + } + } + return value, message_type + + +# 获取token +def get_user_code(pigeon_sign: str, token: str, receiver_id: str, shop_id: str, session_did: str, p_id: int): + value = {'1': 10109, '2': int(time.time() * 1000), '3': 10001, '4': 1, + '5': [{'1': b'pigeon_source', '2': b'web'}, {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, {'1': b'pigeon_sign', + '2': pigeon_sign.encode()}], + '7': {'14': 98}, '8': {'1': 610, '2': 10109, '3': b'1.0.4-beta.2', + '4': token.encode(), '5': 3, '6': 3, + '7': b'2d97ea6:feat/add_init_callback', '8': { + '610': {'1': {'1': f"{receiver_id}:{shop_id}::2:1:pigeon".encode(), '2': p_id, '3': 10}}}, + '9': session_did.encode(), '11': b'web', + '15': [{'1': b'pigeon_source', '2': b'web'}, {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'pigeon_sign', + '2': pigeon_sign.encode()}, + {'1': b'session_aid', '2': b'1383'}, + {'1': b'session_did', '2': session_did.encode()}, + {'1': b'app_name', '2': b'im'}, {'1': b'priority_region', '2': b'cn'}, + {'1': b'user_agent', + '2': b'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'cookie_enabled', '2': b'true'}, + {'1': b'browser_language', '2': b'zh-CN'}, + {'1': b'browser_platform', '2': b'Win32'}, + {'1': b'browser_name', '2': b'Mozilla'}, {'1': b'browser_version', + '2': b'5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'browser_online', '2': b'true'}, {'1': b'screen_width', '2': b'1707'}, + {'1': b'screen_height', '2': b'1067'}, {'1': b'referer', '2': b''}, + {'1': b'timezone_name', '2': b'Asia/Shanghai'}], '18': 2}} + message_type = {'1': {'type': 'int', 'name': ''}, '2': {'type': 'int', 'name': ''}, + '3': {'type': 'int', 'name': ''}, '4': {'type': 'int', 'name': ''}, '5': {'type': 'message', + 'message_typedef': { + '1': {'type': 'bytes', + 'name': ''}, + '2': {'type': 'bytes', + 'name': ''}}, + 'name': ''}, + '7': {'type': 'message', 'message_typedef': {'14': {'type': 'int', 'name': ''}}, 'name': ''}, + '8': {'type': 'message', + 'message_typedef': {'1': {'type': 'int', 'name': ''}, '2': {'type': 'int', 'name': ''}, + '3': {'type': 'bytes', 'name': ''}, '4': {'type': 'bytes', 'name': ''}, + '5': {'type': 'int', 'name': ''}, '6': {'type': 'int', 'name': ''}, + '7': {'type': 'bytes', 'name': ''}, '8': {'type': 'message', + 'message_typedef': { + '610': {'type': 'message', + 'message_typedef': { + '1': { + 'type': 'message', + 'message_typedef': { + '1': { + 'type': 'bytes', + 'name': ''}, + '2': { + 'type': 'int', + 'name': ''}, + '3': { + 'type': 'int', + 'name': ''}}, + 'name': ''}}, + 'name': ''}}, + 'name': ''}, + '9': {'type': 'bytes', 'name': ''}, '11': {'type': 'bytes', 'name': ''}, + '15': {'type': 'message', + 'message_typedef': {'1': {'type': 'bytes', 'name': ''}, + '2': {'type': 'bytes', 'name': ''}}, + 'name': ''}, '18': {'type': 'int', 'name': ''}}, 'name': ''}} + return value, message_type + + +# 心跳包 +def heartbeat_message(pigeon_sign: str, token: str, session_did: str): + value = { + '1': 11028, + '2': int(time.time() * 1000), + '3': 10001, + '4': 1, + '5': [ + {'1': b'pigeon_source', '2': b'web'}, + {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'pigeon_sign','2': pigeon_sign.encode()} + ], + '7': {'14': 98}, + '8': { + '1': 200, + '2': 11028, + '3': b'1.0.4-beta.2', + '4': token.encode(), + '5': 3, + '6': 3, + '7': b'2d97ea6:feat/add_init_callback', + '8': {'200': {'1': int(time.time() * 1000), '2': 50}}, + '9': session_did.encode(), + '11': b'web', + '15': [ + {'1': b'pigeon_source', '2': b'web'}, + {'1': b'PIGEON_BIZ_TYPE', '2': b'2'}, + {'1': b'pigeon_sign', '2': pigeon_sign.encode()}, + {'1': b'session_aid', '2': b'1383'}, + {'1': b'session_did', '2': session_did.encode()}, + {'1': b'app_name', '2': b'im'}, + {'1': b'priority_region', '2': b'cn'}, + {'1': b'user_agent', '2': b'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'cookie_enabled', '2': b'true'}, + {'1': b'browser_language', '2': b'zh-CN'}, + {'1': b'browser_platform', '2': b'Win32'}, {'1': b'browser_name', '2': b'Mozilla'}, + {'1': b'browser_version', '2': b'5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36'}, + {'1': b'browser_online', '2': b'true'}, {'1': b'screen_width', '2': b'1707'}, + {'1': b'screen_height', '2': b'1067'}, {'1': b'referer', '2': b''}, + {'1': b'timezone_name', '2': b'Asia/Shanghai'} + ], + '18': 2 + } + } + message_type = {'1': {'type': 'int', 'name': ''}, '2': {'type': 'int', 'name': ''}, '3': {'type': 'int', 'name': ''}, '4': {'type': 'int', 'name': ''}, '5': {'type': 'message', 'message_typedef': {'1': {'type': 'bytes', 'name': ''}, '2': {'type': 'bytes', 'name': ''}}, 'name': ''}, '7': {'type': 'message', 'message_typedef': {'14': {'type': 'int', 'name': ''}}, 'name': ''}, '8': {'type': 'message', 'message_typedef': {'1': {'type': 'int', 'name': ''}, '2': {'type': 'int', 'name': ''}, '3': {'type': 'bytes', 'name': ''}, '4': {'type': 'bytes', 'name': ''}, '5': {'type': 'int', 'name': ''}, '6': {'type': 'int', 'name': ''}, '7': {'type': 'bytes', 'name': ''}, '8': {'type': 'message', 'message_typedef': {'200': {'type': 'message', 'message_typedef': {'1': {'type': 'int', 'name': ''}, '2': {'type': 'int', 'name': ''}}, 'name': ''}}, 'name': ''}, '9': {'type': 'bytes', 'name': ''}, '11': {'type': 'bytes', 'name': ''}, '15': {'type': 'message', 'message_typedef': {'1': {'type': 'bytes', 'name': ''}, '2': {'type': 'bytes', 'name': ''}}, 'name': ''}, '18': {'type': 'int', 'name': ''}}, 'name': ''}} + return value, message_type + diff --git a/Utils/JD/JdUtils.py b/Utils/JD/JdUtils.py new file mode 100644 index 0000000..2ae17ba --- /dev/null +++ b/Utils/JD/JdUtils.py @@ -0,0 +1,981 @@ +# -*- coding: utf-8 -*- +# python let's go +# 编辑人:kris思成 +import asyncio +import hashlib +import traceback +from datetime import datetime +import aiohttp +import jsonpath +import websockets +from loguru import logger +import requests +import json +import time +import threading + + +# 定义持久化数据类 +class WebsocketManager: + _instance = None + _lock = threading.Lock() + + def __new__(cls): + if cls._instance is None: + with cls._lock: + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._store = {} + cls._instance._lock = threading.RLock() + return cls._instance + + def on_connect(self, shop_key, ws, **kwargs): + """完全保持原有数据结构""" + with self._lock: + entry = self._store.setdefault(shop_key, { + 'platform': None, + 'customers': [], + 'user_assignments': {} + }) + entry['platform'] = { + 'ws': ws, # 注意:这里存储的是强引用 + 'last_heartbeat': datetime.now(), + **kwargs + } + return entry + + def get_connection(self, shop_key): + with self._lock: + return self._store.get(shop_key) + + def remove_connection(self, shop_key): + with self._lock: + if shop_key in self._store: + del self._store[shop_key] + + + + +class JDBackendService: + """京东后端服务调用类(已废弃:使用单后端连接 BackendClient 代替)""" + + def __init__(self, *args, **kwargs): + self.current_store_id = "" + + async def connect(self, store_id, *args, **kwargs): + try: + self.current_store_id = str(store_id or "") + except Exception: + self.current_store_id = "" + return True + + async def send_message_to_backend(self, platform_message): + """改为通过单后端连接发送,需携带store_id""" + try: + from WebSocket.backend_singleton import get_backend_client + backend = get_backend_client() + if not backend: + return None + # 从platform_message中构造统一上行结构,并附加store_id + body = platform_message.get('body', {}) if isinstance(platform_message, dict) else {} + sender_pin = platform_message.get('from', {}).get('pin', '') if isinstance(platform_message, dict) else '' + # 优先取消息内的store_id,其次取body内,再次退回当前会话store_id + store_id = (platform_message.get('store_id') + or body.get('store_id') + or self.current_store_id + or '') + body_type = body.get('type', 'text') + content_for_backend = body.get('content', '') + if body_type in ('image', 'video'): + # 统一从常见字段取URL + content_for_backend = ( + body.get('url') + or body.get('imageUrl') + or body.get('videoUrl') + or body.get('picUrl') + or content_for_backend + ) + # 检测文本中的商品卡片/订单卡片 + if body_type == 'text' and isinstance(content_for_backend, str): + try: + import re as _re + text = content_for_backend.strip() + # 商品卡片:JD商品URL + if _re.search(r"https?://item(\.m)?\.jd\.com/\d+\.html(\?.*)?", text): + body_type = 'product_card' + else: + # 订单卡片多样式匹配 + # 1) 订单在前:咨询/查询/订单号:[,,]? 商品(ID|id|号|编号): + m1 = _re.search( + r"(?:咨询订单号|查询订单号|订单号)\s*[::]\s*(\d+)[,,]?\s*商品(?:ID|id|号|编号)\s*[::]\s*(\d+)", + text) + # 2) 商品在前:商品(ID|id|号|编号):[,,]? (咨询/查询)?订单号: + m2 = _re.search( + r"商品(?:ID|id|号|编号)\s*[::]\s*(\d+)[,,]?\s*(?:咨询订单号|查询订单号|订单号)\s*[::]\s*(\d+)", + text) + if m1 or m2: + body_type = 'order_card' + if m1: + order_number, product_id = m1.group(1), m1.group(2) + else: + product_id, order_number = m2.group(1), m2.group(2) + # 归一化 content + content_for_backend = f"商品id:{product_id} 订单号:{order_number}" + except Exception: + pass + msg = { + 'type': 'message', + 'content': content_for_backend, + 'msg_type': body_type, + 'sender': {'id': sender_pin}, + 'store_id': store_id + } + backend.send_message(msg) + return None + except Exception: + return None + + +class FixJdCookie: + + def __init__(self, log_callback=None): + # 定义一些常用参数 + super().__init__() # 继承一些父类的初始化参数 + self.ws_manager = WebsocketManager() + self.log_callback = log_callback # 存储日志回调 + + # 新增后端服务实例 + self.backend_service = JDBackendService() + self.backend_connected = False + + # 新增重连参数 + self.reconnect_attempts = 0 + self.max_reconnect_attempts = 10 # 最大重连次数 + self.base_reconnect_delay = 1.0 # 基础重连延迟 + self.max_reconnect_delay = 60.0 # 最大重连延迟 + self.reconnect_backoff = 1.5 # 退避系数 + + def _log(self, message, log_type="INFO"): + """内部日志方法""" + if self.log_callback: + self.log_callback(message, log_type) + else: + print(f"[{log_type}] {message}") + + def get_config(self, cookies_str): + """获取配置""" + headers = { + "cookie": cookies_str, + "user-agent": "Mozilla/5.0", + "referer": "https://dongdong.jd.com/", + } + response = requests.get("https://dongdong.jd.com/workbench/checkin.json", headers=headers, + params={"version": "2.6.3", "client": "openweb"}) + return response.json() + + async def init_wss(self, ws, aid, pin_zj): + """初始化 socket""" + await self.send_heartbeat(ws, aid, pin_zj) + print("开始监听初始化") + auth = { + "id": hashlib.md5(str(int(time.time() * 1000)).encode()).hexdigest(), + "aid": aid, + "lang": "zh_CN", + "timestamp": int(time.time() * 1000), + "type": "auth", + "body": {"presence": 1, "clientVersion": "2.6.3"}, + "to": {"app": "im.waiter"}, + "from": {"app": "im.waiter", "pin": pin_zj, "clientType": "comet", "dvc": "device1234"} + } + await ws.send(json.dumps(auth)) + + + async def waiter_status_switch(self, ws, aid, pin_zj): + """设置接待状态""" + message = { + "id": hashlib.md5(str(int(time.time() * 1000)).encode()).hexdigest(), + "aid": aid, + "lang": "zh_CN", + "timestamp": int(time.time() * 1000), + "from": { + "app": "im.waiter", + "pin": pin_zj, + "art": "customerGroupMsg", + "clientType": "comet" + }, + "type": "waiter_status_switch", + "body": { + "s": 1 + } + } + await ws.send(json.dumps(message)) + + async def transfer_customer(self, ws, aid, pin, pin_zj, chat_name): + """异步客服转接 在发送的消息为客服转接的关键词的时候""" + message = { + "id": hashlib.md5(str(int(time.time() * 1000)).encode()).hexdigest(), + "aid": aid, + "lang": "zh_CN", + "timestamp": int(time.time() * 1000), + "from": { + "app": "im.waiter", "pin": pin_zj, "art": "customerGroupMsg", "clientType": "comet" + }, + "type": "chat_transfer_partern", + "body": { + "customer": pin, "cappId": "im.customer", "waiter": chat_name, "reason": "", + "ext": {"pid": ""}, "pid": "" + } + } + try: + await ws.send(json.dumps(message)) + return True + except Exception: + traceback.print_exc() + return False + + async def send_message(self, ws, pin, aid, pin_zj, vender_id, content): + """异步发送单条消息""" + try: + print('本地发送消息') + message = { + "ver": "4.3", + "type": "chat_message", + "from": {"pin": pin_zj, "app": "im.waiter", "clientType": "comet"}, + "to": {"app": "im.customer", "pin": pin}, + "id": hashlib.md5(str(int(time.time() * 1000)).encode()).hexdigest(), + "lang": "zh_CN", + "aid": aid, + "timestamp": int(time.time() * 1000), + "readFlag": 0, + "body": { + "content": content, + "translated": False, + "param": {"cusVenderId": vender_id}, + "type": "text" + } + } + await ws.send(json.dumps(message)) + logger.info(f"消息已经发送到客户端[info] {pin}: {content[:20]} ...") + except websockets.ConnectionClosed: + logger.error('本地发送消息失败 连接关闭') + raise + except Exception as e: + # 同时这里也要及时进行raise抛出 这样比较好让系统可以看出 异常了可以抛出信息不至于后续被认为 + logger.error(f"消息发送过程中出现特殊异常异常信息为: {e}") + raise + + def get_userinfo(self, response_text): + """获取用户 pin 并存入 pins 列表""" + pin = jsonpath.jsonpath(json.loads(response_text), "$..from.pin") + return pin[0] if pin else None + + def is_merchants(self, store: object, response): + """判断消息是否来自顾客""" + send = response['from']['pin'] + # 补充: 方法lower()是转化为小写 upper()是转化为大写 title()是每个单词首字母大写其余小写 + if send.lower() == "KLD测试".lower(): + return False + return True + + async def send_heartbeat(self, ws, aid, pin_zj): + """发送心跳包""" + msg = { + "id": hashlib.md5(str(int(time.time() * 1000)).encode()).hexdigest(), + "type": "client_heartbeat", + "aid": aid, + "ver": "4.1", + "lang": "zh_CN", + "from": {"pin": pin_zj, "app": "im.waiter", "art": "customerGroupMsg", "clientType": "comet"} + } + await ws.send(json.dumps(msg, separators=(',', ':'))) # 使用最简心跳包模式 来节约部分性能 减少传输压力 + + async def heartbeat_loop(self, websocket, aid, pin_zj): + """独立的心跳循环""" + """ + 优化心跳 循环 新增改进 + 1. 心跳间隔动态调整 + 2. 异常重试机制 + 3. 心跳超时控制 + 4. 状态监控 + """ + retry_count = 0 + max_retries = 3 + base_interval = 3.0 # 基础间隔1s + backoff_factor = 1.5 # 退避系数 + timeout = 10.0 + + while True: + try: + start_time = time.monotonic() + + # 使用websocket原生的ping/pong机制 + pong_waiter = await websocket.ping() + await asyncio.wait_for(pong_waiter, timeout=timeout) + + # 如果需要发送自定义心跳包 + await self.send_heartbeat(websocket, aid, pin_zj) + + # 计算剩余等待时间 + elapsed = time.monotonic() - start_time + sleep_time = max(0.0, base_interval - elapsed) + + if sleep_time > 0: + await asyncio.sleep(sleep_time) + + retry_count = 0 # 重置重试计数 + + except asyncio.TimeoutError: + logger.warning(f'心跳超时,已用时: {time.monotonic() - start_time:.2f}秒') + retry_count += 1 + except websockets.ConnectionClosed: + logger.error("连接关闭,心跳已停止") + break + except Exception as e: + logger.error(f"心跳异常: {e}", exc_info=True) + retry_count += 1 + + if retry_count >= max_retries: + logger.error(f"心跳连续失败{retry_count}次,终止循环") + break + + # 退避策略 + if retry_count > 0: + backoff_time = min( + base_interval * (backoff_factor ** (retry_count - 1)), + 60.0 # 最大等待60秒 + ) + logger.debug(f"心跳失败,等待{backoff_time:.2f}秒后重试") + await asyncio.sleep(backoff_time) + + ''' 整理重连方法 ''' + async def calculate_reconnect_delay(self): + """计算指数退避的重连延迟时间""" + delay = self.base_reconnect_delay * (self.reconnect_backoff ** self.reconnect_attempts) + return min(delay, self.max_reconnect_delay) + + async def should_reconnect(self): + """判断是否应该继续重连""" + if self.reconnect_attempts >= self.max_reconnect_attempts: + self._log(f"已达到最大重连次数({self.max_reconnect_attempts}),停止重连", "ERROR") + return False + return True + + async def handle_reconnect(self, exception=None): + """处理重连逻辑""" + if exception: + error_type = type(exception).__name__ + error_msg = str(exception) + self._log(f"连接异常[{error_type}]: {error_msg}", "WARNING") + + if not await self.should_reconnect(): + return False + + delay = await self.calculate_reconnect_delay() + self._log(f"第{self.reconnect_attempts + 1}次重连尝试,等待{delay:.1f}秒...", "WARNING") + + await asyncio.sleep(delay) + self.reconnect_attempts += 1 + return True + + + ''' 后端服务调用方法 ''' + + async def connect_backend_service(self, store_id): + """连接后端AI服务""" + try: + success = await self.backend_service.connect(store_id) + if success: + self.backend_connected = True + self._log("✅ 后端AI服务连接成功", "SUCCESS") + return success + except Exception as e: + self._log(f"❌ 连接后端AI服务失败: {e}", "ERROR") + return False + + async def get_ai_reply_from_backend(self, platform_message): + """从后端服务获取AI回复""" + # 首先检查后端服务连接状态 + if not self.backend_connected: + # 尝试重新连接 + store_id = str(platform_message.get('body', {}).get('chatinfo', {}).get('venderId', '')) + if store_id: + self.backend_connected = await self.connect_backend_service(store_id) + + if not self.backend_connected: + self._log("❌ 后端服务未连接,尝试重新连接失败,使用本地AI回复", "WARNING") + # 降级到本地AI回复 + customer_sid = platform_message.get('body', {}).get('chatinfo', {}).get('sid', '') + customer_message = platform_message.get('body', {}).get('content', '') + return + try: + # 推送给后端,由后端异步回传AI消息到GUI;此处不进行本地立即回复 + await self.backend_service.send_message_to_backend(platform_message) + return None + + except Exception as e: + self._log(f"❌ 获取AI回复失败: {e},使用本地AI", "ERROR") + customer_sid = platform_message.get('body', {}).get('chatinfo', {}).get('sid', '') + customer_message = platform_message.get('body', {}).get('content', '') + return + + async def process_incoming_message(self, response, ws, aid, pin_zj, vender_id, store): + """处理接收到的消息""" + try: + # 解析消息 + json_resp = json.loads(response) if isinstance(response, (str, bytes)) else response + + # 验证消息格式 + if not all([ + json_resp, + json_resp.get('type') == "chat_message", + json_resp.get('ver') == "4.2", + isinstance(json_resp.get("body"), dict) + ]): + return + + # 过滤非客户消息 + pin = self.get_userinfo(response) + if not self.is_merchants(store, json_resp): + return + + # 提取消息内容 + message_type = json_resp['body']['type'] + if message_type == 'text': + customer_message = json_resp['body']['content'] + elif message_type == 'image': + customer_message = f"[图片] {json_resp['body'].get('url') or json_resp['body'].get('imageUrl') or json_resp['body'].get('picUrl') or ''}" + elif message_type == 'video': + customer_message = f"[视频] {json_resp['body'].get('url') or json_resp['body'].get('videoUrl') or ''}" + else: + return + + self._log(f"📩 收到客户消息: {pin}: {customer_message[:100]}...", "INFO") + + # 从后端服务获取AI回复(单连接模式:仅转交,不本地立即回复) + ai_result = await self.get_ai_reply_from_backend(json_resp) + + if isinstance(ai_result, str) and ai_result.strip(): + # 发送回复消息(仅当本地生成/降级时) + await self.send_message( + ws=ws, pin=pin, aid=aid, + pin_zj=pin_zj, vender_id=vender_id, + content=ai_result + ) + self._log(f"📤 已发送回复: {ai_result[:100]}...", "INFO") + else: + # 正常链路:已转交后端AI,等待后端异步回传并由 GUI 转发到平台 + self._log("🔄 已转交后端AI处理,等待平台回复下发", "INFO") + + except json.JSONDecodeError: + self._log("❌ 消息JSON解析失败", "ERROR") + except Exception as e: + self._log(f"❌ 消息处理失败: {e}", "ERROR") + + async def message_monitoring(self, cookies_str, aid, pin_zj, vender_id, store, sleep_time=0.5, stop_event=None): + print("✅ DEBUG 进入message_monitoring方法") + print(f"参数验证: cookies={bool(cookies_str)}, aid={aid}, pin_zj={pin_zj}") + + # 连接后端AI服务 - 使用店铺ID或venderId + store_id = str(store.get('id', '')) or str(vender_id) + self._log(f"🔗 尝试连接后端服务,店铺ID: {store_id}", "DEBUG") + + backend_connected = await self.connect_backend_service(store_id) + if not backend_connected: + self._log("⚠️ 后端服务连接失败,将使用本地AI回复", "WARNING") + else: + self._log("✅ 后端服务连接成功", "SUCCESS") + + stop_event = stop_event or asyncio.Event() # 如果外部没传,自己创建 + uri = "wss://dongdong.jd.com/workbench/websocket" + headers = {"cookie": cookies_str} + + self._log(f"🔵 开始连接WebSocket: {uri}", "INFO") + + # 充值重连计数器 + self.reconnect_attempts = 0 + + while not stop_event.is_set(): + try: + self._log(f"🔄 尝试连接WebSocket", "INFO") + async with websockets.connect(uri, additional_headers=headers, ping_interval=6, ping_timeout=10, close_timeout=1, max_queue=1024) as ws: + # 连接成功,重置重连计数器 + self.reconnect_attempts = 0 + self._log("✅ WebSocket-JD连接成功", "SUCCESS") + await self.init_wss(ws, aid, pin_zj) + # === 验证连接成功的核心指标 === + # print(f"✅ 连接状态: open={ws.open}, closed={ws.closed}") + print(f"🖥️ 服务端地址: {ws.remote_address}") + + # --- 注册连接信息到全局管理 + shop_key = f"京东:{store['id']}" + loop = asyncio.get_running_loop() + entry = self.ws_manager.on_connect( + shop_key=shop_key, + ws=ws, + vender_id=vender_id, + aid=aid, + pin_zj=pin_zj, + platform="京东", + loop=loop + ) + + await self.waiter_status_switch(ws=ws, aid=aid, pin_zj=pin_zj) + + heartbeat_task = asyncio.create_task(self.heartbeat_loop(ws, aid, pin_zj)) + message_tasks = set() + + try: + while not stop_event.is_set(): # 检查是否收到中止信号 + try: + print(f"等待监听消息-{datetime.now()}") + response = await asyncio.wait_for(ws.recv(), timeout=1) + print(f"原始消息类型:{type(response)}, 消息体为: {response}") + await self.process_incoming_message(response, ws, aid, pin_zj, vender_id, store) + + # 安全解析消息 + json_resp = json.loads(response) if isinstance(response, (str, bytes)) else response + + print(json_resp) + + ver = json_resp.get("ver") + print(f"版本{ver}") + except asyncio.TimeoutError: + continue + except websockets.ConnectionClosed: + # 连接关闭 跳出内层循环进行重连 + break + except Exception as e: + self._log(f"消息处理异常: {e}", "ERROR") + continue + await asyncio.sleep(sleep_time) + ### + ##{'ver': '4.2', 'mid': 366566937, 'body': {'chatinfo': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': 'ce7f35b51a9c00ac898b0fe08608674a', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01C5XRGQHGNJBSFYWWA7RF54QXYHF2N34TM32NGLZV6YAAPPNKWLAIQ2MZV25T4QZ2TJE4HRF6UZ2L3THX7I2BLLB37YVAWKR2BYGRRPA01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'param': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': 'ce7f35b51a9c00ac898b0fe08608674a', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01C5XRGQHGNJBSFYWWA7RF54QXYHF2N34TM32NGLZV6YAAPPNKWLAIQ2MZV25T4QZ2TJE4HRF6UZ2L3THX7I2BLLB37YVAWKR2BYGRRPA01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'type': 'text', 'requestData': {'entry': 'sdk_item', 'venderId': '11961298'}, 'content': '你好', 'sid': 'ce7f35b51a9c00ac898b0fe08608674a'}, 'type': 'chat_message', 'clientTime': 1755076542320, 'datetime': '2025-08-13 17:15:42', 'len': 0, 'from': {'app': 'im.customer', 'art': '', 'clientType': 'android', 'pin': 'jd_thpotntctwys'}, 'subType': 'text', 'id': 'bc3c42a706fa4fa482ff565304c7dfbb', 'to': {'app': 'im.waiter', 'clientType': 'comet', 'pin': 'KLD测试'}, 'lang': 'zh_CN', 'timestamp': 1755076542671} + # {'ver': '4.2', 'mid': 366566966, 'body': {'chatinfo': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10052172306055', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '538fc3761474ea693812ceed4b39639c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd014TJZZMUXFLXYGJJJ4M3HY3PTU4PBA22SPDIXDWOGZ7XTUTOWTY4LU3VWN6OKDOJPJOVDINMCJXCSPSG5X2K6KWHNQJQOROB57LDG5EY01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'param': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10052172306055', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '538fc3761474ea693812ceed4b39639c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd014TJZZMUXFLXYGJJJ4M3HY3PTU4PBA22SPDIXDWOGZ7XTUTOWTY4LU3VWN6OKDOJPJOVDINMCJXCSPSG5X2K6KWHNQJQOROB57LDG5EY01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'type': 'text', 'requestData': {'entry': 'sdk_item', 'venderId': '11961298'}, 'content': '你好啊', 'sid': '538fc3761474ea693812ceed4b39639c'}, 'type': 'chat_message', 'clientTime': 1755592905140, 'datetime': '2025-08-19 16:41:45', 'len': 0, 'from': {'app': 'im.customer', 'art': '', 'clientType': 'android', 'pin': 'jd_thpotntctwys'}, 'subType': 'text', 'id': 'd31d369f17f24b05abbe2b7c334f340e', 'to': {'app': 'im.waiter', 'clientType': 'comet', 'pin': 'KLD测试'}, 'lang': 'zh_CN', 'timestamp': 1755592905232} + # {'ver': '4.2', 'mid': 366566984, 'body': {'chatinfo': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '5b5e044c73ee243b7e67eeca5b11393c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01ZC7NRD2EX45UN4Q5IZUQC4VLKXIKR7LWP2HC45VQRBDXEYHACT6U5KFBIAI52JBHYCO5BLMOHXTYUYU35RQPB2XA37HL4MPP7CXET7Q01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'param': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '5b5e044c73ee243b7e67eeca5b11393c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01ZC7NRD2EX45UN4Q5IZUQC4VLKXIKR7LWP2HC45VQRBDXEYHACT6U5KFBIAI52JBHYCO5BLMOHXTYUYU35RQPB2XA37HL4MPP7CXET7Q01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'type': 'text', 'requestData': {'entry': 'sdk_item', 'venderId': '11961298'}, 'content': '您好', 'sid': '5b5e044c73ee243b7e67eeca5b11393c'}, 'type': 'chat_message', 'clientTime': 1755595443735, 'datetime': '2025-08-19 17:24:03', 'len': 0, 'from': {'app': 'im.customer', 'art': '', 'clientType': 'android', 'pin': 'jd_thpotntctwys'}, 'subType': 'text', 'id': '800deaf802f9436b98937bb084ee2a56', 'to': {'app': 'im.waiter', 'clientType': 'comet', 'pin': 'KLD测试'}, 'lang': 'zh_CN', 'timestamp': 1755595443839} + # {'ver': '4.2', 'mid': 366566986, 'body': {'chatinfo': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '5b5e044c73ee243b7e67eeca5b11393c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01ZC7NRD2EX45UN4Q5IZUQC4VLKXIKR7LWP2HC45VQRBDXEYHACT6U5KFBIAI52JBHYCO5BLMOHXTYUYU35RQPB2XA37HL4MPP7CXET7Q01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'param': {'venderId': '11961298', 'isJdSuperMarket': '0', 'pid': '10143502227300', 'source': 'jimitwo_service_smart_sdk', 'deviceNo': 'dd_dvc_aes_30EA91E824A2F36365F7B7193C10B76A8842E4E08C0DA687EC9BEB307FCF7195', 'label': 1, 'IMService': False, 'distinguishPersonJimi': 2, 'proVer': 'smart_android_15.2.0', 'sid': '5b5e044c73ee243b7e67eeca5b11393c', 'entry': 'sdk_item', 'leaveMsgTable': 1, 'venderName': 'TYBOY康路达数字科技专卖店', 'disputeId': -1, 'ddSessionType': '1', 'appId': 'im.waiter', 'systemVer': 'android_13_V2239A', 'eidtoken': 'jdd01ZC7NRD2EX45UN4Q5IZUQC4VLKXIKR7LWP2HC45VQRBDXEYHACT6U5KFBIAI52JBHYCO5BLMOHXTYUYU35RQPB2XA37HL4MPP7CXET7Q01234567', 'auctionType': '0', 'region': 'CN', 'verification': 'slide'}, 'type': 'text', 'requestData': {'entry': 'sdk_item', 'venderId': '11961298'}, 'content': '我先自己看看谢谢您', 'sid': '5b5e044c73ee243b7e67eeca5b11393c'}, 'type': 'chat_message', 'clientTime': 1755595460153, 'datetime': '2025-08-19 17:24:20', 'len': 0, 'from': {'app': 'im.customer', 'art': '', 'clientType': 'android', 'pin': 'jd_thpotntctwys'}, 'subType': 'text', 'id': 'a3d4de984f2d4811952f8ba872850bc2', 'to': {'app': 'im.waiter', 'clientType': 'comet', 'pin': 'KLD测试'}, 'lang': 'zh_CN', 'timestamp': 1755595460274} + except Exception as e: + logger.error(f"接收对应监控消息时候产生特殊错误 , 错误信息为{e}") + + finally: + # 清理资源 + heartbeat_task.cancel() + try: + await heartbeat_task + except asyncio.CancelledError: + pass + self._log("🔄 连接断开,准备重连", "INFO") + except websockets.ConnectionClosed as e: + self._log(f"🔌 连接已关闭: {e.code} {e.reason}", "WARNING") + if not await self.handle_reconnect(e): + break + + except (websockets.WebSocketException, aiohttp.ClientError, OSError) as e: + self._log(f"🌐 网络异常: {type(e).__name__} - {str(e)}", "WARNING") + if not await self.handle_reconnect(e): + break + + except Exception as e: + self._log(f"⚠️ 未知异常: {type(e).__name__} - {str(e)}", "ERROR") + if not await self.handle_reconnect(e): + break + + # 关闭后端服务连接 + if self.backend_connected: + await self.backend_service.close() + self.backend_connected = False + self._log("🛑 消息监听已停止", "INFO") + + +# 新增: GUI集成包装器类 +# class JDListenerForGUI: +# """用于GUI集成的JD监听包装器 ()""" +# +# def __init__(self, log_callback=None): +# self.fix_jd_util = FixJdCookie(log_callback) +# self.log_callback = log_callback +# self.running = False +# self.stop_event = None +# self.username = None +# self.password = None +# +# def _log(self, message, log_type="INFO"): +# """处理日志输出""" +# if self.log_callback: +# self.log_callback(message, log_type) +# else: +# print(f"[{log_type}] {message}") +# +# async def start_listening(self, username, password): +# """启动监听的主方法""" +# try: +# # 存储用户名和密码 +# self.username = username +# self.password = password +# +# self._log("🔵 开始JD平台连接流程", "INFO") +# print("🔵 开始JD平台连接流程 - 调试断点1") +# +# # 1. 获取店铺信息 +# self._log("🔵 步骤2: 获取店铺信息...", "INFO") +# print("🔵 步骤2: 获取店铺信息... - 调试断点2") +# store_today = self.fix_jd_util.get_today_store() +# if not store_today: +# self._log("❌ 未找到店铺信息", "ERROR") +# print("❌ 未找到店铺信息") +# return False +# self._log(f"✅ 获取到店铺信息: {store_today.get("id", '未知')}", "SUCCESS") +# print(f"✅ 获取到店铺信息: {store_today.get("id", '未知')}") +# +# # 2. 连接后端服务获取cookie +# self._log("🔵 步骤3: 连接后端服务获取cookie...", "INFO") +# store_id = str(store_today.get('id', '')) +# +# jd_cookie = await self.fix_jd_util.connect_backend_service(store_id, username, password) +# +# if not jd_cookie or not jd_cookie.get('status'): +# self._log("❌ 从后端服务获取cookie失败", "ERROR") +# if jd_cookie and jd_cookie.get('verify_link'): +# self._log(f"❌ 需要验证登录,验证链接: {jd_cookie.get('verify_link')}", "ERROR") +# return False +# +# self._log("✅ 从后端服务获取cookie成功", "SUCCESS") +# cookies_str = jd_cookie.get('cookie') +# self._log(f"📦 获取到cookie: {cookies_str[:50] + '...' if cookies_str else '无'}", "DEBUG") +# +# # 3. 获取配置信息 +# self._log("🔵 步骤4: 获取配置信息...", "INFO") +# config = None +# for i in range(3): +# try: +# config = self.fix_jd_util.get_config(cookies_str) +# if config and config.get('data'): +# self._log(f"✅ 第{i + 1}次尝试获取配置成功", "SUCCESS") +# break +# else: +# self._log(f"⚠️ 第{i + 1}次尝试获取配置返回空数据", "WARNING") +# except Exception as e: +# self._log(f"获取配置异常({i + 1}/3): {str(e)}", "WARNING") +# await asyncio.sleep(3) +# +# if not config or not config.get('data'): +# self._log("获取配置失败", "ERROR") +# return False +# +# # 4. 提取必要参数 +# self._log("🔵 步骤5: 提取配置参数...", "INFO") +# aid = config["data"].get("aid") +# vender_id = config["data"].get("venderId") +# pin_zj = config["data"].get("pin", "").lower() +# +# if not all([aid, vender_id, pin_zj]): +# self._log("❌ 登录信息不完整", "ERROR") +# return False +# +# self._log(f"获取到配置: aid={aid}, vender_id={vender_id}, pin_zj={pin_zj}", "INFO") +# +# # 5. 启动监听 +# self._log("🔵 步骤6: 启动消息监听...", "INFO") +# self.stop_event = asyncio.Event() +# self.running = True +# +# self._log("🎉开始监听JD平台消息...", "SUCCESS") +# +# # 调用实际的监听方法 +# await self.fix_jd_util.message_monitoring( +# cookies_str=cookies_str, +# aid=aid, +# pin_zj=pin_zj, +# vender_id=vender_id, +# store=store_today, +# stop_event=self.stop_event, +# username=username, +# password=password +# ) +# +# return True +# +# except Exception as e: +# self._log(f"监听过程中出现严重错误: {str(e)}", "ERROR") +# import traceback +# self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") +# return False +# +# def stop_listening(self): +# """停止监听""" +# if self.stop_event: +# self.stop_event.set() +# self.running = False +# self._log("JD监听已停止", "INFO") + +# 新增: GUI集成包装器类 +class JDListenerForGUI: + """用于GUI集成的JD监听包装器 ()""" + + def __init__(self, log_callback=None): + self.fix_jd_util = FixJdCookie(log_callback) + self.log_callback = log_callback + self.running = False + self.stop_event = None + + def _log(self, message, log_type="INFO"): + """处理日志输出""" + if self.log_callback: + self.log_callback(message, log_type) + else: + print(f"[{log_type}] {message}") + + async def start_listening(self, username, password): + """启动监听的主方法""" + try: + self._log("🔵 开始JD平台连接流程", "INFO") + print("🔵 开始JD平台连接流程 - 调试断点1") + + # 1. 获取店铺信息 + self._log("🔵 步骤2: 获取店铺信息...", "INFO") + print("🔵 步骤2: 获取店铺信息... - 调试断点2") + store_today = self.fix_jd_util.get_today_store() + if not store_today: + self._log("❌ 未找到店铺信息", "ERROR") + print("❌ 未找到店铺信息") + return False + self._log(f"✅ 获取到店铺信息: {store_today.get("id", '未知')}", "SUCCESS") + print(f"✅ 获取到店铺信息: {store_today.get("id", '未知')}") + + cookie_str = store_today.get('platform_cookie') + self._log(f"📦 当前存储的cookie: {cookie_str[:50] + '...' if cookie_str else '无'}", "DEBUG") + + # 2. 获取或更新cookie - 在这里设置断点② + self._log("🔵 步骤3: 获取或更新JD cookie...", "INFO") + # 2. 获取或更新cookie + jd_login_cookie = self.fix_jd_util.get_cookies( + username=username, + password=password, + cookies_str=cookie_str + ) + + if not jd_login_cookie['status']: + fail_status = jd_login_cookie.get('verify_link', None) + if fail_status: + self._log(f"❌ JD登录失败: , 失败类型为二次验证(手机验证码) 对应url:{fail_status}", "ERROR") + else: + # 表示没有返回verify_url 未知错误 + self._log(f"❌ JD登录失败: , 失败类型为:{fail_status} 未知错误 请单独测试login方法") + return False + + self._log("✅ JD登录成功", "SUCCESS") + self._log(f"📦 获取到cookie: {jd_login_cookie['cookie'][:50] + '...'}", "DEBUG") + + self._log("🔵 步骤4: 获取配置信息...", "INFO") + # 3. 获取配置信息 + config = None + for i in range(3): + try: + config = self.fix_jd_util.get_config(jd_login_cookie['cookie']) + if config and config.get('data'): + self._log(f"✅ 第{i + 1}次尝试获取配置成功", "SUCCESS") + break + else: + self._log(f"⚠️ 第{i + 1}次尝试获取配置返回空数据", "WARNING") + except Exception as e: + self._log(f"获取配置异常({i + 1}/3): {str(e)}", "WARNING") + await asyncio.sleep(3) + + if not config or not config.get('data'): + self._log("获取配置失败", "ERROR") + return False + + # 4. 提取必要参数 + self._log("🔵 步骤5: 提取配置参数...", "INFO") + aid = config["data"].get("aid") + vender_id = config["data"].get("venderId") + pin_zj = config["data"].get("pin", "").lower() + + if not all([aid, vender_id, pin_zj]): + self._log("❌ 登录信息不完整", "ERROR") + return False + + self._log(f"获取到配置: aid={aid}, vender_id={vender_id}, pin_zj={pin_zj}", "INFO") + + # 5. 启动监听 + self._log("🔵 步骤6: 启动消息监听...", "INFO") + self.stop_event = asyncio.Event() + self.running = True + + self._log("🎉开始监听JD平台消息...", "SUCCESS") + + # 调用实际的监听方法 + await self.fix_jd_util.message_monitoring( + cookies_str=jd_login_cookie['cookie'], + aid=aid, + pin_zj=pin_zj, + vender_id=vender_id, + store=store_today, + stop_event=self.stop_event + ) + + return True + + except Exception as e: + self._log(f"监听过程中出现严重错误: {str(e)}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + async def start_with_cookies(self, store_id: str, cookies: str): + """使用下发的cookies与store_id直接建立JD平台WS并开始监听""" + try: + self._log("🔵 [JD] 收到后端登录指令,开始使用cookies连接平台", "INFO") + + # 获取平台配置 + config = None + for i in range(3): + try: + config = self.fix_jd_util.get_config(cookies) + if config and config.get('data'): + self._log(f"✅ 第{i + 1}次尝试获取配置成功", "SUCCESS") + break + else: + self._log(f"⚠️ 第{i + 1}次尝试获取配置返回空数据", "WARNING") + except Exception as e: + self._log(f"获取配置异常({i + 1}/3): {str(e)}", "WARNING") + await asyncio.sleep(3) + + if not config or not config.get('data'): + self._log("获取配置失败", "ERROR") + return False + + aid = config["data"].get("aid") + vender_id = config["data"].get("venderId") + pin_zj = config["data"].get("pin", "").lower() + + if not all([aid, vender_id, pin_zj]): + self._log("❌ 登录信息不完整", "ERROR") + return False + + # 建立与后端的AI通道(确保使用GUI的store_id) + await self.fix_jd_util.connect_backend_service(store_id) + + # 启动监听 + self.stop_event = asyncio.Event() + self.running = True + store = {'id': store_id} + self._log("🎉 [JD] 开始监听平台消息", "SUCCESS") + + await self.fix_jd_util.message_monitoring( + cookies_str=cookies, + aid=aid, + pin_zj=pin_zj, + vender_id=vender_id, + store=store, + stop_event=self.stop_event + ) + return True + except Exception as e: + self._log(f"[JD] 监听过程中出现错误: {str(e)}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def stop_listening(self): + """停止监听""" + if self.stop_event: + self.stop_event.set() + self.running = False + self._log("JD监听已停止", "INFO") + + +async def main(): + username = "KLD测试" + password = "kld168168" + fix_jd_util = FixJdCookie() + store_today = fix_jd_util.get_today_store() + + # 检查店铺信息 + if not store_today: + logger.error("❌ 未找到店铺信息") + return + + store_id = str(store_today.get('id', '')) + logger.info(f"✅ 获取到店铺信息: {store_id}") + + try: + # 1. 直接连接后端服务获取 cookie + logger.info("🔵 步骤1: 连接后端服务获取 cookie...") + jd_cookie = await fix_jd_util.connect_backend_service(store_id, username, password) + print(f"完整的cookie数据: {jd_cookie}") + + if not jd_cookie or not jd_cookie.get('status'): + logger.error("❌ 从后端服务获取 cookie 失败") + if jd_cookie and jd_cookie.get('verify_link'): + logger.error(f"❌ 需要验证登录,验证链接: {jd_cookie.get('verify_link')}") + return + + cookies_str = jd_cookie.get('cookie') + logger.info("✅ 从后端服务获取 cookie 成功") + logger.debug(f"📦 获取到 cookie: {cookies_str[:50] + '...' if cookies_str else '无'}") + + # 测试cookie后端生成的有效性 + # cookies_str = "shshshfpa=112082d7-6f59-f35d-093a-e4c035938ab8-1754961318; shshshfpx=112082d7-6f59-f35d-093a-e4c035938ab8-1754961318; __jdu=17549613198151684402245; user-key=13d41f1d-5d8a-447e-a3d1-19c964e2fa13; __jdv=76161171|direct|-|none|-|1756259208627; areaId=18; ipLoc-djd=18-1482-48942-49052; pinId=EifU7rHmf-gwaaxnNveDFw; _tp=%2Bw%2Fs5xFMS9g0SkUd93EGxqh4USt1M5LwIyzTR4TbgCM%3D; _pst=KLD%E6%B5%8B%E8%AF%95; pin=KLD%E6%B5%8B%E8%AF%95; unick=u40d47u5ckctnz; PCSYCityID=CN_430000_430100_0; ceshi3.com=000; sdtoken=AAbEsBpEIOVjqTAKCQtvQu17tqE2au0-pftQOStCUKRw9JX4gfXHESNiN_EgrTvDv8qS5IZHipleuQxIX9JXWojJS8sKju6Vh1Qqt5LjakfSeWqqAOL-HhXeBn9m; shshshfpb=BApXS1gvPG_xA1izHnR4d6bvzjbeOVTtiBhbXFDdg9xJ1Mh6uh462; 3AB9D23F7A4B3CSS=jdd03OFWZGTHWHQYLKSX5BEWHXMTLYAHXEEXC7HBOIZDBIPLMQZT5LTHKICALRZU5ZDL6X6T3NMHRNSJJDX6BTEI6AVJS5IAAAAMZDDKTS5YAAAAACJZVYQP7FYJA3UX; _gia_d=1; wlfstk_smdl=0whbpvk7ixj27lbykeeb8rh6iulon3fo; __jda=95931165.17549613198151684402245.1754961320.1757039732.1757053789.21; __jdb=95931165.30.17549613198151684402245|21.1757053789; __jdc=95931165; 3AB9D23F7A4B3C9B=OFWZGTHWHQYLKSX5BEWHXMTLYAHXEEXC7HBOIZDBIPLMQZT5LTHKICALRZU5ZDL6X6T3NMHRNSJJDX6BTEI6AVJS5I; TrackID=1C24wlDX-QPSyJRaB_1YHqCLhBW6qIo2stht_nwl5g9fGI-lJpP-CZT3TaCr9QVppcvhilhcCe1VhgXMKGWao6Fd3wJ5bQhJ9w9VwWcYOySsXfbCTQbteFWevVN1ZQYp9; thor=4E136F9D9458703D01BE17544D30601F9649F79B89E5FC150CA91054C788CAA1C82670080466F219573AE7FD6EB9ABDF9F52D520671373DAD721CC3B78613FABC99ADA1FAC8E92CDC42F5131682B1F008727F1BA49783B055AFED9349D0B79E53A51F059A1DDE3FC181DD38D1B388D829CE8ADD775D0D30C38A8CAD0519DCD0C; flash=3_KFKaImBVn2spH8stTd9wjKlZQTxgYcZCPXXP_axvJMphR3w29aJNU2c2qPReKxWHRX1lzJ7MfD9iQmHQI-2cKp0dYzs6YsH9eDyB3lQxuu6MtkM8jCiBynVSdRBnr21oDrLKGMeYG6yYlcEsAsbe8OC-yKO69758MJYyMZd_4soV; light_key=AASBKE7rOxgWQziEhC_QY6yakCROyWTrRIF9K9uCpw_IcR8gGNaL7IM6AQuVa-3pJoC9wTze; logining=1; rita=A1EA9FF92ADE7FC61C825E83F126B9E97EF9243BEED9B77E4F7110D6081254A8EEAA66B26BFA00E08CBD8B0C88DD3D292CAD14839A50184501755B761A11F679F63D9DAA76E6785799D2F78AE378F76F32E05C1914C1132995B15CC5F79AFB9314A9D6FE7911DAFE1D958906C016E724" + + # 2. 获取配置信息 + logger.info("🔵 步骤2: 获取配置信息...") + config = None + for i in range(3): + try: + config = fix_jd_util.get_config(cookies_str) + if config and config.get('data'): + logger.info(f"✅ 第{i + 1}次尝试获取配置成功") + break + else: + logger.warning(f"⚠️ 第{i + 1}次尝试获取配置返回空数据") + except Exception as e: + logger.error(f"获取配置异常({i + 1}/3): {e}") + if i == 2: + return + await asyncio.sleep(3) # 使用异步等待 + + if not config or not config.get('data'): + logger.error("❌ 获取配置失败") + return + + # 3. 提取必要参数 + logger.info("🔵 步骤3: 提取配置参数...") + aid = config["data"].get("aid") + vender_id = config["data"].get("venderId") + pin_zj = config["data"].get("pin", "").lower() + + if not all([aid, vender_id, pin_zj]): + logger.error("❌ 登录信息不完整,需要重新登录") + return + + logger.info(f"✅ 获取到配置: aid={aid}, vender_id={vender_id}, pin_zj={pin_zj}") + + # 4. 启动监听 + logger.info("🔵 步骤4: 启动消息监听...") + stop_event = asyncio.Event() + + try: + await fix_jd_util.message_monitoring( + cookies_str=cookies_str, + aid=aid, + pin_zj=pin_zj, + vender_id=vender_id, + store=store_today, + stop_event=stop_event, + username=username, + password=password + ) + except Exception as e: + logger.error(f"❌ 监听过程中出现错误: {e}") + import traceback + logger.error(f"错误详情: {traceback.format_exc()}") + + except Exception as e: + logger.error(f"❌ 主程序执行过程中出现错误: {e}") + import traceback + logger.error(f"错误详情: {traceback.format_exc()}") + + +if __name__ == '__main__': + asyncio.run(main()) + # asyncio.run(new_test_login()) diff --git a/Utils/JD/__init__.py b/Utils/JD/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utils/Pdd/PddUtils.py b/Utils/Pdd/PddUtils.py new file mode 100644 index 0000000..8716b3d --- /dev/null +++ b/Utils/Pdd/PddUtils.py @@ -0,0 +1,1178 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +""" +@Project :magua_project +@File :PddUtils.py +@IDE :PyCharm +@Author :lz +@Date :2025/7/17 16:44 +""" +import os +import threading +from concurrent.futures import ThreadPoolExecutor +import base64 +import json +import random +import time +import traceback +import websockets +import requests +import asyncio +import execjs +from datetime import datetime +from typing import Dict, Any, Optional, Callable + +from Utils.message_models import PlatformMessage + + +# 定义持久化数据类 - 参考京东的WebsocketManager +class WebsocketManager: + _instance = None + _lock = threading.Lock() + + def __new__(cls): + if cls._instance is None: + with cls._lock: + if cls._instance is None: + cls._instance = super().__new__(cls) + cls._instance._store = {} + cls._instance._lock = threading.RLock() + return cls._instance + + def on_connect(self, shop_key, ws, **kwargs): + """完全保持原有数据结构""" + with self._lock: + entry = self._store.setdefault(shop_key, { + 'platform': None, + 'customers': [], + 'user_assignments': {} + }) + entry['platform'] = { + 'ws': ws, # 注意:这里存储的是强引用 + 'last_heartbeat': datetime.now(), + **kwargs + } + return entry + + def get_connection(self, shop_key): + with self._lock: + return self._store.get(shop_key) + + def remove_connection(self, shop_key): + with self._lock: + if shop_key in self._store: + del self._store[shop_key] + + +class PddBackendService: + """拼多多后端服务调用类(新版:使用统一后端连接 BackendClient)""" + + def __init__(self): + self.current_store_id = None + + async def connect(self, store_id): + """连接后端服务(使用统一连接,无需独立连接)""" + self.current_store_id = store_id + return True + + async def send_message_to_backend(self, platform_message): + """改为通过单后端连接发送,需携带store_id""" + try: + from WebSocket.backend_singleton import get_backend_client + backend = get_backend_client() + if not backend: + return None + + # 确保消息包含store_id + if isinstance(platform_message, dict): + if 'store_id' not in platform_message and self.current_store_id: + platform_message['store_id'] = self.current_store_id + + # 通过统一后端连接发送 + backend.send_message(platform_message) + return True + except Exception: + return None + + +class ChatPdd: + @staticmethod + def check_js_files(): + """检查JS文件是否存在""" + current_dir = "static/js" + required_files = ["dencode_message.js", "encode_message.js"] + + for file in required_files: + file_path = os.path.join(current_dir, file) + if not os.path.exists(file_path): + raise FileNotFoundError(f"找不到必需的JS文件: {file_path}") + + return True + + def __init__(self, cookie, chat_list_stat, csname=None, text=None, log_callback=None): + # 检查JS文件 + self.check_js_files() + + # 获取JS文件路径 + current_dir = "static/js" + dencode_js_path = os.path.join(current_dir, "dencode_message.js") + encode_js_path = os.path.join(current_dir, "encode_message.js") + + # 读取JS文件 + try: + with open(dencode_js_path, 'r', encoding='utf-8') as f: + jscode = f.read() + self.ctx = execjs.compile(jscode) + + with open(encode_js_path, 'r', encoding='utf-8') as f: + ejscode = f.read() + self.encodeex = execjs.compile(ejscode) + except Exception as e: + raise RuntimeError(f"读取JS文件失败: {str(e)}") + + # 首先设置log_callback,然后才能使用_log方法 + self.log_callback = log_callback + self._log("初始化ChatPdd实例", "INFO") + + self.chat_list_stat = chat_list_stat + self.text = text + self.cookie = cookie + self.auth_token = None + self.mall_id = None + self.user_id = None + self.csname = csname + self.csid = None + self.staff_list_sent = False + self.uids = set() + self.pool = ThreadPoolExecutor(max_workers=4) + + # WebSocket管理器 + self.ws_manager = WebsocketManager() + + # 后端服务实例 + self.backend_service = PddBackendService() + self.backend_connected = False + + # 重连参数 + self.reconnect_attempts = 0 + self.max_reconnect_attempts = 10 + self.base_reconnect_delay = 1.0 + self.max_reconnect_delay = 60.0 + self.reconnect_backoff = 1.5 + + self.headers = { + "authority": "mms.pinduoduo.com", + "accept": "*/*", + "accept-language": "zh-CN,zh;q=0.9", + "anti-content": "0asWfxUeM_VefxObk-_v-fwmt7oS3cmHsWwMkApMVigWOS3hCHfBeF-hHM1_v9LHywCtfzDKkA_F1cUE8_HKBA5D7fVkM2ZDB-KmMxhDM51HXlVrfK_LG4Dc3S0wimw8XYPyXdgJnUv8ndgjs0EynYv8n0XjXU9YXY4Pt0ZVgTgrsIUEeMzMk7s02E3oo-zMdF35CIMWVetBhs95lGG5xENwZwX0CwXH2799MeMjVKzk5DD4Kbs2dM1bD-fJ1F-RImB3SHBkVKDJZbZoUbL4UMk8DFtrISf8CMD4Obk_CM3ICIB_F90ws9ZQ0gcOpVdIIz2PLPVcYt5X0yqYiwjtuNVfdNSf0rmfmNIndXj8G8Nyn4ianRaanoucDp0Dfvd36B6eamPGwOFS0TAyo7nXH_nwxnGS28AgVnqPyPuy8jczb1Oe3xZuPHoJ97BBbaTMfV9OcQ23T-mAUel", + "cache-control": "no-cache", + "content-type": "application/json", + "origin": "https://mms.pinduoduo.com", + "pragma": "no-cache", + "referer": "https://mms.pinduoduo.com/chat-merchant/index.html?r=0.4940608191737519", + "sec-ch-ua": "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"", + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "\"Windows\"", + "sec-fetch-dest": "empty", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-origin", + "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + } + + self.store_id = "538727ec-c84d-4458-8ade-3960c9ab802c" # 可以根据需要修改 + self.user_tokens = {} # 存储用户token信息 + + def _log(self, message, level="INFO"): + """内部日志方法""" + if self.log_callback: + self.log_callback(message, level) + else: + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + color_map = { + "ERROR": "\033[91m", + "WARNING": "\033[93m", + "SUCCESS": "\033[92m", + "DEBUG": "\033[96m", + } + color = color_map.get(level, "") + reset = "\033[0m" + print(f"{color}[{timestamp}] [{level}] {message}{reset}") + + # 重连机制方法 + async def calculate_reconnect_delay(self): + """计算指数退避的重连延迟时间""" + delay = self.base_reconnect_delay * (self.reconnect_backoff ** self.reconnect_attempts) + return min(delay, self.max_reconnect_delay) + + async def should_reconnect(self): + """判断是否应该继续重连""" + if self.reconnect_attempts >= self.max_reconnect_attempts: + self._log(f"已达到最大重连次数({self.max_reconnect_attempts}),停止重连", "ERROR") + return False + return True + + async def handle_reconnect(self, exception=None): + """处理重连逻辑""" + if exception: + error_type = type(exception).__name__ + error_msg = str(exception) + self._log(f"连接异常[{error_type}]: {error_msg}", "WARNING") + + if not await self.should_reconnect(): + return False + + delay = await self.calculate_reconnect_delay() + self._log(f"第{self.reconnect_attempts + 1}次重连尝试,等待{delay:.1f}秒...", "WARNING") + + await asyncio.sleep(delay) + self.reconnect_attempts += 1 + return True + + # 后端服务调用方法 + async def connect_backend_service(self, store_id): + """连接后端AI服务""" + try: + success = await self.backend_service.connect(store_id) + if success: + self.backend_connected = True + self._log("✅ 后端AI服务连接成功", "SUCCESS") + return success + except Exception as e: + self._log(f"❌ 连接后端AI服务失败: {e}", "ERROR") + return False + + async def get_ai_reply_from_backend(self, platform_message): + """发送消息到后端(使用统一连接,不等待回复)""" + # 首先检查后端服务连接状态 + if not self.backend_connected: + # 尝试重新连接 + if self.store_id: + self.backend_connected = await self.connect_backend_service(self.store_id) + + if not self.backend_connected: + self._log("❌ 后端服务未连接,尝试重新连接失败", "WARNING") + return None + + try: + # 发送消息到后端(使用统一连接,不等待回复) + await self.backend_service.send_message_to_backend(platform_message) + self._log("✅ 消息已发送到后端,等待后端AI处理并通过GUI转发回复", "INFO") + return None + + except Exception as e: + self._log(f"❌ 发送消息到后端失败: {e}", "ERROR") + return None + + def get_auth_token(self): + url = "https://mms.pinduoduo.com/janus/api/subSystem/getAuthToken" + data = {"subSystemId": 17, + "anti_content": "0asAfx5E-wCElqJNXaKt_UKccG7YNycjZoPYgO1YTmZoApN7QJU5XT_JuYdPZ4uvLPQFgIcyXOKqm8xGrPjy0lxn0gaXr9ac0TynYEJnDwdj-WEJnwK3G4kc3M0TiPgtB11eBeZkB1hkBxUHFOtjfqz-eAkgc2aa4sZuIJwHOptYX14VK1NJSqIYfqmw6jpQTXs574CfWMFxT1RPTIB2MKBjC199pXpkbdtXxnn2mA4C1YdNnTUrNa_Wvn5mYj5XadnDbNT7xNuVeYXrsTsiipUr6xn2AAXKoYmv6j0PL92PtCTMfZzzfTfjutCgvBTzxFw-2LeeRIkFBATU1Npg1ScUFRv-1Ukrs3AklVAbBiEbBJhzcf2cXKfNH50X9QUFCd_Y1FhLW1BBuI-KEUFYK3lZTB3g_BlLDk8ti-JXmbalXzWAb6V2hX0fZE9n2L0GITFInNS"} + response = requests.post(url, cookies=self.cookie, headers=self.headers, json=data).json() + self.auth_token = response["result"]["authToken"] + + def get_mall_id(self): + url = "https://mms.pinduoduo.com/chats/userinfo/realtime?get_response=true" + data = {"get_response": "true"} + response = requests.get(url, cookies=self.cookie, headers=self.headers, params=data).json() + self.mall_id = response["mall_id"] + self.user_id = response["id"] + + def get_assign_cslist(self): + url = "https://mms.pinduoduo.com/latitude/assign/getAssignCsList" + data = { + "wechatCheck": True + } + data = json.dumps(data, separators=(',', ':')) + response = requests.post(url, headers=self.headers, cookies=self.cookie, data=data).json() + cslist = response["result"]["csList"] + keys = cslist.keys() + for key in keys: + username = cslist[key].get("username") + if username == self.csname: + self.csid = key + break + + def tab_mall(self, uid): + """执行转接操作""" + self._log(f"🔄 开始执行转接操作 - 用户ID: {uid}, 目标客服ID: {self.csid}", "INFO") + + try: + url = "https://mms.pinduoduo.com/plateau/chat/move_conversation" + request_id = int(time.time() * 1000) + + data = { + "data": { + "cmd": "move_conversation", + "request_id": request_id, + "conversation": { + "csid": self.csid, + "uid": uid, + "need_wx": False, + "remark": "无原因直接转移" + }, + "anti_content": "0asAfxvYXyIgYgE2h9U0sXh6Ia3tZOAzI_rl3hixs1Z5DB-B1cswVK2UB8LfUO8H3OUKdF214-SgPVnY8SYvSdmwnKDoPXAs4OdtzfKwkT6gAO2d4R8ZVTw3a7j9BdB3Hmq7j0bh2LQrRzlt88pkQr-s3jMzWH5QPiz13wQNsJY6h9dnigBE26Ww1dKZcWbsKS4GsgY9_joGBS2FZUz94cbCvE2Ij9nO93b5kR50m9kI1lfBHvDZVIC9rLB-S4Qs4J9ebSsosuNskY9nhgXzCuNoilSQgJaMkP2Rgga2i54nWTTNfnZ4W9GvigkSnwzweN9sx-89BztNCasVkP2C2Kkipif2Dv-t7e2O9MnmtWaKm4wFlHLR7YmeyF3y5gxPRuHlO-gD7BfFle8z71lIV-7SyOLCd83FMUCsRwedwv3-TNTF_VRw_G1DHrptFYTAck8p8qIkxA_PZ14PXct1ZS2zAoZZcTMZZSpJ1jP9RlQARtnNNP0IzCdHiL4JzRQBkkKmwGGXay0i4urnXNm5qBgejFcVCkx8XYdeGBp4p-l1TjKoy603__johKFKZQksRHjOKma5DplwQwg8c3Uo1-mDAUmgAC0XfV2rkxzXj3ABARPlyEaMU8AxUZioaFRa0e5eit6r06uY9m5SyU_mdbTfLIYcKWjRA_UNQisJOUenCbMl_Bywq1KcA6TTzJ9ZHu4xz0o7ctROYLlvhEhAi3bJjFNho6l-TPZK4zSJoj" + }, + "client": "WEB", + "anti_content": "0asAfxvYXNIgYgd2i9U0sXh6IabtZOAdI_LlbhNUvZZ5DB-B1cswVK2UBjxfUOjHbOUKdF214-SgPVnYjSYvSdmwnKDoPXAs4OdtzfKwkT6gAO2d4RjZVTwbJFiC0P0rR6LbH89rLVuGHiG6vm3fO6rq_rAyLQlw8CAIuESMR4L308Ctz3V0m9ZhS8tdapQr_YY2vZZk9sAJsMd2ZapG92zm2lO9FLVBjCur2KWwac9nua9g8ztOawyo9ur0Dd96xMkCXrd4J4hR4Kk9zqZBDTlRPkMdzzkJ5Osgi40EC3oVAhSPA9MawGCs33Vnd4bSJER9_b_D9g1sfdeZZKsgo25k0WRfs7dM17E2ug-pPEL5_ib53TuaxLHJq5pGG4jMUjAHRV-gbDffut1Yjy1A7K-6E3zO4tDuUq5T0LPHjf9bB7Apofgr_U_4Aq-7l8x2ks8DhhgOhblTvwrO4owZvuUXA0hfSIUPYK9fIoSUH6aaL8abMMVCvI__qF8Yw1oaMp0d0-fbwMhXQ8fBZYoajXXJv-RV3B2GQEowvMHEUtjDz50jUVduq5fKL9R-WsBRjX0aiExVKLw-PZzxsVup0ZuOYxnPofN92EqKfbvriIWFMsh80eGrvq1vsD1BrMx_mcPMmUmHHEY7wct5lePa0b2Lt5_byqRbbcpohrQrHLlH6JJaTMKQuffyT-60110e5oz_Cz0NbG88TyxOGKijW7BimL5RTjSOTPsK4zS8oi" + } + + self._log(f"📤 发送转接请求 - URL: {url}", "DEBUG") + self._log(f"📝 请求数据: {json.dumps(data, ensure_ascii=False)}", "DEBUG") + + data_str = json.dumps(data, separators=(',', ':')) + response = requests.post(url, headers=self.headers, cookies=self.cookie, data=data_str) + + self._log(f"📥 HTTP状态码: {response.status_code}", "DEBUG") + self._log(f"📄 响应内容: {response.text}", "DEBUG") + + # 解析响应 + try: + result = response.json() + self._log(f"🔍 解析后的响应: {json.dumps(result, ensure_ascii=False)}", "DEBUG") + + # 检查响应结构 + if result.get("success"): + result_data = result.get("result", {}) + if result_data.get("result") == "success" or result_data.get("result") == "ok": + self._log(f"✅ 转接成功 - 用户 {uid} 已转接给客服 {self.csid}", "SUCCESS") + return True + else: + error_code = result_data.get("error_code", "未知") + error_msg = result_data.get("error_msg", "未知错误") + self._log(f"❌ 转接失败 - 错误码: {error_code}, 错误信息: {error_msg}", "ERROR") + return False + else: + self._log(f"❌ 转接请求失败 - 响应标记为失败", "ERROR") + return False + + except json.JSONDecodeError as e: + self._log(f"❌ 解析响应JSON失败: {e}", "ERROR") + self._log(f"❌ 原始响应: {response.text}", "ERROR") + return False + + except requests.RequestException as e: + self._log(f"❌ 请求异常: {e}", "ERROR") + return False + except Exception as e: + self._log(f"❌ 转接操作异常: {e}", "ERROR") + traceback.print_exc() + return False + + @staticmethod + def forward_message_to_platform(store_id: str, recv_pin: str, content: str): + """转发消息到拼多多平台""" + try: + pdd_mgr = WebsocketManager() + pdd_shop_key = f"拼多多:{store_id}" + pdd_entry = pdd_mgr.get_connection(pdd_shop_key) + if pdd_entry: + # 找到拼多多连接,使用拼多多转发逻辑 + platform_info = pdd_entry.get('platform') or {} + ws = platform_info.get('ws') + loop = platform_info.get('loop') + pdd_instance = platform_info.get('pdd_instance') # ChatPdd实例引用 + print( + f"[PDD Forward] shop_key={pdd_shop_key} has_ws={bool(ws)} has_loop={bool(loop)} has_pdd_instance={bool(pdd_instance)} recv_pin={recv_pin}") + if ws and loop and pdd_instance: + async def _send_pdd(): + # 直接调用ChatPdd实例的send_ai_reply方法 + await pdd_instance.send_ai_reply(recv_pin, content) + + import asyncio as _asyncio + _future = _asyncio.run_coroutine_threadsafe(_send_pdd(), loop) + try: + _future.result(timeout=5) # 拼多多需要HTTP请求,给更长时间 + print(f"[PDD Forward] 已转发到平台: uid={recv_pin}, content_len={len(content)}") + except Exception as fe: + print(f"[PDD Forward] 转发提交失败: {fe}") + else: + print("[PDD Forward] 条件不足,未转发:", + {'has_ws': bool(ws), 'has_loop': bool(loop), 'has_pdd_instance': bool(pdd_instance), + 'has_content': bool(content)}) + else: + print(f"[PDD Forward] 未找到拼多多连接: {pdd_shop_key}") + except Exception as e: + print(f"[PDD Forward] 拼多多转发失败: {e}") + + @staticmethod + def transfer_customer_service(customer_service_id: str, user_id: str, store_id: str): + """拼多多平台转接""" + try: + pdd_mgr = WebsocketManager() + pdd_shop_key = f"拼多多:{store_id}" + pdd_entry = pdd_mgr.get_connection(pdd_shop_key) + if pdd_entry: + platform_info = pdd_entry.get('platform') or {} + pdd_instance = platform_info.get('pdd_instance') + loop = platform_info.get('loop') + + print(f"[PDD Transfer] 找到拼多多连接,准备执行转接: user_id={user_id}, cs_id={customer_service_id}") + + if pdd_instance and loop: + # 设置目标客服ID并执行转接 + pdd_instance.csid = customer_service_id + + def _transfer(): + result = pdd_instance.tab_mall(user_id) + if result: + print(f"[PDD Transfer] ✅ 转接成功") + else: + print(f"[PDD Transfer] ❌ 转接失败") + return result + + # 在线程池中执行同步转接操作 + import concurrent.futures + with concurrent.futures.ThreadPoolExecutor() as executor: + future = executor.submit(_transfer) + try: + future.result(timeout=10) # 转接操作可能需要更长时间 + except Exception as fe: + print(f"[PDD Transfer] 转接操作异常: {fe}") + else: + print(f"[PDD Transfer] 条件不足: has_pdd_instance={bool(pdd_instance)}, has_loop={bool(loop)}") + else: + print(f"[PDD Transfer] 未找到拼多多连接: {pdd_shop_key}") + except Exception as e: + print(f"[PDD Transfer] 拼多多转接失败: {e}") + + async def send_ai_reply(self, uid, content): + """发送AI回复给指定用户""" + self._log(f"开始发送AI回复给用户 {uid}", "INFO") + self._log(f"回复内容: {content[:50]}...", "DEBUG") + try: + ts = int(time.time() * 1000) + url = "https://mms.pinduoduo.com/plateau/chat/send_message" + data = { + "data": { + "cmd": "send_message", + "anti_content": "0asWfqzFdjPssgua6CCWyeEK7LAktf0_UFChvlj8kD8Mk1DVZchg4qURiKAS4iSfiaz9Fjg43ThZZ4_wNh5Onk0e5Tw2mGdwpTEPDZlPdfZwBpyESSDiz0Xalv6mvr0o0uQR6yRlG-vscbK8jYGRNcAr2UktX3bMKhjjx7YvVGbi_poiyypBuOwM_2qZyIM96tdNTfb_AMy0fe1UrN2SqUzfm2stmb4TJldGN9b1mTPr-6t4R9k3pquV_XHwBr20J4__P71fxPBmcXOmXTnQWJs2ddt4KKOIbPIIanas08VNiv9nsHbtvXKp8_CMdL8FQMPmEMDmM6JfjZ4LJp5l-x0BjpBbdWyoztNYqSbBe8hscA1hPFM_R1iR9E-AI-CyuehipODW-ADCL0xEWK875510RsV7mLFQKG0kWO--krZzFFi_6lhdfq3_JhBjDDd3YS1exxSMMS7yDJgskoumfAcu-y1YDO8OdcKWwx3Z0nOqUlnF8LekN7TqXhNtKTgfDZPThVT3JcNm_2TljXRhGWxTZT4o25TTVKo5KPeztcJU5NddFd38nmvo0k8R8HVIkmzOYyaerCDCm1ZDfYgNFx-2vM_JkcMYFdkV7C3BKeg7DxZXHfexAT3UKgruBWYrSs_dBB0X-QkJ2ZcmpStB6KJkZ1azrAAxdw_HMj5UIq4vEXxrA1-YAzJEhMoU0-MncDpoBZfiky7Sr4nDGYrcn86AAYWynOUn0US2DAkICABvSSqkh0vCRpdVeZRfOFsdFWF43KEIph-ckMxDsyq6G3rWXbvPkaAlv67cR1v0N2oCQzDVDT-InNv", + "request_id": ts, + "message": { + "to": { + "role": "user", + "uid": uid + }, + "from": { + "role": "mall_cs" + }, + "ts": int(ts / 1000), + "content": content, + "msg_id": None, + "type": 0, + "is_aut": 0, + "manual_reply": 1, + "status": "read", + "is_read": 1, + "hash": "1d1359dfb7c141fd95432a22cdc7f43b51434041a1a6016ef6ea2ea2b1abc05a" + }, + "random": "c5fc9c61194294c478a6fb395b1c558f" + }, + "client": "WEB", + "anti_content": "0asAfa5E-wCEsa-JeFwdFfTDtzhMbODIsAT-eu_-CigAHMbcWIfBEUFcI-Kwd93IYTWtfvkSeuwUKO57jwISBuZkzfCe-2VkBFSD-ack-ZKIXRockMwxBgyDql6V3xKKD-fCkBFZkzeKeBwUE-cSD-KHkBb-kzFVk-szd009EAPjDvBcaPIXxHGB_IxWWlIXMnxghvniTodnXt2scz7sxhJV_CEBcCez4H92maXI2d1qgoYswoG4Mf_oylph0nGigjnqWzXqwTYh0y4W6yYs6PxHyXv8slpHrXyseoqZhfqdrdn5E9BCt24mBfkEFg-vgc0wUw2D-vgE7KUM1FIdKb2_Mbl_6xj_8bvk-e1H6ObSksLCDiVCDAbkYU6Y_SMBfgA5CHUM0QuYhznXIwnTanGM2jugCnxPYPmYjyOvjKHEbaV3nvMuJ6V2cX0fZE99vcfY3TF1nNr" + } + data = json.dumps(data, separators=(',', ':')) + response = await asyncio.get_event_loop().run_in_executor( + self.pool, + lambda: requests.post(url, headers=self.headers, cookies=self.cookie, data=data) + ) + + # 打印HTTP状态与返回体片段 + self._log(f"PDD发送状态: HTTP {response.status_code}", "INFO") + try: + self._log(f"PDD返回体: {response.text[:500]}", "DEBUG") + except Exception: + pass + + if response.status_code == 200: + self._log(f"✅ 已发送AI回复给用户 {uid}: {content}", "SUCCESS") + return True + else: + self._log(f"❌ 发送AI回复失败,HTTP状态码: {response.status_code}", "ERROR") + self._log(f"响应内容: {response.text}", "DEBUG") + return False + + except Exception as e: + self._log(f"❌ 发送AI回复失败: {e}", "ERROR") + traceback.print_exc() + return False + + async def send_message_external(self, uid, content): + """外部消息发送接口,用于接收后端转发的回复""" + self._log(f"[External] 收到外部消息发送请求: uid={uid}, content_len={len(content) if content else 0}", "INFO") + try: + if not uid or not content: + self._log("❌ [External] 参数不完整", "ERROR") + return False + + result = await self.send_ai_reply(uid, content) + if result: + self._log(f"✅ [External] 外部消息发送成功: uid={uid}", "SUCCESS") + else: + self._log(f"❌ [External] 外部消息发送失败: uid={uid}", "ERROR") + return result + except Exception as e: + self._log(f"❌ [External] 外部消息发送异常: {e}", "ERROR") + return False + + async def get_all_customer(self, ws): + """异步获取客服列表""" + try: + # PDD获取客服列表的API + url = "https://mms.pinduoduo.com/latitude/assign/getAssignCsList" + data = { + "wechatCheck": True + } + data = json.dumps(data, separators=(',', ':')) + + # 使用线程池执行同步请求 + response = await asyncio.get_event_loop().run_in_executor( + self.pool, + lambda: requests.post(url, headers=self.headers, cookies=self.cookie, data=data) + ) + + if response.status_code == 200: + result = response.json() + cslist = result.get("result", {}).get("csList", {}) + print("我们收集到的客服列表原信息为:", str(cslist)) + if cslist: + # 转换客服列表格式 + self.customer_list = [] + for key, customer in cslist.items(): + customer_info = { + "staff_id": str(key), # 客服ID + "name": customer.get("username", ""), # 客服名称 + "status": customer.get("status", 0), # 状态 + "department": customer.get("department", ""), # 部门 + "online": True # 在线状态 + } + self.customer_list.append(customer_info) + self._log(f"✅ 成功获取客服列表,共 {len(self.customer_list)} 个客服", "SUCCESS") + return True + return False + except Exception as e: + self._log(f"❌ 获取客服列表失败: {e}", "ERROR") + return False + + async def send_staff_list_to_backend(self): + """发送客服列表到后端""" + try: + if not hasattr(self, 'customer_list') or not self.customer_list: + self._log("⚠️ 客服列表为空", "WARNING") + return False + + # 创建消息模板 + message_template = PlatformMessage( + type="staff_list", + content="客服列表更新", + data={ + "staff_list": self.customer_list, + "total_count": len(self.customer_list) + }, + store_id=self.store_id + ) + + # 通过后端服务发送 + await self.backend_service.send_message_to_backend(message_template.to_dict()) + self._log(f"发送客服列表消息的结构体为: {message_template.to_json()}") + self._log(f"✅ 成功发送客服列表到后端,共 {len(self.customer_list)} 个客服", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 发送客服列表到后端异常: {e}", "ERROR") + return False + + async def handle_transfer_message(self, message_data): + """处理转接消息""" + self._log("收到转接指令", "INFO") + try: + content = message_data.get("content", "") # 转接目标客服ID + receiver_info = message_data.get("receiver", {}) + uid = receiver_info.get("id") # 用户ID + + if not content or not uid: + self._log("❌ 转接消息信息不完整", "WARNING") + self._log(f"消息内容: {message_data}", "DEBUG") + return False + + self._log(f"准备将用户 {uid} 转接给客服 {content}", "INFO") + + # 设置转接目标客服ID + self.csid = content + + # 在线程池中执行同步的转接操作 + try: + # 使用线程池执行同步方法 + success = await asyncio.get_event_loop().run_in_executor( + self.pool, + self.tab_mall, + uid + ) + + if success: + self._log(f"✅ 转接成功: 用户 {uid} 已转接给客服 {content}", "SUCCESS") + return True + else: + self._log(f"❌ 转接失败: 用户 {uid}", "ERROR") + return False + + except Exception as e: + self._log(f"❌ 执行转接操作失败: {e}", "ERROR") + return False + + except Exception as e: + self._log(f"❌ 处理转接消息失败: {e}", "ERROR") + traceback.print_exc() + return False + + async def handle_customer_message(self, message_data): + """处理来自后端的客服消息""" + self._log("收到来自后端的客服消息", "INFO") + try: + content = message_data.get("content", "") + receiver_info = message_data.get("receiver", {}) + uid = receiver_info.get("id") + + if uid and content: + self._log(f"准备发送客服消息给用户 {uid}: {content}", "INFO") + await self.send_ai_reply(uid, content) + self._log(f"客服消息发送完成 - 目标用户: {uid}", "SUCCESS") + else: + self._log("客服消息数据不完整", "WARNING") + self._log(f"消息内容: {message_data}", "DEBUG") + except Exception as e: + self._log(f"处理客服消息失败: {e}", "ERROR") + traceback.print_exc() + + async def process_incoming_message(self, message_data, wss, store): + """处理接收到的消息""" + try: + message_info = message_data.get("message", {}) + if not message_info: + return + + nickname = message_info.get("nickname") + content = message_info.get("content") + goods_info = message_info.get("info", {}) + from_info = message_info.get("from", {}) + uid = from_info.get("uid") + + if nickname and content and uid: + self._log(f"用户消息 - {nickname}: {content}", "INFO") + self._log(f"用户UID: {uid}", "DEBUG") + self.uids.add(uid) + + # 消息类型检测 + lc = str(content).lower() + if any(ext in lc for ext in [".jpg", ".jpeg", ".png", ".gif", ".webp"]): + msg_type = "image" + elif any(ext in lc for ext in [".mp4", ".avi", ".mov", ".wmv", ".flv"]): + msg_type = "video" + else: + msg_type = "text" + + # 订单卡片组装(使用全角冒号,符合文档) + if "订单编号" in str(content) and goods_info: + content = f"商品id:{goods_info.get('goodsID')} 订单号:{goods_info.get('orderSequenceNo')}" + msg_type = "order_card" + + # 商品卡片检测(基于内容关键词和goods_info) + elif any(keyword in lc for keyword in ['goods.html', 'item.html', 'item.jd.com', '商品卡片id:']) or \ + (goods_info and goods_info.get('goodsID') and not goods_info.get('orderSequenceNo')): + msg_type = "product_card" + + # 创建消息模板(符合文档) + message_template = PlatformMessage.create_text_message( + content=content, + sender_id=str(uid), + store_id=self.store_id + ) + message_template.msg_type = msg_type + + try: + print(f"📤(SPEC) 发送到AI: {json.dumps(message_template.to_dict(), ensure_ascii=False)[:300]}...") + except Exception: + pass + + # 从后端服务获取AI回复(单连接模式:仅转交,不本地立即回复) + ai_result = await self.get_ai_reply_from_backend(message_template.to_dict()) + + if isinstance(ai_result, str) and ai_result.strip(): + # 发送回复消息(仅当本地生成/降级时) + await self.send_ai_reply(uid, ai_result) + self._log(f"📤 已发送回复: {ai_result[:100]}...", "INFO") + else: + # 正常链路:已转交后端AI,等待后端异步回传并由 GUI 转发到平台 + self._log("🔄 已转交后端AI处理,等待平台回复下发", "INFO") + + except Exception as e: + self._log(f"❌ 消息处理失败: {e}", "ERROR") + traceback.print_exc() + + @staticmethod + async def heartbeat(wss): + while True: + m = random.randint(100, 200) + h = [0, 0, 0, 0, 0, 0, 0, m, 0, 0, 0, 1, 0, 0, 0, 0] + h = bytes(h) + await wss.send(bytes(h)) + await asyncio.sleep(15) + + async def on_message(self, wss, store): + self._log("开始监听消息", "INFO") + while True: + try: + message = await wss.recv() + self._log(f"收到新消息 {base64.b64encode(message).decode()}", "DEBUG") + try: + text = self.ctx.call("dencode_data", base64.b64encode(message).decode()) + if not isinstance(text, dict): + continue + push = text.get("push_data") or {} + data = push.get("data") + if not data: + self._log("push_data.data 为空,忽略", "DEBUG") + continue + + print(f"原始数据格式打印:{data}") + for d in data: + await self.process_incoming_message(d, wss, store) + + except Exception as e: + # buffer error是正常的,调整为DEBUG级别 + if "buffer error" in str(e): + self._log(f"解析消息失败: {e}", "DEBUG") + else: + self._log(f"解析消息失败: {e}", "ERROR") + traceback.print_exc() + except Exception as e: + # self._log(f"处理消息失败: {e}", "ERROR") + # traceback.print_exc() + pass + + async def message_monitoring(self, cookies_str, store, stop_event=None): + """消息监听主方法""" + print("✅ DEBUG 进入拼多多message_monitoring方法") + print(f"参数验证: cookies={bool(cookies_str)}") + + # 连接后端AI服务 - 使用店铺ID + store_id = str(store.get('id', '')) + self._log(f"🔗 尝试连接后端服务,店铺ID: {store_id}", "DEBUG") + + backend_connected = await self.connect_backend_service(store_id) + if not backend_connected: + self._log("⚠️ 后端服务连接失败,将使用本地AI回复", "WARNING") + else: + self._log("✅ 后端服务连接成功", "SUCCESS") + + stop_event = stop_event or asyncio.Event() + + # 充值重连计数器 + self.reconnect_attempts = 0 + + while not stop_event.is_set(): + try: + self._log(f"🔄 尝试连接拼多多WebSocket", "INFO") + + if self.user_id and self.auth_token: + uri = "wss://titan-ws.pinduoduo.com/" + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", + "Upgrade": "websocket", + "Origin": "https://mms.pinduoduo.com", + "Accept-Encoding": "gzip, deflate, br, zstd", + "Accept-Language": "zh-CN,zh;q=0.9", + "Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits", + "cookie": "; ".join([f"{k}={v}" for k, v in self.cookie.items()]) + } + + async with websockets.connect(uri, additional_headers=headers, ping_interval=20, + ping_timeout=16) as websocket: + # 连接成功,重置重连计数器 + self.reconnect_attempts = 0 + self._log("✅ WebSocket-PDD连接成功", "SUCCESS") + + z = self.encodeex.call("encode_token", str(self.user_id), self.auth_token) + if z: + await websocket.send(bytes(z)) + + # 注册连接信息到全局管理 + shop_key = f"拼多多:{store['id']}" + loop = asyncio.get_running_loop() + entry = self.ws_manager.on_connect( + shop_key=shop_key, + ws=websocket, + platform="拼多多", + loop=loop, + pdd_instance=self # 存储ChatPdd实例引用,用于消息转发 + ) + + # 获取客服列表并发送到后端 + if not self.staff_list_sent: + self._log("🔍 开始获取客服列表...", "INFO") + try: + if await self.get_all_customer(None): + await self.send_staff_list_to_backend() + self.staff_list_sent = True + else: + self._log("⚠️ 获取客服列表失败", "WARNING") + except Exception as e: + self._log(f"❌ 获取或发送客服列表失败: {e}", "ERROR") + + # 启动消息监听和心跳 + await asyncio.gather( + self.heartbeat(websocket), + self.on_message(websocket, store) + ) + else: + self._log("未定制账号token数组", "ERROR") + + except websockets.ConnectionClosed as e: + self._log(f"🔌 连接已关闭: {e.code} {e.reason}", "WARNING") + if not await self.handle_reconnect(e): + break + + except (websockets.WebSocketException, OSError) as e: + self._log(f"🌐 网络异常: {type(e).__name__} - {str(e)}", "WARNING") + if not await self.handle_reconnect(e): + break + + except Exception as e: + self._log(f"⚠️ 未知异常: {type(e).__name__} - {str(e)}", "ERROR") + if not await self.handle_reconnect(e): + break + + # 关闭后端服务连接 + if self.backend_connected: + self.backend_connected = False + self._log("🛑 消息监听已停止", "INFO") + + async def main(self): + self.get_auth_token() + self.get_mall_id() + self.get_assign_cslist() + + # 连接AI服务 + if await self.connect_backend_service(self.store_id): + print("✅ AI服务连接成功") + + store = {'id': self.store_id} + await self.message_monitoring( + cookies_str=self.cookie, + store=store + ) + else: + print("❌ AI服务连接失败") + return + + +class PddListenerForGUI: + """用于GUI集成的拼多多监听包装器""" + + def __init__(self, log_callback: Optional[Callable] = None): + self.pdd_bot = None + self.log_callback = log_callback + self.running = False + self.main_thread = None + self.loop = None + self.startup_success = False + self.startup_event = threading.Event() + self.startup_error = None + + def _log(self, message: str, log_type: str = "INFO"): + if self.log_callback: + self.log_callback(message, log_type) + else: + print(f"[{log_type}] {message}") + + async def start_listening(self, cookie_dict: Dict[str, str], chat_list_stat: bool = False, + csname: Optional[str] = None, text: Optional[str] = None) -> bool: + try: + self._log("🔵 开始拼多多平台连接流程", "INFO") + + if not cookie_dict: + self._log("❌ Cookie信息不能为空", "ERROR") + return False + + self._log(f"✅ Cookie验证通过,包含 {len(cookie_dict)} 个字段", "SUCCESS") + + self.startup_success = False + self.startup_error = None + self.startup_event.clear() + + # 创建ChatPdd实例 + self.pdd_bot = ChatPdd( + cookie=cookie_dict, + text=text, + chat_list_stat=chat_list_stat, + csname=csname, + log_callback=self.log_callback + ) + + self.running = True + self._log("🎉 开始监听拼多多平台消息...", "SUCCESS") + + def run_pdd_main(): + try: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + self.loop = loop + + async def main_wrapper(): + try: + # 直接调用ChatPdd的main方法 + await self.pdd_bot.main() + self.startup_success = True + self._log("✅ ChatPdd主程序执行完成", "SUCCESS") + except Exception as e: + self.startup_error = str(e) + self._log(f"❌ ChatPdd运行出错: {str(e)}", "ERROR") + finally: + self.startup_event.set() + + loop.run_until_complete(main_wrapper()) + + except Exception as e: + self.startup_error = str(e) + self._log(f"❌ ChatPdd运行出错: {str(e)}", "ERROR") + self.startup_event.set() + finally: + self.running = False + + self.main_thread = threading.Thread(target=run_pdd_main, daemon=True) + self.main_thread.start() + + self._log("🔄 等待ChatPdd初始化完成...", "INFO") + + # 只等待初始化完成,不设置超时 + self.startup_event.wait() + + if self.startup_success: + self._log("✅ 拼多多监听启动成功", "SUCCESS") + return True + else: + error_msg = self.startup_error or "未知启动错误" + self._log(f"❌ 拼多多监听启动失败: {error_msg}", "ERROR") + return False + + except Exception as e: + self._log(f"❌ 监听启动过程中出现严重错误: {str(e)}", "ERROR") + return False + + async def start_with_cookies(self, store_id: str, cookies: str): + """使用下发的cookies与store_id直接建立PDD平台WS并开始监听""" + try: + self._log("🔵 [PDD] 收到后端登录指令,开始使用cookies连接平台", "INFO") + + # 验证cookie + if not cookies: + self._log("❌ Cookie信息不能为空", "ERROR") + return False + + self._log(f"✅ [PDD] Cookie验证通过,长度: {len(cookies)}", "SUCCESS") + + # 获取统一后端服务 + from WebSocket.backend_singleton import get_backend_client + backend_service = get_backend_client() + if not backend_service: + self._log("❌ [PDD] 无法获取后端服务", "ERROR") + return False + + # 解析cookies字符串为字典 + cookie_dict = {} + if cookies: + try: + # 如果cookies是字符串形式的字典,先尝试解析 + if cookies.startswith('{') and cookies.endswith('}'): + import ast + import json + try: + # 首先尝试JSON解析(双引号格式) + cookie_dict = json.loads(cookies) if isinstance(cookies, str) else cookies + except json.JSONDecodeError: + # 如果JSON解析失败,尝试Python字典格式(单引号格式) + cookie_dict = ast.literal_eval(cookies) + else: + # 传统的cookie字符串解析 + for cookie_pair in cookies.split(';'): + if '=' in cookie_pair: + key, value = cookie_pair.strip().split('=', 1) + cookie_dict[key] = value + except Exception as e: + self._log(f"⚠️ 解析cookies失败: {e}", "ERROR") + self._log("❌ [PDD] 无法解析cookies,连接失败", "ERROR") + return False + + # 验证cookies解析结果 + if not isinstance(cookie_dict, dict): + self._log("❌ [PDD] cookies解析失败,不是字典格式", "ERROR") + return False + + if not cookie_dict: + self._log("❌ [PDD] cookies为空", "ERROR") + return False + + self._log(f"✅ [PDD] cookies解析成功,包含 {len(cookie_dict)} 个字段", "SUCCESS") + + # 创建ChatPdd实例 + self.pdd_bot = ChatPdd( + cookie=cookie_dict, + text=None, + chat_list_stat=False, + csname=None, + log_callback=self.log_callback + ) + + # 设置store_id和后端服务 + self.pdd_bot.store_id = store_id + # 使用统一的后端服务而不是独立的PddBackendService + backend_service_wrapper = PddBackendService() + await backend_service_wrapper.connect(store_id) + self.pdd_bot.backend_service = backend_service_wrapper + self.pdd_bot.backend_connected = True + + self.running = True + self._log("🎉 [PDD] 开始监听平台消息", "SUCCESS") + + # 获取认证信息 + self.pdd_bot.get_auth_token() + self.pdd_bot.get_mall_id() + self.pdd_bot.get_assign_cslist() + + # 启动监听 + store = {'id': store_id} + await self.pdd_bot.message_monitoring( + cookies_str=cookies, + store=store + ) + self._log("✅ [PDD] 拼多多平台连接成功,开始监听消息", "SUCCESS") + return True + except Exception as e: + self._log(f"❌ [PDD] 监听过程中出现严重错误: {str(e)}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def stop_listening(self): + try: + self._log("🛑 开始停止拼多多监听...", "INFO") + self.running = False + + if self.main_thread and self.main_thread.is_alive(): + try: + self._log("🔄 等待主线程结束...", "DEBUG") + self.main_thread.join(timeout=5.0) + if self.main_thread.is_alive(): + self._log("⚠️ 主线程未在超时时间内结束", "WARNING") + except Exception as e: + self._log(f"⚠️ 等待主线程结束时出错: {e}", "DEBUG") + + self._log("✅ 拼多多监听已停止", "SUCCESS") + + except Exception as e: + self._log(f"❌ 停止监听时出错: {str(e)}", "ERROR") + + def is_running(self) -> bool: + return (self.running and + self.main_thread is not None and + self.main_thread.is_alive() and + self.startup_success) + + def get_status(self) -> Dict[str, Any]: + return { + "running": self.running, + "has_bot": self.pdd_bot is not None, + "main_thread_alive": self.main_thread.is_alive() if self.main_thread else False, + "startup_success": self.startup_success, + "startup_error": self.startup_error + } + + +# 测试函数保留 +async def test_gui_integration(): + def custom_log_callback(message: str, log_type: str): + print(f"[GUI测试] [{log_type}] {message}") + + test_cookies = { + "api_uid": "CiKdOWi361Z8egCe1uihAg==", + "_nano_fp": "Xpmyn5CJXqmbnqPyl9_MofCSZEeib112RR6N1Ah9", + "rckk": "v8QcMiTwfCX72hCnHFVtXSg4oHNvs6Qs", + "_bee": "v8QcMiTwfCX72hCnHFVtXSg4oHNvs6Qs", + "ru1k": "cb1cec9f-8895-4301-8e7e-a56c2c830cc5", + "_f77": "cb1cec9f-8895-4301-8e7e-a56c2c830cc5", + "ru2k": "f24003c6-339b-4498-b995-c4200179d4c6", + "_a42": "f24003c6-339b-4498-b995-c4200179d4c6", + "mms_b84d1838": "3616,3523,3660,3614,3599,3621,3588,3254,3532,3642,3474,3475,3477,3479,3482,1202,1203,1204,1205,3417", + "PASS_ID": "1-Ncbwg/naTW6KMMZg7FCtK5ctxvsC84uMK9wM55CJsDJnnoQ8d5jptFdwMkC08e3lKMJw/mGLQXYNL3iCvwTiCQ_109909969_163439093", + "x-visit-time": "1757554980094", + "JSESSIONID": "329E5C258BD7920211D15E263490C895" + } + + print("🧪 开始测试GUI集成类...") + + listener = PddListenerForGUI(log_callback=custom_log_callback) + + try: + print("\n🔵 启动GUI监听...") + success = await listener.start_listening( + cookie_dict=test_cookies, + chat_list_stat=False, + csname=None, + text="测试" + ) + + if success: + print("✅ GUI监听启动成功") + print(f"📊 当前状态: {listener.get_status()}") + + print("\n🟢 监听运行中,将持续运行直到手动停止...") + while True: + if not listener.is_running(): + print("❌ 监听意外停止") + break + await asyncio.sleep(1) + + print("\n🛑 测试完成,开始停止监听...") + listener.stop_listening() + print(f"📊 停止后状态: {listener.get_status()}") + + print("\n✅ GUI集成类测试完成") + print("📋 测试结果:GUI集成类与原main方法逻辑完全一致") + + else: + print("❌ GUI监听启动失败") + if listener.startup_error: + print(f"❌ 错误原因: {listener.startup_error}") + + except KeyboardInterrupt: + print("\n🛑 用户中断测试") + listener.stop_listening() + except Exception as e: + print(f"❌ 测试过程中出错: {e}") + listener.stop_listening() + + +# 同时保留原有的main函数供直接调用 +async def main(): + cookies = { + "api_uid": "CiKdOWi361Z8egCe1uihAg==", + "_nano_fp": "Xpmyn5CJXqmbnqPyl9_MofCSZEeib112RR6N1Ah9", + "rckk": "v8QcMiTwfCX72hCnHFVtXSg4oHNvs6Qs", + "_bee": "v8QcMiTwfCX72hCnHFVtXSg4oHNvs6Qs", + "ru1k": "cb1cec9f-8895-4301-8e7e-a56c2c830cc5", + "_f77": "cb1cec9f-8895-4301-8e7e-a56c2c830cc5", + "ru2k": "f24003c6-339b-4498-b995-c4200179d4c6", + "_a42": "f24003c6-339b-4498-b995-c4200179d4c6", + "mms_b84d1838": "3616,3523,3660,3614,3599,3621,3588,3254,3532,3642,3474,3475,3477,3479,3482,1202,1203,1204,1205,3417", + "PASS_ID": "1-P3kEWMDAT6n7mZjZpx1poVmxfusHa6Qd0s+dhQlG7SiqNA8A5LCsjbbRpck4WHjVSve3G+x0N4ZEL7Dcz2L+vg_109909969_163439093", + "x-visit-time": "1757399096750", + "JSESSIONID": "04601A22B2F955001EFEA28A2F64ED79" + } + + await ChatPdd(cookie=cookies, chat_list_stat=False).main() + + +if __name__ == '__main__': + # 可以选择直接运行main()或者测试GUI集成 + # 测试GUI集成 + asyncio.run(test_gui_integration()) + # asyncio.run(main()) diff --git a/Utils/Pdd/__init__.py b/Utils/Pdd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utils/QianNiu/QianNiuUtils.py b/Utils/QianNiu/QianNiuUtils.py new file mode 100644 index 0000000..e2d07ed --- /dev/null +++ b/Utils/QianNiu/QianNiuUtils.py @@ -0,0 +1,2322 @@ +# -*- coding: utf-8 -*- +# python let's go +# 编辑人:kris思成 +# sainiu_local_test.py +import asyncio +import json +import os +import uuid +import glob +import time +import hashlib +import subprocess +import logging +from dataclasses import asdict, dataclass +from datetime import datetime, timedelta +from typing import Dict, List, Any, Optional +import websockets +import aiohttp +import sys +import io + +# 设置标准输出编码为UTF-8 +sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') +sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') + + +# 配置日志 +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler("sainiu_test.log"), + logging.StreamHandler() + ] +) +logger = logging.getLogger("SaiNiuTest") + +# 赛牛插件配置 +QN_WS_URL = "ws://127.0.0.1:3030" # 赛牛插件WebSocket地址 +QN_HTTP_API_URL = "http://127.0.0.1:3030/QianNiu/Api" # 赛牛插件HTTP API地址 +STORE_ID = "test_store_001" # 测试店铺ID +STORE_NAME = "测试店铺" # 测试店铺名称 +USER_NICK = "tb420723827:redboat" # 测试账号 + +import ctypes +import hashlib +import time +from ctypes import c_int, c_bool, c_char_p + + +class SaiNiuService: + """赛牛DLL服务管理类""" + + def __init__(self): + self.dll_loaded = False + self.sainiu_api = None + self.port = 3030 # 默认端口 + self.sign_key = b'' # 默认签名密钥 + self.sha256 = True # 使用SHA256签名 + self.python32_path = r"F:\飞书下载地址\shuidrop_gui\Utils\PythonNew32\python32.exe" + self.dll_process = None + + def load_dll(self, dll_path='F:\\飞书下载地址\\shuidrop_gui\\Utils\\PythonNew32\\SaiNiuApi.dll'): + """加载DLL文件 - 使用Python32执行""" + try: + # 切换到DLL目录 + dll_dir = os.path.dirname(dll_path) + os.chdir(dll_dir) + print(f"📁 切换到DLL目录: {dll_dir}") + + # 创建DLL启动脚本 - 完全按照demo的代码 + script_content = '''import ctypes +import hashlib +import time +import json + +# 加载DLL文件 +sainiu_api = ctypes.CDLL('SaiNiuApi.dll') + +# 定义函数参数类型和返回值类型 +sainiu_api.Access_ServerStart.argtypes = [ + ctypes.c_int, + ctypes.c_bool, + ctypes.c_bool, + ctypes.c_bool, + ctypes.c_bool, + ctypes.c_int, + ctypes.c_char_p, + ctypes.c_bool, + ctypes.c_bool +] +sainiu_api.Access_ServerStart.restype = ctypes.c_char_p + +# 调用函数时传入的参数 +port = 3030 +web_socket = True +http_server = True +remote = False +log = True +ws_max = 0 +sign_key = b'' +sha256 = True +version_tip = True + +# 启动服务器 +result = sainiu_api.Access_ServerStart( + port, + web_socket, + http_server, + remote, + log, + ws_max, + sign_key, + sha256, + version_tip +) + +# 解码并打印结果 +try: + result_str = result.decode('gbk') + print(f"Access_ServerStart 服务器启动: {result_str}") +except UnicodeDecodeError: + print(f"Access_ServerStart 服务器启动: {result}") + +# 保持进程运行 +try: + while True: + time.sleep(1) +except KeyboardInterrupt: + pass +''' + + # 保存脚本 + script_path = os.path.join(dll_dir, "dll_loader.py") + with open(script_path, "w", encoding="utf-8") as f: + f.write(script_content) + + # 使用Python32启动脚本 + self.dll_process = subprocess.Popen( + [self.python32_path, script_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, + cwd=dll_dir, + encoding='gbk', + text=True + ) + + # 等待进程启动并获取结果 + try: + stdout, stderr = self.dll_process.communicate(timeout=15) + + if stderr: + print(f"❌ DLL启动错误: {stderr}") + return False + + print(f"✅ 赛牛服务器启动结果: {stdout}") + + # 检查是否启动成功 + if "SUCCESS" in stdout or "成功" in stdout or "200" in stdout: + self.dll_loaded = True + print("✅ DLL加载成功") + return True + else: + print("❌ 服务器启动失败") + return False + + except subprocess.TimeoutExpired: + # 超时不一定表示失败,可能服务正在运行 + print("⏰ DLL启动超时,但服务可能已在后台运行") + self.dll_loaded = True + return True + + except Exception as e: + print(f"❌ 加载SaiNiu DLL失败: {e}") + return False + + + def sign_get_sign(self, post, timestamp): + """计算签名 - 按照官方demo的逻辑修改""" + if not self.sign_key: # 如果签名为空,直接返回空字符串 + return "" + # 拼接字符串 + data = post + str(timestamp) + self.sign_key.decode('utf-8') + # 将字符串转换为字节集 + byte_data = data.encode('utf-8') + # 根据sha256参数选择哈希算法 + if self.sha256: + hash_object = hashlib.sha256(byte_data) + else: + hash_object = hashlib.md5(byte_data) + # 获取十六进制表示并转换为小写 + return hash_object.hexdigest().lower() + + def start_server(self, port=3030, sign_key=b'111111', sha256=True): + """启动赛牛服务器(已在load_dll中完成)""" + if not self.dll_loaded: + print("❌ DLL未加载,请先调用load_dll()") + return False + return True + + def _check_port_listening(self): + """检查端口是否在监听状态""" + try: + import socket + # 尝试连接端口 + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(1) + result = s.connect_ex(('127.0.0.1', self.port)) + if result == 0: + logger.info(f"端口 {self.port} 已在监听") + return True + else: + logger.warning(f"端口 {self.port} 未在监听 (错误码: {result})") + return False + except Exception as e: + logger.error(f"检查端口状态时出错: {e}") + return False + + def _wait_for_port(self, timeout=30): + """等待端口可用""" + start_time = time.time() + while time.time() - start_time < timeout: + if self._check_port_listening(): + # 额外等待一下确保服务完全启动 + time.sleep(2) + # 再次检查 + if self._check_port_listening(): + return True + time.sleep(1) + return False + + def cleanup_old_process(self): + """清理旧的进程和端口""" + try: + import os + import psutil + + # 1. 终止所有相关Python进程 + for proc in psutil.process_iter(['pid', 'name', 'cmdline']): + try: + if proc.info['name'] == 'python32.exe': + cmdline = proc.info['cmdline'] + if any('SaiNiuApi.dll' in cmd for cmd in cmdline): + proc.kill() # 使用kill而不是terminate + logger.info(f"已强制终止旧进程: {proc.info['pid']}") + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue + + # 2. 清理端口占用 + for conn in psutil.net_connections(): + if conn.laddr.port == self.port: + try: + proc = psutil.Process(conn.pid) + proc.kill() + logger.info(f"已终止占用端口{self.port}的进程: {conn.pid}") + except (psutil.NoSuchProcess, psutil.AccessDenied): + continue + + # 3. 等待进程完全退出 + time.sleep(2) + + # 4. 清理可能的临时文件 + temp_files = [ + os.path.join(os.path.dirname(self.dll_path), "dll_loader.py"), + os.path.join(os.path.dirname(self.dll_path), "*.tmp") + ] + for pattern in temp_files: + for f in glob.glob(pattern): + try: + os.remove(f) + logger.info(f"已清理临时文件: {f}") + except: + pass + + except Exception as e: + logger.error(f"清理旧进程时出错: {e}") + + def close(self): + """关闭DLL服务""" + if self.dll_process: + self.dll_process.terminate() + try: + self.dll_process.wait(timeout=5) + except subprocess.TimeoutExpired: + self.dll_process.kill() + + +# 简单的内存缓存实现(替换Django的cache) +class SimpleCache: + def __init__(self): + self._cache = {} + + def get(self, key: str) -> Optional[Any]: + data = self._cache.get(key) + if data and data['expire'] > datetime.now(): + return data['value'] + return None + + def set(self, key: str, value: Any, timeout: int): + self._cache[key] = { + 'value': value, + 'expire': datetime.now() + timedelta(seconds=timeout) + } + + +# 创建全局缓存实例 +cache = SimpleCache() + + +class MockStore: + """模拟店铺对象""" + + def __init__(self, pk, name, account, password): + self.pk = pk + self.store_name = name + self.store_account = account + self.store_password = password + +@dataclass +class MessageTemplate: + """通用消息结构体 - 严格按照WebSocket文档v2格式""" + # 必填字段 + type: str # 消息类型:"message" | "staff_list" | "ping" | "pong" | "transfer" | "connect_success" | "error" + + # 条件必填字段(根据消息类型) + content: Optional[str] = None # 消息内容 + msg_type: Optional[str] = None # 消息实际类型:"text" | "image" | "video" | "product_card" | "order_card" + pin_image: Optional[str] = None # 用户头像URL + sender: Optional[Dict] = None # 发送者信息,必须包含id字段 + store_id: Optional[str] = None # 店铺ID + + # 可选字段 + receiver: Optional[Dict] = None # 接收者信息 + data: Optional[Dict] = None # 扩展数据(如客服列表、验证链接等) + uuid: Optional[str] = None # 心跳包UUID + token: Optional[str] = None # 认证令牌(心跳包可能需要) + + def __post_init__(self): + """初始化后处理""" + # 自动设置msg_type(仅对message类型) + if self.type == "message" and self.msg_type is None and self.content: + self.msg_type = self._detect_msg_type() + + def _detect_msg_type(self) -> str: + """自动检测消息类型""" + if not self.content: + return "text" + + content = self.content.lower() + + # 图片检测 + if any(ext in content for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']): + return "image" + + # 视频检测 + if any(ext in content for ext in ['.mp4', '.avi', '.mov', '.wmv', '.flv']): + return "video" + + # 订单卡片检测 - 支持多种格式 + if ("商品id:" in self.content and "订单号:" in self.content) or \ + ("商品ID:" in self.content and "订单号:" in self.content) or \ + ("咨询订单号:" in self.content and "商品ID:" in self.content): + return "order_card" + + # 商品卡片检测 + if any(keyword in content for keyword in ['goods.html', 'item.html', 'item.jd.com', '商品卡片id:']): + return "product_card" + + # 默认文本消息 + return "text" + + def to_json(self) -> str: + """序列化为JSON字符串""" + return json.dumps(self.to_dict(), ensure_ascii=False) + + def to_dict(self) -> Dict[str, Any]: + """转换为字典,过滤None值""" + result = {} + for key, value in asdict(self).items(): + if value is not None: + result[key] = value + return result + + @classmethod + def from_json(cls, json_str: str): + """从JSON字符串恢复结构体""" + data = json.loads(json_str) + return cls(**data) + + @classmethod + def from_dict(cls, data: Dict[str, Any]): + """从字典创建实例""" + return cls(**data) + + @classmethod + def create_text_message(cls, content: str, sender_id: str, store_id: str, pin_image: str = None): + """创建文本消息""" + return cls( + type="message", + content=content, + msg_type="text", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_image_message(cls, image_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建图片消息""" + return cls( + type="message", + content=image_url, + msg_type="image", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_video_message(cls, video_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建视频消息""" + return cls( + type="message", + content=video_url, + msg_type="video", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_order_card_message(cls, product_id: str, order_number: str, sender_id: str, store_id: str, pin_image: str = None): + """创建订单卡片消息""" + return cls( + type="message", + content=f"商品id:{product_id} 订单号:{order_number}", + msg_type="order_card", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_product_card_message(cls, product_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建商品卡片消息""" + return cls( + type="message", + content=product_url, + msg_type="product_card", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_staff_list_message(cls, staff_list: list, store_id: str): + """创建客服列表消息""" + return cls( + type="staff_list", + content="客服列表更新", + data={"staff_list": staff_list}, + store_id=store_id + ) + + @classmethod + def create_ping_message(cls, uuid_str: str, token: str = None): + """创建心跳检测消息""" + message = cls( + type="ping", + uuid=uuid_str + ) + if token: + message.token = token + return message + + @classmethod + def create_pong_message(cls, uuid_str: str): + """创建心跳回复消息""" + return cls( + type="pong", + uuid=uuid_str + ) + + +class AIServiceConnector: + """AI服务连接器 - 负责与AI后端服务通信(已改为单后端连接)""" + + def __init__(self, backend_host="192.168.5.155", backend_port=8000): + # 旧版后端WS地址移除:统一使用单后端连接(ws/gui//) + self.websocket = None + self.store_id = None + self.connected = False + self.connect_timeout = 60 + self.service_cookie = None + self.message_handlers = {} # 新增:消息处理器字典 + self.pending_ai_replies = {} # 新增:等待AI回复的Future + + self.reconnect_attempts = 0 + self.max_reconnect_attempts = 3 + self.reconnect_delay = 5 # 重连间隔时间(秒) + + + async def connect(self, store_id, auth_dict=None): + """连接后端AI服务:已不再直接连接后端,统一走单后端连接""" + self.store_id = store_id + self.connected = True + return True + + def send_to_backend_single(self, content: str, msg_type: str, sender_pin: str): + """通过单后端连接发送消息,携带store_id""" + try: + from WebSocket.backend_singleton import get_backend_client + backend = get_backend_client() + if not backend: + return False + message = { + 'type': 'message', + 'content': content, + 'msg_type': msg_type, + 'sender': {'id': sender_pin}, + 'store_id': self.store_id + } + backend.send_message(message) + return True + except Exception: + return False + + async def start_message_loop(self): + """启动统一的消息循环处理所有后端消息""" + self._log("🔵 启动统一消息循环...", "INFO") + + while True: # 改为无限循环,支持自动重连 + try: + if not self.connected or not self.websocket: + self._log("🔌 连接断开,尝试重连...", "WARNING") + if not await self._reconnect(): + await asyncio.sleep(self.reconnect_delay) + continue + + try: + message = await asyncio.wait_for(self.websocket.recv(), timeout=30.0) + data = json.loads(message) + message_type = data.get("type") + + self._log(f"📥 收到消息类型: {message_type}", "DEBUG") + + # 分发消息给对应的处理器 + await self._dispatch_message(data, message_type) + + except asyncio.TimeoutError: + continue + except websockets.exceptions.ConnectionClosed as e: + self._log(f"🔌 WebSocket连接关闭: {e}", "WARNING") + self.connected = False + await self._handle_connection_closed() + continue + except Exception as e: + self._log(f"❌ 消息接收异常: {e}", "ERROR") + await asyncio.sleep(1) + + except Exception as e: + self._log(f"❌ 消息循环异常: {e}", "ERROR") + await asyncio.sleep(1) + + async def _reconnect(self): + """重连机制""" + if self.reconnect_attempts >= self.max_reconnect_attempts: + self._log("❌ 重连次数超过限制,停止重连", "ERROR") + return False + + try: + self.reconnect_attempts += 1 + self._log(f"🔄 尝试第 {self.reconnect_attempts} 次重连...", "WARNING") + + # 关闭旧连接 + if self.websocket: + await self.websocket.close() + + # 重新连接 + success = await self.connect(self.store_id) + if success: + self.reconnect_attempts = 0 # 重置重试计数 + self._log("✅ 重连成功", "SUCCESS") + return True + else: + self._log(f"❌ 第 {self.reconnect_attempts} 次重连失败", "WARNING") + return False + + except Exception as e: + self._log(f"❌ 重连过程中出现异常: {e}", "ERROR") + return False + + async def send_message_to_backend(self, message_template): + """发送消息到后端并获取AI回复""" + # 简化连接检查,主要依赖websockets库自身的错误处理 + if not hasattr(self, 'websocket') or self.websocket is None: + self._log("❌ AI服务未连接,尝试重连...", "WARNING") + if not await self._reconnect(): + self._log("❌ 重连失败,无法发送消息", "ERROR") + return None + + try: + message_dict = message_template.to_dict() + user_id = message_template.sender.get("id", "") # 使用sender.id作为key + + # 详细的调试信息 + print("=" * 60) + print("🔍 调试信息 - 准备发送消息到后端:") + print(f"连接状态: {self.connected}") + print(f"WebSocket状态: {self.websocket is not None}") + print(f"消息ID: {message_id}") + print(f"消息内容: {message_dict.get('content', '')[:100]}...") + print("=" * 60) + + # 创建Future来等待回复 + future = asyncio.Future() + self.pending_ai_replies[user_id] = future + + await self.websocket.send(json.dumps(message_dict)) + self._log(f"📤 已发送消息到AI服务: {message_template.content[:50]}...", "DEBUG") + + # 等待AI回复(设置超时) + try: + ai_reply = await asyncio.wait_for(future, timeout=15.0) + self._log(f"✅ 成功获取AI回复: {ai_reply[:50]}...", "SUCCESS") + return ai_reply + + except asyncio.TimeoutError: + self._log("⏰ 等待AI回复超时(15秒)", "WARNING") + self.pending_ai_replies.pop(user_id, None) + return None + except ConnectionError as e: + self._log(f"❌ 连接已断开: {e}", "ERROR") + self.pending_ai_replies.pop(user_id, None) + return None + + except websockets.exceptions.ConnectionClosed: + self._log("❌ 发送消息时连接已关闭", "ERROR") + self.connected = False + self.pending_ai_replies.pop(user_id, None) + return None + except Exception as e: + self._log(f"❌ 发送消息到AI服务失败: {e}", "ERROR") + self.pending_ai_replies.pop(user_id, None) + return None + + async def _dispatch_message(self, data, message_type): + """分发消息到对应的处理器""" + # 处理customer_message类型(客服消息) + if message_type == "customer_message": + handler = self.message_handlers.get("customer_message") + if handler and callable(handler): + asyncio.create_task(handler(data)) + + # 处理message类型(AI回复) + elif message_type == "message": + # 检查是否有等待AI回复的Future - 使用receiver.id匹配 + receiver_info = data.get("receiver", {}) + user_id = receiver_info.get("id", "") + if user_id and user_id in self.pending_ai_replies: + future = self.pending_ai_replies.pop(user_id) + if not future.done(): + future.set_result(data.get("content", "")) + + # 同时调用消息处理器(用于监控) + handler = self.message_handlers.get("message") + if handler and callable(handler): + asyncio.create_task(handler(data)) + + # 可以添加其他消息类型的处理 + else: + self._log(f"📨 未处理的消息类型: {message_type}", "DEBUG") + + def register_message_handler(self, message_type, handler): + """注册消息处理器""" + self.message_handlers[message_type] = handler + self._log(f"✅ 注册消息处理器: {message_type}", "DEBUG") + + # async def listen_for_backend_messages(self, message_callback): + # """监听后端发送的消息""" + # self._log(f"🎯 进入后端消息监听方法,连接状态: {self.connected}", "DEBUG") + # + # if not self.connected or not self.websocket: + # self._log("❌ AI服务未连接,无法监听消息", "ERROR") + # return + # + # self._log("🔵 开始监听后端消息...", "INFO") + # RECV_TIMEOUT = 15.0 + # + # try: + # while self.connected and self.websocket: + # try: + # message = await asyncio.wait_for( + # self.websocket.recv(), + # timeout=RECV_TIMEOUT + # ) + # + # data = json.loads(message) + # self._log(f"📥 收到消息类型: {data.get('type')}", "DEBUG") + # + # if data.get("type") == "customer_message": + # self._log("✅ 处理客服消息", "INFO") + # if callable(message_callback): + # # 使用create_task避免阻塞主循环 + # asyncio.create_task(message_callback(data)) + # + # except asyncio.TimeoutError: + # # 超时是正常的,继续监听 + # continue + # except websockets.exceptions.ConnectionClosed: + # self._log("🔌 连接已关闭", "WARNING") + # self.connected = False + # break + # except Exception as e: + # self._log(f"❌ 消息处理异常: {e}", "ERROR") + # await asyncio.sleep(1) # 避免频繁报错 + # + # except Exception as e: + # self._log(f"❌ 监听循环异常: {e}", "ERROR") + + async def _parse_ai_response(self, response_data): + """解析后端返回的AI回复""" + try: + # 处理连接成功消息 + if response_data.get("type") == "connect_success": + content = response_data.get("content", "") + if content: + self.service_cookie = { + 'cookie': content, + 'status': True + } + self._log("✅ 从连接成功消息中提取到认证信息", "SUCCESS") + return content + + # 检查是否为AI回复消息 + if response_data.get("type") == "message": + content = response_data.get("content", "") + if content: + self._log(f"✅ 成功解析AI回复: {content}", "SUCCESS") + return content + + # 检查其他可能的格式 + if "content" in response_data: + content = response_data.get("content") + if content: + self._log(f"✅ 从content字段获取到回复: {content}", "SUCCESS") + return content + + self._log(f"⚠️ 无法识别的回复格式: {response_data}", "WARNING") + return None + + except Exception as e: + self._log(f"❌ 解析AI回复失败: {e}", "ERROR") + return None + + async def close(self): + """关闭连接""" + if self.websocket: + await self.websocket.close() + self.connected = False + self._log("🔌 已关闭AI服务连接", "INFO") + + def _log(self, message, level="INFO"): + """日志记录""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 根据日志级别添加颜色 + if level == "ERROR": + print(f"\033[91m[{timestamp}] [{level}] {message}\033[0m") # 红色 + elif level == "WARNING": + print(f"\033[93m[{timestamp}] [{level}] {message}\033[0m") # 黄色 + elif level == "SUCCESS": + print(f"\033[92m[{timestamp}] [{level}] {message}\033[0m") # 绿色 + elif level == "DEBUG": + print(f"\033[96m[{timestamp}] [{level}] {message}\033[0m") # 蓝色 + else: + print(f"[{timestamp}] [{level}] {message}") + + def get_service_cookie(self): + """获取服务认证信息""" + return self.service_cookie + + +class AIServiceIntegration: + """AI服务集成类 - 负责处理AI回复相关功能""" + + def __init__(self, store_id="4c4025e3-8702-42fc-bdc2-671e335c0ff7"): + self.store_id = store_id + self.ai_service = AIServiceConnector() + self.loop = None + self._ensure_event_loop() + self.retry_count = 0 + self.max_retries = 3 + + def _ensure_event_loop(self): + """确保事件循环存在""" + try: + self.loop = asyncio.get_event_loop() + except RuntimeError: + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + async def initialize_ai_service(self): + """初始化AI服务""" + try: + self._log("正在初始化AI服务...", "INFO") + success = await self.ai_service.connect(self.store_id) + + if success: + self._log("AI服务初始化成功", "SUCCESS") + self.retry_count = 0 + + # 启动统一的消息循环 + asyncio.create_task(self.ai_service.start_message_loop()) + self._log("✅ 消息循环已启动", "SUCCESS") + + return True + else: + self._log("AI服务初始化失败", "ERROR") + return False + + except Exception as e: + self._log(f"AI服务初始化异常: {e}", "ERROR") + return False + + def register_message_handlers(self, handlers): + """注册消息处理器""" + for message_type, handler in handlers.items(): + self.ai_service.register_message_handler(message_type, handler) + + async def get_ai_reply(self, message_content, sender_nick, avatar_url=""): + """获取AI回复""" + try: + # 确保连接正常 + if not await self.ensure_connection(): + return "您好,感谢您的咨询,我们会尽快回复您!" + + + # 创建消息模板对象 + message_template = MessageTemplate( + type="message", + content=message_content, + sender={ + "id": sender_nick, + "name": f"淘宝用户_{sender_nick}", + "is_customer": True + }, + data={ + "msg_type": "text", + "pin_image": avatar_url + }, + store_id=self.store_id + ) + + control_type = str(message_content) + if control_type.__contains__("http") and (control_type.__contains__(".jpg") or control_type.__contains__(".png")): + message_template = MessageTemplate( + type="message", + content=message_content, + msg_type="image", + pin_image=avatar_url, + sender={"id": sender_nick}, + store_id=self.store_id + ) + + print(f"最终发送给后端的数据📕:{message_template.to_dict()}") + + # 获取AI回复 + ai_reply = await self.ai_service.send_message_to_backend( + message_template=message_template + ) + + if ai_reply: + self._log(f"成功获取AI回复: {ai_reply[:50]}...", "SUCCESS") + else: + self._log("未获取到AI回复", "WARNING") + # 未获取到正常回复 增加重试计数 + self.retry_count += 1 + if self.retry_count >= self.max_retries: + self._log(f"重试次数超过限制,停止重试", "ERROR") + + return ai_reply + + except Exception as e: + logger.error(f"获取AI回复失败: {e}") + return "您好,感谢您的咨询,我们会尽快回复您!" + + # async def start_backend_listening(self, message_callback): + # """启动后端消息监听""" + # if not await self.ensure_connection(): + # self._log("❌ AI服务连接失败,无法启动后端监听", "ERROR") + # return False + # + # try: + # # 直接调用AIServiceConnector的监听方法 + # asyncio.create_task( + # self.ai_service.listen_for_backend_messages(message_callback) + # ) + # self._log("✅ 后端消息监听已启动", "SUCCESS") + # return True + # except Exception as e: + # self._log(f"❌ 启动后端监听失败: {e}", "ERROR") + # return False + + + + def _log(self, message, level="INFO"): + """日志记录""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 根据日志级别添加颜色 + if level == "ERROR": + print(f"\033[91m[{timestamp}] [{level}] {message}\033[0m") # 红色 + elif level == "WARNING": + print(f"\033[93m[{timestamp}] [{level}] {message}\033[0m") # 黄色 + elif level == "SUCCESS": + print(f"\033[92m[{timestamp}] [{level}] {message}\033[0m") # 绿色 + elif level == "DEBUG": + print(f"\033[96m[{timestamp}] [{level}] {message}\033[0m") # 蓝色 + else: + print(f"[{timestamp}] [{level}] {message}") + + async def check_connection(self): + """检查AI服务连接状态""" + if not self.ai_service.connected: + self._log("AI服务连接已断开,尝试重新连接...", "WARNING") + return await self.initialize_ai_service() + return True + + async def ensure_connection(self): + """确保AI服务连接正常""" + try: + # 如果标记为未连接,直接尝试重连 + if not self.ai_service.connected: + self._log("AI服务连接已断开,尝试重新连接...", "WARNING") + success = await self.ai_service.connect(self.store_id) + return success + + # 简单检查:如果websocket对象存在且不是None,就认为连接正常 + # 实际的连接状态会在发送消息时由websockets库自动处理 + if (hasattr(self.ai_service, 'websocket') and + self.ai_service.websocket is not None): + return True + else: + self._log("WebSocket连接不存在", "WARNING") + self.ai_service.connected = False + return await self.ensure_connection() + + except Exception as e: + self._log(f"检查连接状态异常: {e}", "ERROR") + return False + + async def close(self): + """关闭AI服务""" + try: + self._log("正在关闭AI服务...", "INFO") + if self.ai_service: + await self.ai_service.close() + self._log("AI服务已关闭", "SUCCESS") + except Exception as e: + self._log(f"关闭AI服务时发生错误: {e}", "ERROR") + + +class QianNiuClient: + """千牛客户端类 - 负责与赛牛插件通信""" + + def __init__(self, user_nick=None): + self.user_nick: str = user_nick + self.qn_ws = None + self.pending: Dict[str, asyncio.Future] = {} + self.is_connected = False + self.is_authenticated = False # 改为连接成功即认证 + self.message_handler = None + self._http_session = None # 添加会话 + + # 新增:正式账号认证信息 + self.access_type = 1 # 企业版 + self.access_id = "maguabishop" # 你的AccessId + self.access_key = "bWFndWFfYmlzaG9w" # 你的AccessKey + self.auth_token = None # 认证成功后获取的token + self.udid = None # 设备唯一标识 + + # 赛牛服务 + self.sainiu_service = SaiNiuService() + + + async def __aenter__(self): + """异步上下文管理器入口""" + self._http_session = aiohttp.ClientSession() + return self + + async def __aexit__(self, exc_type, exc_val, exc_tb): + """异步上下文管理器出口""" + if self._http_session: + await self._http_session.close() + + # 在 QianNiuClient 类中添加HTTP API调用方法 (新增) + async def _http_api_call(self, post_name: str, data_obj: Dict[str, Any]) -> Dict[str, Any]: + """按官方文档以 form-data 方式调用 QianNiu/Api 接口""" + form = aiohttp.FormData() + form.add_field("post", post_name) + form.add_field("data", json.dumps(data_obj)) + logger.debug(f"[TB-DIAG] HTTP CALL -> {post_name} url={QN_HTTP_API_URL} data={data_obj}") + try: + async with aiohttp.ClientSession() as session: + async with session.post(QN_HTTP_API_URL, data=form, timeout=10) as resp: + text = await resp.text() + logger.debug(f"[TB-DIAG] HTTP RESP <- {post_name} status={resp.status} body={text[:300]}") + if resp.status != 200: + logger.error(f"[QianNiuClient] HTTP接口 {post_name} 调用失败: status={resp.status}") + return {} + try: + return json.loads(text) + except Exception: + logger.error(f"[TB-DIAG] HTTP RESP JSON decode error on {post_name}") + return {} + except Exception as e: + logger.error(f"[QianNiuClient] HTTP接口 {post_name} 调用异常: {e}") + return {} + + async def fetch_buyer_avatar_by_http(self, buyer_nick: str) -> str: + """通过 HTTP GetUserIcon 获取买家头像""" + if not buyer_nick: + return "" + + cache_key = f"avatar:taobao:nick:{buyer_nick}" + cached = cache.get(cache_key) + if cached: + logger.info(f"[TB-头像调试] 💾 缓存命中: {cached}") + return cached + + # 使用正确的 GetUserIcon API + logger.info(f"[TB-头像调试] 📡 调用GetUserIcon API获取头像 - 买家昵称: {buyer_nick}") + resp = await self._http_api_call("GetUserIcon", { + "userNick": self.user_nick, + "buyerNick": buyer_nick, + "siteid": "cntaobao" + }) + + if not resp: + logger.warning(f"[TB-头像调试] ❌ HTTP GetUserIcon 调用失败") + return "" + + # 完整记录API返回数据 + logger.info(f"[TB-头像调试] 📥 GetUserIcon 完整返回数据: {json.dumps(resp, ensure_ascii=False, indent=2)}") + + # 解析返回数据获取头像 + try: + if resp.get("code") != 200: + logger.error(f"[TB-头像调试] ❌ API返回错误: code={resp.get('code')}, msg={resp.get('msg')}") + return "" + + data_block = resp.get("data") or {} + logger.info(f"[TB-头像调试] 🔍 data块内容: {json.dumps(data_block, ensure_ascii=False, indent=2)}") + + # 根据API文档,返回格式为: {"cntaobaotb266770389534":{"iconUrl":"https://..."}} + # 构建key: siteid + buyerNick + avatar_key = f"cntaobao{buyer_nick}" + avatar_data = data_block.get(avatar_key, {}) + avatar_url = avatar_data.get("iconUrl", "") + + if avatar_url: + logger.info(f"[TB-头像调试] ✅ 成功获取头像: {avatar_url}") + + # 处理相对协议的URL + if avatar_url.startswith("//"): + avatar_url = "https:" + avatar_url + + # 缓存头像URL(24小时) + cache.set(cache_key, avatar_url, 60 * 60 * 24) + return avatar_url + else: + logger.warning(f"[TB-头像调试] ❌ 未找到头像信息,key={avatar_key}") + return "" + + except Exception as e: + logger.error(f"[TB-头像调试] GetUserIcon 解析错误: {e}") + return "" + + # 新增连接的初始化 + async def _request_authorization(self): + """请求授权 - 按照官方demo修改""" + trace_id = "Access_Init" # 使用固定的traceId + + try: + # 获取当前的13位时间戳(毫秒级) + current_time = int(time.time() * 1000) + + # 计算JSON数据的签名,参数post参数为"Init" + json_sign = self.sainiu_service.sign_get_sign("Init", current_time) + + auth_msg = { + "type": "Invoke_SaiNiu", + "traceId": trace_id, + "codeType": "Access", + "post": "Init", + "data": { + "AccessType": 1, + "AccessId": "maguabishop", + "AccessKey": "bWFndWFfYmlzaG9w", + "ForceLogin": True + }, + "time": current_time, + "sign": json_sign + } + + await self.qn_ws.send(json.dumps(auth_msg)) + logger.info("已发送授权请求") + print(f"Sent message: {auth_msg}") + + # 不再等待响应,让消息循环处理响应 + return True + + except Exception as e: + logger.error(f"授权请求异常: {e}") + return False + + async def _system_initialization(self): + """系统初始化 - 按照官方demo修改""" + trace_id = "0470bf9489729b2e8a2126a04ab3e272" # 使用固定的traceId + + try: + # 获取当前的13位时间戳(毫秒级) + current_time = int(time.time() * 1000) + + # 计算新的JSON数据的签名,参数post参数为"SysInit" + sys_init_sign = self.sainiu_service.sign_get_sign("SysInit", current_time) + + init_msg = { + "type": "Invoke_SaiNiu", + "traceId": trace_id, + "codeType": "Access", + "post": "SysInit", + "data": { + "number": 20, + "port": 2030, + "token": True, + "connect": True, + "disconnect": True, + "newMessage": True, + "groupMessage": True, + "notice": True, + "event": True, + "assistant": True + }, + "time": current_time, + "sign": sys_init_sign + } + + await self.qn_ws.send(json.dumps(init_msg)) + logger.info("已发送系统初始化请求") + print(f"Sent message: {init_msg}") + + # 不再等待响应,让消息循环处理 + return True + + except Exception as e: + logger.error(f"系统初始化异常: {e}") + return False + + # async def connect(self): + # """连接到赛牛插件 - 修改为不发送初始化消息""" + # logger.info(f"尝试连接到赛牛插件: {QN_WS_URL}") + # print("=== 断点1: 开始连接赛牛插件 ===") + # + # try: + # # 连接WebSocket + # self.qn_ws = await websockets.connect(QN_WS_URL, ping_interval=20, ping_timeout=10) + # self.is_connected = True + # logger.info("成功连接到赛牛插件") + # print("=== 断点2: 成功连接到赛牛插件 ===") + # + # # 正式账号需要执行授权流程 + # print("=== 开始正式账号授权流程 ===") + # + # # 1. 请求授权 + # auth_success = await self._request_authorization() + # if not auth_success: + # logger.error("授权请求失败") + # return False + # + # # 2. 系统初始化 + # init_success = await self._system_initialization() + # if not init_success: + # logger.error("系统初始化失败") + # return False + # + # + # # 测试账号不需要初始化,连接成功即认证成功 + # self.is_authenticated = True + # logger.info("✅ 正式账号认证和初始化成功") + # + # return True + # + # except Exception as e: + # logger.error(f"连接赛牛插件失败: {e}") + # print(f"=== 断点3: 连接失败 - {e} ===") + # self.is_connected = False + # return False + + async def connect(self): + """连接到赛牛插件 - 完整流程""" + logger.info("开始完整的赛牛连接流程") + + try: + # 1. 加载并启动DLL服务 + if not await self._start_sainiu_service(): + logger.error("启动赛牛DLL服务失败") + return False + + # 2. 连接到WebSocket + if not await self._connect_websocket(): + logger.error("连接WebSocket失败") + return False + + # 3. 执行授权流程 + if not await self._request_authorization(): + logger.error("授权请求失败") + return False + + # 4. 系统初始化 + if not await self._system_initialization(): + logger.error("系统初始化失败") + return False + + self.is_authenticated = True + logger.info("✅ 完整的赛牛连接流程成功") + return True + + except Exception as e: + logger.error(f"连接赛牛插件失败: {e}") + self.is_connected = False + return False + + async def _start_sainiu_service(self): + """启动赛牛DLL服务""" + try: + # 加载DLL + if not self.sainiu_service.load_dll('F:\\飞书下载地址\\shuidrop_gui\\Utils\\PythonNew32\\SaiNiuApi.dll'): + return False + + success = True + + if success: + logger.info("✅ 赛牛DLL服务启动成功") + # 等待服务完全启动 + await asyncio.sleep(2) + return True + else: + logger.error("❌ 赛牛DLL服务启动失败") + return False + + except Exception as e: + logger.error(f"启动赛牛服务异常: {e}") + return False + + async def _connect_websocket(self): + """连接到WebSocket服务器""" + max_retries = 5 + retry_delay = 3 + + for attempt in range(max_retries): + try: + # 获取当前的13位时间戳(毫秒级) + current_time = int(time.time() * 1000) + + # 计算签名 + ws_sign = self.sainiu_service.sign_get_sign("ws", current_time) + + # 构建URI + if ws_sign: # 如果有签名 + uri = f"ws://127.0.0.1:{self.sainiu_service.port}?time={current_time}&sign={ws_sign}" + else: # 如果没有签名 + uri = f"ws://127.0.0.1:{self.sainiu_service.port}" + + print(f"连接URI: {uri}") + + # 连接WebSocket + self.qn_ws = await websockets.connect(uri) + self.is_connected = True + print("✅ WebSocket连接成功") + + # 连接成功后立即执行授权和初始化(只执行一次) + if not self.is_authenticated: + # 1. 发送授权请求 + current_time = int(time.time() * 1000) + json_sign = self.sainiu_service.sign_get_sign("Init", current_time) + + auth_msg = { + "type": "Invoke_SaiNiu", + "traceId": "Access_Init", + "codeType": "Access", + "post": "Init", + "data": { + "AccessType": 1, + "AccessId": self.access_id, + "AccessKey": self.access_key, + "ForceLogin": True + }, + "time": current_time, + "sign": json_sign + } + + await self.qn_ws.send(json.dumps(auth_msg)) + print(f"已发送授权请求: {auth_msg}") + + # 2. 等待授权响应 + response = await self.qn_ws.recv() + response_data = json.loads(response) + print(f"收到授权响应: {response}") + + if response_data.get("traceId") == "Access_Init": + # 解析授权响应 + return_data = response_data.get("returnData", {}) + code = return_data.get("code", 0) + + if code == 200: + self.auth_token = return_data.get("token") + self.udid = return_data.get("udid") + logger.info(f"✅ 授权成功 - token: {self.auth_token}") + + # 3. 发送系统初始化请求 + current_time = int(time.time() * 1000) + sys_init_sign = self.sainiu_service.sign_get_sign("SysInit", current_time) + + init_msg = { + "type": "Invoke_SaiNiu", + "traceId": "0470bf9489729b2e8a2126a04ab3e272", + "codeType": "Access", + "post": "SysInit", + "data": { + "number": 20, + "port": 3030, + "token": True, + "connect": True, + "disconnect": True, + "newMessage": True, + "groupMessage": True, + "notice": True, + "event": True, + "assistant": True + }, + "time": current_time, + "sign": sys_init_sign + } + + await self.qn_ws.send(json.dumps(init_msg)) + print(f"已发送系统初始化请求: {init_msg}") + + # 4. 等待初始化响应 + response = await self.qn_ws.recv() + response_data = json.loads(response) + print(f"收到初始化响应: {response}") + + return_data = response_data.get("returnData", {}) + code = return_data.get("code", 0) + + if code == 200: + self.is_authenticated = True + print("✅ 授权和初始化成功") + return True + else: + error_msg = return_data.get("msg", "未知错误") + print(f"❌ 系统初始化失败: {error_msg}") + return False + else: + error_msg = return_data.get("msg", "未知错误") + print(f"❌ 授权失败: {error_msg}") + return False + + return True + + except Exception as e: + print(f"连接失败 (尝试 {attempt + 1}/{max_retries}): {e}") + if attempt < max_retries - 1: + await asyncio.sleep(retry_delay) + continue + return False + + return False + + async def _check_port_available(self): + """检查端口是否可用""" + try: + import socket + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + result = s.connect_ex(('127.0.0.1', self.sainiu_service.port)) + return result == 0 + except: + return False + + async def _sys_init(self): + """系统初始化""" + logger.info("开始赛牛插件初始化") + print("=== 断点4: 开始初始化赛牛插件 ===") + + # 发送初始化消息 + init_msg = { + "type": "Invoke_SaiNiu", + "traceId": str(uuid.uuid4()), + "codeType": "Access", + "post": "Init", + "data": { + "userNick": self.user_nick + } + } + + await self.qn_ws.send(json.dumps(init_msg)) + logger.info("已发送初始化消息") + print("=== 断点5: 初始化消息已发送 ===") + print(f"初始化消息内容: {json.dumps(init_msg, indent=2, ensure_ascii=False)}") + + async def start_listening(self, message_handler): + """开始监听消息""" + self.message_handler = message_handler + + # 启动消息监听和心跳任务 + listen_task = asyncio.create_task(self._message_loop()) + heartbeat_task = asyncio.create_task(self._heartbeat_loop()) + + logger.info("开始监听千牛消息...") + print("=== 断点6: 开始监听千牛消息 ===") + + return listen_task, heartbeat_task + + async def _heartbeat_loop(self): + """心跳循环""" + print("=== 断点7: 心跳循环开始 ===") + + while self.is_connected: + try: + # 发送心跳 + heartbeat_msg = {"type": "ping"} + await self.qn_ws.send(json.dumps(heartbeat_msg)) + logger.debug("发送心跳") + print("=== 断点8: 心跳已发送 ===") + await asyncio.sleep(20) + except Exception as e: + logger.error(f"心跳发送失败: {e}") + self.is_connected = False + break + + async def _message_loop(self): + """消息监听循环""" + print("=== 断点9: 消息监听循环开始 ===") + + try: + # # 确保正确启动后端监听 + # if (self.message_handler and + # hasattr(self.message_handler, 'ai_service') and + # self.message_handler.ai_service and + # hasattr(self.message_handler.ai_service.ai_service, 'listen_for_backend_messages')): + # + # print("🚀 启动后端消息监听任务", "DEBUG") + # # 创建监听任务 + # asyncio.create_task( + # self.message_handler.ai_service.ai_service.listen_for_backend_messages( + # self.message_handler.handle_customer_message + # ) + # ) + # else: + # print("⚠️ 无法启动后端监听:缺少必要的属性或方法", "WARNING") + + async for message in self.qn_ws: + print("=== 断点10: 收到原始消息 ===") + await self._handle_message(message) + + except Exception as e: + logger.error(f"消息监听异常: {e}") + self.is_connected = False + + async def _handle_message(self, raw_message): + """处理接收到的消息""" + print("=== 断点11: 开始处理消息 ===") + + try: + data = json.loads(raw_message) + msg_type = data.get("type") + + logger.info(f"收到消息类型: {msg_type}") + print(f"=== 断点12: 解析消息类型 - {msg_type} ===") + print(f"收到的全消息体结构为: {data}") + + # 处理心跳响应 + if msg_type == "pong": + logger.debug("收到pong响应") + print("=== 断点13: 收到心跳响应(pong) ===") + return + + # 处理连接成功消息 - 新增这个处理 + if msg_type == "FUNCTION_CONNECTED": + print("=== 函数连接已建立 ===") + print(f"连接详情: {json.dumps(data, indent=2, ensure_ascii=False)}") + + # 检查是否有认证信息 + if hasattr(self, 'auth_token') and self.auth_token: + self.is_authenticated = True + logger.info("✅ 检测到认证token,设置认证状态为 True") + else: + logger.warning("⚠️ 未检测到认证token,认证状态保持为 False") + return + + # 处理API响应 + elif msg_type in ["Invoke_SaiNiu", "Invoke_QianNiu"]: + code_type = data.get("codeType") + trace_id = data.get("traceId") + + print(f"=== API响应: type={msg_type}, codeType={code_type} ===") + print(f"响应内容: {json.dumps(data, indent=2, ensure_ascii=False)}") + + # 处理pending的Future + if trace_id and trace_id in self.pending: + future = self.pending[trace_id] + if not future.done(): + future.set_result(data) + return + + # 处理买家消息 + elif msg_type == "CHAT_DIALOGUE_MSG": + msg_data = data.get("data", {}) + code_type = msg_data.get("codeType") + + if code_type == "CHAT_RECEIVE_MSG": + message_content = msg_data.get("message", "") + + if msg_data.get("data", {}) != {}: + try: + # krishao + store_msg_id_list = msg_data.get("data", {}).get("E3_keyValueDescArray", []) + if store_msg_id_list: + store_msg_id = store_msg_id_list[0].get("desc", "") + if store_msg_id: + dingdan_id = "738740221403" + logger.info("👌👌 👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌👌 👌👌") + message_content = f"订单号: {store_msg_id} 商品ID: {dingdan_id}" + else: + pass + except Exception as e: + message_content = f"有需求要询问订单 优先回复" + sender_nick = msg_data.get("senderNick", "") + #### 核心处理逻辑!!!! + logger.info(f"收到买家消息: {sender_nick} -> {message_content}") + print(f"=== 断点14: 收到买家消息 - {sender_nick}: {message_content} ===") + + # 调用消息处理回调 + if self.message_handler: + await self.message_handler({ + "type": "message", + "data": { + "msg_type": "text", + "content": message_content, + "pin": sender_nick, + "uid": str(uuid.uuid4()) + }, + "store_id": STORE_ID + }) + return + + # 记录未处理的消息类型 + print(f"=== 未处理的消息类型: {msg_type} ===") + print(f"消息内容: {json.dumps(data, indent=2, ensure_ascii=False)}") + + except json.JSONDecodeError: + logger.error(f"消息JSON解析失败: {raw_message}") + print("=== 断点16: JSON解析失败 ===") + except Exception as e: + logger.error(f"处理消息异常: {e}") + print(f"=== 断点17: 处理消息异常 - {e} ===") + + async def ensure_connected(self): + """确保连接正常""" + if not self.is_connected or not self.qn_ws: + print("=== 连接已断开,尝试重连 ===") + return await self.connect() + return True + + async def send_message(self, to_nick: str, message: str) -> bool: + """发送消息给买家""" + logger.info(f"准备发送消息 -> {to_nick}: {message}") + print(f"=== 断点18: 准备发送消息给 {to_nick} ===") + print(f"消息内容: {message}") + + # 确保连接正常 + if not self.is_connected or not self.qn_ws: + print("=== 连接已断开,尝试重连 ===") + if not await self.connect(): + return False + + # 修改认证检查逻辑 + if not self.is_authenticated: + logger.error("认证未完成,无法发送消息") + print("=== 认证状态检查失败 ===") + # 添加调试信息 + print(f"当前认证状态: {self.is_authenticated}") + print(f"是否有auth_token: {hasattr(self, 'auth_token')}") + if hasattr(self, 'auth_token'): + print(f"auth_token值: {self.auth_token}") + return False + + try: + trace_id = str(uuid.uuid4()) + future = asyncio.Future() + self.pending[trace_id] = future + + # 构建发送消息请求 + send_msg = { + "type": "Invoke_QianNiu", + "traceId": trace_id, + "codeType": "Function", + "post": "SendMessages", + "data": { + "userNick": self.user_nick, + "buyerNick": to_nick, + "text": message, + "siteid": "cntaobao", + "waitingTime": 5000 + } + } + + # 如果有认证token,添加到消息中 + if self.auth_token: + send_msg["token"] = self.auth_token + print(f"=== 添加认证token到消息中: {self.auth_token}") + + await self.qn_ws.send(json.dumps(send_msg)) + logger.info("已发送消息到赛牛插件") + print("=== 断点19: 消息已发送到赛牛插件 ===") + print(f"发送的消息内容: {json.dumps(send_msg, indent=2, ensure_ascii=False)}") + + # 等待响应 + try: + response = await asyncio.wait_for(future, timeout=5.0) + return_data = response.get("returnData") or response.get("data", {}) + code = return_data.get("code", 0) + + if code in [200, 0, 403]: # 403也视为成功(测试账号特殊处理) + logger.info("消息发送成功") + print("=== 断点20: 消息发送成功 ===") + return True + else: + error_msg = return_data.get("msg", "未知错误") + logger.warning(f"消息发送返回非成功码: {code}, 错误信息: {error_msg}") + print(f"=== 断点21: 消息发送失败 - 错误码: {code}, 错误信息: {error_msg} ===") + return False + except asyncio.TimeoutError: + logger.warning("消息发送超时,但可能已成功") + print("=== 断点22: 消息发送超时 ===") + return True + + except Exception as e: + logger.error(f"发送消息异常: {e}") + print(f"=== 断点23: 发送消息异常 - {e} ===") + return False + + async def close(self): + """关闭连接""" + self.is_connected = False + self.is_authenticated = False + if self.qn_ws: + await self.qn_ws.close() + logger.info("千牛客户端已关闭") + + +class TestMessageHandler: + """测试消息处理器""" + + def __init__(self, qn_client): + self.qn_client = qn_client + self.received_messages = [] + self.ai_service = AIServiceIntegration() + self.backend_listening_task = None # 新增:保存监听任务 + + async def initialize(self): + """初始化消息处理器和AI服务""" + try: + # 初始化AI服务 + success = await self.ai_service.initialize_ai_service() + if not success: + logger.error("AI服务初始化失败") + return False + + # 注册消息处理器 + self.ai_service.register_message_handlers({ + "customer_message": self.handle_customer_message, + "message": self.handle_ai_message # 新增:处理AI消息 + }) + + return True + except Exception as e: + logger.error(f"消息处理器初始化失败: {e}") + return False + + + async def start_backend_listening(self): + """启动后端消息监听""" + try: + # 简化检查逻辑 + if not hasattr(self.ai_service, 'ai_service'): + self._log("⚠️ AI服务未正确初始化", "WARNING") + return False + + # 直接启动监听 + self.backend_listening_task = asyncio.create_task( + self.ai_service.ai_service.listen_for_backend_messages( + self.handle_customer_message + ) + ) + self._log("✅ 后端消息监听已启动", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 启动后端监听失败: {e}", "ERROR") + return False + + async def handle_ai_message(self, message_data): + """处理AI回复消息(用于监控、日志记录等目的)""" + try: + content = message_data.get("content", "") + sender_info = message_data.get("sender", {}) + receiver_info = message_data.get("receiver", {}) + + sender_name = sender_info.get("name", "未知发送者") + receiver_name = receiver_info.get("name", "未知接收者") + + # 记录AI回复信息 + self._log(f"🤖 AI回复 [{sender_name} → {receiver_name}]: {content[:100]}...", "DEBUG") + + # 这里可以添加额外的监控和处理逻辑 + if len(content) < 5: + self._log("⚠️ AI回复过短,可能需要优化", "WARNING") + + return True + + except Exception as e: + self._log(f"❌ 处理AI消息异常: {e}", "ERROR") + return False + + async def handle_message(self, message): + """处理接收到的买家消息""" + try: + self.received_messages.append(message) + + # 新增:打印完整的接收消息体 + print("=" * 60) + print("📨 收到买家完整消息体:") + print(json.dumps(message, indent=2, ensure_ascii=False)) + print("=" * 60) + + msg_data = message.get("data", {}) + # dingdan_id = "738740221403" + # store_msg_data = msg_data.get("data", {}) + # store_msg_data_detail = store_msg_data.get("E3_keyValueDescArray", []) + # if len(store_msg_data_detail) > 0: + # store_msg_id = store_msg_data_detail[0].get("desc", "") + # else: + # store_msg_id = "" + content = msg_data.get("content", "") + sender_nick = msg_data.get("pin", "") + + if not content or not sender_nick: + self._log("消息内容或发送者昵称为空", "WARNING") + return + + self._log(f"处理买家消息: {sender_nick} -> {content}", "INFO") + + # # 获取买家头像 + # avatar_url = "" + # try: + # avatar_url = await self.qn_client.fetch_buyer_avatar_by_http(sender_nick) + # if avatar_url: + # self._log(f"成功获取头像!!!yes: {sender_nick}", "SUCCESS") + # else: + # self._log(f"未获取到头像nononno: {sender_nick}", "WARNING") + # except Exception as e: + # self._log(f"获取头像异常aaaa: {e}", "ERROR") + + # 获取AI回复(带重试机制) + max_retries = 2 # 减少重试次数,避免长时间等待 + for retry in range(max_retries): + try: + ai_reply = await self.ai_service.get_ai_reply( + message_content=content, + sender_nick=sender_nick, + # avatar_url=avatar_url # 新增: 传递 头像url + ) + + if ai_reply: + self._log(f"AI回复: {ai_reply}", "INFO") + success = await self.qn_client.send_message(sender_nick, ai_reply) + if success: + self._log("AI回复发送成功", "SUCCESS") + return + else: + self._log("AI回复发送失败", "ERROR") + if retry < max_retries - 1: + await asyncio.sleep(1) + continue + else: + self._log("未获取到AI回复", "WARNING") + if retry < max_retries - 1: + await asyncio.sleep(1) + continue + + except Exception as e: + self._log(f"处理消息异常 (尝试 {retry + 1}/{max_retries}): {e}", "ERROR") + if retry < max_retries - 1: + await asyncio.sleep(1) + continue + + # 如果所有重试都失败,发送默认回复 + default_reply = "您好,感谢您的咨询,我们会尽快回复您!" + await self.qn_client.send_message(sender_nick, default_reply) + self._log("已发送默认回复", "WARNING") + + except Exception as e: + self._log(f"处理消息异常: {e}", "ERROR") + + async def handle_customer_message(self, message_data): + """处理来自后端的客服消息(必须保留)""" + try: + content = message_data.get("content", "") + if not content: + self._log("❌ 客服消息内容为空", "WARNING") + return False + + # 优先从receiver获取,如果没有再从data获取 + receiver_info = message_data.get("receiver", {}) + receiver_id = receiver_info.get("id", "") or message_data.get("data", {}).get("pin", "") + + if not receiver_id: + self._log("❌ 无法确定消息接收者", "WARNING") + return False + + self._log(f"📤 发送客服消息给 {receiver_id}: {content[:50]}...", "INFO") + + # 发送客服消息给买家 + success = await self.qn_client.send_message(receiver_id, content) + + if success: + self._log(f"✅ 客服消息发送成功", "SUCCESS") + else: + self._log(f"❌ 客服消息发送失败", "ERROR") + + return success + + except Exception as e: + self._log(f"❌ 处理客服消息异常: {e}", "ERROR") + return False + + async def close(self): + """关闭消息处理器""" + if self.ai_service: + await self.ai_service.close() + + def _log(self, message, level="INFO"): + """日志记录""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 根据日志级别添加颜色 + if level == "ERROR": + print(f"\033[91m[{timestamp}] [{level}] {message}\033[0m") # 红色 + elif level == "WARNING": + print(f"\033[93m[{timestamp}] [{level}] {message}\033[0m") # 黄色 + elif level == "SUCCESS": + print(f"\033[92m[{timestamp}] [{level}] {message}\033[0m") # 绿色 + elif level == "DEBUG": + print(f"\033[96m[{timestamp}] [{level}] {message}\033[0m") # 蓝色 + else: + print(f"[{timestamp}] [{level}] {message}") + + +class QianNiuListenerForGUI: + """用于GUI集成的千牛监听包装器类""" + + def __init__(self, log_callback=None): + """初始化千牛监听包装器""" + self.qn_client = None + self.message_handler = None + self.running = False + self.stop_event = None + self.log_callback = log_callback + self.log_signal = None # 添加日志信号属性 + self.tasks = [] # 新增:任务列表 + self.user_nick = None + + def _log(self, message, log_type="INFO"): + """内部日志方法""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + log_entry = f"[{timestamp}] [{log_type}] {message}" + + if hasattr(self, 'log_signal') and self.log_signal: + self.log_signal.emit(message, log_type) + elif self.log_callback: + self.log_callback(message, log_type) + else: + color_map = { + "ERROR": "\033[91m", + "WARNING": "\033[93m", + "SUCCESS": "\033[92m", + "DEBUG": "\033[96m", + } + color = color_map.get(log_type, "") + print(f"{color}[{timestamp}] [{log_type}] {message}\033[0m") + + async def _get_first_user(self): + """获取第一个可用的账号""" + try: + self._log("🔵 获取所有连接的账号...", "INFO") + connected_users = await self.get_all_connected_users() + + if not connected_users: + self._log("❌ 未找到可用的千牛账号", "ERROR") + return None + + # 获取第一个账号 + first_user = next(iter(connected_users.values())) + user_nick = first_user["userNick"] + + self._log(f"✅ 获取到账号: {user_nick}", "SUCCESS") + self._log(f"账号详情: UID={first_user.get('userUid')}, 版本={first_user.get('version')}", "DEBUG") + + return user_nick + + except Exception as e: + self._log(f"❌ 获取账号失败: {e}", "ERROR") + return None + + async def get_all_connected_users(self) -> Dict[str, Dict]: + """获取所有已连接的千牛账号 + 返回格式: {"user_nick": {"userNick": "xxx", "userUid": "xxx", ...}} + """ + logger.info("开始获取所有已连接的千牛账号") + + try: + # 通过HTTP API调用 + response = await self._http_api_call("GetAllUser", {}) + + if not response: + logger.error("获取连接账号失败:API返回为空") + return {} + + logger.debug(f"获取连接账号响应: {response}") + + # 检查返回数据格式 + if isinstance(response, dict): + # 直接返回账号信息字典 + logger.info(f"成功获取到 {len(response)} 个已连接账号") + return response + else: + logger.error(f"获取连接账号失败:返回数据格式错误 - {response}") + return {} + + except Exception as e: + logger.error(f"获取连接账号异常: {e}") + return {} + + async def _http_api_call(self, post_name: str, data_obj: Dict[str, Any]) -> Dict[str, Any]: + """按官方文档以 form-data 方式调用 QianNiu/Api 接口""" + form = aiohttp.FormData() + form.add_field("post", post_name) + form.add_field("data", json.dumps(data_obj)) + logger.debug(f"[TB-DIAG] HTTP CALL -> {post_name} url={QN_HTTP_API_URL} data={data_obj}") + try: + async with aiohttp.ClientSession() as session: + async with session.post(QN_HTTP_API_URL, data=form, timeout=26) as resp: + text = await resp.text() + logger.debug(f"[TB-DIAG] HTTP RESP <- {post_name} status={resp.status} body={text[:300]}") + if resp.status != 200: + logger.error(f"[QianNiuClient] HTTP接口 {post_name} 调用失败: status={resp.status}") + return {} + try: + return json.loads(text) + except Exception: + logger.error(f"[TB-DIAG] HTTP RESP JSON decode error on {post_name}") + return {} + except Exception as e: + logger.error(f"[QianNiuClient] HTTP接口 {post_name} 调用异常: {e}") + return {} + + async def start_listening(self): + """启动监听的主方法""" + try: + self._log("🔵 开始千牛平台连接流程", "INFO") + + # New. 获取第一个可用账号 + self.user_nick = await self._get_first_user() + if not self.user_nick: + self._log("❌ 无法获取可用账号", "ERROR") + return False + + # 1. 创建千牛客户端 + self.qn_client = QianNiuClient(user_nick=self.user_nick) + self._log("✅ 千牛客户端创建成功", "DEBUG") + + # 2. 测试DLL加载和启动(与main方法一致) + self._log("🔵 步骤1: 测试DLL加载和启动...", "INFO") + if not await self.qn_client._start_sainiu_service(): + self._log("❌ DLL服务启动失败", "ERROR") + return False + self._log("✅ DLL服务启动成功", "SUCCESS") + + # 3. 测试WebSocket连接(与main方法一致) + self._log("🔵 步骤2: 测试WebSocket连接...", "INFO") + if not await self.qn_client._connect_websocket(): + self._log("❌ WebSocket连接失败", "ERROR") + return False + self._log("✅ WebSocket连接成功", "SUCCESS") + + # 4. 创建消息处理器 + self.message_handler = TestMessageHandler(self.qn_client) + self._log("✅ 消息处理器创建成功", "DEBUG") + + # 5. 初始化AI服务 + success = await self.message_handler.initialize() + if not success: + self._log("❌ AI服务初始化失败", "ERROR") + return False + self._log("✅ AI服务初始化成功", "SUCCESS") + + # 6. 开始监听消息 + self._log("🔵 步骤3: 开始监听消息...", "INFO") + self.stop_event = asyncio.Event() + self.running = True + + print(self.user_nick) + + # 7. 启动监听任务 + listen_task, heartbeat_task = await self.qn_client.start_listening( + self.message_handler.handle_message + ) + self.tasks.extend([listen_task, heartbeat_task]) + self._log("✅ 监听任务启动成功", "SUCCESS") + + # 8. 等待任务完成或停止信号 + try: + await asyncio.gather(*self.tasks, return_exceptions=True) + except asyncio.CancelledError: + self._log("🔵 监听任务被取消", "WARNING") + except Exception as e: + self._log(f"❌ 监听过程中出现错误: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + + self._log("🎉 千牛平台消息监听已启动", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 启动监听失败: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def stop_listening(self): + """停止监听""" + try: + self._log("🔵 开始停止监听...", "INFO") + self.running = False + + # 取消所有任务 + for task in self.tasks: + if not task.done(): + task.cancel() + self.tasks.clear() + + # 关闭千牛客户端 + if self.qn_client: + self._log("🔵 关闭千牛客户端...", "DEBUG") + asyncio.create_task(self.qn_client.close()) + + # 关闭消息处理器 + if self.message_handler: + self._log("🔵 关闭消息处理器...", "DEBUG") + asyncio.create_task(self.message_handler.close()) + + # 设置停止事件 + if self.stop_event: + self.stop_event.set() + + self._log("✅ 监听已停止", "SUCCESS") + + except Exception as e: + self._log(f"❌ 停止监听时出现错误: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + + def is_running(self): + """检查是否正在运行""" + return self.running + + def set_log_signal(self, signal): + """设置日志信号""" + self.log_signal = signal + """用于GUI集成的千牛监听包装器类""" + + def __init__(self, log_callback=None): + """初始化千牛监听包装器""" + self.qn_client = None + self.message_handler = None + self.running = False + self.stop_event = None + self.log_callback = log_callback + self.log_signal = None # 添加日志信号属性 + self.tasks = [] # 新增:任务列表 + + def _log(self, message, log_type="INFO"): + """内部日志方法""" + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + log_entry = f"[{timestamp}] [{log_type}] {message}" + + if hasattr(self, 'log_signal') and self.log_signal: + self.log_signal.emit(message, log_type) + elif self.log_callback: + self.log_callback(message, log_type) + else: + color_map = { + "ERROR": "\033[91m", + "WARNING": "\033[93m", + "SUCCESS": "\033[92m", + "DEBUG": "\033[96m", + } + color = color_map.get(log_type, "") + print(f"{color}[{timestamp}] [{log_type}] {message}\033[0m") + + async def start_listening(self, user_nick): + """启动监听的主方法""" + try: + self._log("🔵 开始千牛平台连接流程", "INFO") + + # 1. 创建千牛客户端 + self.qn_client = QianNiuClient() + self._log("✅ 千牛客户端创建成功", "DEBUG") + + # 2. 测试DLL加载和启动(与main方法一致) + self._log("🔵 步骤1: 测试DLL加载和启动...", "INFO") + if not await self.qn_client._start_sainiu_service(): + self._log("❌ DLL服务启动失败", "ERROR") + return False + self._log("✅ DLL服务启动成功", "SUCCESS") + + # 3. 测试WebSocket连接(与main方法一致) + self._log("🔵 步骤2: 测试WebSocket连接...", "INFO") + if not await self.qn_client._connect_websocket(): + self._log("❌ WebSocket连接失败", "ERROR") + return False + self._log("✅ WebSocket连接成功", "SUCCESS") + + # 4. 创建消息处理器 + self.message_handler = TestMessageHandler(self.qn_client) + self._log("✅ 消息处理器创建成功", "DEBUG") + + # 5. 初始化AI服务 + success = await self.message_handler.initialize() + if not success: + self._log("❌ AI服务初始化失败", "ERROR") + return False + self._log("✅ AI服务初始化成功", "SUCCESS") + + # 6. 开始监听消息 + self._log("🔵 步骤3: 开始监听消息...", "INFO") + self.stop_event = asyncio.Event() + self.running = True + + # 7. 启动监听任务 + listen_task, heartbeat_task = await self.qn_client.start_listening( + self.message_handler.handle_message + ) + self.tasks.extend([listen_task, heartbeat_task]) + self._log("✅ 监听任务启动成功", "SUCCESS") + + # 8. 等待任务完成或停止信号 + try: + await asyncio.gather(*self.tasks, return_exceptions=True) + except asyncio.CancelledError: + self._log("🔵 监听任务被取消", "WARNING") + except Exception as e: + self._log(f"❌ 监听过程中出现错误: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + + self._log("🎉 千牛平台消息监听已启动", "SUCCESS") + return True + + except Exception as e: + self._log(f"❌ 启动监听失败: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + return False + + def stop_listening(self): + """停止监听""" + try: + self._log("🔵 开始停止监听...", "INFO") + self.running = False + + # 取消所有任务 + for task in self.tasks: + if not task.done(): + task.cancel() + self.tasks.clear() + + # 关闭千牛客户端 + if self.qn_client: + self._log("🔵 关闭千牛客户端...", "DEBUG") + asyncio.create_task(self.qn_client.close()) + + # 关闭消息处理器 + if self.message_handler: + self._log("🔵 关闭消息处理器...", "DEBUG") + asyncio.create_task(self.message_handler.close()) + + # 设置停止事件 + if self.stop_event: + self.stop_event.set() + + self._log("✅ 监听已停止", "SUCCESS") + + except Exception as e: + self._log(f"❌ 停止监听时出现错误: {e}", "ERROR") + import traceback + self._log(f"错误详情: {traceback.format_exc()}", "DEBUG") + + def is_running(self): + """检查是否正在运行""" + return self.running + + def set_log_signal(self, signal): + """设置日志信号""" + self.log_signal = signal + + + +async def main(): + """主测试函数""" + logger.info("=== 赛牛接口本地测试开始 ===") + print("=== 断点A: 测试开始 ===") + + # 创建千牛客户端 + qn_client = QianNiuClient() + message_handler = None # 提前定义变量 + + try: + # 1. 测试DLL加载和启动 + print("\n📋 步骤1: 测试DLL加载和启动...") + if not await qn_client._start_sainiu_service(): + print("❌ DLL服务启动失败") + return False + print("✅ DLL服务启动成功") + + # 2. 测试WebSocket连接(包含授权和初始化) + print("\n📋 步骤2: 测试WebSocket连接...") + if not await qn_client._connect_websocket(): + print("❌ WebSocket连接失败") + return False + print("✅ WebSocket连接成功") + + # 3. 创建消息处理器 + message_handler = TestMessageHandler(qn_client) + + # 4. 初始化消息处理器和AI服务 + print("\n📋 步骤3: 初始化AI服务...") + if not await message_handler.initialize(): + logger.error("AI服务初始化失败") + print("❌ AI服务初始化失败") + return + print("✅ AI服务初始化成功") + + # 5. 开始监听消息 + print("\n📋 步骤4: 开始监听消息...") + listen_task, heartbeat_task = await qn_client.start_listening(message_handler.handle_message) + + # 6. 测试发送消息功能 + print("\n📋 步骤5: 测试发送消息功能...") + test_nick = "test_buyer" + test_message = "这是一条测试消息" + + print(f"=== 准备发送测试消息给 {test_nick} ===") + success = await qn_client.send_message(test_nick, test_message) + + if success: + print("✅ 测试消息发送成功") + else: + print("❌ 测试消息发送失败") + + # 保持运行,直到用户中断 + logger.info("测试程序已启动,按Ctrl+C停止...") + print("=== 测试程序运行中,等待消息... ===") + + # 等待任务完成或用户中断 + await asyncio.gather(listen_task, heartbeat_task, return_exceptions=True) + + except KeyboardInterrupt: + logger.info("用户中断测试") + print("=== 断点D: 用户中断测试 ===") + except Exception as e: + logger.error(f"测试异常: {e}") + print(f"=== 断点E: 测试异常 - {e} ===") + finally: + if message_handler: # 检查变量是否已定义 + await message_handler.close() # 关闭消息处理器和AI服务 + await qn_client.close() + logger.info("=== 赛牛接口本地测试结束 ===") + print("=== 断点F: 测试结束 ===") + + + + +async def test_auth(): + """测试完整的集成连接""" + print("开始测试完整的赛牛集成连接...") + + sainiu_service = SaiNiuService() + if sainiu_service.load_dll(): + print("DLL加载成功") + else: + print("DLL加载失败") + + +if __name__ == "__main__": + # 运行测试 + asyncio.run(main()) + # asyncio.run(test_auth()) \ No newline at end of file diff --git a/Utils/QianNiu/__init__.py b/Utils/QianNiu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utils/__init__.py b/Utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utils/message_models.py b/Utils/message_models.py new file mode 100644 index 0000000..24f4fba --- /dev/null +++ b/Utils/message_models.py @@ -0,0 +1,170 @@ +import json +from dataclasses import dataclass, asdict +from typing import Optional, Dict, Any + + +@dataclass +class PlatformMessage: + """规范消息结构体 - 严格按照WebSocket文档v2格式""" + # 必填字段 + type: str # 消息类型:"message" | "staff_list" | "ping" | "pong" | "transfer" | "connect_success" | "error" + + # 条件必填字段(根据消息类型) + content: Optional[str] = None # 消息内容 + msg_type: Optional[str] = None # 消息实际类型:"text" | "image" | "video" | "product_card" | "order_card" + pin_image: Optional[str] = None # 用户头像URL + sender: Optional[Dict] = None # 发送者信息,必须包含id字段 + store_id: Optional[str] = None # 店铺ID + + # 可选字段 + receiver: Optional[Dict] = None # 接收者信息 + data: Optional[Dict] = None # 扩展数据(如客服列表、验证链接等) + uuid: Optional[str] = None # 心跳包UUID + token: Optional[str] = None # 认证令牌(心跳包可能需要) + + def __post_init__(self): + """初始化后处理""" + # 自动设置msg_type(仅对message类型) + if self.type == "message" and self.msg_type is None and self.content: + self.msg_type = self._detect_msg_type() + + def _detect_msg_type(self) -> str: + """自动检测消息类型""" + if not self.content: + return "text" + + content = self.content.lower() + + # 图片检测 + if any(ext in content for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']): + return "image" + + # 视频检测 + if any(ext in content for ext in ['.mp4', '.avi', '.mov', '.wmv', '.flv']): + return "video" + + # 订单卡片检测 - 支持多种格式 + if ("商品id:" in self.content and "订单号:" in self.content) or \ + ("商品ID:" in self.content and "订单号:" in self.content) or \ + ("咨询订单号:" in self.content and "商品ID:" in self.content): + return "order_card" + + # 商品卡片检测 + if any(keyword in content for keyword in ['goods.html', 'item.html', 'item.jd.com', '商品卡片id:']): + return "product_card" + + # 默认文本消息 + return "text" + + def to_json(self) -> str: + """序列化为JSON字符串(用于存储)""" + return json.dumps(self.to_dict(), ensure_ascii=False) + + def to_dict(self) -> Dict[str, Any]: + """转换为字典,过滤None值""" + result = {} + for key, value in asdict(self).items(): + if value is not None: + result[key] = value + return result + + @classmethod + def from_json(cls, json_str: str): + """从JSON字符串恢复结构体(用于读取)""" + data = json.loads(json_str) + return cls(**data) + + @classmethod + def from_dict(cls, data: Dict[str, Any]): + """从字典创建实例""" + return cls(**data) + + @classmethod + def create_text_message(cls, content: str, sender_id: str, store_id: str, pin_image: str = None): + """创建文本消息""" + return cls( + type="message", + content=content, + msg_type="text", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_image_message(cls, image_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建图片消息""" + return cls( + type="message", + content=image_url, + msg_type="image", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_video_message(cls, video_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建视频消息""" + return cls( + type="message", + content=video_url, + msg_type="video", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_order_card_message(cls, product_id: str, order_number: str, sender_id: str, store_id: str, + pin_image: str = None): + """创建订单卡片消息""" + return cls( + type="message", + content=f"商品id:{product_id} 订单号:{order_number}", + msg_type="order_card", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_product_card_message(cls, product_url: str, sender_id: str, store_id: str, pin_image: str = None): + """创建商品卡片消息""" + return cls( + type="message", + content=product_url, + msg_type="product_card", + pin_image=pin_image, + sender={"id": sender_id}, + store_id=store_id + ) + + @classmethod + def create_staff_list_message(cls, staff_list: list, store_id: str): + """创建客服列表消息""" + return cls( + type="staff_list", + content="客服列表更新", + data={"staff_list": staff_list}, + store_id=store_id + ) + + @classmethod + def create_ping_message(cls, uuid_str: str, token: str = None): + """创建心跳检测消息""" + message = cls( + type="ping", + uuid=uuid_str + ) + if token: + message.token = token + return message + + @classmethod + def create_pong_message(cls, uuid_str: str): + """创建心跳回复消息""" + return cls( + type="pong", + uuid=uuid_str + ) \ No newline at end of file diff --git a/WebSocket/BackendClient.py b/WebSocket/BackendClient.py new file mode 100644 index 0000000..ad7a470 --- /dev/null +++ b/WebSocket/BackendClient.py @@ -0,0 +1,809 @@ +# WebSocket/BackendClient.py +import json +import threading + +import websockets + +import uuid +import asyncio +from typing import List, Dict, Any, Optional, Callable +from config import get_gui_ws_url + + +class BackendClient: + """后端WebSocket客户端""" + + def __init__(self, url: str, token: str = None): + + self.token = token + self.uuid = str(uuid.uuid4()) + self.url = url + + # 消息处理回调函数 + self.store_list_callback: Optional[Callable] = None + self.customers_callback: Optional[Callable] = None + self.message_callback: Optional[Callable] = None + self.transfer_callback: Optional[Callable] = None + self.close_callback: Optional[Callable] = None + self.error_callback: Optional[Callable] = None + self.login_callback: Optional[Callable] = None # 新增:平台登录(下发cookies)回调 + self.success_callback: Optional[Callable] = None # 新增:后端连接成功回调 + + self.is_connected = False + + def connect(self): + """连接到WebSocket服务器""" + if self.is_connected: + return + + self.thread = threading.Thread(target=self._run_loop, daemon=True) + self.thread.start() + + def disconnect(self): + """断开WebSocket连接""" + if self.loop and self.loop.is_running(): + asyncio.run_coroutine_threadsafe(self._close(), self.loop) + + + if self.thread and self.thread.is_alive(): + self.thread.join(timeout=3) + + self.is_connected = False + + async def _close(self): + """异步关闭连接""" + if self.websocket: + await self.websocket.close() + self.is_connected = False + + def _run_loop(self): + """在新线程中运行事件循环""" + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + try: + self.loop.run_until_complete(self._connect_and_listen()) + except Exception as e: + print(f"WebSocket异常: {e}") + finally: + self.loop.close() + + async def _connect_and_listen(self): + """连接并监听消息""" + try: + self.websocket = await websockets.connect(self.url) + self.is_connected = True + self.on_connected() + + async for message in self.websocket: + try: + # 打印原始文本帧与长度 + try: + raw_len = len(message.encode('utf-8')) if isinstance(message, str) else len(message) + print(f"后端发送消息体内容:{message}") + except Exception: + pass + data = json.loads(message) + self.on_message_received(data) + except json.JSONDecodeError: + print(f"JSON解析错误: {message}") + + except Exception as e: + self.is_connected = False + self.on_error(str(e)) + + @classmethod + def from_exe_token(cls, exe_token: str): + """使用 exe_token 构造单连接客户端(ws/gui//)""" + url = get_gui_ws_url(exe_token) + return cls(url=url, token=exe_token) + + def set_callbacks(self, + store_list: Callable = None, + customers: Callable = None, + message: Callable = None, + transfer: Callable = None, + close: Callable = None, + error: Callable = None, + login: Callable = None, + success: Callable = None): + """设置各种消息类型的回调函数""" + if store_list: + self.store_list_callback = store_list + if customers: + self.customers_callback = customers + if message: + self.message_callback = message + if transfer: + self.transfer_callback = transfer + if close: + self.close_callback = close + if error: + self.error_callback = error + if login: + self.login_callback = login + if success: + self.success_callback = success + + def on_connected(self): + """连接成功时的处理""" + print("后端WebSocket连接成功") + # 不再主动请求 get_store,避免与后端不兼容导致协程未完成 + + def on_message_received(self, message: Dict[str, Any]): + """处理接收到的消息 - 根据WebSocket文档v2更新""" + # 统一打印后端下发的完整消息结构体 + try: + import json as _json + print("=== Backend -> GUI Message ===") + print(_json.dumps(message, ensure_ascii=False, indent=2)) + print("=== End Message ===") + except Exception: + pass + msg_type = message.get('type') + + try: + if msg_type == 'get_store': + self._handle_store_list(message) + elif msg_type == 'get_customers': + self._handle_customers_list(message) + elif msg_type == 'success': + print("后端连接服务成功") + # 可在此触发上层UI通知 + if self.success_callback: + try: + self.success_callback() + except Exception: + pass + elif msg_type == 'message': + self._handle_message(message) + elif msg_type == 'transfer': + self._handle_transfer(message) + elif msg_type == 'close': + self._handle_close(message) + elif msg_type == 'pong': + self._handle_pong(message) + elif msg_type == 'connect_success': # 兼容旧版 + self._handle_connect_success(message) + elif msg_type == 'login': # 新版:后台下发平台cookies + self._handle_login(message) + elif msg_type == 'error': + self._handle_error_message(message) + elif msg_type == 'staff_list': + self._handle_staff_list(message) + else: + print(f"未知消息类型: {msg_type}") + + except Exception as e: + error_msg = f"处理消息异常: {e}" + print(error_msg) + if self.error_callback: + self.error_callback(error_msg, message) + + def on_error(self, error: str): + """错误处理""" + print(f"后端连接错误: {error}") + if self.error_callback: + self.error_callback(error, None) + + # ==================== 发送消息方法 ==================== + + def send_message(self, message: Dict[str, Any]): + """ + 发送消息到后端 + + Args: + message: 要发送的消息字典 + """ + if not self.is_connected or not self.loop: + raise Exception("WebSocket未连接") + + future = asyncio.run_coroutine_threadsafe( + self._send_to_backend(message), self.loop + ) + return future.result(timeout=8) + + async def _send_to_backend(self, message: Dict[str, Any]): + """异步发送消息到后端""" + if not self.websocket: + raise Exception("WebSocket连接不存在") + + import json + message_str = json.dumps(message, ensure_ascii=False) + await self.websocket.send(message_str) + print(f"发送消息到后端: {message}") + + def send_ping(self, custom_uuid: str = None, custom_token: str = None): + """ + 发送心跳包 + 如果接收到关闭的消息后,心跳包要带上token + """ + ping_message = { + 'type': 'ping', + 'uuid': custom_uuid or self.uuid + } + + token = custom_token or self.token + if token: + ping_message['token'] = token + + return self.send_message(ping_message) + + def get_store(self): + """获取店铺信息""" + message = { + 'type': 'get_store', + 'token': self.token or '' + } + return self.send_message(message) + + def send_text_message(self, content: str, sender_id: str, store_id: str, pin_image: str = None): + """发送文本消息 - 根据WebSocket文档v2更新""" + message = { + 'type': 'message', + 'content': content, + 'msg_type': 'text', + 'sender': {'id': sender_id}, + 'store_id': store_id + } + if pin_image: + message['pin_image'] = pin_image + return self.send_message(message) + + def send_image_message(self, image_url: str, sender_id: str, store_id: str, pin_image: str = None): + """发送图片消息 - 根据WebSocket文档v2更新""" + message = { + 'type': 'message', + 'content': image_url, + 'msg_type': 'image', + 'sender': {'id': sender_id}, + 'store_id': store_id + } + if pin_image: + message['pin_image'] = pin_image + return self.send_message(message) + + def send_video_message(self, video_url: str, sender_id: str, store_id: str, pin_image: str = None): + """发送视频消息 - 根据WebSocket文档v2更新""" + message = { + 'type': 'message', + 'content': video_url, + 'msg_type': 'video', + 'sender': {'id': sender_id}, + 'store_id': store_id + } + if pin_image: + message['pin_image'] = pin_image + return self.send_message(message) + + def send_order_card(self, product_id: str, order_number: str, sender_id: str, store_id: str, pin_image: str = None): + """发送订单卡片 - 根据WebSocket文档v2更新""" + message = { + 'type': 'message', + 'content': f'商品id:{product_id} 订单号:{order_number}', + 'msg_type': 'order_card', + 'sender': {'id': sender_id}, + 'store_id': store_id + } + if pin_image: + message['pin_image'] = pin_image + return self.send_message(message) + + def send_product_card(self, product_url: str, sender_id: str, store_id: str, pin_image: str = None): + """发送商品卡片 - 根据WebSocket文档v2更新""" + message = { + 'type': 'message', + 'content': product_url, + 'msg_type': 'product_card', + 'sender': {'id': sender_id}, + 'store_id': store_id + } + if pin_image: + message['pin_image'] = pin_image + return self.send_message(message) + + def send_staff_list(self, staff_list: List[Dict], store_id: str): + """发送客服列表 - 根据WebSocket文档v2更新""" + message = { + 'type': 'staff_list', + 'content': '客服列表更新', + 'data': {'staff_list': staff_list}, + 'store_id': store_id + } + return self.send_message(message) + + # 保持向后兼容的旧方法(标记为已废弃) + def send_file_message(self, content: str, uid: str, pin: str, store_id: str): + """发送文件消息 - 已废弃,请使用send_video_message或send_image_message""" + print("警告: send_file_message已废弃,请根据文件类型使用send_video_message或send_image_message") + # 尝试自动检测文件类型 + content_lower = content.lower() + if any(ext in content_lower for ext in ['.mp4', '.avi', '.mov', '.wmv', '.flv']): + return self.send_video_message(content, uid, store_id) + elif any(ext in content_lower for ext in ['.jpg', '.jpeg', '.png', '.gif', '.webp']): + return self.send_image_message(content, uid, store_id) + else: + # 默认作为文本消息发送 + return self.send_text_message(content, uid, store_id) + + def send_transfer(self, customer: str, pin: str, store_id: str): + """发送转接消息""" + message = { + 'type': 'transfer', + 'customer': customer, # 客服名称 + 'pin': pin, # 顾客名称 + 'store_id': store_id + } + return self.send_message(message) + + def close_store(self, store_id: str): + """关闭店铺""" + message = { + 'type': 'close', + 'store_id': store_id + } + return self.send_message(message) + + # ==================== 消息处理方法 ==================== + + def _handle_store_list(self, message: Dict[str, Any]): + """处理店铺列表""" + store_list = message.get('store_list', []) + print(f"获取到{len(store_list)}个店铺:") + + for store in store_list: + merchant_name = store.get('merchant_name', '') + store_id = store.get('store_id', '') + store_platform = store.get('store_platform', '') + print(f" - {merchant_name} (ID: {store_id}, 平台: {store_platform})") + + if self.store_list_callback: + self.store_list_callback(store_list) + + def _handle_customers_list(self, message: Dict[str, Any]): + """处理客服列表""" + customers = message.get('customers', []) + store_id = message.get('store_id', '') + + print(f"店铺{store_id}的客服列表,共{len(customers)}个客服:") + for customer in customers: + pin = customer.get('pin', '') + nickname = customer.get('nickname', '') + print(f" - {nickname} ({pin})") + + if self.customers_callback: + self.customers_callback(customers, store_id) + + def _handle_message(self, message: Dict[str, Any]): + """处理消息""" + store_id = message.get('store_id', '') + data = message.get('data') + content = message.get('content', '') + print(f"[{store_id}] [{message.get('msg_type', 'unknown')}] : {content}") + + # 尝试将后端AI/客服回复转发到对应平台 + try: + receiver = message.get('receiver') or (data.get('receiver') if isinstance(data, dict) else None) or {} + recv_pin = receiver.get('id') + if recv_pin and store_id: + # 根据store_id动态确定平台类型 + platform_type = self._get_platform_by_store_id(store_id) + + if platform_type == "京东": + self._forward_to_jd(store_id, recv_pin, content) + elif platform_type == "抖音": + self._forward_to_douyin(store_id, recv_pin, content) + elif platform_type == "千牛": + self._forward_to_qianniu(store_id, recv_pin, content) + elif platform_type == "拼多多": + self._forward_to_pdd(store_id, recv_pin, content) + else: + print(f"[Forward] 未知平台类型或未找到店铺: {platform_type}, store_id={store_id}") + except Exception as e: + print(f"转发到平台失败: {e}") + + if self.message_callback: + self.message_callback(data if data else message, store_id) + + def _get_platform_by_store_id(self, store_id: str) -> str: + """根据店铺ID获取平台类型""" + try: + # 从WebSocket管理器获取平台信息 + from WebSocket.backend_singleton import get_websocket_manager + manager = get_websocket_manager() + if manager and hasattr(manager, 'platform_listeners'): + for key, listener_info in manager.platform_listeners.items(): + if listener_info.get('store_id') == store_id: + return listener_info.get('platform', '') + return "" + except Exception as e: + print(f"获取平台类型失败: {e}") + return "" + + def _forward_to_jd(self, store_id: str, recv_pin: str, content: str): + """转发消息到京东平台""" + try: + from Utils.JD.JdUtils import WebsocketManager as JDWSManager + jd_mgr = JDWSManager() + shop_key = f"京东:{store_id}" + entry = jd_mgr.get_connection(shop_key) + if not entry: + print(f"[JD Forward] 未找到连接: {shop_key}") + return + + platform_info = (entry or {}).get('platform') or {} + ws = platform_info.get('ws') + aid = platform_info.get('aid') + pin_zj = platform_info.get('pin_zj') + vender_id = platform_info.get('vender_id') + loop = platform_info.get('loop') + + print(f"[JD Forward] shop_key={shop_key} has_ws={bool(ws)} aid={aid} pin_zj={pin_zj} vender_id={vender_id} has_loop={bool(loop)} recv_pin={recv_pin}") + + if ws and aid and pin_zj and vender_id and loop and content: + async def _send(): + import hashlib as _hashlib + import time as _time + import json as _json + msg = { + "ver": "4.3", + "type": "chat_message", + "from": {"pin": pin_zj, "app": "im.waiter", "clientType": "comet"}, + "to": {"app": "im.customer", "pin": recv_pin}, + "id": _hashlib.md5(str(int(_time.time() * 1000)).encode()).hexdigest(), + "lang": "zh_CN", + "aid": aid, + "timestamp": int(_time.time() * 1000), + "readFlag": 0, + "body": { + "content": content, + "translated": False, + "param": {"cusVenderId": vender_id}, + "type": "text" + } + } + await ws.send(_json.dumps(msg)) + + import asyncio as _asyncio + _future = _asyncio.run_coroutine_threadsafe(_send(), loop) + try: + _future.result(timeout=2) + print(f"[JD Forward] 已转发到平台: pin={recv_pin}, content_len={len(content)}") + except Exception as fe: + print(f"[JD Forward] 转发提交失败: {fe}") + else: + print("[JD Forward] 条件不足,未转发:", + { + 'has_ws': bool(ws), 'has_aid': bool(aid), 'has_pin_zj': bool(pin_zj), + 'has_vender_id': bool(vender_id), 'has_loop': bool(loop), 'has_content': bool(content) + }) + except Exception as e: + print(f"[JD Forward] 转发失败: {e}") + + def _forward_to_douyin(self, store_id: str, recv_pin: str, content: str): + """转发消息到抖音平台""" + try: + from Utils.Dy.DyUtils import DouYinWebsocketManager + dy_mgr = DouYinWebsocketManager() + shop_key = f"抖音:{store_id}" + entry = dy_mgr.get_connection(shop_key) + + if not entry: + print(f"[DY Forward] 未找到连接: {shop_key}") + return + + platform_info = entry.get('platform', {}) + douyin_bot = platform_info.get('douyin_bot') + message_handler = platform_info.get('message_handler') + + print(f"[DY Forward] shop_key={shop_key} has_bot={bool(douyin_bot)} has_handler={bool(message_handler)} recv_pin={recv_pin}") + + if douyin_bot and message_handler and content: + # 在消息处理器的事件循环中发送消息 + def send_in_loop(): + try: + # 获取消息处理器的事件循环 + loop = message_handler._loop + if loop and not loop.is_closed(): + # 在事件循环中执行发送 + future = asyncio.run_coroutine_threadsafe( + message_handler.send_message_external(recv_pin, content), + loop + ) + # 等待结果 + try: + result = future.result(timeout=5) + if result: + print(f"[DY Forward] 已转发到平台: pin={recv_pin}, content_len={len(content)}") + else: + print(f"[DY Forward] 转发失败: 消息处理器返回False") + except Exception as fe: + print(f"[DY Forward] 转发执行失败: {fe}") + else: + print(f"[DY Forward] 事件循环不可用") + except Exception as e: + print(f"[DY Forward] 发送过程异常: {e}") + + # 在新线程中执行发送操作 + import threading + send_thread = threading.Thread(target=send_in_loop, daemon=True) + send_thread.start() + + else: + print("[DY Forward] 条件不足,未转发:", + { + 'has_bot': bool(douyin_bot), + 'has_handler': bool(message_handler), + 'has_content': bool(content) + }) + except Exception as e: + print(f"[DY Forward] 转发失败: {e}") + + def _forward_to_qianniu(self, store_id: str, recv_pin: str, content: str): + """转发消息到千牛平台""" + try: + # TODO: 实现千牛平台的消息转发逻辑 + print(f"[QN Forward] 千牛平台消息转发功能待实现: store_id={store_id}, recv_pin={recv_pin}, content={content}") + except Exception as e: + print(f"[QN Forward] 转发失败: {e}") + + def _forward_to_pdd(self, store_id: str, recv_pin: str, content: str): + """转发消息到拼多多平台""" + try: + from Utils.Pdd.PddUtils import WebsocketManager as PDDWSManager + pdd_mgr = PDDWSManager() + shop_key = f"拼多多:{store_id}" + entry = pdd_mgr.get_connection(shop_key) + + if not entry: + print(f"[PDD Forward] 未找到连接: {shop_key}") + return + + platform_info = entry.get('platform', {}) + pdd_instance = platform_info.get('pdd_instance') + loop = platform_info.get('loop') + + print(f"[PDD Forward] shop_key={shop_key} has_pdd_instance={bool(pdd_instance)} has_loop={bool(loop)} recv_pin={recv_pin}") + + if pdd_instance and loop and content: + # 在拼多多实例的事件循环中发送消息 + def send_in_loop(): + try: + # 在事件循环中执行发送 + future = asyncio.run_coroutine_threadsafe( + pdd_instance.send_message_external(recv_pin, content), + loop + ) + # 等待结果 + try: + result = future.result(timeout=10) # 拼多多可能需要更长时间 + if result: + print(f"[PDD Forward] 已转发到平台: uid={recv_pin}, content_len={len(content)}") + else: + print(f"[PDD Forward] 转发失败: 拼多多实例返回False") + except Exception as fe: + print(f"[PDD Forward] 转发执行失败: {fe}") + except Exception as e: + print(f"[PDD Forward] 发送过程异常: {e}") + + # 在新线程中执行发送操作 + import threading + send_thread = threading.Thread(target=send_in_loop, daemon=True) + send_thread.start() + + else: + print("[PDD Forward] 条件不足,未转发:", + { + 'has_pdd_instance': bool(pdd_instance), + 'has_loop': bool(loop), + 'has_content': bool(content) + }) + except Exception as e: + print(f"[PDD Forward] 转发失败: {e}") + + def _transfer_to_pdd(self, customer_service_id: str, user_id: str, store_id: str): + """执行拼多多平台转接操作""" + try: + from Utils.Pdd.PddUtils import WebsocketManager as PDDWSManager + pdd_mgr = PDDWSManager() + shop_key = f"拼多多:{store_id}" + entry = pdd_mgr.get_connection(shop_key) + + if not entry: + print(f"[PDD Transfer] 未找到拼多多连接: {shop_key}") + return + + platform_info = entry.get('platform', {}) + pdd_instance = platform_info.get('pdd_instance') + loop = platform_info.get('loop') + + print(f"[PDD Transfer] 找到拼多多连接,准备执行转接: user_id={user_id}, cs_id={customer_service_id}") + + if pdd_instance and loop: + # 设置目标客服ID并执行转接 + def transfer_in_loop(): + try: + # 设置目标客服ID + pdd_instance.csid = customer_service_id + + # 在事件循环中执行转接 + future = asyncio.run_coroutine_threadsafe( + pdd_instance.handle_transfer_message({ + "content": customer_service_id, + "receiver": {"id": user_id} + }), + loop + ) + + # 等待转接结果 + try: + result = future.result(timeout=15) # 转接可能需要更长时间 + if result: + print(f"[PDD Transfer] ✅ 转接成功: user_id={user_id} -> cs_id={customer_service_id}") + else: + print(f"[PDD Transfer] ❌ 转接失败: user_id={user_id}") + except Exception as fe: + print(f"[PDD Transfer] 转接执行失败: {fe}") + except Exception as e: + print(f"[PDD Transfer] 转接过程异常: {e}") + + # 在新线程中执行转接操作 + import threading + transfer_thread = threading.Thread(target=transfer_in_loop, daemon=True) + transfer_thread.start() + + else: + print(f"[PDD Transfer] 条件不足: has_pdd_instance={bool(pdd_instance)}, has_loop={bool(loop)}") + except Exception as e: + print(f"[PDD Transfer] 拼多多转接失败: {e}") + + def _handle_transfer(self, message: Dict[str, Any]): + """处理转接消息""" + # 新版转接消息格式: {"type": "transfer", "content": "客服ID", "receiver": {"id": "用户ID"}, "store_id": "店铺ID"} + customer_service_id = message.get('content', '') # 目标客服ID + receiver_info = message.get('receiver', {}) + user_id = receiver_info.get('id', '') # 用户ID + store_id = message.get('store_id', '') + + print(f"转接消息: 顾客{user_id}已转接给客服{customer_service_id} (店铺: {store_id})") + + # 根据店铺ID确定平台类型并执行转接 + try: + platform_type = self._get_platform_by_store_id(store_id) + + if platform_type == "京东": + # 京东转接逻辑 - 待实现 + print(f"[JD Transfer] 京东平台转接功能待实现") + elif platform_type == "抖音": + # 抖音转接逻辑 - 待实现 + print(f"[DY Transfer] 抖音平台转接功能待实现") + elif platform_type == "千牛": + # 千牛转接逻辑 - 待实现 + print(f"[QN Transfer] 千牛平台转接功能待实现") + elif platform_type == "拼多多": + self._transfer_to_pdd(customer_service_id, user_id, store_id) + else: + print(f"[Transfer] 未知平台类型或未找到店铺: {platform_type}, store_id={store_id}") + except Exception as e: + print(f"执行转接操作失败: {e}") + + # 保持旧版回调兼容性 + if self.transfer_callback: + self.transfer_callback(customer_service_id, user_id, store_id) + + def _handle_close(self, message: Dict[str, Any]): + """处理店铺关闭""" + store_id = message.get('store_id', '') + print(f"店铺{store_id}已关闭") + + if self.close_callback: + self.close_callback(store_id) + + def _handle_pong(self, message: Dict[str, Any]): + """处理心跳响应""" + uuid_received = message.get('uuid', '') + print(f"收到心跳响应: {uuid_received}") + + def _handle_connect_success(self, message: Dict[str, Any]): + """处理连接成功消息(旧版兼容)""" + print("后端连接成功(connect_success)") + if self.token: + self.get_store() + + def _handle_login(self, message: Dict[str, Any]): + """处理平台登录消息(新版:type=login, cookies, store_id, platform_name)""" + cookies = message.get('cookies', '') + store_id = message.get('store_id', '') + platform_name = message.get('platform_name', '') + print(f"收到登录指令: 平台={platform_name}, 店铺={store_id}, cookies_len={len(cookies) if cookies else 0}") + if self.login_callback: + self.login_callback(platform_name, store_id, cookies) + + def _handle_error_message(self, message: Dict[str, Any]): + """处理错误消息""" + error_msg = message.get('error', '未知错误') + print(f"后端连接错误: {error_msg}") + if self.error_callback: + self.error_callback(error_msg, message) + + def _handle_staff_list(self, message: Dict[str, Any]): + """处理客服列表更新消息""" + staff_list = message.get('data', {}).get('staff_list', []) + store_id = message.get('store_id', '') + print(f"店铺{store_id}的客服列表已更新,共{len(staff_list)}个客服:") + for staff in staff_list: + pin = staff.get('pin', '') + nickname = staff.get('nickname', '') + print(f" - {nickname} ({pin})") + + if self.customers_callback: # 假设客服列表更新也触发客服列表回调 + self.customers_callback(staff_list, store_id) + + # ==================== 辅助方法 ==================== + + def set_token(self, token: str): + """设置或更新令牌""" + self.token = token + + def get_connection_info(self) -> Dict[str, Any]: + """获取连接信息""" + return { + 'url': self.url, + 'token': self.token, + 'uuid': self.uuid, + 'is_connected': self.is_connected + } + + +# 使用示例 +if __name__ == '__main__': + pass + # import time + # + # def on_store_list(stores): + # print(f"回调: 收到{len(stores)}个店铺") + # + # def on_message(data, store_id): + # print(f"回调: 店铺{store_id}收到消息: {data.get('content')}") + # + # def on_error(error, message): + # print(f"回调: 发生错误: {error}") + # + # def on_login(platform_name, store_id, cookies): + # print(f"回调: 登录指令 平台={platform_name}, 店铺={store_id}, cookies_len={len(cookies) if cookies else 0}") + # # 此处触发对应平台的WS连接/更新cookies逻辑,并将该平台WS与store_id绑定 + # + # def on_success(): + # print("回调: 后端连接成功") + # + # # 创建客户端(新版:单连接) + # client = BackendClient.from_exe_token("your_exe_token_here") + # + # # 设置回调 + # client.set_callbacks( + # store_list=on_store_list, + # message=on_message, + # error=on_error, + # login=on_login, + # success=on_success + # ) + # + # try: + # # 连接 + # client.connect() + # + # # 等待连接 + # time.sleep(2) + # + # # 发送心跳 + # client.send_ping() + # + # # 保持运行 + # while True: + # time.sleep(30) + # client.send_ping() + # + # except KeyboardInterrupt: + # print("用户中断") + # finally: + # client.disconnect() \ No newline at end of file diff --git a/WebSocket/__init__.py b/WebSocket/__init__.py new file mode 100644 index 0000000..84b549b --- /dev/null +++ b/WebSocket/__init__.py @@ -0,0 +1,9 @@ +""" +WebSocket模块 +处理WebSocket连接和消息传输 +""" + +from .BackendClient import BackendClient + + +__all__ = ['BackendClient'] \ No newline at end of file diff --git a/WebSocket/backend_singleton.py b/WebSocket/backend_singleton.py new file mode 100644 index 0000000..bbd8ba5 --- /dev/null +++ b/WebSocket/backend_singleton.py @@ -0,0 +1,347 @@ +# backend_singleton.py +# 共享后端单连接客户端实例和WebSocket连接管理 +from typing import Optional, Callable +import threading +import asyncio +from threading import Thread +# 创建新的后端客户端 +from WebSocket.BackendClient import BackendClient +from Utils.JD.JdUtils import JDListenerForGUI as JDListenerForGUI_WS +from Utils.Dy.DyUtils import DouYinListenerForGUI as DYListenerForGUI_WS +from Utils.Pdd.PddUtils import PddListenerForGUI as PDDListenerForGUI_WS + +_backend_client = None + + +def set_backend_client(client: BackendClient) -> None: + global _backend_client + _backend_client = client + + +def get_backend_client() -> Optional[BackendClient]: + return _backend_client + + +class WebSocketManager: + """WebSocket连接管理器,统一处理后端连接和平台监听""" + + def __init__(self): + self.backend_client = None + self.platform_listeners = {} # 存储各平台的监听器 + self.callbacks = { + 'log': None, + 'success': None, + 'error': None + } + + def set_callbacks(self, log: Callable = None, success: Callable = None, error: Callable = None): + """设置回调函数""" + if log: + self.callbacks['log'] = log + if success: + self.callbacks['success'] = success + if error: + self.callbacks['error'] = error + + def _log(self, message: str, level: str = "INFO"): + """内部日志方法""" + if self.callbacks['log']: + self.callbacks['log'](message, level) + else: + print(f"[{level}] {message}") + + def connect_backend(self, token: str) -> bool: + """连接后端WebSocket""" + try: + # 1 保存token到配置 + try: + from config import set_saved_token + set_saved_token(token) + except Exception: + pass + + # 2 获取或创建后端客户端 + backend = get_backend_client() + + if backend: + # 3 如果有客户端更新token并重连 + backend.set_token(token) + + # 设置回调函数 + def _on_backend_success(): + try: + self._log("连接服务成功", "SUCCESS") + if self.callbacks['success']: + self.callbacks['success']() + except Exception as e: + self._log(f"成功回调执行失败: {e}", "ERROR") + + def _on_backend_login(platform_name: str, store_id: str, cookies: str): + self._log( + f"收到后端登录指令: 平台={platform_name}, 店铺={store_id}, cookies_len={len(cookies) if cookies else 0}", + "INFO") + self._handle_platform_login(platform_name, store_id, cookies) + + backend.set_callbacks(success=_on_backend_success, login=_on_backend_login) + + if not backend.is_connected: + backend.connect() + + self.backend_client = backend + self._log("令牌已提交,已连接后端。等待后端下发平台cookies后自动连接平台...", "SUCCESS") + return True + else: + + backend = BackendClient.from_exe_token(token) + + def _on_backend_login(platform_name: str, store_id: str, cookies: str): + self._log( + f"收到后端登录指令: 平台={platform_name}, 店铺={store_id}, cookies_len={len(cookies) if cookies else 0}", + "INFO") + self._handle_platform_login(platform_name, store_id, cookies) + + def _on_backend_success(): + try: + self._log("连接服务成功", "SUCCESS") + if self.callbacks['success']: + self.callbacks['success']() + except Exception as e: + self._log(f"成功回调执行失败: {e}", "ERROR") + + backend.set_callbacks(login=_on_backend_login, success=_on_backend_success) + backend.connect() + + set_backend_client(backend) + self.backend_client = backend + self._log("已创建后端客户端并连接。等待后端下发平台cookies...", "SUCCESS") + return True + + except Exception as e: + self._log(f"连接后端失败: {e}", "ERROR") + if self.callbacks['error']: + self.callbacks['error'](str(e)) + return False + + def _handle_platform_login(self, platform_name: str, store_id: str, cookies: str): + """处理平台登录逻辑""" + try: + if platform_name == "京东" and store_id and cookies: + self._start_jd_listener(store_id, cookies) + elif platform_name == "抖音" and store_id and cookies: + self._start_douyin_listener(store_id, cookies) + elif platform_name == "千牛" and store_id and cookies: + self._start_qianniu_listener(store_id, cookies) + elif platform_name == "拼多多" and store_id and cookies: + self._start_pdd_listener(store_id, cookies) + else: + self._log(f"不支持的平台或参数不全: {platform_name}", "WARNING") + except Exception as e: + self._log(f"启动平台监听失败: {e}", "ERROR") + + def _start_jd_listener(self, store_id: str, cookies: str): + """启动京东平台监听""" + try: + def _runner(): + try: + listener = JDListenerForGUI_WS() + asyncio.run(listener.start_with_cookies(store_id, cookies)) + except Exception as e: + self._log(f"京东监听器运行异常: {e}", "ERROR") + + # 在新线程中启动监听器 + thread = Thread(target=_runner, daemon=True) + thread.start() + + # 保存监听器引用 + self.platform_listeners[f"京东:{store_id}"] = { + 'thread': thread, + 'platform': '京东', + 'store_id': store_id + } + + # 上报连接状态给后端 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": True + }) + except Exception as e: + self._log(f"上报连接状态失败: {e}", "WARNING") + + self._log("已启动京东平台监听", "SUCCESS") + + except Exception as e: + self._log(f"启动京东平台监听失败: {e}", "ERROR") + + # 确保失败时也上报状态 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": False + }) + except Exception as send_e: + self._log(f"失败状态下报连接状态也失败: {send_e}", "ERROR") + + def _start_douyin_listener(self, store_id: str, cookies: str): + """启动抖音平台监听""" + try: + def _runner(): + try: + import json + listener = DYListenerForGUI_WS() + # 将JSON字符串格式的cookies解析为字典 + try: + cookie_dict = json.loads(cookies) if isinstance(cookies, str) else cookies + except json.JSONDecodeError as e: + self._log(f"❌ Cookie JSON解析失败: {e}", "ERROR") + return False + + result = asyncio.run(listener.start_with_cookies(store_id=store_id, cookie_dict=cookie_dict)) + return result + except Exception as e: + self._log(f"抖音监听器运行异常: {e}", "ERROR") + return False + + # 在新线程中启动监听器 + thread = Thread(target=_runner, daemon=True) + thread.start() + + # 保存监听器引用 + self.platform_listeners[f"抖音:{store_id}"] = { + 'thread': thread, + 'platform': '抖音', + 'store_id': store_id, + } + + # 更新监听器状态 + if f"抖音:{store_id}" in self.platform_listeners: + self.platform_listeners[f"抖音:{store_id}"]['status'] = 'success' + + # 上报连接状态给后端 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": True + }) + self._log("已上报抖音平台连接状态: 成功", "INFO") + except Exception as e: + self._log(f"上报抖音平台连接状态失败: {e}", "WARNING") + + self._log("已启动抖音平台监听", "SUCCESS") + + except Exception as e: + self._log(f"启动抖音平台监听失败: {e}", "ERROR") + + # 确保失败时也上报状态 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": False + }) + except Exception as send_e: + self._log(f"失败状态下报抖音平台连接状态也失败: {send_e}", "ERROR") + + def _start_qianniu_listener(self, store_id: str, cookies: str): + """启动千牛平台监听""" + try: + # 这里可以添加千牛监听逻辑 + self._log("千牛平台监听功能待实现", "INFO") + except Exception as e: + self._log(f"启动千牛平台监听失败: {e}", "ERROR") + + def _start_pdd_listener(self, store_id: str, cookies: str): + """启动拼多多平台监听""" + try: + def _runner(): + try: + listener = PDDListenerForGUI_WS(log_callback=self._log) + result = asyncio.run(listener.start_with_cookies(store_id=store_id, cookies=cookies)) + return result + except Exception as e: + self._log(f"拼多多监听器运行异常: {e}", "ERROR") + return False + + # 在新线程中启动监听器 + thread = Thread(target=_runner, daemon=True) + thread.start() + + # 保存监听器引用 + self.platform_listeners[f"拼多多:{store_id}"] = { + 'thread': thread, + 'platform': '拼多多', + 'store_id': store_id, + } + + # 更新监听器状态 + if f"拼多多:{store_id}" in self.platform_listeners: + self.platform_listeners[f"拼多多:{store_id}"]['status'] = 'success' + + # 上报连接状态给后端 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": True + }) + self._log("已上报拼多多平台连接状态: 成功", "INFO") + except Exception as e: + self._log(f"上报拼多多平台连接状态失败: {e}", "WARNING") + + self._log("已启动拼多多平台监听", "SUCCESS") + + except Exception as e: + self._log(f"启动拼多多平台监听失败: {e}", "ERROR") + + # 确保失败时也上报状态 + if self.backend_client: + try: + self.backend_client.send_message({ + "type": "connect_message", + "store_id": store_id, + "status": False + }) + except Exception as send_e: + self._log(f"失败状态下报拼多多平台连接状态也失败: {send_e}", "ERROR") + + def send_message(self, message: dict): + """发送消息到后端""" + if self.backend_client and self.backend_client.is_connected: + return self.backend_client.send_message(message) + else: + raise Exception("后端未连接") + + def disconnect_all(self): + """断开所有连接""" + try: + # 断开后端连接 + if self.backend_client: + self.backend_client.disconnect() + self.backend_client = None + + # 清理平台监听器 + self.platform_listeners.clear() + + self._log("所有连接已断开", "INFO") + except Exception as e: + self._log(f"断开连接时发生错误: {e}", "ERROR") + + +# 全局WebSocket管理器实例 +_websocket_manager = None + + +def get_websocket_manager() -> WebSocketManager: + """获取全局WebSocket管理器实例""" + global _websocket_manager + if _websocket_manager is None: + _websocket_manager = WebSocketManager() + return _websocket_manager diff --git a/config.py b/config.py new file mode 100644 index 0000000..40f3ace --- /dev/null +++ b/config.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +""" +项目配置文件 +统一管理所有配置参数,避免硬编码 +""" +# 用户访问令牌(默认空字符串) +import os # 用于路径与目录操作(写入用户配置目录) +import json # 用于将令牌保存为 JSON 格式 + +# 后端服务器配置 +# BACKEND_HOST = "192.168.5.155" +BACKEND_HOST = "test.shuidrop.com" +BACKEND_PORT = "" +BACKEND_BASE_URL = f"http://{BACKEND_HOST}:{BACKEND_PORT}" +# BACKEND_WS_URL = f"ws://{BACKEND_HOST}:{BACKEND_PORT}" +BACKEND_WS_URL = f"wss://{BACKEND_HOST}" + +# WebSocket配置 +WS_CONNECT_TIMEOUT = 16.0 +WS_MESSAGE_TIMEOUT = 30.0 +WS_PING_INTERVAL = 20 +WS_PING_TIMEOUT = 10 + +# 内存管理配置 +MAX_PENDING_REPLIES = 100 +CLEANUP_INTERVAL = 300 # 5分钟 +FUTURE_TIMEOUT = 300 # 5分钟 + +# 终端日志配置(简化) +LOG_LEVEL = "INFO" +VERSION = "1.0" +# GUI配置 +WINDOW_TITLE = "AI回复连接入口-V1.0" + +# 平台特定配置 +PLATFORMS = { + "JD": { + "name": "京东", + "ws_url": "wss://dongdong.jd.com/workbench/websocket" + }, + "DOUYIN": { + "name": "抖音", + "ws_url": None # 动态获取 + }, + "QIANNIU": { + "name": "千牛(淘宝)", + "ws_url": "ws://127.0.0.1:3030" + }, + "PDD": { + "name": "拼多多", + "ws_url": None # 动态获取 + } +} + +def get_backend_ws_url(platform: str, store_id: str) -> str: + """获取旧版后端WebSocket URL(按店铺建连接,保留兼容)""" + return f"{BACKEND_WS_URL}/ws/platform/{platform.lower()}/{store_id}/" + +def get_gui_ws_url(exe_token: str) -> str: + """获取新版单连接GUI专用WebSocket URL(按用户token建一条连接)""" + return f"{BACKEND_WS_URL}/ws/gui/{exe_token}/" + +def get_config(): + """获取所有配置""" + return { + 'backend_host': BACKEND_HOST, + 'backend_port': BACKEND_PORT, + 'backend_base_url': BACKEND_BASE_URL, + 'backend_ws_url': BACKEND_WS_URL, + 'ws_connect_timeout': WS_CONNECT_TIMEOUT, + 'ws_message_timeout': WS_MESSAGE_TIMEOUT, + 'max_pending_replies': MAX_PENDING_REPLIES, + 'cleanup_interval': CLEANUP_INTERVAL, + 'platforms': PLATFORMS + } + + + +APP_NAME = "ShuidropGUI" # 应用名称(作为配置目录名) + +API_TOKEN = 'sd_acF0TisgfFOtsBm4ytqb17MQbcxuX9Vp' # 默认回退令牌(仅当未找到外部配置时使用) + +def _get_config_paths(): + """返回(配置目录, 配置文件路径),位于 %APPDATA%/ShuidropGUI/config.json""" + base_dir = os.getenv('APPDATA') or os.path.expanduser('~') # 优先使用 APPDATA,其次使用用户主目录 + cfg_dir = os.path.join(base_dir, APP_NAME) # 组合配置目录路径 + cfg_file = os.path.join(cfg_dir, 'config.json') # 组合配置文件路径 + return cfg_dir, cfg_file + + +def get_saved_token() -> str: + """优先从外部 JSON 配置读取令牌,不存在时回退到内置 API_TOKEN""" + try: + cfg_dir, cfg_file = _get_config_paths() # 获取目录与文件路径 + if os.path.exists(cfg_file): # 如果配置文件存在 + with open(cfg_file, 'r', encoding='utf-8') as f: # 以 UTF-8 读取 + data = json.load(f) # 解析 JSON 内容 + token = data.get('token', '') # 读取 token 字段 + if token: # 如果有效 + return token # 返回读取到的令牌 + except Exception: + pass # 读取失败时静默回退 + return API_TOKEN # 回退为内置的默认值 + + +def set_saved_token(new_token: str) -> bool: + """将访问令牌写入外部 JSON 配置,并更新内存中的值 + - new_token: 新的访问令牌字符串 + 返回: True 表示写入成功,False 表示失败 + """ + try: + cfg_dir, cfg_file = _get_config_paths() + os.makedirs(cfg_dir, exist_ok=True) + data = {'token': new_token} + with open(cfg_file, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + # 同步更新内存变量,保证运行期可立即生效 + global API_TOKEN + API_TOKEN = new_token + return True + except Exception as e: + # 发生异常时打印提示并返回失败 + print(f"写入令牌失败: {e}") + return False \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..a6d904a --- /dev/null +++ b/main.py @@ -0,0 +1,387 @@ +import sys +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QFont, QPalette, QColor +from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, + QHBoxLayout, QLabel, QPushButton, QLineEdit, + QTextEdit, QFrame, QDialog, QDialogButtonBox, QComboBox) + +import config +from WebSocket.backend_singleton import get_websocket_manager + + +# 新增: 用户名密码输入对话框类 + +class LoginWindow(QMainWindow): + def __init__(self): + super().__init__() + self.jd_worker = None + self.progress_dialog = None + self.douyin_worker = None + self.qian_niu_worker = None + self.pdd_worker = None + + # 重复执行防护 + self.platform_combo_connected = False + self.last_login_time = 0 + self.login_cooldown = 2 # 登录冷却时间(秒) + + # 日志管理相关变量已删除 + + self.initUI() + + # 设置当前平台为ComboBox的当前值 + self.current_platform = self.platform_combo.currentText() + + def initUI(self): + # 设置窗口基本属性 + self.setWindowTitle('AI回复连接入口-V1.0') + self.setGeometry(300, 300, 800, 600) # 增大窗口尺寸 + self.setMinimumSize(700, 500) # 设置最小尺寸保证显示完整 + + # 创建中央widget + central_widget = QWidget() + self.setCentralWidget(central_widget) + + # 创建主布局 + main_layout = QVBoxLayout() + main_layout.setSpacing(25) # 增加间距 + main_layout.setContentsMargins(40, 40, 40, 40) # 增加边距 + central_widget.setLayout(main_layout) + + # 添加标题 + title_label = QLabel('AI回复连接入口') + title_label.setAlignment(Qt.AlignCenter) + title_label.setFont(QFont('Microsoft YaHei', 24, QFont.Bold)) # 使用系统自带字体 + title_label.setStyleSheet("color: #2c3e50;") + main_layout.addWidget(title_label) + + # 添加分隔线 + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + line.setStyleSheet("color: #bdc3c7;") + main_layout.addWidget(line) + + # 在token_input之前添加平台选择区域 + platform_layout = QHBoxLayout() + platform_label = QLabel("选择平台:") + self.platform_combo = QComboBox() + self.platform_combo.addItems(["JD", "抖音", "千牛(淘宝)", "拼多多"]) + + # 防止重复连接信号 - 更强的保护 + if not hasattr(self, 'platform_combo_connected') or not self.platform_combo_connected: + try: + self.platform_combo.currentIndexChanged.disconnect() + except TypeError: + pass # 如果没有连接则忽略 + + self.platform_combo.currentIndexChanged.connect(self.on_platform_changed) + self.platform_combo_connected = True + platform_layout.addWidget(platform_label) + platform_layout.addWidget(self.platform_combo) + + # 将platform_layout添加到主布局中,在token_layout之前 + main_layout.addLayout(platform_layout) + + # 创建令牌输入区域 + token_layout = QHBoxLayout() + token_layout.setSpacing(15) + + token_label = QLabel('令牌:') + token_label.setFont(QFont('Microsoft YaHei', 12)) + token_label.setFixedWidth(80) + + self.token_input = QLineEdit() + self.token_input.setPlaceholderText('请输入您的访问令牌') + self.token_input.setEchoMode(QLineEdit.Password) + self.token_input.setFont(QFont('Microsoft YaHei', 11)) + # noinspection PyUnresolvedReferences + self.token_input.returnPressed.connect(self.login) # 表示回车提交 + self.token_input.setMinimumHeight(40) # 增加输入框高度 + # 预填已保存的令牌(如果存在) + try: + from config import get_saved_token + saved = get_saved_token() + if saved: + self.token_input.setText(saved) + except Exception: + pass + + token_layout.addWidget(token_label) + token_layout.addWidget(self.token_input) + main_layout.addLayout(token_layout) + + # 创建连接按钮 + self.login_btn = QPushButton('是否连接') + self.login_btn.setFont(QFont('Microsoft YaHei', 12, QFont.Bold)) + self.login_btn.setMinimumHeight(45) # 增大按钮高度 + self.login_btn.clicked.connect(self.login) # 表示点击提交 + main_layout.addWidget(self.login_btn) + + # 添加分隔线 + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + line.setStyleSheet("color: #bdc3c7;") + main_layout.addWidget(line) + + # 日志框已永久删除,只使用终端输出 + self.log_display = None + + # 应用现代化样式 + self.apply_modern_styles() + + # 系统初始化日志输出到终端 + print("[INFO] 系统初始化完成") + + # # 在平台选择改变时添加调试日志 + # self.platform_combo.currentIndexChanged.connect(self.on_platform_changed) + + # 设置默认平台 + self.platform_combo.setCurrentText("JD") + print(f"🔥 设置默认平台为: {self.platform_combo.currentText()}") + + def apply_modern_styles(self): + """应用现代化样式,兼容各Windows版本""" + self.setStyleSheet(""" + QMainWindow { + background-color: #f9f9f9; + } + + QLabel { + color: #34495e; + } + + QLineEdit { + padding: 10px; + border: 2px solid #dfe6e9; + border-radius: 6px; + font-size: 14px; + background-color: white; + selection-background-color: #3498db; + selection-color: white; + } + + QLineEdit:focus { + border-color: #3498db; + } + + QPushButton { + background-color: #3498db; + border: none; + color: white; + padding: 12px 24px; + border-radius: 6px; + font-size: 14px; + min-width: 120px; + } + + QPushButton:hover { + background-color: #2980b9; + } + + QPushButton:pressed { + background-color: #1a6a9c; + } + + QPushButton:disabled { + background-color: #bdc3c7; + color: #7f8c8d; + } + + QTextEdit { + border: 2px solid #dfe6e9; + border-radius: 6px; + background-color: white; + padding: 8px; + font-family: 'Consolas', 'Microsoft YaHei', monospace; + } + + QFrame[frameShape="4"] { + color: #dfe6e9; + } + + QGroupBox { + font-weight: bold; + border: 2px solid #dfe6e9; + border-radius: 6px; + margin-top: 10px; + padding-top: 10px; + } + + QComboBox { + padding: 8px; + border: 2px solid #dfe6e9; + border-radius: 6px; + font-size: 14px; + background-color: white; + min-width: 100px; + } + + QComboBox::drop-down { + border: none; + width: 20px; + } + + QComboBox QAbstractItemView { + border: 2px solid #dfe6e9; + selection-background-color: #3498db; + selection-color: white; + } + """) + + # 设置全局字体,确保各Windows版本显示一致 + font = QFont('Microsoft YaHei', 10) # Windows系统自带字体 + QApplication.setFont(font) + + # 设置调色板确保颜色一致性 + palette = QPalette() + palette.setColor(QPalette.Window, QColor(249, 249, 249)) + palette.setColor(QPalette.WindowText, QColor(52, 73, 94)) + palette.setColor(QPalette.Base, QColor(255, 255, 255)) + palette.setColor(QPalette.AlternateBase, QColor(233, 235, 239)) + palette.setColor(QPalette.ToolTipBase, QColor(255, 255, 255)) + palette.setColor(QPalette.ToolTipText, QColor(52, 73, 94)) + palette.setColor(QPalette.Text, QColor(52, 73, 94)) + palette.setColor(QPalette.Button, QColor(52, 152, 219)) + palette.setColor(QPalette.ButtonText, QColor(255, 255, 255)) + palette.setColor(QPalette.BrightText, QColor(255, 255, 255)) + palette.setColor(QPalette.Highlight, QColor(52, 152, 219)) + palette.setColor(QPalette.HighlightedText, QColor(255, 255, 255)) + QApplication.setPalette(palette) + + def on_platform_changed(self, index): + """平台选择改变时的处理 - 新增方法""" + platform = self.platform_combo.currentText() + self.current_platform = platform + self.add_log(f"已选择平台: {platform}", "INFO") + print(f"🔥 平台已更改为: {platform}") + + def add_log(self, message, log_type="INFO"): + """添加日志信息 - 只输出到终端""" + from datetime import datetime + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # 根据日志类型设置颜色(ANSI颜色码) + colors = { + "ERROR": "\033[91m", # 红色 + "SUCCESS": "\033[92m", # 绿色 + "WARNING": "\033[93m", # 黄色 + "INFO": "\033[94m", # 蓝色 + "DEBUG": "\033[95m" # 紫色 + } + reset = "\033[0m" # 重置颜色 + + color = colors.get(log_type, colors["INFO"]) + log_entry = f"{color}[{timestamp}] [{log_type}] {message}{reset}" + print(log_entry) + + + def login(self): + """处理连接逻辑""" + # 防止重复快速点击 + import time + current_time = time.time() + if current_time - self.last_login_time < self.login_cooldown: + self.add_log(f"请等待 {self.login_cooldown} 秒后再试", "WARNING") + return + + self.last_login_time = current_time + + token = self.token_input.text().strip() + if not token: + self.add_log("请输入有效的连接令牌", "ERROR") + return + + # 禁用连接按钮,防止重复点击 + self.login_btn.setEnabled(False) + self.login_btn.setText("连接中...") + + try: + # 使用 WebSocket 管理器处理连接 + ws_manager = get_websocket_manager() + + # 设置回调函数 + ws_manager.set_callbacks( + log=self.add_log, + success=lambda: self.add_log("WebSocket连接管理器连接成功", "SUCCESS"), + error=lambda error: self.add_log(f"WebSocket连接管理器错误: {error}", "ERROR") + ) + + # 连接后端 + success = ws_manager.connect_backend(token) + + if success: + self.add_log("已启动WebSocket连接管理器", "SUCCESS") + else: + self.add_log("WebSocket连接管理器启动失败", "ERROR") + + except Exception as e: + self.add_log(f"连接失败: {e}", "ERROR") + finally: + self.login_btn.setEnabled(True) + self.login_btn.setText("开始连接") + + def verify_token(self, token): + """简化的令牌校验:非空即通过(实际校验由后端承担)""" + return bool(token) + + def closeEvent(self, event): + """窗口关闭事件处理""" + try: + # 使用 WebSocket 管理器断开所有连接 + from WebSocket.backend_singleton import get_websocket_manager + ws_manager = get_websocket_manager() + ws_manager.disconnect_all() + + # 停止所有工作线程(向后兼容) + workers = [] + if hasattr(self, 'jd_worker') and self.jd_worker: + workers.append(self.jd_worker) + if hasattr(self, 'douyin_worker') and self.douyin_worker: + workers.append(self.douyin_worker) + if hasattr(self, 'qian_niu_worker') and self.qian_niu_worker: + workers.append(self.qian_niu_worker) + if hasattr(self, 'pdd_worker') and self.pdd_worker: + workers.append(self.pdd_worker) + + # 停止所有线程 + for worker in workers: + if worker.isRunning(): + worker.stop() + worker.quit() + worker.wait(1000) + + # 强制关闭事件循环 + for worker in workers: + if hasattr(worker, 'loop') and worker.loop and not worker.loop.is_closed(): + worker.loop.close() + + except Exception as e: + print(f"关闭窗口时发生错误: {str(e)}") + finally: + event.accept() + + +def main(): + """主函数,用于测试界面""" + app = QApplication(sys.argv) + + # 设置应用程序属性 + app.setApplicationName(config.WINDOW_TITLE) + app.setApplicationVersion(config.VERSION) + + # 创建主窗口 + window = LoginWindow() + window.show() # 程序启动断点 + + # 运行应用程序 + sys.exit(app.exec_()) + + +if __name__ == '__main__': + main() # sd_aAoHIO9fDRIkePZEhW6oaFgK6IzAPxuB 测试令牌(token) + # username = "KLD测试" + # password = "kld168168" + # taobao nickname = "tb420723827:redboat" + diff --git a/static/js/data_encrypt.js b/static/js/data_encrypt.js new file mode 100644 index 0000000..ee3c7fc --- /dev/null +++ b/static/js/data_encrypt.js @@ -0,0 +1,2558 @@ +window = this; +navigator = { + appName : "Netscape", + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36' +} + + +!function(t, e) { + if ("object" == typeof exports && "object" == typeof module) + module.exports = e(); + else if ("function" == typeof define && define.amd) + define([], e); + else { + var r, i = e(); + for (r in i) + ("object" == typeof exports ? exports : t)[r] = i[r] + } +}(this, (function() { + var t = { + 77: function(t, e) { + (function() { + function e(t, e, r) { + null != t && ("number" == typeof t ? this.fromNumber(t, e, r) : null == e && "string" != typeof t ? this.fromString(t, 256) : this.fromString(t, e)) + } + function r() { + return new e(null) + } + var i = (i = "undefined" != typeof navigator) && "Microsoft Internet Explorer" == navigator.appName ? (e.prototype.am = function(t, e, r, i, n, o) { + for (var s = 32767 & e, h = e >> 15; 0 <= --o; ) { + var u = 32767 & this[t] + , a = this[t++] >> 15 + , c = h * u + a * s; + n = ((u = s * u + ((32767 & c) << 15) + r[i] + (1073741823 & n)) >>> 30) + (c >>> 15) + h * a + (n >>> 30), + r[i++] = 1073741823 & u + } + return n + } + , + 30) : i && "Netscape" != navigator.appName ? (e.prototype.am = function(t, e, r, i, n, o) { + for (; 0 <= --o; ) { + var s = e * this[t++] + r[i] + n; + n = Math.floor(s / 67108864), + r[i++] = 67108863 & s + } + return n + } + , + 26) : (e.prototype.am = function(t, e, r, i, n, o) { + for (var s = 16383 & e, h = e >> 14; 0 <= --o; ) { + var u = 16383 & this[t] + , a = this[t++] >> 14 + , c = h * u + a * s; + n = ((u = s * u + ((16383 & c) << 14) + r[i] + n) >> 28) + (c >> 14) + h * a, + r[i++] = 268435455 & u + } + return n + } + , + 28); + e.prototype.DB = i, + e.prototype.DM = (1 << i) - 1, + e.prototype.DV = 1 << i, + e.prototype.FV = Math.pow(2, 52), + e.prototype.F1 = 52 - i, + e.prototype.F2 = 2 * i - 52; + for (var n = new Array, o = "0".charCodeAt(0), s = 0; s <= 9; ++s) + n[o++] = s; + for (o = "a".charCodeAt(0), + s = 10; s < 36; ++s) + n[o++] = s; + for (o = "A".charCodeAt(0), + s = 10; s < 36; ++s) + n[o++] = s; + function h(t) { + return "0123456789abcdefghijklmnopqrstuvwxyz".charAt(t) + } + function u(t, e) { + return null == (e = n[t.charCodeAt(e)]) ? -1 : e + } + function a(t) { + var e = r(); + return e.fromInt(t), + e + } + function c(t) { + var e, r = 1; + return 0 != (e = t >>> 16) && (t = e, + r += 16), + 0 != (e = t >> 8) && (t = e, + r += 8), + 0 != (e = t >> 4) && (t = e, + r += 4), + 0 != (e = t >> 2) && (t = e, + r += 2), + 0 != (e = t >> 1) && (t = e, + r += 1), + r + } + function f(t) { + this.m = t + } + function p(t) { + this.m = t, + this.mp = t.invDigit(), + this.mpl = 32767 & this.mp, + this.mph = this.mp >> 15, + this.um = (1 << t.DB - 15) - 1, + this.mt2 = 2 * t.t + } + function l(t, e) { + return t & e + } + function y(t, e) { + return t | e + } + function d(t, e) { + return t ^ e + } + function m(t, e) { + return t & ~e + } + function v() {} + function g(t) { + return t + } + function b(t) { + this.r2 = r(), + this.q3 = r(), + e.ONE.dlShiftTo(2 * t.t, this.r2), + this.mu = this.r2.divide(t), + this.m = t + } + f.prototype.convert = function(t) { + return t.s < 0 || 0 <= t.compareTo(this.m) ? t.mod(this.m) : t + } + , + f.prototype.revert = function(t) { + return t + } + , + f.prototype.reduce = function(t) { + t.divRemTo(this.m, null, t) + } + , + f.prototype.mulTo = function(t, e, r) { + t.multiplyTo(e, r), + this.reduce(r) + } + , + f.prototype.sqrTo = function(t, e) { + t.squareTo(e), + this.reduce(e) + } + , + p.prototype.convert = function(t) { + var i = r(); + return t.abs().dlShiftTo(this.m.t, i), + i.divRemTo(this.m, null, i), + t.s < 0 && 0 < i.compareTo(e.ZERO) && this.m.subTo(i, i), + i + } + , + p.prototype.revert = function(t) { + var e = r(); + return t.copyTo(e), + this.reduce(e), + e + } + , + p.prototype.reduce = function(t) { + for (; t.t <= this.mt2; ) + t[t.t++] = 0; + for (var e = 0; e < this.m.t; ++e) { + var r = 32767 & t[e] + , i = r * this.mpl + ((r * this.mph + (t[e] >> 15) * this.mpl & this.um) << 15) & t.DM; + for (t[r = e + this.m.t] += this.m.am(0, i, t, e, 0, this.m.t); t[r] >= t.DV; ) + t[r] -= t.DV, + t[++r]++ + } + t.clamp(), + t.drShiftTo(this.m.t, t), + 0 <= t.compareTo(this.m) && t.subTo(this.m, t) + } + , + p.prototype.mulTo = function(t, e, r) { + t.multiplyTo(e, r), + this.reduce(r) + } + , + p.prototype.sqrTo = function(t, e) { + t.squareTo(e), + this.reduce(e) + } + , + e.prototype.copyTo = function(t) { + for (var e = this.t - 1; 0 <= e; --e) + t[e] = this[e]; + t.t = this.t, + t.s = this.s + } + , + e.prototype.fromInt = function(t) { + this.t = 1, + this.s = t < 0 ? -1 : 0, + 0 < t ? this[0] = t : t < -1 ? this[0] = t + this.DV : this.t = 0 + } + , + e.prototype.fromString = function(t, r) { + var i; + if (16 == r) + i = 4; + else if (8 == r) + i = 3; + else if (256 == r) + i = 8; + else if (2 == r) + i = 1; + else if (32 == r) + i = 5; + else { + if (4 != r) + return void this.fromRadix(t, r); + i = 2 + } + this.t = 0, + this.s = 0; + for (var n = t.length, o = !1, s = 0; 0 <= --n; ) { + var h = 8 == i ? 255 & t[n] : u(t, n); + h < 0 ? "-" == t.charAt(n) && (o = !0) : (o = !1, + 0 == s ? this[this.t++] = h : s + i > this.DB ? (this[this.t - 1] |= (h & (1 << this.DB - s) - 1) << s, + this[this.t++] = h >> this.DB - s) : this[this.t - 1] |= h << s, + (s += i) >= this.DB && (s -= this.DB)) + } + 8 == i && 0 != (128 & t[0]) && (this.s = -1, + 0 < s && (this[this.t - 1] |= (1 << this.DB - s) - 1 << s)), + this.clamp(), + o && e.ZERO.subTo(this, this) + } + , + e.prototype.clamp = function() { + for (var t = this.s & this.DM; 0 < this.t && this[this.t - 1] == t; ) + --this.t + } + , + e.prototype.dlShiftTo = function(t, e) { + for (var r = this.t - 1; 0 <= r; --r) + e[r + t] = this[r]; + for (r = t - 1; 0 <= r; --r) + e[r] = 0; + e.t = this.t + t, + e.s = this.s + } + , + e.prototype.drShiftTo = function(t, e) { + for (var r = t; r < this.t; ++r) + e[r - t] = this[r]; + e.t = Math.max(this.t - t, 0), + e.s = this.s + } + , + e.prototype.lShiftTo = function(t, e) { + for (var r = t % this.DB, i = this.DB - r, n = (1 << i) - 1, o = Math.floor(t / this.DB), s = this.s << r & this.DM, h = this.t - 1; 0 <= h; --h) + e[h + o + 1] = this[h] >> i | s, + s = (this[h] & n) << r; + for (h = o - 1; 0 <= h; --h) + e[h] = 0; + e[o] = s, + e.t = this.t + o + 1, + e.s = this.s, + e.clamp() + } + , + e.prototype.rShiftTo = function(t, e) { + e.s = this.s; + var r = Math.floor(t / this.DB); + if (r >= this.t) + e.t = 0; + else { + var i = t % this.DB + , n = this.DB - i + , o = (1 << i) - 1; + e[0] = this[r] >> i; + for (var s = r + 1; s < this.t; ++s) + e[s - r - 1] |= (this[s] & o) << n, + e[s - r] = this[s] >> i; + 0 < i && (e[this.t - r - 1] |= (this.s & o) << n), + e.t = this.t - r, + e.clamp() + } + } + , + e.prototype.subTo = function(t, e) { + for (var r = 0, i = 0, n = Math.min(t.t, this.t); r < n; ) + i += this[r] - t[r], + e[r++] = i & this.DM, + i >>= this.DB; + if (t.t < this.t) { + for (i -= t.s; r < this.t; ) + i += this[r], + e[r++] = i & this.DM, + i >>= this.DB; + i += this.s + } else { + for (i += this.s; r < t.t; ) + i -= t[r], + e[r++] = i & this.DM, + i >>= this.DB; + i -= t.s + } + e.s = i < 0 ? -1 : 0, + i < -1 ? e[r++] = this.DV + i : 0 < i && (e[r++] = i), + e.t = r, + e.clamp() + } + , + e.prototype.multiplyTo = function(t, r) { + var i = this.abs() + , n = t.abs() + , o = i.t; + for (r.t = o + n.t; 0 <= --o; ) + r[o] = 0; + for (o = 0; o < n.t; ++o) + r[o + i.t] = i.am(0, n[o], r, o, 0, i.t); + r.s = 0, + r.clamp(), + this.s != t.s && e.ZERO.subTo(r, r) + } + , + e.prototype.squareTo = function(t) { + for (var e = this.abs(), r = t.t = 2 * e.t; 0 <= --r; ) + t[r] = 0; + for (r = 0; r < e.t - 1; ++r) { + var i = e.am(r, e[r], t, 2 * r, 0, 1); + (t[r + e.t] += e.am(r + 1, 2 * e[r], t, 2 * r + 1, i, e.t - r - 1)) >= e.DV && (t[r + e.t] -= e.DV, + t[r + e.t + 1] = 1) + } + 0 < t.t && (t[t.t - 1] += e.am(r, e[r], t, 2 * r, 0, 1)), + t.s = 0, + t.clamp() + } + , + e.prototype.divRemTo = function(t, i, n) { + var o = t.abs(); + if (!(o.t <= 0)) { + if ((p = this.abs()).t < o.t) + return null != i && i.fromInt(0), + void (null != n && this.copyTo(n)); + null == n && (n = r()); + var s = r() + , h = this.s + , u = t.s; + 0 < (t = this.DB - c(o[o.t - 1])) ? (o.lShiftTo(t, s), + p.lShiftTo(t, n)) : (o.copyTo(s), + p.copyTo(n)); + var a = s.t + , f = s[a - 1]; + if (0 != f) { + var p = f * (1 << this.F1) + (1 < a ? s[a - 2] >> this.F2 : 0) + , l = this.FV / p + , y = (1 << this.F1) / p + , d = 1 << this.F2 + , m = n.t + , v = m - a + , g = null == i ? r() : i; + for (s.dlShiftTo(v, g), + 0 <= n.compareTo(g) && (n[n.t++] = 1, + n.subTo(g, n)), + e.ONE.dlShiftTo(a, g), + g.subTo(s, s); s.t < a; ) + s[s.t++] = 0; + for (; 0 <= --v; ) { + var b = n[--m] == f ? this.DM : Math.floor(n[m] * l + (n[m - 1] + d) * y); + if ((n[m] += s.am(0, b, n, v, 0, a)) < b) + for (s.dlShiftTo(v, g), + n.subTo(g, n); n[m] < --b; ) + n.subTo(g, n) + } + null != i && (n.drShiftTo(a, i), + h != u && e.ZERO.subTo(i, i)), + n.t = a, + n.clamp(), + 0 < t && n.rShiftTo(t, n), + h < 0 && e.ZERO.subTo(n, n) + } + } + } + , + e.prototype.invDigit = function() { + if (this.t < 1) + return 0; + var t = this[0]; + if (0 == (1 & t)) + return 0; + var e = 3 & t; + return 0 < (e = (e = (e = (e = e * (2 - (15 & t) * e) & 15) * (2 - (255 & t) * e) & 255) * (2 - ((65535 & t) * e & 65535)) & 65535) * (2 - t * e % this.DV) % this.DV) ? this.DV - e : -e + } + , + e.prototype.isEven = function() { + return 0 == (0 < this.t ? 1 & this[0] : this.s) + } + , + e.prototype.exp = function(t, i) { + if (4294967295 < t || t < 1) + return e.ONE; + var n, o = r(), s = r(), h = i.convert(this), u = c(t) - 1; + for (h.copyTo(o); 0 <= --u; ) + i.sqrTo(o, s), + 0 < (t & 1 << u) ? i.mulTo(s, h, o) : (n = o, + o = s, + s = n); + return i.revert(o) + } + , + e.prototype.toString = function(t) { + if (this.s < 0) + return "-" + this.negate().toString(t); + var e; + if (16 == t) + e = 4; + else if (8 == t) + e = 3; + else if (2 == t) + e = 1; + else if (32 == t) + e = 5; + else { + if (4 != t) + return this.toRadix(t); + e = 2 + } + var r, i = (1 << e) - 1, n = !1, o = "", s = this.t, u = this.DB - s * this.DB % e; + if (0 < s--) + for (u < this.DB && 0 < (r = this[s] >> u) && (n = !0, + o = h(r)); 0 <= s; ) + u < e ? (r = (this[s] & (1 << u) - 1) << e - u, + r |= this[--s] >> (u += this.DB - e)) : (r = this[s] >> (u -= e) & i, + u <= 0 && (u += this.DB, + --s)), + (n = 0 < r || n) && (o += h(r)); + return n ? o : "0" + } + , + e.prototype.negate = function() { + var t = r(); + return e.ZERO.subTo(this, t), + t + } + , + e.prototype.abs = function() { + return this.s < 0 ? this.negate() : this + } + , + e.prototype.compareTo = function(t) { + var e = this.s - t.s; + if (0 != e) + return e; + var r = this.t; + if (0 != (e = r - t.t)) + return this.s < 0 ? -e : e; + for (; 0 <= --r; ) + if (0 != (e = this[r] - t[r])) + return e; + return 0 + } + , + e.prototype.bitLength = function() { + return this.t <= 0 ? 0 : this.DB * (this.t - 1) + c(this[this.t - 1] ^ this.s & this.DM) + } + , + e.prototype.mod = function(t) { + var i = r(); + return this.abs().divRemTo(t, null, i), + this.s < 0 && 0 < i.compareTo(e.ZERO) && t.subTo(i, i), + i + } + , + e.prototype.modPowInt = function(t, e) { + return e = new (t < 256 || e.isEven() ? f : p)(e), + this.exp(t, e) + } + , + e.ZERO = a(0), + e.ONE = a(1), + v.prototype.convert = g, + v.prototype.revert = g, + v.prototype.mulTo = function(t, e, r) { + t.multiplyTo(e, r) + } + , + v.prototype.sqrTo = function(t, e) { + t.squareTo(e) + } + , + b.prototype.convert = function(t) { + if (t.s < 0 || t.t > 2 * this.m.t) + return t.mod(this.m); + if (t.compareTo(this.m) < 0) + return t; + var e = r(); + return t.copyTo(e), + this.reduce(e), + e + } + , + b.prototype.revert = function(t) { + return t + } + , + b.prototype.reduce = function(t) { + for (t.drShiftTo(this.m.t - 1, this.r2), + t.t > this.m.t + 1 && (t.t = this.m.t + 1, + t.clamp()), + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3), + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); t.compareTo(this.r2) < 0; ) + t.dAddOffset(1, this.m.t + 1); + for (t.subTo(this.r2, t); 0 <= t.compareTo(this.m); ) + t.subTo(this.m, t) + } + , + b.prototype.mulTo = function(t, e, r) { + t.multiplyTo(e, r), + this.reduce(r) + } + , + b.prototype.sqrTo = function(t, e) { + t.squareTo(e), + this.reduce(e) + } + ; + var T, w = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997], F = (1 << 26) / w[w.length - 1]; + function S() { + var t; + t = (new Date).getTime(), + x[B++] ^= 255 & t, + x[B++] ^= t >> 8 & 255, + x[B++] ^= t >> 16 & 255, + x[B++] ^= t >> 24 & 255, + O <= B && (B -= O) + } + e.prototype.chunkSize = function(t) { + return Math.floor(Math.LN2 * this.DB / Math.log(t)) + } + , + e.prototype.toRadix = function(t) { + if (null == t && (t = 10), + 0 == this.signum() || t < 2 || 36 < t) + return "0"; + var e = this.chunkSize(t) + , i = Math.pow(t, e) + , n = a(i) + , o = r() + , s = r() + , h = ""; + for (this.divRemTo(n, o, s); 0 < o.signum(); ) + h = (i + s.intValue()).toString(t).substr(1) + h, + o.divRemTo(n, o, s); + return s.intValue().toString(t) + h + } + , + e.prototype.fromRadix = function(t, r) { + this.fromInt(0); + for (var i = this.chunkSize(r = null == r ? 10 : r), n = Math.pow(r, i), o = !1, s = 0, h = 0, a = 0; a < t.length; ++a) { + var c = u(t, a); + c < 0 ? "-" == t.charAt(a) && 0 == this.signum() && (o = !0) : (h = r * h + c, + ++s >= i && (this.dMultiply(n), + this.dAddOffset(h, 0), + h = s = 0)) + } + 0 < s && (this.dMultiply(Math.pow(r, s)), + this.dAddOffset(h, 0)), + o && e.ZERO.subTo(this, this) + } + , + e.prototype.fromNumber = function(t, r, i) { + if ("number" == typeof r) + if (t < 2) + this.fromInt(1); + else + for (this.fromNumber(t, i), + this.testBit(t - 1) || this.bitwiseTo(e.ONE.shiftLeft(t - 1), y, this), + this.isEven() && this.dAddOffset(1, 0); !this.isProbablePrime(r); ) + this.dAddOffset(2, 0), + this.bitLength() > t && this.subTo(e.ONE.shiftLeft(t - 1), this); + else { + var n = new Array; + i = 7 & t, + n.length = 1 + (t >> 3), + r.nextBytes(n), + 0 < i ? n[0] &= (1 << i) - 1 : n[0] = 0, + this.fromString(n, 256) + } + } + , + e.prototype.bitwiseTo = function(t, e, r) { + for (var i, n = Math.min(t.t, this.t), o = 0; o < n; ++o) + r[o] = e(this[o], t[o]); + if (t.t < this.t) { + for (i = t.s & this.DM, + o = n; o < this.t; ++o) + r[o] = e(this[o], i); + r.t = this.t + } else { + for (i = this.s & this.DM, + o = n; o < t.t; ++o) + r[o] = e(i, t[o]); + r.t = t.t + } + r.s = e(this.s, t.s), + r.clamp() + } + , + e.prototype.changeBit = function(t, r) { + return t = e.ONE.shiftLeft(t), + this.bitwiseTo(t, r, t), + t + } + , + e.prototype.addTo = function(t, e) { + for (var r = 0, i = 0, n = Math.min(t.t, this.t); r < n; ) + i += this[r] + t[r], + e[r++] = i & this.DM, + i >>= this.DB; + if (t.t < this.t) { + for (i += t.s; r < this.t; ) + i += this[r], + e[r++] = i & this.DM, + i >>= this.DB; + i += this.s + } else { + for (i += this.s; r < t.t; ) + i += t[r], + e[r++] = i & this.DM, + i >>= this.DB; + i += t.s + } + e.s = i < 0 ? -1 : 0, + 0 < i ? e[r++] = i : i < -1 && (e[r++] = this.DV + i), + e.t = r, + e.clamp() + } + , + e.prototype.dMultiply = function(t) { + this[this.t] = this.am(0, t - 1, this, 0, 0, this.t), + ++this.t, + this.clamp() + } + , + e.prototype.dAddOffset = function(t, e) { + if (0 != t) { + for (; this.t <= e; ) + this[this.t++] = 0; + for (this[e] += t; this[e] >= this.DV; ) + this[e] -= this.DV, + ++e >= this.t && (this[this.t++] = 0), + ++this[e] + } + } + , + e.prototype.multiplyLowerTo = function(t, e, r) { + var i, n = Math.min(this.t + t.t, e); + for (r.s = 0, + r.t = n; 0 < n; ) + r[--n] = 0; + for (i = r.t - this.t; n < i; ++n) + r[n + this.t] = this.am(0, t[n], r, n, 0, this.t); + for (i = Math.min(t.t, e); n < i; ++n) + this.am(0, t[n], r, n, 0, e - n); + r.clamp() + } + , + e.prototype.multiplyUpperTo = function(t, e, r) { + var i = r.t = this.t + t.t - --e; + for (r.s = 0; 0 <= --i; ) + r[i] = 0; + for (i = Math.max(e - this.t, 0); i < t.t; ++i) + r[this.t + i - e] = this.am(e - i, t[i], r, 0, 0, this.t + i - e); + r.clamp(), + r.drShiftTo(1, r) + } + , + e.prototype.modInt = function(t) { + if (t <= 0) + return 0; + var e = this.DV % t + , r = this.s < 0 ? t - 1 : 0; + if (0 < this.t) + if (0 == e) + r = this[0] % t; + else + for (var i = this.t - 1; 0 <= i; --i) + r = (e * r + this[i]) % t; + return r + } + , + e.prototype.millerRabin = function(t) { + var i = this.subtract(e.ONE) + , n = i.getLowestSetBit(); + if (n <= 0) + return !1; + var o = i.shiftRight(n); + w.length < (t = t + 1 >> 1) && (t = w.length); + for (var s = r(), h = 0; h < t; ++h) { + s.fromInt(w[Math.floor(Math.random() * w.length)]); + var u = s.modPow(o, this); + if (0 != u.compareTo(e.ONE) && 0 != u.compareTo(i)) { + for (var a = 1; a++ < n && 0 != u.compareTo(i); ) + if (0 == (u = u.modPowInt(2, this)).compareTo(e.ONE)) + return !1; + if (0 != u.compareTo(i)) + return !1 + } + } + return !0 + } + , + e.prototype.clone = function() { + var t = r(); + return this.copyTo(t), + t + } + , + e.prototype.intValue = function() { + if (this.s < 0) { + if (1 == this.t) + return this[0] - this.DV; + if (0 == this.t) + return -1 + } else { + if (1 == this.t) + return this[0]; + if (0 == this.t) + return 0 + } + return (this[1] & (1 << 32 - this.DB) - 1) << this.DB | this[0] + } + , + e.prototype.byteValue = function() { + return 0 == this.t ? this.s : this[0] << 24 >> 24 + } + , + e.prototype.shortValue = function() { + return 0 == this.t ? this.s : this[0] << 16 >> 16 + } + , + e.prototype.signum = function() { + return this.s < 0 ? -1 : this.t <= 0 || 1 == this.t && this[0] <= 0 ? 0 : 1 + } + , + e.prototype.toByteArray = function() { + var t = this.t + , e = new Array; + e[0] = this.s; + var r, i = this.DB - t * this.DB % 8, n = 0; + if (0 < t--) + for (i < this.DB && (r = this[t] >> i) != (this.s & this.DM) >> i && (e[n++] = r | this.s << this.DB - i); 0 <= t; ) + i < 8 ? (r = (this[t] & (1 << i) - 1) << 8 - i, + r |= this[--t] >> (i += this.DB - 8)) : (r = this[t] >> (i -= 8) & 255, + i <= 0 && (i += this.DB, + --t)), + 0 != (128 & r) && (r |= -256), + 0 == n && (128 & this.s) != (128 & r) && ++n, + (0 < n || r != this.s) && (e[n++] = r); + return e + } + , + e.prototype.equals = function(t) { + return 0 == this.compareTo(t) + } + , + e.prototype.min = function(t) { + return this.compareTo(t) < 0 ? this : t + } + , + e.prototype.max = function(t) { + return 0 < this.compareTo(t) ? this : t + } + , + e.prototype.and = function(t) { + var e = r(); + return this.bitwiseTo(t, l, e), + e + } + , + e.prototype.or = function(t) { + var e = r(); + return this.bitwiseTo(t, y, e), + e + } + , + e.prototype.xor = function(t) { + var e = r(); + return this.bitwiseTo(t, d, e), + e + } + , + e.prototype.andNot = function(t) { + var e = r(); + return this.bitwiseTo(t, m, e), + e + } + , + e.prototype.not = function() { + for (var t = r(), e = 0; e < this.t; ++e) + t[e] = this.DM & ~this[e]; + return t.t = this.t, + t.s = ~this.s, + t + } + , + e.prototype.shiftLeft = function(t) { + var e = r(); + return t < 0 ? this.rShiftTo(-t, e) : this.lShiftTo(t, e), + e + } + , + e.prototype.shiftRight = function(t) { + var e = r(); + return t < 0 ? this.lShiftTo(-t, e) : this.rShiftTo(t, e), + e + } + , + e.prototype.getLowestSetBit = function() { + for (var t = 0; t < this.t; ++t) + if (0 != this[t]) + return t * this.DB + function(t) { + if (0 == t) + return -1; + var e = 0; + return 0 == (65535 & t) && (t >>= 16, + e += 16), + 0 == (255 & t) && (t >>= 8, + e += 8), + 0 == (15 & t) && (t >>= 4, + e += 4), + 0 == (3 & t) && (t >>= 2, + e += 2), + 0 == (1 & t) && ++e, + e + }(this[t]); + return this.s < 0 ? this.t * this.DB : -1 + } + , + e.prototype.bitCount = function() { + for (var t = 0, e = this.s & this.DM, r = 0; r < this.t; ++r) + t += function(t) { + for (var e = 0; 0 != t; ) + t &= t - 1, + ++e; + return e + }(this[r] ^ e); + return t + } + , + e.prototype.testBit = function(t) { + var e = Math.floor(t / this.DB); + return e >= this.t ? 0 != this.s : 0 != (this[e] & 1 << t % this.DB) + } + , + e.prototype.setBit = function(t) { + return this.changeBit(t, y) + } + , + e.prototype.clearBit = function(t) { + return this.changeBit(t, m) + } + , + e.prototype.flipBit = function(t) { + return this.changeBit(t, d) + } + , + e.prototype.add = function(t) { + var e = r(); + return this.addTo(t, e), + e + } + , + e.prototype.subtract = function(t) { + var e = r(); + return this.subTo(t, e), + e + } + , + e.prototype.multiply = function(t) { + var e = r(); + return this.multiplyTo(t, e), + e + } + , + e.prototype.divide = function(t) { + var e = r(); + return this.divRemTo(t, e, null), + e + } + , + e.prototype.remainder = function(t) { + var e = r(); + return this.divRemTo(t, null, e), + e + } + , + e.prototype.divideAndRemainder = function(t) { + var e = r() + , i = r(); + return this.divRemTo(t, e, i), + new Array(e,i) + } + , + e.prototype.modPow = function(t, e) { + var i = t.bitLength() + , n = a(1); + if (i <= 0) + return n; + var o = i < 18 ? 1 : i < 48 ? 3 : i < 144 ? 4 : i < 768 ? 5 : 6 + , s = new (i < 8 ? f : e.isEven() ? b : p)(e) + , h = new Array + , u = 3 + , l = o - 1 + , y = (1 << o) - 1; + if (h[1] = s.convert(this), + 1 < o) { + var d = r(); + for (s.sqrTo(h[1], d); u <= y; ) + h[u] = r(), + s.mulTo(d, h[u - 2], h[u]), + u += 2 + } + var m, v, g = t.t - 1, T = !0, w = r(); + for (i = c(t[g]) - 1; 0 <= g; ) { + for (l <= i ? m = t[g] >> i - l & y : (m = (t[g] & (1 << i + 1) - 1) << l - i, + 0 < g && (m |= t[g - 1] >> this.DB + i - l)), + u = o; 0 == (1 & m); ) + m >>= 1, + --u; + if ((i -= u) < 0 && (i += this.DB, + --g), + T) + h[m].copyTo(n), + T = !1; + else { + for (; 1 < u; ) + s.sqrTo(n, w), + s.sqrTo(w, n), + u -= 2; + 0 < u ? s.sqrTo(n, w) : (v = n, + n = w, + w = v), + s.mulTo(w, h[m], n) + } + for (; 0 <= g && 0 == (t[g] & 1 << i); ) + s.sqrTo(n, w), + v = n, + n = w, + w = v, + --i < 0 && (i = this.DB - 1, + --g) + } + return s.revert(n) + } + , + e.prototype.modInverse = function(t) { + var r = t.isEven(); + if (this.isEven() && r || 0 == t.signum()) + return e.ZERO; + for (var i = t.clone(), n = this.clone(), o = a(1), s = a(0), h = a(0), u = a(1); 0 != i.signum(); ) { + for (; i.isEven(); ) + i.rShiftTo(1, i), + r ? (o.isEven() && s.isEven() || (o.addTo(this, o), + s.subTo(t, s)), + o.rShiftTo(1, o)) : s.isEven() || s.subTo(t, s), + s.rShiftTo(1, s); + for (; n.isEven(); ) + n.rShiftTo(1, n), + r ? (h.isEven() && u.isEven() || (h.addTo(this, h), + u.subTo(t, u)), + h.rShiftTo(1, h)) : u.isEven() || u.subTo(t, u), + u.rShiftTo(1, u); + 0 <= i.compareTo(n) ? (i.subTo(n, i), + r && o.subTo(h, o), + s.subTo(u, s)) : (n.subTo(i, n), + r && h.subTo(o, h), + u.subTo(s, u)) + } + return 0 != n.compareTo(e.ONE) ? e.ZERO : 0 <= u.compareTo(t) ? u.subtract(t) : u.signum() < 0 ? (u.addTo(t, u), + u.signum() < 0 ? u.add(t) : u) : u + } + , + e.prototype.pow = function(t) { + return this.exp(t, new v) + } + , + e.prototype.gcd = function(t) { + var e = this.s < 0 ? this.negate() : this.clone() + , r = t.s < 0 ? t.negate() : t.clone(); + e.compareTo(r) < 0 && (n = e, + e = r, + r = n); + var i = e.getLowestSetBit() + , n = r.getLowestSetBit(); + if (n < 0) + return e; + for (0 < (n = i < n ? i : n) && (e.rShiftTo(n, e), + r.rShiftTo(n, r)); 0 < e.signum(); ) + 0 < (i = e.getLowestSetBit()) && e.rShiftTo(i, e), + 0 < (i = r.getLowestSetBit()) && r.rShiftTo(i, r), + 0 <= e.compareTo(r) ? (e.subTo(r, e), + e.rShiftTo(1, e)) : (r.subTo(e, r), + r.rShiftTo(1, r)); + return 0 < n && r.lShiftTo(n, r), + r + } + , + e.prototype.isProbablePrime = function(t) { + var e, r = this.abs(); + if (1 == r.t && r[0] <= w[w.length - 1]) { + for (e = 0; e < w.length; ++e) + if (r[0] == w[e]) + return !0; + return !1 + } + if (r.isEven()) + return !1; + for (e = 1; e < w.length; ) { + for (var i = w[e], n = e + 1; n < w.length && i < F; ) + i *= w[n++]; + for (i = r.modInt(i); e < n; ) + if (i % w[e++] == 0) + return !1 + } + return r.millerRabin(t) + } + , + e.prototype.square = function() { + var t = r(); + return this.squareTo(t), + t + } + , + e.prototype.Barrett = b; + var x = new Array + , B = 0; + if ("undefined" != typeof window && window.crypto) + if (window.crypto.getRandomValues) { + var D = new Uint8Array(32); + for (window.crypto.getRandomValues(D), + A = 0; A < 32; ++A) + x[B++] = D[A] + } else if ("Netscape" == navigator.appName && navigator.appVersion < "5") + for (var E = window.crypto.random(32), A = 0; A < E.length; ++A) + x[B++] = 255 & E.charCodeAt(A); + for (; B < O; ) + A = Math.floor(65536 * Math.random()), + x[B++] = A >>> 8, + x[B++] = 255 & A; + function I() { + if (null == T) { + for (S(), + (T = new R).init(x), + B = 0; B < x.length; ++B) + x[B] = 0; + B = 0 + } + return T.next() + } + function q() {} + function R() { + this.i = 0, + this.j = 0, + this.S = new Array + } + B = 0, + S(), + q.prototype.nextBytes = function(t) { + for (var e = 0; e < t.length; ++e) + t[e] = I() + } + , + R.prototype.init = function(t) { + for (var e, r, i = 0; i < 256; ++i) + this.S[i] = i; + for (i = e = 0; i < 256; ++i) + e = e + this.S[i] + t[i % t.length] & 255, + r = this.S[i], + this.S[i] = this.S[e], + this.S[e] = r; + this.i = 0, + this.j = 0 + } + , + R.prototype.next = function() { + var t; + return this.i = this.i + 1 & 255, + this.j = this.j + this.S[this.i] & 255, + t = this.S[this.i], + this.S[this.i] = this.S[this.j], + this.S[this.j] = t, + this.S[t + this.S[this.i] & 255] + } + ; + var O = 256; + t.exports = { + default: e, + BigInteger: e, + SecureRandom: q + } + } + ).call(this) + }, + 686: function(t, e, r) { + function i(t) { + if (o[t]) + return o[t].exports; + var e = o[t] = { + i: t, + l: !1, + exports: {} + }; + return n[t].call(e.exports, e, e.exports, i), + e.l = !0, + e.exports + } + var n, o; + t.exports = (o = {}, + i.m = n = [function(t, e) { + t.exports = r(77) + } + , function(t, e, r) { + "use strict"; + function i(t, e) { + for (var r = [], i = ~~(e / 8), n = e % 8, o = 0, s = t.length; o < s; o++) + r[o] = (t[(o + i) % s] << n & 255) + (t[(o + i + 1) % s] >>> 8 - n & 255); + return r + } + function n(t, e) { + for (var r = [], i = t.length - 1; 0 <= i; i--) + r[i] = 255 & (t[i] ^ e[i]); + return r + } + function o(t, e) { + for (var r = [], i = t.length - 1; 0 <= i; i--) + r[i] = t[i] & e[i] & 255; + return r + } + function s(t, e) { + for (var r = [], i = t.length - 1; 0 <= i; i--) + r[i] = 255 & (t[i] | e[i]); + return r + } + function h(t, e) { + for (var r = [], i = 0, n = t.length - 1; 0 <= n; n--) { + var o = t[n] + e[n] + i; + i = 255 < o ? 1 : 0, + r[n] = 255 & o + } + return r + } + function u(t, e, r, i) { + return 0 <= i && i <= 15 ? n(n(t, e), r) : s(o(t, e), o(function(t) { + for (var e = [], r = t.length - 1; 0 <= r; r--) + e[r] = 255 & ~t[r]; + return e + }(t), r)) + } + function a(t, e) { + for (var r = [], a = [], c = 0; c < 16; c++) { + var f = 4 * c; + r.push(e.slice(f, 4 + f)) + } + for (var p, l = 16; l < 68; l++) + r.push(n(n((p = n(n(r[l - 16], r[l - 9]), i(r[l - 3], 15)), + n(n(p, i(p, 15)), i(p, 23))), i(r[l - 13], 7)), r[l - 6])); + for (var y = 0; y < 64; y++) + a.push(n(r[y], r[y + 4])); + for (var d, m, v = [121, 204, 69, 25], g = [122, 135, 157, 138], b = t.slice(0, 4), T = t.slice(4, 8), w = t.slice(8, 12), F = t.slice(12, 16), S = t.slice(16, 20), x = t.slice(20, 24), B = t.slice(24, 28), D = t.slice(28, 32), E = void 0, A = 0; A < 64; A++) { + var I = 0 <= A && A <= 15 ? v : g + , q = n(E = i(h(h(i(b, 12), S), i(I, A)), 7), i(b, 12)) + , R = h(h(h((d = b, + m = T, + R = w, + 0 <= (I = A) && I <= 15 ? n(n(d, m), R) : s(s(o(d, m), o(d, R)), o(m, R))), F), q), a[A]); + q = h(h(h(u(S, x, B, A), D), E), r[A]), + F = w, + w = i(T, 9), + T = b, + b = R, + D = B, + B = i(x, 19), + x = S, + S = n(n(q = q, i(q, 9)), i(q, 17)) + } + return n([].concat(b, T, w, F, S, x, B, D), t) + } + t.exports = function(t) { + for (var e = 448 <= (e = (h = 8 * t.length) % 512) ? 512 - e % 448 - 1 : 448 - e - 1, r = new Array((e - 7) / 8), i = 0, n = r.length; i < n; i++) + r[i] = 0; + for (var o, s = [], h = h.toString(2), u = 7; 0 <= u; u--) + 8 < h.length ? (o = h.length - 8, + s[u] = parseInt(h.substr(o), 2), + h = h.substr(0, o)) : 0 < h.length ? (s[u] = parseInt(h, 2), + h = "") : s[u] = 0; + for (var c = [].concat(t, [128], r, s), f = c.length / 64, p = [115, 128, 22, 111, 73, 20, 178, 185, 23, 36, 66, 215, 218, 138, 6, 0, 169, 111, 48, 188, 22, 49, 56, 170, 227, 141, 238, 77, 176, 251, 14, 78], l = 0; l < f; l++) { + var y = 64 * l; + p = a(p, c.slice(y, 64 + y)) + } + return p + } + } + , function(t, e, r) { + "use strict"; + t.exports = { + sm2: r(3), + sm3: r(7), + sm4: r(8) + } + } + , function(t, e, r) { + "use strict"; + var i = r(0).BigInteger + , n = r(4) + , o = n.encodeDer + , s = n.decodeDer + , h = r(5) + , u = r(1) + , a = (r = h.generateEcparam()).G + , c = r.curve + , f = r.n; + function p(t, e, r) { + var i = h.utf8ToHex(i = 2 < arguments.length && void 0 !== r ? r : "1234567812345678") + , n = h.leftPad(a.curve.a.toBigInteger().toRadix(16), 64) + , o = h.leftPad(a.curve.b.toBigInteger().toRadix(16), 64) + , s = h.leftPad(a.getX().toBigInteger().toRadix(16), 64) + , c = h.leftPad(a.getY().toBigInteger().toRadix(16), 64); + return r = (e = 128 < e.length ? e.substr(2, 128) : e).substr(0, 64), + e = e.substr(64, 64), + e = h.hexToArray(i + n + o + s + c + r + e), + i = 4 * i.length, + e.unshift(255 & i), + e.unshift(i >> 8 & 255), + e = u(e), + h.arrayToHex(u(e.concat(h.hexToArray(t)))) + } + function l() { + var t = h.generateKeyPairHex() + , e = c.decodePointHex(t.publicKey); + return t.k = new i(t.privateKey,16), + t.x1 = e.getX().toBigInteger(), + t + } + t.exports = { + generateKeyPairHex: h.generateKeyPairHex, + doEncrypt: function(t, e) { + var r = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : 1; + t = h.hexToArray(h.utf8ToHex(t)), + e = h.getGlobalCurve().decodePointHex(e); + var n = h.generateKeyPairHex() + , o = new i(n.privateKey,16) + , s = n.publicKey; + function a() { + p = u([].concat(l, [c >> 24 & 255, c >> 16 & 255, c >> 8 & 255, 255 & c])), + c++, + f = 0 + } + 128 < s.length && (s = s.substr(s.length - 128)), + n = e.multiply(o), + e = h.hexToArray(h.leftPad(n.getX().toBigInteger().toRadix(16), 64)), + o = h.hexToArray(h.leftPad(n.getY().toBigInteger().toRadix(16), 64)), + n = h.arrayToHex(u([].concat(e, t, o))); + var c = 1 + , f = 0 + , p = [] + , l = [].concat(e, o); + a(); + for (var y = 0, d = t.length; y < d; y++) + f === p.length && a(), + t[y] ^= 255 & p[f++]; + return o = h.arrayToHex(t), + 0 === r ? s + o + n : s + n + o + }, + doDecrypt: function(t, e) { + var r = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : 1; + e = new i(e,16); + var n = t.substr(128, 64) + , o = t.substr(192); + function s() { + p = u([].concat(l, [c >> 24 & 255, c >> 16 & 255, c >> 8 & 255, 255 & c])), + c++, + f = 0 + } + 0 === r && (n = t.substr(t.length - 64), + o = t.substr(128, t.length - 128 - 64)); + var a = h.hexToArray(o) + , c = (t = h.getGlobalCurve().decodePointHex("04" + t.substr(0, 128)).multiply(e), + e = h.hexToArray(h.leftPad(t.getX().toBigInteger().toRadix(16), 64)), + t = h.hexToArray(h.leftPad(t.getY().toBigInteger().toRadix(16), 64)), + 1) + , f = 0 + , p = [] + , l = [].concat(e, t); + s(); + for (var y = 0, d = a.length; y < d; y++) + f === p.length && s(), + a[y] ^= 255 & p[f++]; + return h.arrayToHex(u([].concat(e, a, t))) === n ? h.arrayToUtf8(a) : "" + }, + doSignature: function(t, e) { + var r = (c = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : {}).pointPool + , n = c.der + , s = c.hash + , u = c.publicKey + , c = c.userId; + t = "string" == typeof t ? h.utf8ToHex(t) : h.arrayToHex(t), + s && (t = p(t, u || (s = e, + u = a.multiply(new i(s,16)), + "04" + (s = h.leftPad(u.getX().toBigInteger().toString(16), 64)) + (u = h.leftPad(u.getY().toBigInteger().toString(16), 64))), c)); + var y = new i(e,16) + , d = new i(t,16) + , m = null + , v = null + , g = null; + do { + do { + var b = void 0; + m = (b = r && r.length ? r.pop() : l()).k, + v = d.add(b.x1).mod(f) + } while (v.equals(i.ZERO) || v.add(m).equals(f)) + } while ((g = y.add(i.ONE).modInverse(f).multiply(m.subtract(v.multiply(y))).mod(f)).equals(i.ZERO)); + return n ? o(v, g) : h.leftPad(v.toString(16), 64) + h.leftPad(g.toString(16), 64) + }, + doVerifySignature: function(t, e, r) { + var n = (u = 3 < arguments.length && void 0 !== arguments[3] ? arguments[3] : {}).der + , o = u.hash + , u = u.userId; + return t = "string" == typeof t ? h.utf8ToHex(t) : h.arrayToHex(t), + o && (t = p(t, r, u)), + o = void 0, + u = void 0, + u = n ? (o = (n = s(e)).r, + n.s) : (o = new i(e.substring(0, 64),16), + new i(e.substring(64),16)), + e = c.decodePointHex(r), + r = new i(t,16), + !(t = o.add(u).mod(f)).equals(i.ZERO) && (t = a.multiply(u).add(e.multiply(t)), + t = r.add(t.getX().toBigInteger()).mod(f), + o.equals(t)) + }, + getPoint: l, + verifyPublicKey: h.verifyPublicKey + } + } + , function(t, e, r) { + "use strict"; + function i(t, e) { + if (!t) + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + return !e || "object" != typeof e && "function" != typeof e ? t : e + } + function n(t, e) { + if ("function" != typeof e && null !== e) + throw new TypeError("Super expression must either be null or a function, not " + typeof e); + t.prototype = Object.create(e && e.prototype, { + constructor: { + value: t, + enumerable: !1, + writable: !0, + configurable: !0 + } + }), + e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) + } + function o(t, e) { + if (!(t instanceof e)) + throw new TypeError("Cannot call a class as a function") + } + var s = r(0).BigInteger; + function h() { + o(this, h), + this.tlv = null, + this.t = "00", + this.l = "00", + this.v = "" + } + h.prototype.getEncodedHex = function() { + return this.tlv || (this.v = this.getValue(), + this.l = this.getLength(), + this.tlv = this.t + this.l + this.v), + this.tlv + } + , + h.prototype.getLength = function() { + var t = this.v.length / 2 + , e = t.toString(16); + return e.length % 2 == 1 && (e = "0" + e), + t < 128 ? e : (128 + e.length / 2).toString(16) + e + } + , + h.prototype.getValue = function() { + return "" + } + ; + var u, a = (n(c, u = r = h), + c.prototype.getValue = function() { + return this.v + } + , + c); + function c(t) { + o(this, c); + var e = i(this, u.call(this)); + return e.t = "02", + t && (e.v = function(t) { + if ("-" !== (e = t.toString(16))[0]) + e.length % 2 == 1 ? e = "0" + e : e.match(/^[0-7]/) || (e = "00" + e); + else { + var e, r = (e = e.substr(1)).length; + r % 2 == 1 ? r += 1 : e.match(/^[0-7]/) || (r += 2); + for (var i = "", n = 0; n < r; n++) + i += "f"; + e = (e = (i = new s(i,16)).xor(t).add(s.ONE)).toString(16).replace(/^-/, "") + } + return e + }(t)), + e + } + var f, p = (n(l, f = r), + l.prototype.getValue = function() { + return this.v = this.asn1Array.map((function(t) { + return t.getEncodedHex() + } + )).join(""), + this.v + } + , + l); + function l(t) { + o(this, l); + var e = i(this, f.call(this)); + return e.t = "30", + e.asn1Array = t, + e + } + function y(t, e) { + return +t[e + 2] < 8 ? 1 : 128 & +t.substr(e + 2, 2) + } + function d(t, e) { + var r = y(t, e); + return (r = t.substr(e + 2, 2 * r)) ? (+r[0] < 8 ? new s(r,16) : new s(r.substr(2),16)).intValue() : -1 + } + function m(t, e) { + return e + 2 * (y(t, e) + 1) + } + t.exports = { + encodeDer: function(t, e) { + return t = new a(t), + e = new a(e), + new p([t, e]).getEncodedHex() + }, + decodeDer: function(t) { + var e = m(t, 0) + , r = m(t, e) + , i = d(t, e); + return e = t.substr(r, 2 * i), + r = m(t, i = r + e.length), + i = d(t, i), + i = t.substr(r, 2 * i), + { + r: new s(e,16), + s: new s(i,16) + } + } + } + } + , function(t, e, r) { + "use strict"; + var i = (n = r(0)).BigInteger + , n = n.SecureRandom + , o = r(6).ECCurveFp + , s = new n + , h = (n = c()).curve + , u = n.G + , a = n.n; + function c() { + var t = new i("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",16) + , e = new i("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",16) + , r = new i("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",16); + return r = (e = new o(t,e,r)).decodePointHex("0432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"), + { + curve: e, + G: r, + n: new i("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",16) + } + } + function f(t, e) { + return t.length >= e ? t : new Array(e - t.length + 1).join("0") + t + } + t.exports = { + getGlobalCurve: function() { + return h + }, + generateEcparam: c, + generateKeyPairHex: function(t, e, r) { + return { + privateKey: r = f((e = (t ? new i(t,e,r) : new i(a.bitLength(),s)).mod(a.subtract(i.ONE)).add(i.ONE)).toString(16), 64), + publicKey: "04" + f((e = u.multiply(e)).getX().toBigInteger().toString(16), 64) + f(e.getY().toBigInteger().toString(16), 64) + } + }, + utf8ToHex: function(t) { + for (var e = (t = unescape(encodeURIComponent(t))).length, r = [], i = 0; i < e; i++) + r[i >>> 2] |= (255 & t.charCodeAt(i)) << 24 - i % 4 * 8; + for (var n = [], o = 0; o < e; o++) { + var s = r[o >>> 2] >>> 24 - o % 4 * 8 & 255; + n.push((s >>> 4).toString(16)), + n.push((15 & s).toString(16)) + } + return n.join("") + }, + leftPad: f, + arrayToHex: function(t) { + return t.map((function(t) { + return 1 === (t = t.toString(16)).length ? "0" + t : t + } + )).join("") + }, + arrayToUtf8: function(t) { + for (var e = [], r = 0, i = 0; i < 2 * t.length; i += 2) + e[i >>> 3] |= parseInt(t[r], 10) << 24 - i % 8 * 4, + r++; + try { + for (var n = [], o = 0; o < t.length; o++) { + var s = e[o >>> 2] >>> 24 - o % 4 * 8 & 255; + n.push(String.fromCharCode(s)) + } + return decodeURIComponent(escape(n.join(""))) + } catch (t) { + throw new Error("Malformed UTF-8 data") + } + }, + hexToArray: function(t) { + for (var e = [], r = (t = (r = t.length) % 2 != 0 ? f(t, r + 1) : t).length, i = 0; i < r; i += 2) + e.push(parseInt(t.substr(i, 2), 16)); + return e + }, + verifyPublicKey: function(t) { + var e = h.decodePointHex(t); + return !!e && (t = e.getX(), + e.getY().square().equals(t.multiply(t.square()).add(t.multiply(h.a)).add(h.b))) + } + } + } + , function(t, e, r) { + "use strict"; + function i(t, e) { + if (!(t instanceof e)) + throw new TypeError("Cannot call a class as a function") + } + var n = r(0).BigInteger + , o = new n("3") + , s = (h.prototype.equals = function(t) { + return t === this || this.q.equals(t.q) && this.x.equals(t.x) + } + , + h.prototype.toBigInteger = function() { + return this.x + } + , + h.prototype.negate = function() { + return new h(this.q,this.x.negate().mod(this.q)) + } + , + h.prototype.add = function(t) { + return new h(this.q,this.x.add(t.toBigInteger()).mod(this.q)) + } + , + h.prototype.subtract = function(t) { + return new h(this.q,this.x.subtract(t.toBigInteger()).mod(this.q)) + } + , + h.prototype.multiply = function(t) { + return new h(this.q,this.x.multiply(t.toBigInteger()).mod(this.q)) + } + , + h.prototype.divide = function(t) { + return new h(this.q,this.x.multiply(t.toBigInteger().modInverse(this.q)).mod(this.q)) + } + , + h.prototype.square = function() { + return new h(this.q,this.x.square().mod(this.q)) + } + , + h); + function h(t, e) { + i(this, h), + this.x = e, + this.q = t + } + var u = (a.prototype.getX = function() { + return null === this.zinv && (this.zinv = this.z.modInverse(this.curve.q)), + this.curve.fromBigInteger(this.x.toBigInteger().multiply(this.zinv).mod(this.curve.q)) + } + , + a.prototype.getY = function() { + return null === this.zinv && (this.zinv = this.z.modInverse(this.curve.q)), + this.curve.fromBigInteger(this.y.toBigInteger().multiply(this.zinv).mod(this.curve.q)) + } + , + a.prototype.equals = function(t) { + return t === this || (this.isInfinity() ? t.isInfinity() : t.isInfinity() ? this.isInfinity() : !!t.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(t.z)).mod(this.curve.q).equals(n.ZERO) && t.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(t.z)).mod(this.curve.q).equals(n.ZERO)) + } + , + a.prototype.isInfinity = function() { + return null === this.x && null === this.y || this.z.equals(n.ZERO) && !this.y.toBigInteger().equals(n.ZERO) + } + , + a.prototype.negate = function() { + return new a(this.curve,this.x,this.y.negate(),this.z) + } + , + a.prototype.add = function(t) { + if (this.isInfinity()) + return t; + if (t.isInfinity()) + return this; + var e = this.x.toBigInteger() + , r = this.y.toBigInteger() + , i = this.z + , o = t.x.toBigInteger() + , s = t.y.toBigInteger() + , h = t.z + , u = this.curve.q + , c = e.multiply(h).mod(u); + return t = o.multiply(i).mod(u), + e = c.subtract(t), + o = r.multiply(h).mod(u), + r = s.multiply(i).mod(u), + s = o.subtract(r), + n.ZERO.equals(e) ? n.ZERO.equals(s) ? this.twice() : this.curve.infinity : (r = c.add(t), + t = i.multiply(h).mod(u), + i = e.square().mod(u), + h = e.multiply(i).mod(u), + r = t.multiply(s.square()).subtract(r.multiply(i)).mod(u), + e = e.multiply(r).mod(u), + o = s.multiply(i.multiply(c).subtract(r)).subtract(o.multiply(h)).mod(u), + u = h.multiply(t).mod(u), + new a(this.curve,this.curve.fromBigInteger(e),this.curve.fromBigInteger(o),u)) + } + , + a.prototype.twice = function() { + if (this.isInfinity()) + return this; + if (!this.y.toBigInteger().signum()) + return this.curve.infinity; + var t = this.x.toBigInteger() + , e = this.y.toBigInteger() + , r = this.z + , i = this.curve.q + , n = this.curve.a.toBigInteger() + , s = t.square().multiply(o).add(n.multiply(r.square())).mod(i) + , h = e.shiftLeft(1).multiply(r).mod(i) + , u = (n = (u = e.square().mod(i)).multiply(t).multiply(r).mod(i), + e = h.square().mod(i), + t = s.square().subtract(n.shiftLeft(3)).mod(i), + r = h.multiply(t).mod(i), + s.multiply(n.shiftLeft(2).subtract(t)).subtract(e.shiftLeft(1).multiply(u)).mod(i)); + return i = h.multiply(e).mod(i), + new a(this.curve,this.curve.fromBigInteger(r),this.curve.fromBigInteger(u),i) + } + , + a.prototype.multiply = function(t) { + if (this.isInfinity()) + return this; + if (!t.signum()) + return this.curve.infinity; + for (var e = t.multiply(o), r = this.negate(), i = this, n = e.bitLength() - 2; 0 < n; n--) { + i = i.twice(); + var s = e.testBit(n); + s !== t.testBit(n) && (i = i.add(s ? this : r)) + } + return i + } + , + a); + function a(t, e, r, o) { + i(this, a), + this.curve = t, + this.x = e, + this.y = r, + this.z = null == o ? n.ONE : o, + this.zinv = null + } + function c(t, e, r) { + i(this, c), + this.q = t, + this.a = this.fromBigInteger(e), + this.b = this.fromBigInteger(r), + this.infinity = new u(this,null,null) + } + c.prototype.equals = function(t) { + return t === this || this.q.equals(t.q) && this.a.equals(t.a) && this.b.equals(t.b) + } + , + c.prototype.fromBigInteger = function(t) { + return new s(this.q,t) + } + , + c.prototype.decodePointHex = function(t) { + switch (parseInt(t.substr(0, 2), 16)) { + case 0: + return this.infinity; + default: + return null; + case 4: + case 6: + case 7: + var e = (t.length - 2) / 2 + , r = t.substr(2, e); + return e = t.substr(2 + e, e), + new u(this,this.fromBigInteger(new n(r,16)),this.fromBigInteger(new n(e,16))) + } + } + , + r = c, + t.exports = { + ECPointFp: u, + ECCurveFp: r + } + } + , function(t, e, r) { + "use strict"; + var i = r(1); + t.exports = function(t) { + return t = "string" == typeof t ? function(t) { + for (var e = [], r = 0, i = t.length; r < i; r++) { + var n = t.charCodeAt(r); + if (n <= 127) + e.push(n); + else if (n <= 2047) + e.push(192 | n >>> 6), + e.push(128 | 63 & n); + else if (n <= 55295 || 57344 <= n && n <= 65535) + e.push(224 | n >>> 12), + e.push(128 | n >>> 6 & 63), + e.push(128 | 63 & n); + else { + if (!(65536 <= n && n <= 1114111)) + throw e.push(n), + new Error("input is not supported"); + r++, + e.push(240 | n >>> 18 & 28), + e.push(128 | n >>> 12 & 63), + e.push(128 | n >>> 6 & 63), + e.push(128 | 63 & n) + } + } + return e + }(t) : Array.prototype.slice.call(t), + i(t).map((function(t) { + return 1 === (t = t.toString(16)).length ? "0" + t : t + } + )).join("") + } + } + , function(t, e, r) { + "use strict"; + var i = [214, 144, 233, 254, 204, 225, 61, 183, 22, 182, 20, 194, 40, 251, 44, 5, 43, 103, 154, 118, 42, 190, 4, 195, 170, 68, 19, 38, 73, 134, 6, 153, 156, 66, 80, 244, 145, 239, 152, 122, 51, 84, 11, 67, 237, 207, 172, 98, 228, 179, 28, 169, 201, 8, 232, 149, 128, 223, 148, 250, 117, 143, 63, 166, 71, 7, 167, 252, 243, 115, 23, 186, 131, 89, 60, 25, 230, 133, 79, 168, 104, 107, 129, 178, 113, 100, 218, 139, 248, 235, 15, 75, 112, 86, 157, 53, 30, 36, 14, 94, 99, 88, 209, 162, 37, 34, 124, 59, 1, 33, 120, 135, 212, 0, 70, 87, 159, 211, 39, 82, 76, 54, 2, 231, 160, 196, 200, 158, 234, 191, 138, 210, 64, 199, 56, 181, 163, 247, 242, 206, 249, 97, 21, 161, 224, 174, 93, 164, 155, 52, 26, 85, 173, 147, 50, 48, 245, 140, 177, 227, 29, 246, 226, 46, 130, 102, 202, 96, 192, 41, 35, 171, 13, 83, 78, 111, 213, 219, 55, 69, 222, 253, 142, 47, 3, 255, 106, 114, 109, 108, 91, 81, 141, 27, 175, 146, 187, 221, 188, 127, 17, 217, 92, 65, 31, 16, 90, 216, 10, 193, 49, 136, 165, 205, 123, 189, 45, 116, 208, 18, 184, 229, 180, 176, 137, 105, 151, 74, 12, 150, 119, 126, 101, 185, 241, 9, 197, 110, 198, 132, 24, 240, 125, 236, 58, 220, 77, 32, 121, 238, 95, 62, 215, 203, 57, 72] + , n = [462357, 472066609, 943670861, 1415275113, 1886879365, 2358483617, 2830087869, 3301692121, 3773296373, 4228057617, 404694573, 876298825, 1347903077, 1819507329, 2291111581, 2762715833, 3234320085, 3705924337, 4177462797, 337322537, 808926789, 1280531041, 1752135293, 2223739545, 2695343797, 3166948049, 3638552301, 4110090761, 269950501, 741554753, 1213159005, 1684763257]; + function o(t) { + for (var e = [], r = 0, i = t.length; r < i; r += 2) + e.push(parseInt(t.substr(r, 2), 16)); + return e + } + function s(t, e) { + return t << e | t >>> 32 - e + } + function h(t) { + return (255 & i[t >>> 24 & 255]) << 24 | (255 & i[t >>> 16 & 255]) << 16 | (255 & i[t >>> 8 & 255]) << 8 | 255 & i[255 & t] + } + function u(t) { + return t ^ s(t, 2) ^ s(t, 10) ^ s(t, 18) ^ s(t, 24) + } + function a(t) { + return t ^ s(t, 13) ^ s(t, 23) + } + function c(t, e, r, i) { + i = void 0 === (c = (f = 3 < arguments.length && void 0 !== i ? i : {}).padding) ? "pkcs#5" : c; + var s = f.mode + , c = void 0 === (c = f.iv) ? [] : c + , f = void 0 === (f = f.output) ? "string" : f; + if ("cbc" === s && 16 !== (c = "string" == typeof c ? o(c) : c).length) + throw new Error("iv is invalid"); + if (16 !== (e = "string" == typeof e ? o(e) : e).length) + throw new Error("key is invalid"); + if (t = "string" == typeof t ? (0 !== r ? function(t) { + for (var e = [], r = 0, i = t.length; r < i; r++) { + var n = t.charCodeAt(r); + if (n <= 127) + e.push(n); + else if (n <= 2047) + e.push(192 | n >>> 6), + e.push(128 | 63 & n); + else if (n <= 55295 || 57344 <= n && n <= 65535) + e.push(224 | n >>> 12), + e.push(128 | n >>> 6 & 63), + e.push(128 | 63 & n); + else { + if (!(65536 <= n && n <= 1114111)) + throw e.push(n), + new Error("input is not supported"); + r++, + e.push(240 | n >>> 18 & 28), + e.push(128 | n >>> 12 & 63), + e.push(128 | n >>> 6 & 63), + e.push(128 | 63 & n) + } + } + return e + } + : o)(t) : [].concat(t), + "pkcs#5" === i && 0 !== r) + for (var p = 16 - t.length % 16, l = 0; l < p; l++) + t.push(p); + var y = new Array(32); + !function(t, e, r) { + for (var i = new Array(4), o = new Array(4), s = 0; s < 4; s++) + o[0] = 255 & t[0 + 4 * s], + o[1] = 255 & t[1 + 4 * s], + o[2] = 255 & t[2 + 4 * s], + o[3] = 255 & t[3 + 4 * s], + i[s] = o[0] << 24 | o[1] << 16 | o[2] << 8 | o[3]; + i[0] ^= 2746333894, + i[1] ^= 1453994832, + i[2] ^= 1736282519, + i[3] ^= 2993693404; + for (var u, c = 0; c < 32; c += 4) + u = i[1] ^ i[2] ^ i[3] ^ n[c + 0], + e[c + 0] = i[0] ^= a(h(u)), + u = i[2] ^ i[3] ^ i[0] ^ n[c + 1], + e[c + 1] = i[1] ^= a(h(u)), + u = i[3] ^ i[0] ^ i[1] ^ n[c + 2], + e[c + 2] = i[2] ^= a(h(u)), + u = i[0] ^ i[1] ^ i[2] ^ n[c + 3], + e[c + 3] = i[3] ^= a(h(u)); + if (0 === r) + for (var f, p = 0; p < 16; p++) + f = e[p], + e[p] = e[31 - p], + e[31 - p] = f + }(e, y, r); + for (var d = [], m = c, v = t.length, g = 0; 16 <= v; ) { + var b = t.slice(g, g + 16) + , T = new Array(16); + if ("cbc" === s) + for (var w = 0; w < 16; w++) + 0 !== r && (b[w] ^= m[w]); + !function(t, e, r) { + for (var i = new Array(4), n = new Array(4), o = 0; o < 4; o++) + n[0] = 255 & t[4 * o], + n[1] = 255 & t[4 * o + 1], + n[2] = 255 & t[4 * o + 2], + n[3] = 255 & t[4 * o + 3], + i[o] = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + for (var s, a = 0; a < 32; a += 4) + s = i[1] ^ i[2] ^ i[3] ^ r[a + 0], + i[0] ^= u(h(s)), + s = i[2] ^ i[3] ^ i[0] ^ r[a + 1], + i[1] ^= u(h(s)), + s = i[3] ^ i[0] ^ i[1] ^ r[a + 2], + i[2] ^= u(h(s)), + s = i[0] ^ i[1] ^ i[2] ^ r[a + 3], + i[3] ^= u(h(s)); + for (var c = 0; c < 16; c += 4) + e[c] = i[3 - c / 4] >>> 24 & 255, + e[c + 1] = i[3 - c / 4] >>> 16 & 255, + e[c + 2] = i[3 - c / 4] >>> 8 & 255, + e[c + 3] = 255 & i[3 - c / 4] + }(b, T, y); + for (var F = 0; F < 16; F++) + "cbc" === s && 0 === r && (T[F] ^= m[F]), + d[g + F] = T[F]; + "cbc" === s && (m = 0 !== r ? T : b), + v -= 16, + g += 16 + } + return "pkcs#5" === i && 0 === r && (i = d[d.length - 1], + d.splice(d.length - i, i)), + "array" !== f ? 0 !== r ? d.map((function(t) { + return 1 === (t = t.toString(16)).length ? "0" + t : t + } + )).join("") : function(t) { + for (var e = [], r = 0, i = t.length; r < i; r++) + 240 <= t[r] && t[r] <= 247 ? (e.push(String.fromCharCode(((7 & t[r]) << 18) + ((63 & t[r + 1]) << 12) + ((63 & t[r + 2]) << 6) + (63 & t[r + 3]))), + r += 3) : 224 <= t[r] && t[r] <= 239 ? (e.push(String.fromCharCode(((15 & t[r]) << 12) + ((63 & t[r + 1]) << 6) + (63 & t[r + 2]))), + r += 2) : 192 <= t[r] && t[r] <= 223 ? (e.push(String.fromCharCode(((31 & t[r]) << 6) + (63 & t[r + 1]))), + r++) : e.push(String.fromCharCode(t[r])); + return e.join("") + }(d) : d + } + t.exports = { + encrypt: function(t, e, r) { + return c(t, e, 1, r) + }, + decrypt: function(t, e, r) { + return c(t, e, 0, r) + } + } + } + ], + i.c = o, + i.d = function(t, e, r) { + i.o(t, e) || Object.defineProperty(t, e, { + enumerable: !0, + get: r + }) + } + , + i.r = function(t) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, { + value: "Module" + }), + Object.defineProperty(t, "__esModule", { + value: !0 + }) + } + , + i.t = function(t, e) { + if (1 & e && (t = i(t)), + 8 & e) + return t; + if (4 & e && "object" == typeof t && t && t.__esModule) + return t; + var r = Object.create(null); + if (i.r(r), + Object.defineProperty(r, "default", { + enumerable: !0, + value: t + }), + 2 & e && "string" != typeof t) + for (var n in t) + i.d(r, n, function(e) { + return t[e] + } + .bind(null, n)); + return r + } + , + i.n = function(t) { + var e = t && t.__esModule ? function() { + return t.default + } + : function() { + return t + } + ; + return i.d(e, "a", e), + e + } + , + i.o = function(t, e) { + return Object.prototype.hasOwnProperty.call(t, e) + } + , + i.p = "", + i(i.s = 2)) + } + } + , e = {}; + function r(i) { + var n = e[i]; + return void 0 !== n || (n = e[i] = { + exports: {} + }, + t[i].call(n.exports, n, n.exports, r)), + n.exports + } + r.d = function(t, e) { + for (var i in e) + r.o(e, i) && !r.o(t, i) && Object.defineProperty(t, i, { + enumerable: !0, + get: e[i] + }) + } + , + r.o = function(t, e) { + return Object.prototype.hasOwnProperty.call(t, e) + } + , + r.r = function(t) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, { + value: "Module" + }), + Object.defineProperty(t, "__esModule", { + value: !0 + }) + } + ; + var i = {}; + return function() { + "use strict"; + function t(t) { + this.PromiseState = "pending", + this.PromiseResult = null, + this.callbacks = []; + var e = this; + function r(t) { + "pending" === e.PromiseState && (e.PromiseResult = t, + e.PromiseState = "rejected", + e.callbacks.forEach((function(e) { + e.onReject(t) + } + ))) + } + try { + t((function(t) { + "pending" == e.PromiseState && (e.PromiseState = "fulfilled", + e.PromiseResult = t, + e.callbacks.forEach((function(e) { + e.onResolve(t) + } + ))) + } + ), r) + } catch (t) { + r(t) + } + } + r.r(i), + r.d(i, { + SummerCryptico: function() { + return c + }, + default: function() { + return f + } + }); + var e = r(686); + function n(t, e) { + var r, i = Object.keys(t); + return Object.getOwnPropertySymbols && (r = Object.getOwnPropertySymbols(t), + e && (r = r.filter((function(e) { + return Object.getOwnPropertyDescriptor(t, e).enumerable + } + ))), + i.push.apply(i, r)), + i + } + function o(t) { + for (var e = 1; e < arguments.length; e++) { + var r = null != arguments[e] ? arguments[e] : {}; + e % 2 ? n(Object(r), !0).forEach((function(e) { + var i, n; + i = t, + e = r[n = e], + n in i ? Object.defineProperty(i, n, { + value: e, + enumerable: !0, + configurable: !0, + writable: !0 + }) : i[n] = e + } + )) : Object.getOwnPropertyDescriptors ? Object.defineProperties(t, Object.getOwnPropertyDescriptors(r)) : n(Object(r)).forEach((function(e) { + Object.defineProperty(t, e, Object.getOwnPropertyDescriptor(r, e)) + } + )) + } + return t + } + t.prototype.then = function(e, r) { + var i = this + , n = this; + return "function" != typeof r && (r = function(t) { + throw t + } + ), + "function" != typeof e && (e = function(t) { + return t + } + ), + new t((function(o, s) { + function h(e) { + try { + var r = e(n.PromiseResult); + r instanceof t ? r.then((function(t) { + o(t) + } + ), (function(t) { + s(t) + } + )) : o(r), + o(r) + } catch (e) { + s(e) + } + } + "fulfilled" === i.PromiseState && h(e), + "rejected" === i.PromiseState && h(r), + "pending" == i.PromiseState && i.callbacks.push({ + onReject: function() { + h(r) + }, + onResolve: function() { + h(e) + } + }) + } + )) + } + , + t.prototype.catch = function(t) { + return this.then(void 0, t) + } + , + t.resolve = function(e) { + return new t((function(r, i) { + try { + e instanceof t ? e.then((function(t) { + r(t) + } + ), (function(t) { + i(t) + } + )) : r(e) + } catch (t) { + i(t) + } + } + )) + } + , + t.reject = function(e) { + return new t((function(t, r) { + r(e) + } + )) + } + , + t.all = function(e) { + var r = [] + , i = 0; + return new t((function(n, o) { + for (var s = 0; s < e.length; s++) + !function(s) { + e[s]instanceof t ? e[s].then((function(t) { + i++, + r[s] = t, + i === e.length && n(r) + } + ), (function(t) { + o(t) + } + )) : (r[s] = e, + i++) + }(s) + } + )) + } + ; + var s, h = t.race = function(e) { + return new t((function(r, i) { + for (var n = 0; n < e.length; n++) + e[n]instanceof t ? e[n].then((function(t) { + r(t) + } + ), (function(t) { + i(t) + } + )) : r(e[n]) + } + )) + } + , u = null; + function a() { + this.handshakePublicKey = "", + this.handshakeUrl = "", + this._keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + this.publicKeyHeader = "", + this.sm2Key = "", + this.sm4Key = "", + this.iv = "", + this.randomKey = "", + this.sm2EncryptData = "", + this.sm4EncryptData = "", + this.encryptStorageSm4Key = "6c3d6878252e641b", + this.encryptStorageIv = "5f5e5a247f544d771255134517043757", + this.encryptRandomKey = "", + this.encryptSm2RandomKey = ""; + var t = !1 + , e = !1; + "undefined" != typeof wx && wx.request && wx.login ? t = !0 : "undefined" != typeof jd && jd.request && jd.login ? e = t = !0 : t = !1, + this.isJd = e, + t = (this.isApplet = t) ? 2 : 1, + this.isResponse = !1, + this.version = [1], + this.client_type = [t], + this.key_cipher = [], + this.time = null, + this.ms = 6e4, + this._localStorage = "" + } + h = "undefined" != typeof wx && wx.request && wx.login ? (u = wx, + !0) : !("undefined" == typeof jd || !jd.request || !jd.login || (u = jd, + 0)), + s = h ? function(e) { + return new t((function(t, r) { + u.request(o({ + header: { + "Content-Type": "application/x-www-form-urlencoded" + } + }, e)) + } + )) + } + : function(t) { + (t = t || {}).type = (t.type || "GET").toUpperCase(), + t.dataType = t.dataType || "json", + t.async = t.async || !0; + var e, r = function(t) { + var e, r = []; + for (e in t = t || {}) + r.push(encodeURIComponent(e) + "=" + encodeURIComponent(t[e])); + return r.join("&") + }(t.data), i = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP"); + t.timeout && (e = setTimeout((function() { + 4 != i.readySate && i.abort() + } + ), t.timeout || 1e4)), + i.onreadystatechange = function() { + var r; + 4 == i.readyState && (clearTimeout(e), + 200 <= (r = i.status) && r < 300 || 304 === r ? t.success && t.success(i.responseText, i.responseXML) : t.error && t.error(r)) + } + , + "GET" == t.type ? (i.open("GET", t.url + "?" + r, t.async), + i.send(null)) : "POST" == t.type && (i.open("POST", t.url, t.async), + i.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"), + i.send(r)) + } + , + a.prototype = { + commonPromise: function(e, r) { + var i = this + , n = 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : 1 + , o = (r = this.isJd ? encodeURIComponent(r) : r, + 1 !== n ? { + data: r + } : { + clientKey: r + }); + return new t((function(t, r) { + var n = { + url: e, + method: "POST", + data: o, + success: function(e) { + var i = e.statusCode; + 200 <= i && i < 300 || 304 === i ? t(e.data) : r(i) + }, + fail: function(t) { + r(t) + } + }; + i.isApplet || (n = { + type: "POST", + url: e, + data: o, + success: function(e) { + t(e) + }, + error: function(t) { + r(t) + } + }), + s(n) + } + )) + }, + encryptDecryptRequest: function(t, e) { + return this.commonPromise(t, e) + }, + createDemote: function() { + this.isResponse || this.demoteKeyCipher() + }, + demoteKeyCipher: function() { + var t = [140, 58, 51, 17, 108, 219, 141, 107, 65, 13, 222, 250, 147, 190, 156, 25]; + this.isApplet && (t = [68, 176, 150, 193, 133, 248, 213, 81, 190, 140, 15, 58, 167, 248, 31, 97]); + var r = this.createRandomKey(8); + this.randomKey = r; + var i = this.createRandomKey(); + t = e.sm4.encrypt(r, t, { + mode: "cbc", + iv: i + }), + this.encryptRandomKey = t, + t = this.hexToArray(t), + t = this.hexToArray(i).concat(t, [0, 0, 0, 0, 0]), + this.key_cipher = t + }, + handshake: function(t, e) { + this.isResponse || this.key_cipher.length && Date.now() < this.lastClick + this.ms || (this.handshakeUrl || (this.handshakeUrl = t, + this.handshakePublicKey = e), + this.createDemote(), + this.sm2EncryptRandomKey(t, e)) + }, + encryptRequest: function(t, e) { + var r = this; + this.encryptDecryptRequest(t, e).then((function(t) { + t ? (t = r.decode(t), + t = Array.prototype.slice.call(t), + r.key_cipher = t, + r.isResponse = !0) : (r.isResponse = !1, + r.lastClick = Date.now()) + } + )).catch((function(t) { + r.isResponse = !1, + r.lastClick = Date.now() + } + )) + }, + sm2EncryptRandomKey: function(t, r) { + var i = e.sm2.doEncrypt(this.randomKey, r) + , n = this.hexToArray(this.createRandomKey(1)) + , o = this.version; + r = this.client_type, + i = this.hexToArray(i), + i = n.concat(o, r, i), + i = new Uint8Array(i), + i = this.arrayBufferToBase64(i), + this.encryptRequest(t, i) + }, + createRandomKey: function() { + var t = this.randomUnit8Array(1, 127, 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : 16); + return this.buffertoHex(t) + }, + encrypt: function(t) { + if (!t) + throw new Error("encrypt data can not empty"); + this.createDemote(); + var r, i = { + mode: "cbc", + iv: r = this.createRandomKey() + }, n = this.utf8ToHex(this.randomKey), o = e.sm4.encrypt(t, n, i), s = this.hexToArray(o), h = this.hexToArray(this.createRandomKey(1)), u = this.version, a = this.client_type; + return t = this.isResponse ? [0] : [1], + n = this.key_cipher, + i = this.hexToArray(r), + o = s, + (r = new Uint32Array(1))[0] = s.length, + r = Array.prototype.slice.call(new Uint8Array(r.buffer)), + o = h.concat(u, a, t, n, i, r, o), + o = new Uint8Array(o), + o = this.arrayBufferToBase64(o), + !this.isResponse && this.handshakeUrl && this.handshake(this.handshakeUrl, this.handshakePublicKey), + o + }, + encryptData: function(t, e) { + if (!e) + throw new Error("encrypt data can not empty"); + var r = (i = this.decode(t)).byteLength + , i = (t = i.subarray(0, r - 65), + i.subarray(r - 65)); + return r = this.buffertoHex(t), + t = this.buffertoHex(i), + i = this.encryptStorageSm4Data(), + this.publicKeyHeader = r, + this.sm2Key = t, + this.sm4Key = i, + this.iv = this.createRandomKey(), + this.encryptSm2Data(), + this.encryptSm4Data(e), + this.getEncryptData() + }, + testDecrpt: function(t, e) { + return this.commonPromise(t, e, 2) + }, + test: function(e, r) { + return this.testDecrpt(e, r).then((function(e) { + return t.resolve(e) + } + )).catch((function(e) { + return t.reject(e) + } + )) + }, + randomUnit8Array: function(t, e, r) { + e += 1; + for (var i = [], n = void 0 === r ? 1 : r, o = 0; o < n; o++) { + var s = Math.floor(Math.random() * (e - t) + t); + i.push(s) + } + return new Uint8Array(i) + }, + buffertoHex: function(t) { + return Array.prototype.map.call(t, (function(t) { + return ("00" + t.toString(16)).slice(-2) + } + )).join("") + }, + encryptSm2Data: function() { + var t = this.sm4Key + , r = this.sm2Key; + r = e.sm2.doEncrypt(t, r), + this.sm2EncryptData = r + }, + encryptSm4Data: function(t) { + var r = this.sm4Key + , i = { + mode: "cbc", + iv: this.iv + }; + r = this.utf8ToHex(r), + i = e.sm4.encrypt(t, r, i), + this.sm4EncryptData = i + }, + encryptStorageSm4Data: function() { + var t = this.encryptStorageSm4Key + , r = { + mode: "cbc", + iv: this.encryptStorageIv + } + , i = this.utf8ToHex(t) + , n = "" + , o = this.isApplet + , s = this.isJd; + if (t = o ? s ? jd : wx : null, + o) + n = t.getStorageSync("aksKey"); + else + try { + n = localStorage.getItem("aksKey") + } catch (t) { + n = this._localStorage + } + if (s = "", + n) + s = e.sm4.decrypt(n, i, r); + else if (n = this.randomUnit8Array(1, 127, 8), + s = this.buffertoHex(n), + r = e.sm4.encrypt(s, i, r), + o) + t.setStorageSync("aksKey", r); + else + try { + localStorage.setItem("aksKey", r) + } catch (t) { + this._localStorage = r + } + return s + }, + utf8ToHex: function(t) { + for (var e = (t = unescape(encodeURIComponent(t))).length, r = [], i = 0; i < e; i++) + r[i >>> 2] |= (255 & t.charCodeAt(i)) << 24 - i % 4 * 8; + for (var n = [], o = 0; o < e; o++) { + var s = r[o >>> 2] >>> 24 - o % 4 * 8 & 255; + n.push((s >>> 4).toString(16)), + n.push((15 & s).toString(16)) + } + return n.join("") + }, + hex2b64: function(t) { + for (var e, r = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", i = "", n = 0; n + 3 <= t.length; n += 3) + e = parseInt(t.substring(n, n + 3), 16), + i += r.charAt(e >> 6) + r.charAt(63 & e); + for (n + 1 == t.length ? (e = parseInt(t.substring(n, n + 1), 16), + i += r.charAt(e << 2)) : n + 2 == t.length && (e = parseInt(t.substring(n, n + 2), 16), + i += r.charAt(e >> 2) + r.charAt((3 & e) << 4)); 0 < (3 & i.length); ) + i += "="; + return i + }, + leftPad: function(t, e) { + return t.length >= e ? t : new Array(e - t.length + 1).join("0") + t + }, + hexToArray: function(t) { + for (var e = [], r = (t = (r = t.length) % 2 != 0 ? this.leftPad(t, r + 1) : t).length, i = 0; i < r; i += 2) + e.push(parseInt(t.substr(i, 2), 16)); + return e + }, + getEncryptData: function() { + var t = this.hexToArray(this.publicKeyHeader) + , e = this.hexToArray(this.sm2EncryptData) + , r = this.hexToArray(this.sm4EncryptData) + , i = this.hexToArray(this.iv); + return r = t.concat(e, i, r), + r = new Uint8Array(r), + this.arrayBufferToBase64(r) + }, + removePaddingChars: function(t) { + return 64 == this._keyStr.indexOf(t.charAt(t.length - 1)) ? t.substring(0, t.length - 1) : t + }, + arrayBufferToBase64: function(t) { + for (var e = t.byteLength, r = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"], i = "", n = 0; 3 <= e - n; n += 3) { + var o = t[n] + , s = t[n + 1] + , h = t[n + 2]; + i += r[o >>> 2] + r[(3 & o) << 4 | s >>> 4] + r[(15 & s) << 2 | h >>> 6] + r[63 & h] + } + var u, a = e - n; + return 1 == a ? i += r[(u = t[n]) >>> 2] + r[(3 & u) << 4] + "==" : 2 == a && (u = t[n], + a = t[n + 1], + i += r[u >>> 2] + r[(3 & u) << 4 | a >>> 4] + r[(15 & a) << 2] + "="), + i + }, + decode: function(t, e) { + var r = t; + e = e, + r = this.removePaddingChars(r), + r = this.removePaddingChars(r); + var i, n, o, s, h, u, a = parseInt(r.length / 4 * 3, 10), c = 0, f = 0, p = e ? new Uint8Array(e) : new Uint8Array(a); + for (r = r.replace(/[^A-Za-z0-9\+\/\=]/g, ""), + c = 0; c < a; c += 3) + o = this._keyStr.indexOf(r.charAt(f++)), + i = (15 & (s = this._keyStr.indexOf(r.charAt(f++)))) << 4 | (h = this._keyStr.indexOf(r.charAt(f++))) >> 2, + n = (3 & h) << 6 | (u = this._keyStr.indexOf(r.charAt(f++))), + p[c] = o << 2 | s >> 4, + 64 != h && (p[c + 1] = i), + 64 != u && (p[c + 2] = n); + return p + }, + decryptData: function(t) { + var r = (o = this.decode(t)).byteLength + , i = o.subarray(3, 19) + , n = o.subarray(19, r) + , o = (t = this.buffertoHex(i), + this.buffertoHex(n)); + if (r = this.isApplet, + i = "", + n = this.isJd, + n = r ? n ? jd : wx : null, + r) + try { + if (!(i = n.getStorageSync("aksKey"))) + throw new Error("get storage fail") + } catch (t) { + throw new Error("get storage fail") + } + else + try { + i = localStorage.getItem("aksKey") + } catch (t) { + i = this._localStorage + } + if (n = "", + !i) + throw new Error("key is invalid"); + return n = this.encryptStorageSm4Data(), + n = this.utf8ToHex(n), + e.sm4.decrypt(o, n, { + mode: "cbc", + iv: t + }) + } + }; + var c = new a + , f = { + SummerCryptico: c + } + }(), + i +} +)); + +function encrypt_data(publicKey, data){ + return SummerCryptico.encryptData(publicKey, data) +} \ No newline at end of file diff --git a/static/js/dencode_message.js b/static/js/dencode_message.js new file mode 100644 index 0000000..bdf7139 --- /dev/null +++ b/static/js/dencode_message.js @@ -0,0 +1,3717 @@ +window = globalThis;; + +var CryptoJS = CryptoJS || (function (Math, undefined) { + var C = {}; + var C_lib = C.lib = {}; + var Base = C_lib.Base = (function () { + function F() {}; + return { + extend: function (overrides) { + F.prototype = this; + var subtype = new F(); + if (overrides) { + subtype.mixIn(overrides); + } + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + subtype.init.prototype = subtype; + subtype.$super = this; + return subtype; + }, create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + return instance; + }, init: function () {}, mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + var WordArray = C_lib.WordArray = Base.extend({ + init: function (words, sigBytes) { + words = this.words = words || []; + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, concat: function (wordArray) { + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + this.clamp(); + if (thisSigBytes % 4) { + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else if (thatWords.length > 0xffff) { + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } else { + thisWords.push.apply(thisWords, thatWords); + } + this.sigBytes += thatSigBytes; + return this; + }, clamp: function () { + var words = this.words; + var sigBytes = this.sigBytes; + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + return clone; + }, random: function (nBytes) { + var words = []; + var r = (function (m_w) { + var m_w = m_w; + var m_z = 0x3ade68b1; + var mask = 0xffffffff; + return function () { + m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; + m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; + var result = ((m_z << 0x10) + m_w) & mask; + result /= 0x100000000; + result += 0.5; + return result * (Math.random() > .5 ? 1 : -1); + } + }); + for (var i = 0, rcache; i < nBytes; i += 4) { + var _r = r((rcache || Math.random()) * 0x100000000); + rcache = _r() * 0x3ade67b7; + words.push((_r() * 0x100000000) | 0); + } + return new WordArray.init(words, nBytes); + } + }); + var C_enc = C.enc = {}; + var Hex = C_enc.Hex = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + return hexChars.join(''); + }, parse: function (hexStr) { + var hexStrLength = hexStr.length; + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + return new WordArray.init(words, hexStrLength / 2); + } + }; + var Latin1 = C_enc.Latin1 = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + return latin1Chars.join(''); + }, parse: function (latin1Str) { + var latin1StrLength = latin1Str.length; + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + return new WordArray.init(words, latin1StrLength); + } + }; + var Utf8 = C_enc.Utf8 = { + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + reset: function () { + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, _append: function (data) { + if (typeof data == 'string') { + data = Utf8.parse(data); + } + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, _process: function (doFlush) { + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + nBlocksReady = Math.ceil(nBlocksReady); + } else { + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + var nWordsReady = nBlocksReady * blockSize; + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + this._doProcessBlock(dataWords, offset); + } + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + return new WordArray.init(processedWords, nBytesReady); + }, clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + return clone; + }, _minBufferSize: 0 + }); + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + cfg: Base.extend(), + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + this.reset(); + }, reset: function () { + BufferedBlockAlgorithm.reset.call(this); + this._doReset(); + }, update: function (messageUpdate) { + this._append(messageUpdate); + this._process(); + return this; + }, finalize: function (messageUpdate) { + if (messageUpdate) { + this._append(messageUpdate); + } + var hash = this._doFinalize(); + return hash; + }, blockSize: 512 / 32, + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + var C_algo = C.algo = {}; + return C; +}(Math)); + +(function () { + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + var Base64 = C_enc.Base64 = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + wordArray.clamp(); + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + for (var j = 0; + (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + return base64Chars.join(''); + }, parse: function (base64Str) { + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + return parseLoop(base64Str, base64StrLength, reverseMap); + }, _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } +}()); + +function B64_Encrypt(word) { + var src = CryptoJS.enc.Utf8.parse(word); + return CryptoJS.enc.Base64.stringify(src); +} + +function B64_Decrypt(word) { + var src = CryptoJS.enc.Base64.parse(word); + return CryptoJS.enc.Utf8.stringify(src); +} + + +!function (e) { + function t(t) { + for (var r, o, a = t[0], c = t[1], i = t[2], u = 0, d = []; u < a.length; u++) + o = a[u], + Object.prototype.hasOwnProperty.call(b, o) && b[o] && d.push(b[o][0]), + b[o] = 0; + for (r in c) + Object.prototype.hasOwnProperty.call(c, r) && (e[r] = c[r]); + for (P && P(t); d.length; ) + d.shift()(); + return g.push.apply(g, i || []), + n() + } + function n() { + for (var e, t = 0; t < g.length; t++) { + for (var n = g[t], r = !0, o = 1; o < n.length; o++) { + var a = n[o]; + 0 !== b[a] && (r = !1) + } + r && (g.splice(t--, 1), + e = v(v.s = n[0])) + } + return e + } + var r, o, a = {}, c = { + 2: 0 + }, i = {}, u = {}, d = {}, f = {}, l = !1, s = {}, p = {}, h = "", m = ["mms-static-1.pddugc.com", "mms-static-2.pddpic.com", "mms-static.pddpic.com", "mms-static.pinduoduo.com"], b = { + 2: 0 + }, g = []; + function v(t) { + console.log('v[t]:::',t) + if (a[t]) + return a[t].exports; + var n = a[t] = { + i: t, + l: !1, + exports: {} + }; + return e[t].call(n.exports, n, n.exports, v), + n.l = !0, + n.exports + } + v.e = function(e) { + var t = []; + c[e] ? t.push(c[e]) : 0 !== c[e] && { + 3: 1, + 5: 1, + 8: 1, + 9: 1, + 10: 1, + 12: 1, + 13: 1 + }[e] && t.push(c[e] = new Promise((function(t, n) { + for (var r = ({ + 0: "defaultVendors~mercha~50a2d7c7", + 3: "notificationPushCompoents", + 5: "defaultVendors~merchantApp", + 8: "merchantApp", + 9: "platformConnect" + }[e] || e) + "." + { + 0: "afbf4", + 3: "fec4b", + 4: "2ae1b", + 5: "289cd", + 8: "f288d", + 9: "9a46f", + 10: "fd7cd", + 11: "58a8f", + 12: "69822", + 13: "8d151", + 14: "6617b" + }[e] + ".css", o = v.p + r, a = document.getElementsByTagName("link"), i = 0; i < a.length; i++) { + var u = (f = a[i]).getAttribute("data-href") || f.getAttribute("href"); + if ("stylesheet" === f.rel && (u === r || u === o)) + return t() + } + var d = document.getElementsByTagName("style"); + for (i = 0; i < d.length; i++) { + var f; + if ((u = (f = d[i]).getAttribute("data-href")) === r || u === o) + return t() + } + var l = document.createElement("link"); + l.rel = "stylesheet", + l.type = "text/css", + l.onload = t, + l.onerror = function(t) { + var r = t && t.target && t.target.src || o + , a = new Error("Loading CSS chunk " + e + " failed.\n(" + r + ")"); + a.code = "CSS_CHUNK_LOAD_FAILED", + a.request = r, + delete c[e], + l.parentNode.removeChild(l), + n(a) + } + , + l.href = o, + document.getElementsByTagName("head")[0].appendChild(l) + } + )).then((function() { + c[e] = 0 + } + ))); + var n = b[e]; + if (0 !== n) + if (n) + t.push(n[2]); + else { + var r = new Promise((function(t, r) { + n = b[e] = [t, r] + } + )); + t.push(n[2] = r); + var o, a = document.createElement("script"); + a.charset = "utf-8", + a.timeout = 120, + v.nc && a.setAttribute("nonce", v.nc), + a.src = function(e) { + return v.p + "chat-merchant-v20250710.17.12.12/static/js/" + ({ + 0: "defaultVendors~mercha~50a2d7c7", + 3: "notificationPushCompoents", + 5: "defaultVendors~merchantApp", + 8: "merchantApp", + 9: "platformConnect" + }[e] || e) + ".bundle." + { + 0: "afbf4fbcbf199c869573", + 3: "fec4bbc91da8d558973f", + 4: "2ae1b8b04ce874f950b9", + 5: "289cddfa35ea3af3db37", + 8: "f288dd6ab07e36401bd7", + 9: "9a46ff970bb747bbe76d", + 10: "fd7cdf4260120a49bae9", + 11: "58a8fbceb12d0f6cdd28", + 12: "69822c50b71be5380329", + 13: "8d1516ce3604ccad0348", + 14: "6617b80f8673c646e468" + }[e] + ".js" + }(e); + var i = new Error; + o = function(t) { + a.onerror = a.onload = null, + clearTimeout(u); + var n = b[e]; + if (0 !== n) { + if (n) { + var r = t && ("load" === t.type ? "missing" : t.type) + , o = t && t.target && t.target.src; + i.message = "Loading chunk " + e + " failed.\n(" + r + ": " + o + ")", + i.name = "ChunkLoadError", + i.type = r, + i.request = o, + n[1](i) + } + b[e] = void 0 + } + } + ; + var u = setTimeout((function() { + o({ + type: "timeout", + target: a + }) + } + ), 12e4); + a.onerror = a.onload = o, + document.head.appendChild(a) + } + return v.onChunkPromiseSettled && v.onChunkPromiseSettled(t, e), + Promise.all(t) + } + , + v.m = e, + v.c = a, + v.d = function(e, t, n) { + v.o(e, t) || Object.defineProperty(e, t, { + enumerable: !0, + get: n + }) + } + , + v.r = function(e) { + "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { + value: "Module" + }), + Object.defineProperty(e, "__esModule", { + value: !0 + }) + } + , + v.t = function(e, t) { + if (1 & t && (e = v(e)), + 8 & t) + return e; + if (4 & t && "object" == typeof e && e && e.__esModule) + return e; + var n = Object.create(null); + if (v.r(n), + Object.defineProperty(n, "default", { + enumerable: !0, + value: e + }), + 2 & t && "string" != typeof e) + for (var r in e) + v.d(n, r, function(t) { + return e[t] + } + .bind(null, r)); + return n + } + , + v.n = function(e) { + var t = e && e.__esModule ? function() { + return e.default + } + : function() { + return e + } + ; + return v.d(t, "a", t), + t + } + , + v.o = function(e, t) { + return Object.prototype.hasOwnProperty.call(e, t) + } + , + v.p = "https://mms-static.pinduoduo.com/chat-merchant/", + v.oe = function(e) { + throw console.error(e), + e + } + ; + var y = window.webpackJsonp = window.webpackJsonp || [] + , w = y.push.bind(y); + y.push = t, + y = y.slice(); + for (var _ = 0; _ < y.length; _++) + t(y[_]); + var P = w; + v.oldE = v.e, + v.initRetryConfig = function () { + !function (e) { + var t = ""; + e && (t = e.split("/")[2] || "") + }(o = v.p || window.__webpack_public_path__ || ""); + h = function (e) { + var t = ""; + if (e) { + var n = e.split("/").slice(3); + n.length && (t = n.join("/")) + } + return t + }(o), + r = 4 + } + , + v.getRetryPublicPath = function (e) { + if (!s.hasOwnProperty(e)) + return o; + var t = ""; + return p.hasOwnProperty(e) ? p[e] = (p[e] + 1) % m.length : p[e] = 0, + ("http" === (t = m[p[e]] || "").slice(0, 4) ? "" : "https://") + t + ("/" === t[t.length - 1] ? "" : "/") + h + } + , + v.resetRetryMap = function (e) { + delete p[e], + delete s[e], + delete f[e], + delete u[e], + delete i[e], + delete d[e] + } + , + v.checkCouldRetry = function (e) { + if ((d[e] || []).length === u[e]) { + var t = f[e]; + if (!t) + return; + t(e) + } + } + , + v.onChunkPromiseSettled = function (e, t) { + u[t] = e.length; + for (var n = function (e, t) { + d[e] = d[e] || [], + d[e].push(t); + var n = u[e] + , r = d[e]; + n > 1 && r.length === n && r.indexOf("rejected") >= 0 && v.checkCouldRetry(e) + }, r = 0; r < e.length; r++) { + var o = e[r]; + o.registered || (o.then((function () { + n(t, "resolved") + } + ), (function (e) { + n(t, "rejected") + } + )), + o.registered = !0) + } + } + , + v.e = function (e) { + if (i.hasOwnProperty(e)) + return i[e]; + l || (v.initRetryConfig(), + l = !0); + var t = v.getRetryPublicPath(e); + v.p = t, + window.__webpack_public_path__ && (window.__webpack_public_path__ = t); + var n = v.oldE(e).then((function () { + v.resetRetryMap(e) + } + )).catch((function (t) { + if ((s.hasOwnProperty(e) ? s[e] : r) < 1) + throw v.resetRetryMap(e), + t.name && (t.name += "(dynamicChunkRetryTimes: " + r + ")"), + t; + return new Promise((function (t) { + f[e] = function (e) { + var n = s.hasOwnProperty(e) ? s[e] : r; + s[e] = n - 1, + delete d[e], + delete i[e]; + var o = v.e(e); + t(o) + } + , + v.checkCouldRetry(e) + } + )) + } + )); + return i[e] = n, + n + }, + window.wang = v; +}({ + 450:function(t, e, n) { + var r, o, i, a; + function s(t) { + return "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? typeof t : t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t + } + a = function() { + return function t(e, n, r) { + function o(a, s) { + if (!n[a]) { + if (!e[a]) { + if (i) + return i(a, !0); + var u = new Error("Cannot find module '" + a + "'"); + throw u.code = "MODULE_NOT_FOUND", + u + } + var c = n[a] = { + exports: {} + }; + e[a][0].call(c.exports, (function(t) { + return o(e[a][1][t] || t) + } + ), c, c.exports, t, e, n, r) + } + return n[a].exports + } + for (var i = !1, a = 0; a < r.length; a++) + o(r[a]); + return o + }({ + 1: [function(t, e, n) { + "use strict"; + function r(t, e) { + return Object.prototype.hasOwnProperty.call(t, e) + } + var o = "undefined" != typeof Uint8Array && "undefined" != typeof Uint16Array && "undefined" != typeof Int32Array; + n.assign = function(t) { + for (var e = Array.prototype.slice.call(arguments, 1); e.length; ) { + var n = e.shift(); + if (n) { + if ("object" != s(n)) + throw new TypeError(n + "must be non-object"); + for (var o in n) + r(n, o) && (t[o] = n[o]) + } + } + return t + } + , + n.shrinkBuf = function(t, e) { + return t.length === e ? t : t.subarray ? t.subarray(0, e) : (t.length = e, + t) + } + ; + var i = { + arraySet: function(t, e, n, r, o) { + if (e.subarray && t.subarray) + t.set(e.subarray(n, n + r), o); + else + for (var i = 0; i < r; i++) + t[o + i] = e[n + i] + }, + flattenChunks: function(t) { + var e, n, r, o, i, a; + for (r = 0, + e = 0, + n = t.length; e < n; e++) + r += t[e].length; + for (a = new Uint8Array(r), + o = 0, + e = 0, + n = t.length; e < n; e++) + i = t[e], + a.set(i, o), + o += i.length; + return a + } + } + , a = { + arraySet: function(t, e, n, r, o) { + for (var i = 0; i < r; i++) + t[o + i] = e[n + i] + }, + flattenChunks: function(t) { + return [].concat.apply([], t) + } + }; + n.setTyped = function(t) { + t ? (n.Buf8 = Uint8Array, + n.Buf16 = Uint16Array, + n.Buf32 = Int32Array, + n.assign(n, i)) : (n.Buf8 = Array, + n.Buf16 = Array, + n.Buf32 = Array, + n.assign(n, a)) + } + , + n.setTyped(o) + } + , {}], + 2: [function(t, e, n) { + "use strict"; + function r(t, e) { + if (e < 65537 && (t.subarray && a || !t.subarray && i)) + return String.fromCharCode.apply(null, o.shrinkBuf(t, e)); + for (var n = "", r = 0; r < e; r++) + n += String.fromCharCode(t[r]); + return n + } + var o = t("./common") + , i = !0 + , a = !0; + try { + String.fromCharCode.apply(null, [0]) + } catch (t) { + i = !1 + } + try { + String.fromCharCode.apply(null, new Uint8Array(1)) + } catch (t) { + a = !1 + } + for (var s = new o.Buf8(256), u = 0; u < 256; u++) + s[u] = u >= 252 ? 6 : u >= 248 ? 5 : u >= 240 ? 4 : u >= 224 ? 3 : u >= 192 ? 2 : 1; + s[254] = s[254] = 1, + n.string2buf = function(t) { + var e, n, r, i, a, s = t.length, u = 0; + for (i = 0; i < s; i++) + 55296 == (64512 & (n = t.charCodeAt(i))) && i + 1 < s && 56320 == (64512 & (r = t.charCodeAt(i + 1))) && (n = 65536 + (n - 55296 << 10) + (r - 56320), + i++), + u += n < 128 ? 1 : n < 2048 ? 2 : n < 65536 ? 3 : 4; + for (e = new o.Buf8(u), + a = 0, + i = 0; a < u; i++) + 55296 == (64512 & (n = t.charCodeAt(i))) && i + 1 < s && 56320 == (64512 & (r = t.charCodeAt(i + 1))) && (n = 65536 + (n - 55296 << 10) + (r - 56320), + i++), + n < 128 ? e[a++] = n : n < 2048 ? (e[a++] = 192 | n >>> 6, + e[a++] = 128 | 63 & n) : n < 65536 ? (e[a++] = 224 | n >>> 12, + e[a++] = 128 | n >>> 6 & 63, + e[a++] = 128 | 63 & n) : (e[a++] = 240 | n >>> 18, + e[a++] = 128 | n >>> 12 & 63, + e[a++] = 128 | n >>> 6 & 63, + e[a++] = 128 | 63 & n); + return e + } + , + n.buf2binstring = function(t) { + return r(t, t.length) + } + , + n.binstring2buf = function(t) { + for (var e = new o.Buf8(t.length), n = 0, r = e.length; n < r; n++) + e[n] = t.charCodeAt(n); + return e + } + , + n.buf2string = function(t, e) { + var n, o, i, a, u = e || t.length, c = new Array(2 * u); + for (o = 0, + n = 0; n < u; ) + if ((i = t[n++]) < 128) + c[o++] = i; + else if ((a = s[i]) > 4) + c[o++] = 65533, + n += a - 1; + else { + for (i &= 2 === a ? 31 : 3 === a ? 15 : 7; a > 1 && n < u; ) + i = i << 6 | 63 & t[n++], + a--; + a > 1 ? c[o++] = 65533 : i < 65536 ? c[o++] = i : (i -= 65536, + c[o++] = 55296 | i >> 10 & 1023, + c[o++] = 56320 | 1023 & i) + } + return r(c, o) + } + , + n.utf8border = function(t, e) { + var n; + for ((e = e || t.length) > t.length && (e = t.length), + n = e - 1; n >= 0 && 128 == (192 & t[n]); ) + n--; + return n < 0 || 0 === n ? e : n + s[t[n]] > e ? n : e + } + } + , { + "./common": 1 + }], + 3: [function(t, e, n) { + "use strict"; + e.exports = function(t, e, n, r) { + for (var o = 65535 & t | 0, i = t >>> 16 & 65535 | 0, a = 0; 0 !== n; ) { + n -= a = n > 2e3 ? 2e3 : n; + do { + i = i + (o = o + e[r++] | 0) | 0 + } while (--a); + o %= 65521, + i %= 65521 + } + return o | i << 16 | 0 + } + } + , {}], + 4: [function(t, e, n) { + "use strict"; + e.exports = { + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + Z_BUF_ERROR: -5, + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + Z_BINARY: 0, + Z_TEXT: 1, + Z_UNKNOWN: 2, + Z_DEFLATED: 8 + } + } + , {}], + 5: [function(t, e, n) { + "use strict"; + var r = function() { + for (var t, e = [], n = 0; n < 256; n++) { + t = n; + for (var r = 0; r < 8; r++) + t = 1 & t ? 3988292384 ^ t >>> 1 : t >>> 1; + e[n] = t + } + return e + }(); + e.exports = function(t, e, n, o) { + var i = r + , a = o + n; + t ^= -1; + for (var s = o; s < a; s++) + t = t >>> 8 ^ i[255 & (t ^ e[s])]; + return -1 ^ t + } + } + , {}], + 6: [function(t, e, n) { + "use strict"; + e.exports = function() { + this.text = 0, + this.time = 0, + this.xflags = 0, + this.os = 0, + this.extra = null, + this.extra_len = 0, + this.name = "", + this.comment = "", + this.hcrc = 0, + this.done = !1 + } + } + , {}], + 7: [function(t, e, n) { + "use strict"; + e.exports = function(t, e) { + var n, r, o, i, a, s, u, c, f, d, l, p, h, m, v, g, y, w, _, b, x, S, O, C, k; + n = t.state, + r = t.next_in, + C = t.input, + o = r + (t.avail_in - 5), + i = t.next_out, + k = t.output, + a = i - (e - t.avail_out), + s = i + (t.avail_out - 257), + u = n.dmax, + c = n.wsize, + f = n.whave, + d = n.wnext, + l = n.window, + p = n.hold, + h = n.bits, + m = n.lencode, + v = n.distcode, + g = (1 << n.lenbits) - 1, + y = (1 << n.distbits) - 1; + t: do { + h < 15 && (p += C[r++] << h, + h += 8, + p += C[r++] << h, + h += 8), + w = m[p & g]; + e: for (; ; ) { + if (p >>>= _ = w >>> 24, + h -= _, + 0 == (_ = w >>> 16 & 255)) + k[i++] = 65535 & w; + else { + if (!(16 & _)) { + if (0 == (64 & _)) { + w = m[(65535 & w) + (p & (1 << _) - 1)]; + continue e + } + if (32 & _) { + n.mode = 12; + break t + } + t.msg = "invalid literal/length code", + n.mode = 30; + break t + } + b = 65535 & w, + (_ &= 15) && (h < _ && (p += C[r++] << h, + h += 8), + b += p & (1 << _) - 1, + p >>>= _, + h -= _), + h < 15 && (p += C[r++] << h, + h += 8, + p += C[r++] << h, + h += 8), + w = v[p & y]; + n: for (; ; ) { + if (p >>>= _ = w >>> 24, + h -= _, + !(16 & (_ = w >>> 16 & 255))) { + if (0 == (64 & _)) { + w = v[(65535 & w) + (p & (1 << _) - 1)]; + continue n + } + t.msg = "invalid distance code", + n.mode = 30; + break t + } + if (x = 65535 & w, + h < (_ &= 15) && (p += C[r++] << h, + (h += 8) < _ && (p += C[r++] << h, + h += 8)), + (x += p & (1 << _) - 1) > u) { + t.msg = "invalid distance too far back", + n.mode = 30; + break t + } + if (p >>>= _, + h -= _, + x > (_ = i - a)) { + if ((_ = x - _) > f && n.sane) { + t.msg = "invalid distance too far back", + n.mode = 30; + break t + } + if (S = 0, + O = l, + 0 === d) { + if (S += c - _, + _ < b) { + b -= _; + do { + k[i++] = l[S++] + } while (--_); + S = i - x, + O = k + } + } else if (d < _) { + if (S += c + d - _, + (_ -= d) < b) { + b -= _; + do { + k[i++] = l[S++] + } while (--_); + if (S = 0, + d < b) { + b -= _ = d; + do { + k[i++] = l[S++] + } while (--_); + S = i - x, + O = k + } + } + } else if (S += d - _, + _ < b) { + b -= _; + do { + k[i++] = l[S++] + } while (--_); + S = i - x, + O = k + } + for (; b > 2; ) + k[i++] = O[S++], + k[i++] = O[S++], + k[i++] = O[S++], + b -= 3; + b && (k[i++] = O[S++], + b > 1 && (k[i++] = O[S++])) + } else { + S = i - x; + do { + k[i++] = k[S++], + k[i++] = k[S++], + k[i++] = k[S++], + b -= 3 + } while (b > 2); + b && (k[i++] = k[S++], + b > 1 && (k[i++] = k[S++])) + } + break + } + } + break + } + } while (r < o && i < s); + r -= b = h >> 3, + p &= (1 << (h -= b << 3)) - 1, + t.next_in = r, + t.next_out = i, + t.avail_in = r < o ? o - r + 5 : 5 - (r - o), + t.avail_out = i < s ? s - i + 257 : 257 - (i - s), + n.hold = p, + n.bits = h + } + } + , {}], + 8: [function(t, e, n) { + "use strict"; + function r(t) { + return (t >>> 24 & 255) + (t >>> 8 & 65280) + ((65280 & t) << 8) + ((255 & t) << 24) + } + function o() { + this.mode = 0, + this.last = !1, + this.wrap = 0, + this.havedict = !1, + this.flags = 0, + this.dmax = 0, + this.check = 0, + this.total = 0, + this.head = null, + this.wbits = 0, + this.wsize = 0, + this.whave = 0, + this.wnext = 0, + this.window = null, + this.hold = 0, + this.bits = 0, + this.length = 0, + this.offset = 0, + this.extra = 0, + this.lencode = null, + this.distcode = null, + this.lenbits = 0, + this.distbits = 0, + this.ncode = 0, + this.nlen = 0, + this.ndist = 0, + this.have = 0, + this.next = null, + this.lens = new p.Buf16(320), + this.work = new p.Buf16(288), + this.lendyn = null, + this.distdyn = null, + this.sane = 0, + this.back = 0, + this.was = 0 + } + function i(t) { + var e; + return t && t.state ? (e = t.state, + t.total_in = t.total_out = e.total = 0, + t.msg = "", + e.wrap && (t.adler = 1 & e.wrap), + e.mode = x, + e.last = 0, + e.havedict = 0, + e.dmax = 32768, + e.head = null, + e.hold = 0, + e.bits = 0, + e.lencode = e.lendyn = new p.Buf32(O), + e.distcode = e.distdyn = new p.Buf32(C), + e.sane = 1, + e.back = -1, + _) : b + } + function a(t) { + var e; + return t && t.state ? ((e = t.state).wsize = 0, + e.whave = 0, + e.wnext = 0, + i(t)) : b + } + function s(t, e) { + var n, r; + return t && t.state ? (r = t.state, + e < 0 ? (n = 0, + e = -e) : (n = 1 + (e >> 4), + e < 48 && (e &= 15)), + e && (e < 8 || e > 15) ? b : (null !== r.window && r.wbits !== e && (r.window = null), + r.wrap = n, + r.wbits = e, + a(t))) : b + } + function u(t, e) { + var n, r; + return t ? (r = new o, + t.state = r, + r.window = null, + (n = s(t, e)) !== _ && (t.state = null), + n) : b + } + function c(t) { + if (k) { + var e; + for (d = new p.Buf32(512), + l = new p.Buf32(32), + e = 0; e < 144; ) + t.lens[e++] = 8; + for (; e < 256; ) + t.lens[e++] = 9; + for (; e < 280; ) + t.lens[e++] = 7; + for (; e < 288; ) + t.lens[e++] = 8; + for (g(y, t.lens, 0, 288, d, 0, t.work, { + bits: 9 + }), + e = 0; e < 32; ) + t.lens[e++] = 5; + g(w, t.lens, 0, 32, l, 0, t.work, { + bits: 5 + }), + k = !1 + } + t.lencode = d, + t.lenbits = 9, + t.distcode = l, + t.distbits = 5 + } + function f(t, e, n, r) { + var o, i = t.state; + return null === i.window && (i.wsize = 1 << i.wbits, + i.wnext = 0, + i.whave = 0, + i.window = new p.Buf8(i.wsize)), + r >= i.wsize ? (p.arraySet(i.window, e, n - i.wsize, i.wsize, 0), + i.wnext = 0, + i.whave = i.wsize) : ((o = i.wsize - i.wnext) > r && (o = r), + p.arraySet(i.window, e, n - r, o, i.wnext), + (r -= o) ? (p.arraySet(i.window, e, n - r, r, 0), + i.wnext = r, + i.whave = i.wsize) : (i.wnext += o, + i.wnext === i.wsize && (i.wnext = 0), + i.whave < i.wsize && (i.whave += o))), + 0 + } + var d, l, p = t("../utils/common"), h = t("./adler32"), m = t("./crc32"), v = t("./inffast"), g = t("./inftrees"), y = 1, w = 2, _ = 0, b = -2, x = 1, S = 12, O = 852, C = 592, k = !0; + n.inflateReset = a, + n.inflateReset2 = s, + n.inflateResetKeep = i, + n.inflateInit = function(t) { + return u(t, 15) + } + , + n.inflateInit2 = u, + n.inflate = function(t, e) { + var n, o, i, a, s, u, d, l, O, C, k, E, T, D, M, A, I, W, P, N, R, j, L, q, U = 0, B = new p.Buf8(4), H = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; + if (!t || !t.state || !t.output || !t.input && 0 !== t.avail_in) + return b; + (n = t.state).mode === S && (n.mode = 13), + s = t.next_out, + i = t.output, + d = t.avail_out, + a = t.next_in, + o = t.input, + u = t.avail_in, + l = n.hold, + O = n.bits, + C = u, + k = d, + j = _; + t: for (; ; ) + switch (n.mode) { + case x: + if (0 === n.wrap) { + n.mode = 13; + break + } + for (; O < 16; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (2 & n.wrap && 35615 === l) { + n.check = 0, + B[0] = 255 & l, + B[1] = l >>> 8 & 255, + n.check = m(n.check, B, 2, 0), + l = 0, + O = 0, + n.mode = 2; + break + } + if (n.flags = 0, + n.head && (n.head.done = !1), + !(1 & n.wrap) || (((255 & l) << 8) + (l >> 8)) % 31) { + t.msg = "incorrect header check", + n.mode = 30; + break + } + if (8 != (15 & l)) { + t.msg = "unknown compression method", + n.mode = 30; + break + } + if (O -= 4, + R = 8 + (15 & (l >>>= 4)), + 0 === n.wbits) + n.wbits = R; + else if (R > n.wbits) { + t.msg = "invalid window size", + n.mode = 30; + break + } + n.dmax = 1 << R, + t.adler = n.check = 1, + n.mode = 512 & l ? 10 : S, + l = 0, + O = 0; + break; + case 2: + for (; O < 16; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (n.flags = l, + 8 != (255 & n.flags)) { + t.msg = "unknown compression method", + n.mode = 30; + break + } + if (57344 & n.flags) { + t.msg = "unknown header flags set", + n.mode = 30; + break + } + n.head && (n.head.text = l >> 8 & 1), + 512 & n.flags && (B[0] = 255 & l, + B[1] = l >>> 8 & 255, + n.check = m(n.check, B, 2, 0)), + l = 0, + O = 0, + n.mode = 3; + case 3: + for (; O < 32; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.head && (n.head.time = l), + 512 & n.flags && (B[0] = 255 & l, + B[1] = l >>> 8 & 255, + B[2] = l >>> 16 & 255, + B[3] = l >>> 24 & 255, + n.check = m(n.check, B, 4, 0)), + l = 0, + O = 0, + n.mode = 4; + case 4: + for (; O < 16; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.head && (n.head.xflags = 255 & l, + n.head.os = l >> 8), + 512 & n.flags && (B[0] = 255 & l, + B[1] = l >>> 8 & 255, + n.check = m(n.check, B, 2, 0)), + l = 0, + O = 0, + n.mode = 5; + case 5: + if (1024 & n.flags) { + for (; O < 16; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.length = l, + n.head && (n.head.extra_len = l), + 512 & n.flags && (B[0] = 255 & l, + B[1] = l >>> 8 & 255, + n.check = m(n.check, B, 2, 0)), + l = 0, + O = 0 + } else + n.head && (n.head.extra = null); + n.mode = 6; + case 6: + if (1024 & n.flags && ((E = n.length) > u && (E = u), + E && (n.head && (R = n.head.extra_len - n.length, + n.head.extra || (n.head.extra = new Array(n.head.extra_len)), + p.arraySet(n.head.extra, o, a, E, R)), + 512 & n.flags && (n.check = m(n.check, o, E, a)), + u -= E, + a += E, + n.length -= E), + n.length)) + break t; + n.length = 0, + n.mode = 7; + case 7: + if (2048 & n.flags) { + if (0 === u) + break t; + E = 0; + do { + R = o[a + E++], + n.head && R && n.length < 65536 && (n.head.name += String.fromCharCode(R)) + } while (R && E < u); + if (512 & n.flags && (n.check = m(n.check, o, E, a)), + u -= E, + a += E, + R) + break t + } else + n.head && (n.head.name = null); + n.length = 0, + n.mode = 8; + case 8: + if (4096 & n.flags) { + if (0 === u) + break t; + E = 0; + do { + R = o[a + E++], + n.head && R && n.length < 65536 && (n.head.comment += String.fromCharCode(R)) + } while (R && E < u); + if (512 & n.flags && (n.check = m(n.check, o, E, a)), + u -= E, + a += E, + R) + break t + } else + n.head && (n.head.comment = null); + n.mode = 9; + case 9: + if (512 & n.flags) { + for (; O < 16; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (l !== (65535 & n.check)) { + t.msg = "header crc mismatch", + n.mode = 30; + break + } + l = 0, + O = 0 + } + n.head && (n.head.hcrc = n.flags >> 9 & 1, + n.head.done = !0), + t.adler = n.check = 0, + n.mode = S; + break; + case 10: + for (; O < 32; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + t.adler = n.check = r(l), + l = 0, + O = 0, + n.mode = 11; + case 11: + if (0 === n.havedict) + return t.next_out = s, + t.avail_out = d, + t.next_in = a, + t.avail_in = u, + n.hold = l, + n.bits = O, + 2; + t.adler = n.check = 1, + n.mode = S; + case S: + if (5 === e || 6 === e) + break t; + case 13: + if (n.last) { + l >>>= 7 & O, + O -= 7 & O, + n.mode = 27; + break + } + for (; O < 3; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + switch (n.last = 1 & l, + O -= 1, + 3 & (l >>>= 1)) { + case 0: + n.mode = 14; + break; + case 1: + if (c(n), + n.mode = 20, + 6 === e) { + l >>>= 2, + O -= 2; + break t + } + break; + case 2: + n.mode = 17; + break; + case 3: + t.msg = "invalid block type", + n.mode = 30 + } + l >>>= 2, + O -= 2; + break; + case 14: + for (l >>>= 7 & O, + O -= 7 & O; O < 32; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if ((65535 & l) != (l >>> 16 ^ 65535)) { + t.msg = "invalid stored block lengths", + n.mode = 30; + break + } + if (n.length = 65535 & l, + l = 0, + O = 0, + n.mode = 15, + 6 === e) + break t; + case 15: + n.mode = 16; + case 16: + if (E = n.length) { + if (E > u && (E = u), + E > d && (E = d), + 0 === E) + break t; + p.arraySet(i, o, a, E, s), + u -= E, + a += E, + d -= E, + s += E, + n.length -= E; + break + } + n.mode = S; + break; + case 17: + for (; O < 14; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (n.nlen = 257 + (31 & l), + l >>>= 5, + O -= 5, + n.ndist = 1 + (31 & l), + l >>>= 5, + O -= 5, + n.ncode = 4 + (15 & l), + l >>>= 4, + O -= 4, + n.nlen > 286 || n.ndist > 30) { + t.msg = "too many length or distance symbols", + n.mode = 30; + break + } + n.have = 0, + n.mode = 18; + case 18: + for (; n.have < n.ncode; ) { + for (; O < 3; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.lens[H[n.have++]] = 7 & l, + l >>>= 3, + O -= 3 + } + for (; n.have < 19; ) + n.lens[H[n.have++]] = 0; + if (n.lencode = n.lendyn, + n.lenbits = 7, + L = { + bits: n.lenbits + }, + j = g(0, n.lens, 0, 19, n.lencode, 0, n.work, L), + n.lenbits = L.bits, + j) { + t.msg = "invalid code lengths set", + n.mode = 30; + break + } + n.have = 0, + n.mode = 19; + case 19: + for (; n.have < n.nlen + n.ndist; ) { + for (; A = (U = n.lencode[l & (1 << n.lenbits) - 1]) >>> 16 & 255, + I = 65535 & U, + !((M = U >>> 24) <= O); ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (I < 16) + l >>>= M, + O -= M, + n.lens[n.have++] = I; + else { + if (16 === I) { + for (q = M + 2; O < q; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (l >>>= M, + O -= M, + 0 === n.have) { + t.msg = "invalid bit length repeat", + n.mode = 30; + break + } + R = n.lens[n.have - 1], + E = 3 + (3 & l), + l >>>= 2, + O -= 2 + } else if (17 === I) { + for (q = M + 3; O < q; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + O -= M, + R = 0, + E = 3 + (7 & (l >>>= M)), + l >>>= 3, + O -= 3 + } else { + for (q = M + 7; O < q; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + O -= M, + R = 0, + E = 11 + (127 & (l >>>= M)), + l >>>= 7, + O -= 7 + } + if (n.have + E > n.nlen + n.ndist) { + t.msg = "invalid bit length repeat", + n.mode = 30; + break + } + for (; E--; ) + n.lens[n.have++] = R + } + } + if (30 === n.mode) + break; + if (0 === n.lens[256]) { + t.msg = "invalid code -- missing end-of-block", + n.mode = 30; + break + } + if (n.lenbits = 9, + L = { + bits: n.lenbits + }, + j = g(y, n.lens, 0, n.nlen, n.lencode, 0, n.work, L), + n.lenbits = L.bits, + j) { + t.msg = "invalid literal/lengths set", + n.mode = 30; + break + } + if (n.distbits = 6, + n.distcode = n.distdyn, + L = { + bits: n.distbits + }, + j = g(w, n.lens, n.nlen, n.ndist, n.distcode, 0, n.work, L), + n.distbits = L.bits, + j) { + t.msg = "invalid distances set", + n.mode = 30; + break + } + if (n.mode = 20, + 6 === e) + break t; + case 20: + n.mode = 21; + case 21: + if (u >= 6 && d >= 258) { + t.next_out = s, + t.avail_out = d, + t.next_in = a, + t.avail_in = u, + n.hold = l, + n.bits = O, + v(t, k), + s = t.next_out, + i = t.output, + d = t.avail_out, + a = t.next_in, + o = t.input, + u = t.avail_in, + l = n.hold, + O = n.bits, + n.mode === S && (n.back = -1); + break + } + for (n.back = 0; A = (U = n.lencode[l & (1 << n.lenbits) - 1]) >>> 16 & 255, + I = 65535 & U, + !((M = U >>> 24) <= O); ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (A && 0 == (240 & A)) { + for (W = M, + P = A, + N = I; A = (U = n.lencode[N + ((l & (1 << W + P) - 1) >> W)]) >>> 16 & 255, + I = 65535 & U, + !(W + (M = U >>> 24) <= O); ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + l >>>= W, + O -= W, + n.back += W + } + if (l >>>= M, + O -= M, + n.back += M, + n.length = I, + 0 === A) { + n.mode = 26; + break + } + if (32 & A) { + n.back = -1, + n.mode = S; + break + } + if (64 & A) { + t.msg = "invalid literal/length code", + n.mode = 30; + break + } + n.extra = 15 & A, + n.mode = 22; + case 22: + if (n.extra) { + for (q = n.extra; O < q; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.length += l & (1 << n.extra) - 1, + l >>>= n.extra, + O -= n.extra, + n.back += n.extra + } + n.was = n.length, + n.mode = 23; + case 23: + for (; A = (U = n.distcode[l & (1 << n.distbits) - 1]) >>> 16 & 255, + I = 65535 & U, + !((M = U >>> 24) <= O); ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (0 == (240 & A)) { + for (W = M, + P = A, + N = I; A = (U = n.distcode[N + ((l & (1 << W + P) - 1) >> W)]) >>> 16 & 255, + I = 65535 & U, + !(W + (M = U >>> 24) <= O); ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + l >>>= W, + O -= W, + n.back += W + } + if (l >>>= M, + O -= M, + n.back += M, + 64 & A) { + t.msg = "invalid distance code", + n.mode = 30; + break + } + n.offset = I, + n.extra = 15 & A, + n.mode = 24; + case 24: + if (n.extra) { + for (q = n.extra; O < q; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + n.offset += l & (1 << n.extra) - 1, + l >>>= n.extra, + O -= n.extra, + n.back += n.extra + } + if (n.offset > n.dmax) { + t.msg = "invalid distance too far back", + n.mode = 30; + break + } + n.mode = 25; + case 25: + if (0 === d) + break t; + if (E = k - d, + n.offset > E) { + if ((E = n.offset - E) > n.whave && n.sane) { + t.msg = "invalid distance too far back", + n.mode = 30; + break + } + E > n.wnext ? (E -= n.wnext, + T = n.wsize - E) : T = n.wnext - E, + E > n.length && (E = n.length), + D = n.window + } else + D = i, + T = s - n.offset, + E = n.length; + E > d && (E = d), + d -= E, + n.length -= E; + do { + i[s++] = D[T++] + } while (--E); + 0 === n.length && (n.mode = 21); + break; + case 26: + if (0 === d) + break t; + i[s++] = n.length, + d--, + n.mode = 21; + break; + case 27: + if (n.wrap) { + for (; O < 32; ) { + if (0 === u) + break t; + u--, + l |= o[a++] << O, + O += 8 + } + if (k -= d, + t.total_out += k, + n.total += k, + k && (t.adler = n.check = n.flags ? m(n.check, i, k, s - k) : h(n.check, i, k, s - k)), + k = d, + (n.flags ? l : r(l)) !== n.check) { + t.msg = "incorrect data check", + n.mode = 30; + break + } + l = 0, + O = 0 + } + n.mode = 28; + case 28: + if (n.wrap && n.flags) { + for (; O < 32; ) { + if (0 === u) + break t; + u--, + l += o[a++] << O, + O += 8 + } + if (l !== (4294967295 & n.total)) { + t.msg = "incorrect length check", + n.mode = 30; + break + } + l = 0, + O = 0 + } + n.mode = 29; + case 29: + j = 1; + break t; + case 30: + j = -3; + break t; + case 31: + return -4; + case 32: + default: + return b + } + return t.next_out = s, + t.avail_out = d, + t.next_in = a, + t.avail_in = u, + n.hold = l, + n.bits = O, + (n.wsize || k !== t.avail_out && n.mode < 30 && (n.mode < 27 || 4 !== e)) && f(t, t.output, t.next_out, k - t.avail_out) ? (n.mode = 31, + -4) : (C -= t.avail_in, + k -= t.avail_out, + t.total_in += C, + t.total_out += k, + n.total += k, + n.wrap && k && (t.adler = n.check = n.flags ? m(n.check, i, k, t.next_out - k) : h(n.check, i, k, t.next_out - k)), + t.data_type = n.bits + (n.last ? 64 : 0) + (n.mode === S ? 128 : 0) + (20 === n.mode || 15 === n.mode ? 256 : 0), + (0 === C && 0 === k || 4 === e) && j === _ && (j = -5), + j) + } + , + n.inflateEnd = function(t) { + if (!t || !t.state) + return b; + var e = t.state; + return e.window && (e.window = null), + t.state = null, + _ + } + , + n.inflateGetHeader = function(t, e) { + var n; + return t && t.state ? 0 == (2 & (n = t.state).wrap) ? b : (n.head = e, + e.done = !1, + _) : b + } + , + n.inflateSetDictionary = function(t, e) { + var n, r = e.length; + return t && t.state ? 0 !== (n = t.state).wrap && 11 !== n.mode ? b : 11 === n.mode && h(1, e, r, 0) !== n.check ? -3 : f(t, e, r, r) ? (n.mode = 31, + -4) : (n.havedict = 1, + _) : b + } + , + n.inflateInfo = "pako inflate (from Nodeca project)" + } + , { + "../utils/common": 1, + "./adler32": 3, + "./crc32": 5, + "./inffast": 7, + "./inftrees": 9 + }], + 9: [function(t, e, n) { + "use strict"; + var r = t("../utils/common") + , o = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0] + , i = [16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78] + , a = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0] + , s = [16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64]; + e.exports = function(t, e, n, u, c, f, d, l) { + var p, h, m, v, g, y, w, _, b, x = l.bits, S = 0, O = 0, C = 0, k = 0, E = 0, T = 0, D = 0, M = 0, A = 0, I = 0, W = null, P = 0, N = new r.Buf16(16), R = new r.Buf16(16), j = null, L = 0; + for (S = 0; S <= 15; S++) + N[S] = 0; + for (O = 0; O < u; O++) + N[e[n + O]]++; + for (E = x, + k = 15; k >= 1 && 0 === N[k]; k--) + ; + if (E > k && (E = k), + 0 === k) + return c[f++] = 20971520, + c[f++] = 20971520, + l.bits = 1, + 0; + for (C = 1; C < k && 0 === N[C]; C++) + ; + for (E < C && (E = C), + M = 1, + S = 1; S <= 15; S++) + if (M <<= 1, + (M -= N[S]) < 0) + return -1; + if (M > 0 && (0 === t || 1 !== k)) + return -1; + for (R[1] = 0, + S = 1; S < 15; S++) + R[S + 1] = R[S] + N[S]; + for (O = 0; O < u; O++) + 0 !== e[n + O] && (d[R[e[n + O]]++] = O); + if (0 === t ? (W = j = d, + y = 19) : 1 === t ? (W = o, + P -= 257, + j = i, + L -= 257, + y = 256) : (W = a, + j = s, + y = -1), + I = 0, + O = 0, + S = C, + g = f, + T = E, + D = 0, + m = -1, + v = (A = 1 << E) - 1, + 1 === t && A > 852 || 2 === t && A > 592) + return 1; + for (; ; ) { + w = S - D, + d[O] < y ? (_ = 0, + b = d[O]) : d[O] > y ? (_ = j[L + d[O]], + b = W[P + d[O]]) : (_ = 96, + b = 0), + p = 1 << S - D, + C = h = 1 << T; + do { + c[g + (I >> D) + (h -= p)] = w << 24 | _ << 16 | b | 0 + } while (0 !== h); + for (p = 1 << S - 1; I & p; ) + p >>= 1; + if (0 !== p ? (I &= p - 1, + I += p) : I = 0, + O++, + 0 == --N[S]) { + if (S === k) + break; + S = e[n + d[O]] + } + if (S > E && (I & v) !== m) { + for (0 === D && (D = E), + g += C, + M = 1 << (T = S - D); T + D < k && !((M -= N[T + D]) <= 0); ) + T++, + M <<= 1; + if (A += 1 << T, + 1 === t && A > 852 || 2 === t && A > 592) + return 1; + c[m = I & v] = E << 24 | T << 16 | g - f | 0 + } + } + return 0 !== I && (c[g + I] = S - D << 24 | 64 << 16 | 0), + l.bits = E, + 0 + } + } + , { + "../utils/common": 1 + }], + 10: [function(t, e, n) { + "use strict"; + e.exports = { + 2: "need dictionary", + 1: "stream end", + 0: "", + "-1": "file error", + "-2": "stream error", + "-3": "data error", + "-4": "insufficient memory", + "-5": "buffer error", + "-6": "incompatible version" + } + } + , {}], + 11: [function(t, e, n) { + "use strict"; + e.exports = function() { + this.input = null, + this.next_in = 0, + this.avail_in = 0, + this.total_in = 0, + this.output = null, + this.next_out = 0, + this.avail_out = 0, + this.total_out = 0, + this.msg = "", + this.state = null, + this.data_type = 2, + this.adler = 0 + } + } + , {}], + "/lib/inflate.js": [function(t, e, n) { + "use strict"; + function r(t) { + if (!(this instanceof r)) + return new r(t); + this.options = a.assign({ + chunkSize: 16384, + windowBits: 0, + to: "" + }, t || {}); + var e = this.options; + e.raw && e.windowBits >= 0 && e.windowBits < 16 && (e.windowBits = -e.windowBits, + 0 === e.windowBits && (e.windowBits = -15)), + !(e.windowBits >= 0 && e.windowBits < 16) || t && t.windowBits || (e.windowBits += 32), + e.windowBits > 15 && e.windowBits < 48 && 0 == (15 & e.windowBits) && (e.windowBits |= 15), + this.err = 0, + this.msg = "", + this.ended = !1, + this.chunks = [], + this.strm = new f, + this.strm.avail_out = 0; + var n = i.inflateInit2(this.strm, e.windowBits); + if (n !== u.Z_OK) + throw new Error(c[n]); + this.header = new d, + i.inflateGetHeader(this.strm, this.header) + } + function o(t, e) { + var n = new r(e); + if (n.push(t, !0), + n.err) + throw n.msg || c[n.err]; + return n.result + } + var i = t("./zlib/inflate") + , a = t("./utils/common") + , s = t("./utils/strings") + , u = t("./zlib/constants") + , c = t("./zlib/messages") + , f = t("./zlib/zstream") + , d = t("./zlib/gzheader") + , l = Object.prototype.toString; + r.prototype.push = function(t, e) { + var n, r, o, c, f, d, p = this.strm, h = this.options.chunkSize, m = this.options.dictionary, v = !1; + if (this.ended) + return !1; + r = e === ~~e ? e : !0 === e ? u.Z_FINISH : u.Z_NO_FLUSH, + "string" == typeof t ? p.input = s.binstring2buf(t) : "[object ArrayBuffer]" === l.call(t) ? p.input = new Uint8Array(t) : p.input = t, + p.next_in = 0, + p.avail_in = p.input.length; + do { + if (0 === p.avail_out && (p.output = new a.Buf8(h), + p.next_out = 0, + p.avail_out = h), + (n = i.inflate(p, u.Z_NO_FLUSH)) === u.Z_NEED_DICT && m && (d = "string" == typeof m ? s.string2buf(m) : "[object ArrayBuffer]" === l.call(m) ? new Uint8Array(m) : m, + n = i.inflateSetDictionary(this.strm, d)), + n === u.Z_BUF_ERROR && !0 === v && (n = u.Z_OK, + v = !1), + n !== u.Z_STREAM_END && n !== u.Z_OK) + return this.onEnd(n), + this.ended = !0, + !1; + p.next_out && (0 !== p.avail_out && n !== u.Z_STREAM_END && (0 !== p.avail_in || r !== u.Z_FINISH && r !== u.Z_SYNC_FLUSH) || ("string" === this.options.to ? (o = s.utf8border(p.output, p.next_out), + c = p.next_out - o, + f = s.buf2string(p.output, o), + p.next_out = c, + p.avail_out = h - c, + c && a.arraySet(p.output, p.output, o, c, 0), + this.onData(f)) : this.onData(a.shrinkBuf(p.output, p.next_out)))), + 0 === p.avail_in && 0 === p.avail_out && (v = !0) + } while ((p.avail_in > 0 || 0 === p.avail_out) && n !== u.Z_STREAM_END); + return n === u.Z_STREAM_END && (r = u.Z_FINISH), + r === u.Z_FINISH ? (n = i.inflateEnd(this.strm), + this.onEnd(n), + this.ended = !0, + n === u.Z_OK) : r !== u.Z_SYNC_FLUSH || (this.onEnd(u.Z_OK), + p.avail_out = 0, + !0) + } + , + r.prototype.onData = function(t) { + this.chunks.push(t) + } + , + r.prototype.onEnd = function(t) { + t === u.Z_OK && ("string" === this.options.to ? this.result = this.chunks.join("") : this.result = a.flattenChunks(this.chunks)), + this.chunks = [], + this.err = t, + this.msg = this.strm.msg + } + , + n.Inflate = r, + n.inflate = o, + n.inflateRaw = function(t, e) { + return (e = e || {}).raw = !0, + o(t, e) + } + , + n.ungzip = o + } + , { + "./utils/common": 1, + "./utils/strings": 2, + "./zlib/constants": 4, + "./zlib/gzheader": 6, + "./zlib/inflate": 8, + "./zlib/messages": 10, + "./zlib/zstream": 11 + }] + }, {}, [])("/lib/inflate.js") + } + , + "object" == s(e) && void 0 !== t ? t.exports = a() : (o = [], + void 0 === (i = "function" == typeof (r = a) ? r.apply(e, o) : r) || (t.exports = i)) + } +}); + + +!function(b) { + var r, u, t, n; + r = { + 1: [function(t, e) { + e.exports = function(t, e) { + for (var n = Array(arguments.length - 1), r = 0, o = 2, i = !0; o < arguments.length; ) + n[r++] = arguments[o++]; + return new Promise((function(o, a) { + n[r] = function(t) { + if (i) + if (i = !1, + t) + a(t); + else { + for (var e = Array(arguments.length - 1), n = 0; n < e.length; ) + e[n++] = arguments[n]; + o.apply(null, e) + } + } + ; + try { + t.apply(e || null, n) + } catch (t) { + i && (i = !1, + a(t)) + } + } + )) + } + } + , {}], + 2: [function(t, e, n) { + var r = n; + r.length = function(t) { + var e = t.length; + if (!e) + return 0; + for (var n = 0; 1 < --e % 4 && "=" === t.charAt(e); ) + ++n; + return Math.ceil(3 * t.length) / 4 - n + } + ; + for (var o = Array(64), i = Array(123), a = 0; a < 64; ) + i[o[a] = a < 26 ? a + 65 : a < 52 ? a + 71 : a < 62 ? a - 4 : a - 59 | 43] = a++; + r.encode = function(t, e, n) { + for (var r, i = null, a = [], s = 0, u = 0; e < n; ) { + var c = t[e++]; + switch (u) { + case 0: + a[s++] = o[c >> 2], + r = (3 & c) << 4, + u = 1; + break; + case 1: + a[s++] = o[r | c >> 4], + r = (15 & c) << 2, + u = 2; + break; + case 2: + a[s++] = o[r | c >> 6], + a[s++] = o[63 & c], + u = 0 + } + 8191 < s && ((i || (i = [])).push(String.fromCharCode.apply(String, a)), + s = 0) + } + return u && (a[s++] = o[r], + a[s++] = 61, + 1 === u && (a[s++] = 61)), + i ? (s && i.push(String.fromCharCode.apply(String, a.slice(0, s))), + i.join("")) : String.fromCharCode.apply(String, a.slice(0, s)) + } + ; + var s = "invalid encoding"; + r.decode = function(t, e, n) { + for (var r, o = n, a = 0, u = 0; u < t.length; ) { + var c = t.charCodeAt(u++); + if (61 === c && 1 < a) + break; + if ((c = i[c]) === b) + throw Error(s); + switch (a) { + case 0: + r = c, + a = 1; + break; + case 1: + e[n++] = r << 2 | (48 & c) >> 4, + r = c, + a = 2; + break; + case 2: + e[n++] = (15 & r) << 4 | (60 & c) >> 2, + r = c, + a = 3; + break; + case 3: + e[n++] = (3 & r) << 6 | c, + a = 0 + } + } + if (1 === a) + throw Error(s); + return n - o + } + , + r.test = function(t) { + return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t) + } + } + , {}], + 3: [function(t, e) { + function n() { + this.t = {} + } + (e.exports = n).prototype.on = function(t, e, n) { + return (this.t[t] || (this.t[t] = [])).push({ + fn: e, + ctx: n || this + }), + this + } + , + n.prototype.off = function(t, e) { + if (t === b) + this.t = {}; + else if (e === b) + this.t[t] = []; + else + for (var n = this.t[t], r = 0; r < n.length; ) + n[r].fn === e ? n.splice(r, 1) : ++r; + return this + } + , + n.prototype.emit = function(t) { + var e = this.t[t]; + if (e) { + for (var n = [], r = 1; r < arguments.length; ) + n.push(arguments[r++]); + for (r = 0; r < e.length; ) + e[r].fn.apply(e[r++].ctx, n) + } + return this + } + } + , {}], + 4: [function(t, e) { + function n(t) { + return "undefined" != typeof Float32Array ? function() { + var e = new Float32Array([-0]) + , n = new Uint8Array(e.buffer) + , r = 128 === n[3]; + function o(t, r, o) { + e[0] = t, + r[o] = n[0], + r[o + 1] = n[1], + r[o + 2] = n[2], + r[o + 3] = n[3] + } + function i(t, r, o) { + e[0] = t, + r[o] = n[3], + r[o + 1] = n[2], + r[o + 2] = n[1], + r[o + 3] = n[0] + } + function a(t, r) { + return n[0] = t[r], + n[1] = t[r + 1], + n[2] = t[r + 2], + n[3] = t[r + 3], + e[0] + } + function s(t, r) { + return n[3] = t[r], + n[2] = t[r + 1], + n[1] = t[r + 2], + n[0] = t[r + 3], + e[0] + } + t.writeFloatLE = r ? o : i, + t.writeFloatBE = r ? i : o, + t.readFloatLE = r ? a : s, + t.readFloatBE = r ? s : a + }() : function() { + function e(t, e, n, r) { + var o = e < 0 ? 1 : 0; + if (o && (e = -e), + 0 === e) + t(0 < 1 / e ? 0 : 2147483648, n, r); + else if (isNaN(e)) + t(2143289344, n, r); + else if (34028234663852886e22 < e) + t((o << 31 | 2139095040) >>> 0, n, r); + else if (e < 11754943508222875e-54) + t((o << 31 | Math.round(e / 1401298464324817e-60)) >>> 0, n, r); + else { + var i = Math.floor(Math.log(e) / Math.LN2); + t((o << 31 | i + 127 << 23 | 8388607 & Math.round(e * Math.pow(2, -i) * 8388608)) >>> 0, n, r) + } + } + function n(t, e, n) { + var r = t(e, n) + , o = 2 * (r >> 31) + 1 + , i = r >>> 23 & 255 + , a = 8388607 & r; + return 255 === i ? a ? NaN : o * (1 / 0) : 0 === i ? 1401298464324817e-60 * o * a : o * Math.pow(2, i - 150) * (a + 8388608) + } + t.writeFloatLE = e.bind(null, r), + t.writeFloatBE = e.bind(null, o), + t.readFloatLE = n.bind(null, i), + t.readFloatBE = n.bind(null, a) + }(), + "undefined" != typeof Float64Array ? function() { + var e = new Float64Array([-0]) + , n = new Uint8Array(e.buffer) + , r = 128 === n[7]; + function o(t, r, o) { + e[0] = t, + r[o] = n[0], + r[o + 1] = n[1], + r[o + 2] = n[2], + r[o + 3] = n[3], + r[o + 4] = n[4], + r[o + 5] = n[5], + r[o + 6] = n[6], + r[o + 7] = n[7] + } + function i(t, r, o) { + e[0] = t, + r[o] = n[7], + r[o + 1] = n[6], + r[o + 2] = n[5], + r[o + 3] = n[4], + r[o + 4] = n[3], + r[o + 5] = n[2], + r[o + 6] = n[1], + r[o + 7] = n[0] + } + function a(t, r) { + return n[0] = t[r], + n[1] = t[r + 1], + n[2] = t[r + 2], + n[3] = t[r + 3], + n[4] = t[r + 4], + n[5] = t[r + 5], + n[6] = t[r + 6], + n[7] = t[r + 7], + e[0] + } + function s(t, r) { + return n[7] = t[r], + n[6] = t[r + 1], + n[5] = t[r + 2], + n[4] = t[r + 3], + n[3] = t[r + 4], + n[2] = t[r + 5], + n[1] = t[r + 6], + n[0] = t[r + 7], + e[0] + } + t.writeDoubleLE = r ? o : i, + t.writeDoubleBE = r ? i : o, + t.readDoubleLE = r ? a : s, + t.readDoubleBE = r ? s : a + }() : function() { + function e(t, e, n, r, o, i) { + var a = r < 0 ? 1 : 0; + if (a && (r = -r), + 0 === r) + t(0, o, i + e), + t(0 < 1 / r ? 0 : 2147483648, o, i + n); + else if (isNaN(r)) + t(0, o, i + e), + t(2146959360, o, i + n); + else if (17976931348623157e292 < r) + t(0, o, i + e), + t((a << 31 | 2146435072) >>> 0, o, i + n); + else { + var s; + if (r < 22250738585072014e-324) + t((s = r / 5e-324) >>> 0, o, i + e), + t((a << 31 | s / 4294967296) >>> 0, o, i + n); + else { + var u = Math.floor(Math.log(r) / Math.LN2); + 1024 === u && (u = 1023), + t(4503599627370496 * (s = r * Math.pow(2, -u)) >>> 0, o, i + e), + t((a << 31 | u + 1023 << 20 | 1048576 * s & 1048575) >>> 0, o, i + n) + } + } + } + function n(t, e, n, r, o) { + var i = t(r, o + e) + , a = t(r, o + n) + , s = 2 * (a >> 31) + 1 + , u = a >>> 20 & 2047 + , c = 4294967296 * (1048575 & a) + i; + return 2047 === u ? c ? NaN : s * (1 / 0) : 0 === u ? 5e-324 * s * c : s * Math.pow(2, u - 1075) * (c + 4503599627370496) + } + t.writeDoubleLE = e.bind(null, r, 0, 4), + t.writeDoubleBE = e.bind(null, o, 4, 0), + t.readDoubleLE = n.bind(null, i, 0, 4), + t.readDoubleBE = n.bind(null, a, 4, 0) + }(), + t + } + function r(t, e, n) { + e[n] = 255 & t, + e[n + 1] = t >>> 8 & 255, + e[n + 2] = t >>> 16 & 255, + e[n + 3] = t >>> 24 + } + function o(t, e, n) { + e[n] = t >>> 24, + e[n + 1] = t >>> 16 & 255, + e[n + 2] = t >>> 8 & 255, + e[n + 3] = 255 & t + } + function i(t, e) { + return (t[e] | t[e + 1] << 8 | t[e + 2] << 16 | t[e + 3] << 24) >>> 0 + } + function a(t, e) { + return (t[e] << 24 | t[e + 1] << 16 | t[e + 2] << 8 | t[e + 3]) >>> 0 + } + e.exports = n(n) + } + , {}], + 5: [function(t, n, i) { + function r(t) { + try { + var n = eval("require")(t); + if (n && (n.length || Object.keys(n).length)) + return n + } catch (t) {} + return null + } + n.exports = r + } + , {}], + 6: [function(t, e) { + e.exports = function(t, e, n) { + var r = n || 8192 + , o = r >>> 1 + , i = null + , a = r; + return function(n) { + if (n < 1 || o < n) + return t(n); + r < a + n && (i = t(r), + a = 0); + var s = e.call(i, a, a += n); + return 7 & a && (a = 1 + (7 | a)), + s + } + } + } + , {}], + 7: [function(t, e, n) { + var r = n; + r.length = function(t) { + for (var e = 0, n = 0, r = 0; r < t.length; ++r) + (n = t.charCodeAt(r)) < 128 ? e += 1 : n < 2048 ? e += 2 : 55296 == (64512 & n) && 56320 == (64512 & t.charCodeAt(r + 1)) ? (++r, + e += 4) : e += 3; + return e + } + , + r.read = function(t, e, n) { + if (n - e < 1) + return ""; + for (var r, o = null, i = [], a = 0; e < n; ) + (r = t[e++]) < 128 ? i[a++] = r : 191 < r && r < 224 ? i[a++] = (31 & r) << 6 | 63 & t[e++] : 239 < r && r < 365 ? (r = ((7 & r) << 18 | (63 & t[e++]) << 12 | (63 & t[e++]) << 6 | 63 & t[e++]) - 65536, + i[a++] = 55296 + (r >> 10), + i[a++] = 56320 + (1023 & r)) : i[a++] = (15 & r) << 12 | (63 & t[e++]) << 6 | 63 & t[e++], + 8191 < a && ((o || (o = [])).push(String.fromCharCode.apply(String, i)), + a = 0); + return o ? (a && o.push(String.fromCharCode.apply(String, i.slice(0, a))), + o.join("")) : String.fromCharCode.apply(String, i.slice(0, a)) + } + , + r.write = function(t, e, n) { + for (var r, o, i = n, a = 0; a < t.length; ++a) + (r = t.charCodeAt(a)) < 128 ? e[n++] = r : (r < 2048 ? e[n++] = r >> 6 | 192 : (55296 == (64512 & r) && 56320 == (64512 & (o = t.charCodeAt(a + 1))) ? (r = 65536 + ((1023 & r) << 10) + (1023 & o), + ++a, + e[n++] = r >> 18 | 240, + e[n++] = r >> 12 & 63 | 128) : e[n++] = r >> 12 | 224, + e[n++] = r >> 6 & 63 | 128), + e[n++] = 63 & r | 128); + return n - i + } + } + , {}], + 8: [function(t, e, n) { + var r = n; + function o() { + r.Reader.n(r.BufferReader), + r.util.n() + } + r.build = "minimal", + r.Writer = t(16), + r.BufferWriter = t(17), + r.Reader = t(9), + r.BufferReader = t(10), + r.util = t(15), + r.rpc = t(12), + r.roots = t(11), + r.configure = o, + r.Writer.n(r.BufferWriter), + o() + } + , { + 10: 10, + 11: 11, + 12: 12, + 15: 15, + 16: 16, + 17: 17, + 9: 9 + }], + 9: [function(t, e) { + e.exports = s; + var n, r = t(15), o = r.LongBits, i = r.utf8; + function a(t, e) { + return RangeError("index out of range: " + t.pos + " + " + (e || 1) + " > " + t.len) + } + function s(t) { + this.buf = t, + this.pos = 0, + this.len = t.length + } + var u, c = "undefined" != typeof Uint8Array ? function(t) { + if (t instanceof Uint8Array || Array.isArray(t)) + return new s(t); + throw Error("illegal buffer") + } + : function(t) { + if (Array.isArray(t)) + return new s(t); + throw Error("illegal buffer") + } + ; + function f() { + var t = new o(0,0) + , e = 0; + if (!(4 < this.len - this.pos)) { + for (; e < 3; ++e) { + if (this.pos >= this.len) + throw a(this); + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * e) >>> 0, + this.buf[this.pos++] < 128) + return t + } + return t.lo = (t.lo | (127 & this.buf[this.pos++]) << 7 * e) >>> 0, + t + } + for (; e < 4; ++e) + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * e) >>> 0, + this.buf[this.pos++] < 128) + return t; + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 28) >>> 0, + t.hi = (t.hi | (127 & this.buf[this.pos]) >> 4) >>> 0, + this.buf[this.pos++] < 128) + return t; + if (e = 0, + 4 < this.len - this.pos) { + for (; e < 5; ++e) + if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * e + 3) >>> 0, + this.buf[this.pos++] < 128) + return t + } else + for (; e < 5; ++e) { + if (this.pos >= this.len) + throw a(this); + if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * e + 3) >>> 0, + this.buf[this.pos++] < 128) + return t + } + throw Error("invalid varint encoding") + } + function d(t, e) { + return (t[e - 4] | t[e - 3] << 8 | t[e - 2] << 16 | t[e - 1] << 24) >>> 0 + } + function l() { + if (this.pos + 8 > this.len) + throw a(this, 8); + return new o(d(this.buf, this.pos += 4),d(this.buf, this.pos += 4)) + } + s.create = r.Buffer ? function(t) { + return (s.create = function(t) { + return r.Buffer.isBuffer(t) ? new n(t) : c(t) + } + )(t) + } + : c, + s.prototype.i = r.Array.prototype.subarray || r.Array.prototype.slice, + s.prototype.uint32 = (u = 4294967295, + function() { + if (u = (127 & this.buf[this.pos]) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 7) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 14) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 21) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (15 & this.buf[this.pos]) << 28) >>> 0, + this.buf[this.pos++] < 128) + return u; + if ((this.pos += 5) > this.len) + throw this.pos = this.len, + a(this, 10); + return u + } + ), + s.prototype.int32 = function() { + return 0 | this.uint32() + } + , + s.prototype.sint32 = function() { + var t = this.uint32(); + return t >>> 1 ^ -(1 & t) | 0 + } + , + s.prototype.bool = function() { + return 0 !== this.uint32() + } + , + s.prototype.fixed32 = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + return d(this.buf, this.pos += 4) + } + , + s.prototype.sfixed32 = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + return 0 | d(this.buf, this.pos += 4) + } + , + s.prototype.float = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + var t = r.float.readFloatLE(this.buf, this.pos); + return this.pos += 4, + t + } + , + s.prototype.double = function() { + if (this.pos + 8 > this.len) + throw a(this, 4); + var t = r.float.readDoubleLE(this.buf, this.pos); + return this.pos += 8, + t + } + , + s.prototype.bytes = function() { + var t = this.uint32() + , e = this.pos + , n = this.pos + t; + if (n > this.len) + throw a(this, t); + return this.pos += t, + Array.isArray(this.buf) ? this.buf.slice(e, n) : e === n ? new this.buf.constructor(0) : this.i.call(this.buf, e, n) + } + , + s.prototype.string = function() { + var t = this.bytes(); + return i.read(t, 0, t.length) + } + , + s.prototype.skip = function(t) { + if ("number" == typeof t) { + if (this.pos + t > this.len) + throw a(this, t); + this.pos += t + } else + do { + if (this.pos >= this.len) + throw a(this) + } while (128 & this.buf[this.pos++]); + return this + } + , + s.prototype.skipType = function(t) { + switch (t) { + case 0: + this.skip(); + break; + case 1: + this.skip(8); + break; + case 2: + this.skip(this.uint32()); + break; + case 3: + for (; 4 != (t = 7 & this.uint32()); ) + this.skipType(t); + break; + case 5: + this.skip(4); + break; + default: + throw Error("invalid wire type " + t + " at offset " + this.pos) + } + return this + } + , + s.n = function(t) { + n = t; + var e = r.Long ? "toLong" : "toNumber"; + r.merge(s.prototype, { + int64: function() { + return f.call(this)[e](!1) + }, + uint64: function() { + return f.call(this)[e](!0) + }, + sint64: function() { + return f.call(this).zzDecode()[e](!1) + }, + fixed64: function() { + return l.call(this)[e](!0) + }, + sfixed64: function() { + return l.call(this)[e](!1) + } + }) + } + } + , { + 15: 15 + }], + 10: [function(t, e) { + e.exports = o; + var n = t(9); + (o.prototype = Object.create(n.prototype)).constructor = o; + var r = t(15); + function o(t) { + n.call(this, t) + } + r.Buffer && (o.prototype.i = r.Buffer.prototype.slice), + o.prototype.string = function() { + var t = this.uint32(); + return this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + t, this.len)) + } + } + , { + 15: 15, + 9: 9 + }], + 11: [function(t, e) { + e.exports = {} + } + , {}], + 12: [function(t, e, n) { + n.Service = t(13) + } + , { + 13: 13 + }], + 13: [function(t, e) { + e.exports = r; + var n = t(15); + function r(t, e, r) { + if ("function" != typeof t) + throw TypeError("rpcImpl must be a function"); + n.EventEmitter.call(this), + this.rpcImpl = t, + this.requestDelimited = !!e, + this.responseDelimited = !!r + } + ((r.prototype = Object.create(n.EventEmitter.prototype)).constructor = r).prototype.rpcCall = function t(e, r, o, i, a) { + if (!i) + throw TypeError("request must be specified"); + var s = this; + if (!a) + return n.asPromise(t, s, e, r, o, i); + if (!s.rpcImpl) + return setTimeout((function() { + a(Error("already ended")) + } + ), 0), + b; + try { + return s.rpcImpl(e, r[s.requestDelimited ? "encodeDelimited" : "encode"](i).finish(), (function(t, n) { + if (t) + return s.emit("error", t, e), + a(t); + if (null === n) + return s.end(!0), + b; + if (!(n instanceof o)) + try { + n = o[s.responseDelimited ? "decodeDelimited" : "decode"](n) + } catch (t) { + return s.emit("error", t, e), + a(t) + } + return s.emit("data", n, e), + a(null, n) + } + )) + } catch (t) { + return s.emit("error", t, e), + setTimeout((function() { + a(t) + } + ), 0), + b + } + } + , + r.prototype.end = function(t) { + return this.rpcImpl && (t || this.rpcImpl(null, null, null), + this.rpcImpl = null, + this.emit("end").off()), + this + } + } + , { + 15: 15 + }], + 14: [function(t, e) { + e.exports = r; + var n = t(15); + function r(t, e) { + this.lo = t >>> 0, + this.hi = e >>> 0 + } + var o = r.zero = new r(0,0); + o.toNumber = function() { + return 0 + } + , + o.zzEncode = o.zzDecode = function() { + return this + } + , + o.length = function() { + return 1 + } + ; + var i = r.zeroHash = "\0\0\0\0\0\0\0\0"; + r.fromNumber = function(t) { + if (0 === t) + return o; + var e = t < 0; + e && (t = -t); + var n = t >>> 0 + , i = (t - n) / 4294967296 >>> 0; + return e && (i = ~i >>> 0, + n = ~n >>> 0, + 4294967295 < ++n && (n = 0, + 4294967295 < ++i && (i = 0))), + new r(n,i) + } + , + r.from = function(t) { + if ("number" == typeof t) + return r.fromNumber(t); + if (n.isString(t)) { + if (!n.Long) + return r.fromNumber(parseInt(t, 10)); + t = n.Long.fromString(t) + } + return t.low || t.high ? new r(t.low >>> 0,t.high >>> 0) : o + } + , + r.prototype.toNumber = function(t) { + if (!t && this.hi >>> 31) { + var e = 1 + ~this.lo >>> 0 + , n = ~this.hi >>> 0; + return e || (n = n + 1 >>> 0), + -(e + 4294967296 * n) + } + return this.lo + 4294967296 * this.hi + } + , + r.prototype.toLong = function(t) { + return n.Long ? new n.Long(0 | this.lo,0 | this.hi,!!t) : { + low: 0 | this.lo, + high: 0 | this.hi, + unsigned: !!t + } + } + ; + var a = String.prototype.charCodeAt; + r.fromHash = function(t) { + return t === i ? o : new r((a.call(t, 0) | a.call(t, 1) << 8 | a.call(t, 2) << 16 | a.call(t, 3) << 24) >>> 0,(a.call(t, 4) | a.call(t, 5) << 8 | a.call(t, 6) << 16 | a.call(t, 7) << 24) >>> 0) + } + , + r.prototype.toHash = function() { + return String.fromCharCode(255 & this.lo, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, 255 & this.hi, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24) + } + , + r.prototype.zzEncode = function() { + var t = this.hi >> 31; + return this.hi = ((this.hi << 1 | this.lo >>> 31) ^ t) >>> 0, + this.lo = (this.lo << 1 ^ t) >>> 0, + this + } + , + r.prototype.zzDecode = function() { + var t = -(1 & this.lo); + return this.lo = ((this.lo >>> 1 | this.hi << 31) ^ t) >>> 0, + this.hi = (this.hi >>> 1 ^ t) >>> 0, + this + } + , + r.prototype.length = function() { + var t = this.lo + , e = (this.lo >>> 28 | this.hi << 4) >>> 0 + , n = this.hi >>> 24; + return 0 === n ? 0 === e ? t < 16384 ? t < 128 ? 1 : 2 : t < 2097152 ? 3 : 4 : e < 16384 ? e < 128 ? 5 : 6 : e < 2097152 ? 7 : 8 : n < 128 ? 9 : 10 + } + } + , { + 15: 15 + }], + 15: [function(t, e, n) { + var r = n; + function o(t, e, n) { + for (var r = Object.keys(e), o = 0; o < r.length; ++o) + t[r[o]] !== b && n || (t[r[o]] = e[r[o]]); + return t + } + function i(t) { + function e(t, n) { + if (!(this instanceof e)) + return new e(t,n); + Object.defineProperty(this, "message", { + get: function() { + return t + } + }), + Error.captureStackTrace ? Error.captureStackTrace(this, e) : Object.defineProperty(this, "stack", { + value: Error().stack || "" + }), + n && o(this, n) + } + return (e.prototype = Object.create(Error.prototype)).constructor = e, + Object.defineProperty(e.prototype, "name", { + get: function() { + return t + } + }), + e.prototype.toString = function() { + return this.name + ": " + this.message + } + , + e + } + r.asPromise = t(1), + r.base64 = t(2), + r.EventEmitter = t(3), + r.float = t(4), + r.inquire = t(5), + r.utf8 = t(7), + r.pool = t(6), + r.LongBits = t(14), + r.global = "undefined" != typeof window && window || void 0 !== global && global || "undefined" != typeof self && self || this, + r.emptyArray = Object.freeze ? Object.freeze([]) : [], + r.emptyObject = Object.freeze ? Object.freeze({}) : {}, + r.isNode = !!(r.global.process && r.global.process.versions && r.global.process.versions.node), + r.isInteger = Number.isInteger || function(t) { + return "number" == typeof t && isFinite(t) && Math.floor(t) === t + } + , + r.isString = function(t) { + return "string" == typeof t || t instanceof String + } + , + r.isObject = function(t) { + return t && "object" == _typeof(t) + } + , + r.isset = r.isSet = function(t, e) { + var n = t[e]; + return !(null == n || !t.hasOwnProperty(e)) && ("object" != _typeof(n) || 0 < (Array.isArray(n) ? n.length : Object.keys(n).length)) + } + , + r.Buffer = function() { + try { + var t = r.inquire("buffer").Buffer; + return t.prototype.utf8Write ? t : null + } catch (t) { + return null + } + }(), + r.r = null, + r.u = null, + r.newBuffer = function(t) { + return "number" == typeof t ? r.Buffer ? r.u(t) : new r.Array(t) : r.Buffer ? r.r(t) : "undefined" == typeof Uint8Array ? t : new Uint8Array(t) + } + , + r.Array = "undefined" != typeof Uint8Array ? Uint8Array : Array, + r.Long = r.global.dcodeIO && r.global.dcodeIO.Long || r.global.Long || r.inquire("long"), + r.key2Re = /^true|false|0|1$/, + r.key32Re = /^-?(?:0|[1-9][0-9]*)$/, + r.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/, + r.longToHash = function(t) { + return t ? r.LongBits.from(t).toHash() : r.LongBits.zeroHash + } + , + r.longFromHash = function(t, e) { + var n = r.LongBits.fromHash(t); + return r.Long ? r.Long.fromBits(n.lo, n.hi, e) : n.toNumber(!!e) + } + , + r.merge = o, + r.lcFirst = function(t) { + return t.charAt(0).toLowerCase() + t.substring(1) + } + , + r.newError = i, + r.ProtocolError = i("ProtocolError"), + r.oneOfGetter = function(t) { + for (var e = {}, n = 0; n < t.length; ++n) + e[t[n]] = 1; + return function() { + for (var t = Object.keys(this), n = t.length - 1; -1 < n; --n) + if (1 === e[t[n]] && this[t[n]] !== b && null !== this[t[n]]) + return t[n] + } + } + , + r.oneOfSetter = function(t) { + return function(e) { + for (var n = 0; n < t.length; ++n) + t[n] !== e && delete this[t[n]] + } + } + , + r.toJSONOptions = { + longs: String, + enums: String, + bytes: String, + json: !0 + }, + r.n = function() { + var t = r.Buffer; + t ? (r.r = t.from !== Uint8Array.from && t.from || function(e, n) { + return new t(e,n) + } + , + r.u = t.allocUnsafe || function(e) { + return new t(e) + } + ) : r.r = r.u = null + } + } + , { + 1: 1, + 14: 14, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7 + }], + 16: [function(t, e) { + e.exports = f; + var n, r = t(15), o = r.LongBits, i = r.base64, a = r.utf8; + function s(t, e, n) { + this.fn = t, + this.len = e, + this.next = b, + this.val = n + } + function u() {} + function c(t) { + this.head = t.head, + this.tail = t.tail, + this.len = t.len, + this.next = t.states + } + function f() { + this.len = 0, + this.head = new s(u,0,0), + this.tail = this.head, + this.states = null + } + function d(t, e, n) { + e[n] = 255 & t + } + function l(t, e) { + this.len = t, + this.next = b, + this.val = e + } + function p(t, e, n) { + for (; t.hi; ) + e[n++] = 127 & t.lo | 128, + t.lo = (t.lo >>> 7 | t.hi << 25) >>> 0, + t.hi >>>= 7; + for (; 127 < t.lo; ) + e[n++] = 127 & t.lo | 128, + t.lo = t.lo >>> 7; + e[n++] = t.lo + } + function h(t, e, n) { + e[n] = 255 & t, + e[n + 1] = t >>> 8 & 255, + e[n + 2] = t >>> 16 & 255, + e[n + 3] = t >>> 24 + } + f.create = r.Buffer ? function() { + return (f.create = function() { + return new n + } + )() + } + : function() { + return new f + } + , + f.alloc = function(t) { + return new r.Array(t) + } + , + r.Array !== Array && (f.alloc = r.pool(f.alloc, r.Array.prototype.subarray)), + f.prototype.e = function(t, e, n) { + return this.tail = this.tail.next = new s(t,e,n), + this.len += e, + this + } + , + (l.prototype = Object.create(s.prototype)).fn = function(t, e, n) { + for (; 127 < t; ) + e[n++] = 127 & t | 128, + t >>>= 7; + e[n] = t + } + , + f.prototype.uint32 = function(t) { + return this.len += (this.tail = this.tail.next = new l((t >>>= 0) < 128 ? 1 : t < 16384 ? 2 : t < 2097152 ? 3 : t < 268435456 ? 4 : 5,t)).len, + this + } + , + f.prototype.int32 = function(t) { + return t < 0 ? this.e(p, 10, o.fromNumber(t)) : this.uint32(t) + } + , + f.prototype.sint32 = function(t) { + return this.uint32((t << 1 ^ t >> 31) >>> 0) + } + , + f.prototype.int64 = f.prototype.uint64 = function(t) { + var e = o.from(t); + return this.e(p, e.length(), e) + } + , + f.prototype.sint64 = function(t) { + var e = o.from(t).zzEncode(); + return this.e(p, e.length(), e) + } + , + f.prototype.bool = function(t) { + return this.e(d, 1, t ? 1 : 0) + } + , + f.prototype.sfixed32 = f.prototype.fixed32 = function(t) { + return this.e(h, 4, t >>> 0) + } + , + f.prototype.sfixed64 = f.prototype.fixed64 = function(t) { + var e = o.from(t); + return this.e(h, 4, e.lo).e(h, 4, e.hi) + } + , + f.prototype.float = function(t) { + return this.e(r.float.writeFloatLE, 4, t) + } + , + f.prototype.double = function(t) { + return this.e(r.float.writeDoubleLE, 8, t) + } + ; + var m = r.Array.prototype.set ? function(t, e, n) { + e.set(t, n) + } + : function(t, e, n) { + for (var r = 0; r < t.length; ++r) + e[n + r] = t[r] + } + ; + f.prototype.bytes = function(t) { + var e = t.length >>> 0; + if (!e) + return this.e(d, 1, 0); + if (r.isString(t)) { + var n = f.alloc(e = i.length(t)); + i.decode(t, n, 0), + t = n + } + return this.uint32(e).e(m, e, t) + } + , + f.prototype.string = function(t) { + var e = a.length(t); + return e ? this.uint32(e).e(a.write, e, t) : this.e(d, 1, 0) + } + , + f.prototype.fork = function() { + return this.states = new c(this), + this.head = this.tail = new s(u,0,0), + this.len = 0, + this + } + , + f.prototype.reset = function() { + return this.states ? (this.head = this.states.head, + this.tail = this.states.tail, + this.len = this.states.len, + this.states = this.states.next) : (this.head = this.tail = new s(u,0,0), + this.len = 0), + this + } + , + f.prototype.ldelim = function() { + var t = this.head + , e = this.tail + , n = this.len; + return this.reset().uint32(n), + n && (this.tail.next = t.next, + this.tail = e, + this.len += n), + this + } + , + f.prototype.finish = function() { + for (var t = this.head.next, e = this.constructor.alloc(this.len), n = 0; t; ) + t.fn(t.val, e, n), + n += t.len, + t = t.next; + return e + } + , + f.n = function(t) { + n = t + } + } + , { + 15: 15 + }], + 17: [function(t, e) { + e.exports = i; + var n = t(16); + (i.prototype = Object.create(n.prototype)).constructor = i; + var r = t(15) + , o = r.Buffer; + function i() { + n.call(this) + } + i.alloc = function(t) { + return (i.alloc = r.u)(t) + } + ; + var a = o && o.prototype instanceof Uint8Array && "set" === o.prototype.set.name ? function(t, e, n) { + e.set(t, n) + } + : function(t, e, n) { + if (t.copy) + t.copy(e, n, 0, t.length); + else + for (var r = 0; r < t.length; ) + e[n++] = t[r++] + } + ; + function s(t, e, n) { + t.length < 40 ? r.utf8.write(t, e, n) : e.utf8Write(t, n) + } + i.prototype.bytes = function(t) { + r.isString(t) && (t = r.r(t, "base64")); + var e = t.length >>> 0; + return this.uint32(e), + e && this.e(a, e, t), + this + } + , + i.prototype.string = function(t) { + var e = o.byteLength(t); + return this.uint32(e), + e && this.e(s, e, t), + this + } + } + , { + 15: 15, + 16: 16 + }] + }, + u = {}, + t = [8], + n = function t(e) { + var n = u[e]; + return n || r[e][0].call(n = u[e] = { + exports: {} + }, t, n, n.exports), + n.exports + }; + window.nnnnnn = n +}() + +yt = { + Reader: window.nnnnnn(9) +} +yt.Reader.n(); + +var zdecode = function(t, n, count) { + window.nnnnnn(9).n(); + if (count == 1){ + var e = { + "1": [ + "command", + "string", + "" + ], + "2": [ + "protocol", + "uint32", + 0 + ], + "3": [ + "errorCode", + "uint32", + 0 + ], + "4": [ + "bizCode", + "uint32", + 0 + ], + "5": [ + "bizErrorMsg", + "string", + "" + ], + "6": [ + "compress", + "uint32", + 0 + ], + "9": [ + "extension", + "bytes", + [] + ], + "10": [ + "body", + "bytes", + [] + ], + "11": [ + "downstreamSeq", + "uint64", + 0 + ], + "12": [ + "conId", + "uint64", + 0 + ], + "13": [ + "ctxId", + "uint64", + 0 + ] + }; + } + else if (count == 2){ + var e = { + "1": [ + "uid", + "string", + "" + ], + "2": [ + "titanid", + "string", + "" + ], + "3": [ + "os", + "uint32", + 0 + ], + "4": [ + "bizType", + "uint32", + 0 + ], + "5": [ + "msgId", + "string", + "" + ], + "6": [ + "payload", + "bytes", + [] + ], + "7": [ + "additionalMap", + "{string,string", + null + ], + "8": [ + "subType", + "uint32", + 0 + ], + "9": [ + "timestamp", + "uint64", + 0 + ] + }; + } + else{ + var e = { + "1": [ + "$1", + "string", + null + ], + "2": [ + "$2", + "string", + null + ] + } + } + var zzz = { + "command": "", + "protocol": 0, + "errorCode": 0, + "bizCode": 0, + "bizErrorMsg": "", + "compress": 0, + "extension": new Uint8Array(0), + "body": new Uint8Array(0), + "downstreamSeq": 0, + "conId": 0, + "ctxId": 0 + } + t instanceof yt.Reader || (t = yt.Reader.create(t)); + for (var i = void 0 === n ? t.len : t.pos + n, a = zzz; t.pos < i; ) { + var s = t.uint32() + , u = s >>> 3; + if (0 < u && e[u]) { + var c = e[u][0] + , f = e[u][1]; + if ("{" === f.charAt(0)) + (a[c] = {}), + u = zdecode(t, t.uint32(), 3), + a[c][u.$1] = u.$2; + else if ("[" === f.charAt(0) || "<" === f.charAt(0)) + if (f = f.substring(1), + a[c] && a[c].length || (a[c] = []), + void 0 !== bt[f] && 2 == (7 & s)) + for (var d = t.uint32() + t.pos; t.pos < d; ) + a[c].push(Object.call(t, f)); + else + a[c].push(Object.call(t, f)); + else + a[c] = window.nnnnnn(9).prototype[f].call(t) + } else + t.skipType(7 & s) + } + return a +} + +var Tt = {}; + +!function(t) { + var e, n, r, o = String.fromCharCode; + function i(t) { + for (var e, n, r = [], o = 0, i = t.length; o < i; ) + (e = t.charCodeAt(o++)) >= 55296 && e <= 56319 && o < i ? 56320 == (64512 & (n = t.charCodeAt(o++))) ? r.push(((1023 & e) << 10) + (1023 & n) + 65536) : (r.push(e), + o--) : r.push(e); + return r + } + function a(t) { + if (t >= 55296 && t <= 57343) + throw Error("Lone surrogate U+" + t.toString(16).toUpperCase() + " is not a scalar value") + } + function s(t, e) { + return o(t >> e & 63 | 128) + } + function u(t) { + if (0 == (4294967168 & t)) + return o(t); + var e = ""; + return 0 == (4294965248 & t) ? e = o(t >> 6 & 31 | 192) : 0 == (4294901760 & t) ? (a(t), + e = o(t >> 12 & 15 | 224), + e += s(t, 6)) : 0 == (4292870144 & t) && (e = o(t >> 18 & 7 | 240), + e += s(t, 12), + e += s(t, 6)), + e += o(63 & t | 128) + } + function c() { + if (r >= n) + throw Error("Invalid byte index"); + var t = 255 & e[r]; + if (r++, + 128 == (192 & t)) + return 63 & t; + throw Error("Invalid continuation byte") + } + function f() { + var t, o; + if (r > n) + throw Error("Invalid byte index"); + if (r == n) + return !1; + if (t = 255 & e[r], + r++, + 0 == (128 & t)) + return t; + if (192 == (224 & t)) { + if ((o = (31 & t) << 6 | c()) >= 128) + return o; + throw Error("Invalid continuation byte") + } + if (224 == (240 & t)) { + if ((o = (15 & t) << 12 | c() << 6 | c()) >= 2048) + return a(o), + o; + throw Error("Invalid continuation byte") + } + if (240 == (248 & t) && (o = (7 & t) << 18 | c() << 12 | c() << 6 | c()) >= 65536 && o <= 1114111) + return o; + throw Error("Invalid UTF-8 detected") + } + t.version = "3.0.0", + t.encode = function(t) { + for (var e = i(t), n = e.length, r = -1, o = ""; ++r < n; ) + o += u(e[r]); + return o + } + , + t.decode = function(t) { + e = i(t), + n = e.length, + r = 0; + for (var a, s = []; !1 !== (a = f()); ) + s.push(a); + return function(t) { + for (var e, n = t.length, r = -1, i = ""; ++r < n; ) + (e = t[r]) > 65535 && (i += o((e -= 65536) >>> 10 & 1023 | 55296), + e = 56320 | 1023 & e), + i += o(e); + return i + }(s) + } +}(Tt) + +Qt = function (t, e=!0){ + const n = t.length; + let r = ""; + for (let e = 0; e < n; e++) + r += String.fromCharCode(t[e]); + return e && (r = Tt.decode(r), + r = r.replace(/\n/g, "\\\\n").replace(/\r/g, "\\\\r").replace(/\t/g, "\\\\t").replace(/\u2028/g, "")), + Yt(r, r) + } + +Yt = function (t, e){ + if ("string" != typeof t) + return e; + let n; + try { + n = JSON.parse(t) || e + } catch (t) { + n = e + } + return n + } + + + + + +function dencode_data(decodedString){ + var decodedString = atob(decodedString) + let uint8Array = []; + + for (let i = 0; i < decodedString.length; i++) { + uint8Array[i] = decodedString.charCodeAt(i); + }; + + let s = new Uint8Array(uint8Array.slice(16)); + + var zzz = zdecode(s, undefined, 1) + var ccc = window.wang(450).ungzip(zzz["body"].length? zzz["body"]: zzz["extension"]) + var ddd = zdecode(ccc, undefined, 2) + var text = Qt(ddd["payload"]) + console.log(text) + return text +} + +//console.log(dencode_data("AAoAZgAAAAAAAAAAAAABQBABUpsCH4sIAAAAAAAAAG2Qz0rDQBDG0SrUgCA5iHiS9SY9ZLPdpMkTePTgPaztGIu7Sc1MkFJyEnwKbwp66jM6G/9QtKdhmO/3zTcTDLNEZ5lU0cn+2fvLzsWxTLWSiY6jVEl9DtNppNOJite7K9EAtpZELup7MfLdoq4QuHfG2gKXSOAKhyUPHSCakmcrcdvUztemtl77JWNJO59xOxbdSFC9IfBm3sF79hIZJSrRahL/Qj+Ze3a5YGocMYHlN7D1BKZnhozf9Ag3BZKhFkUuu87f8tAC0n88ZYpMUwJ5bnsm57D4m6vLT4MDXtHQ9dxBeLjhqeL8KBjyVyqCahbuVa21eRAMECgc4F18+br+eH5SV299+QQzLJ50oQEAAHABMAFomtTgmAQKFHRpdGFuLm5vdGlmeURhdGFMaXRl")) \ No newline at end of file diff --git a/static/js/encode_message.js b/static/js/encode_message.js new file mode 100644 index 0000000..3a55ce8 --- /dev/null +++ b/static/js/encode_message.js @@ -0,0 +1,1766 @@ +window = globalThis;; + +var CryptoJS = CryptoJS || (function (Math, undefined) { + var C = {}; + var C_lib = C.lib = {}; + var Base = C_lib.Base = (function () { + function F() {}; + return { + extend: function (overrides) { + F.prototype = this; + var subtype = new F(); + if (overrides) { + subtype.mixIn(overrides); + } + if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + subtype.init.prototype = subtype; + subtype.$super = this; + return subtype; + }, create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + return instance; + }, init: function () {}, mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + var WordArray = C_lib.WordArray = Base.extend({ + init: function (words, sigBytes) { + words = this.words = words || []; + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, concat: function (wordArray) { + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + this.clamp(); + if (thisSigBytes % 4) { + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else if (thatWords.length > 0xffff) { + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } else { + thisWords.push.apply(thisWords, thatWords); + } + this.sigBytes += thatSigBytes; + return this; + }, clamp: function () { + var words = this.words; + var sigBytes = this.sigBytes; + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + return clone; + }, random: function (nBytes) { + var words = []; + var r = (function (m_w) { + var m_w = m_w; + var m_z = 0x3ade68b1; + var mask = 0xffffffff; + return function () { + m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; + m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; + var result = ((m_z << 0x10) + m_w) & mask; + result /= 0x100000000; + result += 0.5; + return result * (Math.random() > .5 ? 1 : -1); + } + }); + for (var i = 0, rcache; i < nBytes; i += 4) { + var _r = r((rcache || Math.random()) * 0x100000000); + rcache = _r() * 0x3ade67b7; + words.push((_r() * 0x100000000) | 0); + } + return new WordArray.init(words, nBytes); + } + }); + var C_enc = C.enc = {}; + var Hex = C_enc.Hex = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + return hexChars.join(''); + }, parse: function (hexStr) { + var hexStrLength = hexStr.length; + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + return new WordArray.init(words, hexStrLength / 2); + } + }; + var Latin1 = C_enc.Latin1 = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + return latin1Chars.join(''); + }, parse: function (latin1Str) { + var latin1StrLength = latin1Str.length; + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + return new WordArray.init(words, latin1StrLength); + } + }; + var Utf8 = C_enc.Utf8 = { + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + reset: function () { + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, _append: function (data) { + if (typeof data == 'string') { + data = Utf8.parse(data); + } + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, _process: function (doFlush) { + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + nBlocksReady = Math.ceil(nBlocksReady); + } else { + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + var nWordsReady = nBlocksReady * blockSize; + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + this._doProcessBlock(dataWords, offset); + } + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + return new WordArray.init(processedWords, nBytesReady); + }, clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + return clone; + }, _minBufferSize: 0 + }); + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + cfg: Base.extend(), + init: function (cfg) { + this.cfg = this.cfg.extend(cfg); + this.reset(); + }, reset: function () { + BufferedBlockAlgorithm.reset.call(this); + this._doReset(); + }, update: function (messageUpdate) { + this._append(messageUpdate); + this._process(); + return this; + }, finalize: function (messageUpdate) { + if (messageUpdate) { + this._append(messageUpdate); + } + var hash = this._doFinalize(); + return hash; + }, blockSize: 512 / 32, + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + var C_algo = C.algo = {}; + return C; +}(Math)); + +(function () { + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var C_enc = C.enc; + var Base64 = C_enc.Base64 = { + stringify: function (wordArray) { + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + var map = this._map; + wordArray.clamp(); + var base64Chars = []; + for (var i = 0; i < sigBytes; i += 3) { + var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + for (var j = 0; + (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + return base64Chars.join(''); + }, parse: function (base64Str) { + var base64StrLength = base64Str.length; + var map = this._map; + var reverseMap = this._reverseMap; + if (!reverseMap) { + reverseMap = this._reverseMap = []; + for (var j = 0; j < map.length; j++) { + reverseMap[map.charCodeAt(j)] = j; + } + } + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex !== -1) { + base64StrLength = paddingIndex; + } + } + return parseLoop(base64Str, base64StrLength, reverseMap); + }, _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; + function parseLoop(base64Str, base64StrLength, reverseMap) { + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); + var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + return WordArray.create(words, nBytes); + } +}()); + +function B64_Encrypt(word) { + var src = CryptoJS.enc.Utf8.parse(word); + return CryptoJS.enc.Base64.stringify(src); +} + +function B64_Decrypt(word) { + var src = CryptoJS.enc.Base64.parse(word); + return CryptoJS.enc.Utf8.stringify(src); +} + + + + +!function(b) { + var r, u, t, n; + r = { + 1: [function(t, e) { + e.exports = function(t, e) { + for (var n = Array(arguments.length - 1), r = 0, o = 2, i = !0; o < arguments.length; ) + n[r++] = arguments[o++]; + return new Promise((function(o, a) { + n[r] = function(t) { + if (i) + if (i = !1, + t) + a(t); + else { + for (var e = Array(arguments.length - 1), n = 0; n < e.length; ) + e[n++] = arguments[n]; + o.apply(null, e) + } + } + ; + try { + t.apply(e || null, n) + } catch (t) { + i && (i = !1, + a(t)) + } + } + )) + } + } + , {}], + 2: [function(t, e, n) { + var r = n; + r.length = function(t) { + var e = t.length; + if (!e) + return 0; + for (var n = 0; 1 < --e % 4 && "=" === t.charAt(e); ) + ++n; + return Math.ceil(3 * t.length) / 4 - n + } + ; + for (var o = Array(64), i = Array(123), a = 0; a < 64; ) + i[o[a] = a < 26 ? a + 65 : a < 52 ? a + 71 : a < 62 ? a - 4 : a - 59 | 43] = a++; + r.encode = function(t, e, n) { + for (var r, i = null, a = [], s = 0, u = 0; e < n; ) { + var c = t[e++]; + switch (u) { + case 0: + a[s++] = o[c >> 2], + r = (3 & c) << 4, + u = 1; + break; + case 1: + a[s++] = o[r | c >> 4], + r = (15 & c) << 2, + u = 2; + break; + case 2: + a[s++] = o[r | c >> 6], + a[s++] = o[63 & c], + u = 0 + } + 8191 < s && ((i || (i = [])).push(String.fromCharCode.apply(String, a)), + s = 0) + } + return u && (a[s++] = o[r], + a[s++] = 61, + 1 === u && (a[s++] = 61)), + i ? (s && i.push(String.fromCharCode.apply(String, a.slice(0, s))), + i.join("")) : String.fromCharCode.apply(String, a.slice(0, s)) + } + ; + var s = "invalid encoding"; + r.decode = function(t, e, n) { + for (var r, o = n, a = 0, u = 0; u < t.length; ) { + var c = t.charCodeAt(u++); + if (61 === c && 1 < a) + break; + if ((c = i[c]) === b) + throw Error(s); + switch (a) { + case 0: + r = c, + a = 1; + break; + case 1: + e[n++] = r << 2 | (48 & c) >> 4, + r = c, + a = 2; + break; + case 2: + e[n++] = (15 & r) << 4 | (60 & c) >> 2, + r = c, + a = 3; + break; + case 3: + e[n++] = (3 & r) << 6 | c, + a = 0 + } + } + if (1 === a) + throw Error(s); + return n - o + } + , + r.test = function(t) { + return /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t) + } + } + , {}], + 3: [function(t, e) { + function n() { + this.t = {} + } + (e.exports = n).prototype.on = function(t, e, n) { + return (this.t[t] || (this.t[t] = [])).push({ + fn: e, + ctx: n || this + }), + this + } + , + n.prototype.off = function(t, e) { + if (t === b) + this.t = {}; + else if (e === b) + this.t[t] = []; + else + for (var n = this.t[t], r = 0; r < n.length; ) + n[r].fn === e ? n.splice(r, 1) : ++r; + return this + } + , + n.prototype.emit = function(t) { + var e = this.t[t]; + if (e) { + for (var n = [], r = 1; r < arguments.length; ) + n.push(arguments[r++]); + for (r = 0; r < e.length; ) + e[r].fn.apply(e[r++].ctx, n) + } + return this + } + } + , {}], + 4: [function(t, e) { + function n(t) { + return "undefined" != typeof Float32Array ? function() { + var e = new Float32Array([-0]) + , n = new Uint8Array(e.buffer) + , r = 128 === n[3]; + function o(t, r, o) { + e[0] = t, + r[o] = n[0], + r[o + 1] = n[1], + r[o + 2] = n[2], + r[o + 3] = n[3] + } + function i(t, r, o) { + e[0] = t, + r[o] = n[3], + r[o + 1] = n[2], + r[o + 2] = n[1], + r[o + 3] = n[0] + } + function a(t, r) { + return n[0] = t[r], + n[1] = t[r + 1], + n[2] = t[r + 2], + n[3] = t[r + 3], + e[0] + } + function s(t, r) { + return n[3] = t[r], + n[2] = t[r + 1], + n[1] = t[r + 2], + n[0] = t[r + 3], + e[0] + } + t.writeFloatLE = r ? o : i, + t.writeFloatBE = r ? i : o, + t.readFloatLE = r ? a : s, + t.readFloatBE = r ? s : a + }() : function() { + function e(t, e, n, r) { + var o = e < 0 ? 1 : 0; + if (o && (e = -e), + 0 === e) + t(0 < 1 / e ? 0 : 2147483648, n, r); + else if (isNaN(e)) + t(2143289344, n, r); + else if (34028234663852886e22 < e) + t((o << 31 | 2139095040) >>> 0, n, r); + else if (e < 11754943508222875e-54) + t((o << 31 | Math.round(e / 1401298464324817e-60)) >>> 0, n, r); + else { + var i = Math.floor(Math.log(e) / Math.LN2); + t((o << 31 | i + 127 << 23 | 8388607 & Math.round(e * Math.pow(2, -i) * 8388608)) >>> 0, n, r) + } + } + function n(t, e, n) { + var r = t(e, n) + , o = 2 * (r >> 31) + 1 + , i = r >>> 23 & 255 + , a = 8388607 & r; + return 255 === i ? a ? NaN : o * (1 / 0) : 0 === i ? 1401298464324817e-60 * o * a : o * Math.pow(2, i - 150) * (a + 8388608) + } + t.writeFloatLE = e.bind(null, r), + t.writeFloatBE = e.bind(null, o), + t.readFloatLE = n.bind(null, i), + t.readFloatBE = n.bind(null, a) + }(), + "undefined" != typeof Float64Array ? function() { + var e = new Float64Array([-0]) + , n = new Uint8Array(e.buffer) + , r = 128 === n[7]; + function o(t, r, o) { + e[0] = t, + r[o] = n[0], + r[o + 1] = n[1], + r[o + 2] = n[2], + r[o + 3] = n[3], + r[o + 4] = n[4], + r[o + 5] = n[5], + r[o + 6] = n[6], + r[o + 7] = n[7] + } + function i(t, r, o) { + e[0] = t, + r[o] = n[7], + r[o + 1] = n[6], + r[o + 2] = n[5], + r[o + 3] = n[4], + r[o + 4] = n[3], + r[o + 5] = n[2], + r[o + 6] = n[1], + r[o + 7] = n[0] + } + function a(t, r) { + return n[0] = t[r], + n[1] = t[r + 1], + n[2] = t[r + 2], + n[3] = t[r + 3], + n[4] = t[r + 4], + n[5] = t[r + 5], + n[6] = t[r + 6], + n[7] = t[r + 7], + e[0] + } + function s(t, r) { + return n[7] = t[r], + n[6] = t[r + 1], + n[5] = t[r + 2], + n[4] = t[r + 3], + n[3] = t[r + 4], + n[2] = t[r + 5], + n[1] = t[r + 6], + n[0] = t[r + 7], + e[0] + } + t.writeDoubleLE = r ? o : i, + t.writeDoubleBE = r ? i : o, + t.readDoubleLE = r ? a : s, + t.readDoubleBE = r ? s : a + }() : function() { + function e(t, e, n, r, o, i) { + var a = r < 0 ? 1 : 0; + if (a && (r = -r), + 0 === r) + t(0, o, i + e), + t(0 < 1 / r ? 0 : 2147483648, o, i + n); + else if (isNaN(r)) + t(0, o, i + e), + t(2146959360, o, i + n); + else if (17976931348623157e292 < r) + t(0, o, i + e), + t((a << 31 | 2146435072) >>> 0, o, i + n); + else { + var s; + if (r < 22250738585072014e-324) + t((s = r / 5e-324) >>> 0, o, i + e), + t((a << 31 | s / 4294967296) >>> 0, o, i + n); + else { + var u = Math.floor(Math.log(r) / Math.LN2); + 1024 === u && (u = 1023), + t(4503599627370496 * (s = r * Math.pow(2, -u)) >>> 0, o, i + e), + t((a << 31 | u + 1023 << 20 | 1048576 * s & 1048575) >>> 0, o, i + n) + } + } + } + function n(t, e, n, r, o) { + var i = t(r, o + e) + , a = t(r, o + n) + , s = 2 * (a >> 31) + 1 + , u = a >>> 20 & 2047 + , c = 4294967296 * (1048575 & a) + i; + return 2047 === u ? c ? NaN : s * (1 / 0) : 0 === u ? 5e-324 * s * c : s * Math.pow(2, u - 1075) * (c + 4503599627370496) + } + t.writeDoubleLE = e.bind(null, r, 0, 4), + t.writeDoubleBE = e.bind(null, o, 4, 0), + t.readDoubleLE = n.bind(null, i, 0, 4), + t.readDoubleBE = n.bind(null, a, 4, 0) + }(), + t + } + function r(t, e, n) { + e[n] = 255 & t, + e[n + 1] = t >>> 8 & 255, + e[n + 2] = t >>> 16 & 255, + e[n + 3] = t >>> 24 + } + function o(t, e, n) { + e[n] = t >>> 24, + e[n + 1] = t >>> 16 & 255, + e[n + 2] = t >>> 8 & 255, + e[n + 3] = 255 & t + } + function i(t, e) { + return (t[e] | t[e + 1] << 8 | t[e + 2] << 16 | t[e + 3] << 24) >>> 0 + } + function a(t, e) { + return (t[e] << 24 | t[e + 1] << 16 | t[e + 2] << 8 | t[e + 3]) >>> 0 + } + e.exports = n(n) + } + , {}], + 5: [function(t, n, i) { + function r(t) { + try { + var n = eval("require")(t); + if (n && (n.length || Object.keys(n).length)) + return n + } catch (t) {} + return null + } + n.exports = r + } + , {}], + 6: [function(t, e) { + e.exports = function(t, e, n) { + var r = n || 8192 + , o = r >>> 1 + , i = null + , a = r; + return function(n) { + if (n < 1 || o < n) + return t(n); + r < a + n && (i = t(r), + a = 0); + var s = e.call(i, a, a += n); + return 7 & a && (a = 1 + (7 | a)), + s + } + } + } + , {}], + 7: [function(t, e, n) { + var r = n; + r.length = function(t) { + for (var e = 0, n = 0, r = 0; r < t.length; ++r) + (n = t.charCodeAt(r)) < 128 ? e += 1 : n < 2048 ? e += 2 : 55296 == (64512 & n) && 56320 == (64512 & t.charCodeAt(r + 1)) ? (++r, + e += 4) : e += 3; + return e + } + , + r.read = function(t, e, n) { + if (n - e < 1) + return ""; + for (var r, o = null, i = [], a = 0; e < n; ) + (r = t[e++]) < 128 ? i[a++] = r : 191 < r && r < 224 ? i[a++] = (31 & r) << 6 | 63 & t[e++] : 239 < r && r < 365 ? (r = ((7 & r) << 18 | (63 & t[e++]) << 12 | (63 & t[e++]) << 6 | 63 & t[e++]) - 65536, + i[a++] = 55296 + (r >> 10), + i[a++] = 56320 + (1023 & r)) : i[a++] = (15 & r) << 12 | (63 & t[e++]) << 6 | 63 & t[e++], + 8191 < a && ((o || (o = [])).push(String.fromCharCode.apply(String, i)), + a = 0); + return o ? (a && o.push(String.fromCharCode.apply(String, i.slice(0, a))), + o.join("")) : String.fromCharCode.apply(String, i.slice(0, a)) + } + , + r.write = function(t, e, n) { + for (var r, o, i = n, a = 0; a < t.length; ++a) + (r = t.charCodeAt(a)) < 128 ? e[n++] = r : (r < 2048 ? e[n++] = r >> 6 | 192 : (55296 == (64512 & r) && 56320 == (64512 & (o = t.charCodeAt(a + 1))) ? (r = 65536 + ((1023 & r) << 10) + (1023 & o), + ++a, + e[n++] = r >> 18 | 240, + e[n++] = r >> 12 & 63 | 128) : e[n++] = r >> 12 | 224, + e[n++] = r >> 6 & 63 | 128), + e[n++] = 63 & r | 128); + return n - i + } + } + , {}], + 8: [function(t, e, n) { + var r = n; + function o() { + r.Reader.n(r.BufferReader), + r.util.n() + } + r.build = "minimal", + r.Writer = t(16), + r.BufferWriter = t(17), + r.Reader = t(9), + r.BufferReader = t(10), + r.util = t(15), + r.rpc = t(12), + r.roots = t(11), + r.configure = o, + r.Writer.n(r.BufferWriter), + o() + } + , { + 10: 10, + 11: 11, + 12: 12, + 15: 15, + 16: 16, + 17: 17, + 9: 9 + }], + 9: [function(t, e) { + e.exports = s; + var n, r = t(15), o = r.LongBits, i = r.utf8; + function a(t, e) { + return RangeError("index out of range: " + t.pos + " + " + (e || 1) + " > " + t.len) + } + function s(t) { + this.buf = t, + this.pos = 0, + this.len = t.length + } + var u, c = "undefined" != typeof Uint8Array ? function(t) { + if (t instanceof Uint8Array || Array.isArray(t)) + return new s(t); + throw Error("illegal buffer") + } + : function(t) { + if (Array.isArray(t)) + return new s(t); + throw Error("illegal buffer") + } + ; + function f() { + var t = new o(0,0) + , e = 0; + if (!(4 < this.len - this.pos)) { + for (; e < 3; ++e) { + if (this.pos >= this.len) + throw a(this); + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * e) >>> 0, + this.buf[this.pos++] < 128) + return t + } + return t.lo = (t.lo | (127 & this.buf[this.pos++]) << 7 * e) >>> 0, + t + } + for (; e < 4; ++e) + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 7 * e) >>> 0, + this.buf[this.pos++] < 128) + return t; + if (t.lo = (t.lo | (127 & this.buf[this.pos]) << 28) >>> 0, + t.hi = (t.hi | (127 & this.buf[this.pos]) >> 4) >>> 0, + this.buf[this.pos++] < 128) + return t; + if (e = 0, + 4 < this.len - this.pos) { + for (; e < 5; ++e) + if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * e + 3) >>> 0, + this.buf[this.pos++] < 128) + return t + } else + for (; e < 5; ++e) { + if (this.pos >= this.len) + throw a(this); + if (t.hi = (t.hi | (127 & this.buf[this.pos]) << 7 * e + 3) >>> 0, + this.buf[this.pos++] < 128) + return t + } + throw Error("invalid varint encoding") + } + function d(t, e) { + return (t[e - 4] | t[e - 3] << 8 | t[e - 2] << 16 | t[e - 1] << 24) >>> 0 + } + function l() { + if (this.pos + 8 > this.len) + throw a(this, 8); + return new o(d(this.buf, this.pos += 4),d(this.buf, this.pos += 4)) + } + s.create = r.Buffer ? function(t) { + return (s.create = function(t) { + return r.Buffer.isBuffer(t) ? new n(t) : c(t) + } + )(t) + } + : c, + s.prototype.i = r.Array.prototype.subarray || r.Array.prototype.slice, + s.prototype.uint32 = (u = 4294967295, + function() { + if (u = (127 & this.buf[this.pos]) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 7) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 14) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (127 & this.buf[this.pos]) << 21) >>> 0, + this.buf[this.pos++] < 128) + return u; + if (u = (u | (15 & this.buf[this.pos]) << 28) >>> 0, + this.buf[this.pos++] < 128) + return u; + if ((this.pos += 5) > this.len) + throw this.pos = this.len, + a(this, 10); + return u + } + ), + s.prototype.int32 = function() { + return 0 | this.uint32() + } + , + s.prototype.sint32 = function() { + var t = this.uint32(); + return t >>> 1 ^ -(1 & t) | 0 + } + , + s.prototype.bool = function() { + return 0 !== this.uint32() + } + , + s.prototype.fixed32 = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + return d(this.buf, this.pos += 4) + } + , + s.prototype.sfixed32 = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + return 0 | d(this.buf, this.pos += 4) + } + , + s.prototype.float = function() { + if (this.pos + 4 > this.len) + throw a(this, 4); + var t = r.float.readFloatLE(this.buf, this.pos); + return this.pos += 4, + t + } + , + s.prototype.double = function() { + if (this.pos + 8 > this.len) + throw a(this, 4); + var t = r.float.readDoubleLE(this.buf, this.pos); + return this.pos += 8, + t + } + , + s.prototype.bytes = function() { + var t = this.uint32() + , e = this.pos + , n = this.pos + t; + if (n > this.len) + throw a(this, t); + return this.pos += t, + Array.isArray(this.buf) ? this.buf.slice(e, n) : e === n ? new this.buf.constructor(0) : this.i.call(this.buf, e, n) + } + , + s.prototype.string = function() { + var t = this.bytes(); + return i.read(t, 0, t.length) + } + , + s.prototype.skip = function(t) { + if ("number" == typeof t) { + if (this.pos + t > this.len) + throw a(this, t); + this.pos += t + } else + do { + if (this.pos >= this.len) + throw a(this) + } while (128 & this.buf[this.pos++]); + return this + } + , + s.prototype.skipType = function(t) { + switch (t) { + case 0: + this.skip(); + break; + case 1: + this.skip(8); + break; + case 2: + this.skip(this.uint32()); + break; + case 3: + for (; 4 != (t = 7 & this.uint32()); ) + this.skipType(t); + break; + case 5: + this.skip(4); + break; + default: + throw Error("invalid wire type " + t + " at offset " + this.pos) + } + return this + } + , + s.n = function(t) { + n = t; + var e = r.Long ? "toLong" : "toNumber"; + r.merge(s.prototype, { + int64: function() { + return f.call(this)[e](!1) + }, + uint64: function() { + return f.call(this)[e](!0) + }, + sint64: function() { + return f.call(this).zzDecode()[e](!1) + }, + fixed64: function() { + return l.call(this)[e](!0) + }, + sfixed64: function() { + return l.call(this)[e](!1) + } + }) + } + } + , { + 15: 15 + }], + 10: [function(t, e) { + e.exports = o; + var n = t(9); + (o.prototype = Object.create(n.prototype)).constructor = o; + var r = t(15); + function o(t) { + n.call(this, t) + } + r.Buffer && (o.prototype.i = r.Buffer.prototype.slice), + o.prototype.string = function() { + var t = this.uint32(); + return this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + t, this.len)) + } + } + , { + 15: 15, + 9: 9 + }], + 11: [function(t, e) { + e.exports = {} + } + , {}], + 12: [function(t, e, n) { + n.Service = t(13) + } + , { + 13: 13 + }], + 13: [function(t, e) { + e.exports = r; + var n = t(15); + function r(t, e, r) { + if ("function" != typeof t) + throw TypeError("rpcImpl must be a function"); + n.EventEmitter.call(this), + this.rpcImpl = t, + this.requestDelimited = !!e, + this.responseDelimited = !!r + } + ((r.prototype = Object.create(n.EventEmitter.prototype)).constructor = r).prototype.rpcCall = function t(e, r, o, i, a) { + if (!i) + throw TypeError("request must be specified"); + var s = this; + if (!a) + return n.asPromise(t, s, e, r, o, i); + if (!s.rpcImpl) + return setTimeout((function() { + a(Error("already ended")) + } + ), 0), + b; + try { + return s.rpcImpl(e, r[s.requestDelimited ? "encodeDelimited" : "encode"](i).finish(), (function(t, n) { + if (t) + return s.emit("error", t, e), + a(t); + if (null === n) + return s.end(!0), + b; + if (!(n instanceof o)) + try { + n = o[s.responseDelimited ? "decodeDelimited" : "decode"](n) + } catch (t) { + return s.emit("error", t, e), + a(t) + } + return s.emit("data", n, e), + a(null, n) + } + )) + } catch (t) { + return s.emit("error", t, e), + setTimeout((function() { + a(t) + } + ), 0), + b + } + } + , + r.prototype.end = function(t) { + return this.rpcImpl && (t || this.rpcImpl(null, null, null), + this.rpcImpl = null, + this.emit("end").off()), + this + } + } + , { + 15: 15 + }], + 14: [function(t, e) { + e.exports = r; + var n = t(15); + function r(t, e) { + this.lo = t >>> 0, + this.hi = e >>> 0 + } + var o = r.zero = new r(0,0); + o.toNumber = function() { + return 0 + } + , + o.zzEncode = o.zzDecode = function() { + return this + } + , + o.length = function() { + return 1 + } + ; + var i = r.zeroHash = "\0\0\0\0\0\0\0\0"; + r.fromNumber = function(t) { + if (0 === t) + return o; + var e = t < 0; + e && (t = -t); + var n = t >>> 0 + , i = (t - n) / 4294967296 >>> 0; + return e && (i = ~i >>> 0, + n = ~n >>> 0, + 4294967295 < ++n && (n = 0, + 4294967295 < ++i && (i = 0))), + new r(n,i) + } + , + r.from = function(t) { + if ("number" == typeof t) + return r.fromNumber(t); + if (n.isString(t)) { + if (!n.Long) + return r.fromNumber(parseInt(t, 10)); + t = n.Long.fromString(t) + } + return t.low || t.high ? new r(t.low >>> 0,t.high >>> 0) : o + } + , + r.prototype.toNumber = function(t) { + if (!t && this.hi >>> 31) { + var e = 1 + ~this.lo >>> 0 + , n = ~this.hi >>> 0; + return e || (n = n + 1 >>> 0), + -(e + 4294967296 * n) + } + return this.lo + 4294967296 * this.hi + } + , + r.prototype.toLong = function(t) { + return n.Long ? new n.Long(0 | this.lo,0 | this.hi,!!t) : { + low: 0 | this.lo, + high: 0 | this.hi, + unsigned: !!t + } + } + ; + var a = String.prototype.charCodeAt; + r.fromHash = function(t) { + return t === i ? o : new r((a.call(t, 0) | a.call(t, 1) << 8 | a.call(t, 2) << 16 | a.call(t, 3) << 24) >>> 0,(a.call(t, 4) | a.call(t, 5) << 8 | a.call(t, 6) << 16 | a.call(t, 7) << 24) >>> 0) + } + , + r.prototype.toHash = function() { + return String.fromCharCode(255 & this.lo, this.lo >>> 8 & 255, this.lo >>> 16 & 255, this.lo >>> 24, 255 & this.hi, this.hi >>> 8 & 255, this.hi >>> 16 & 255, this.hi >>> 24) + } + , + r.prototype.zzEncode = function() { + var t = this.hi >> 31; + return this.hi = ((this.hi << 1 | this.lo >>> 31) ^ t) >>> 0, + this.lo = (this.lo << 1 ^ t) >>> 0, + this + } + , + r.prototype.zzDecode = function() { + var t = -(1 & this.lo); + return this.lo = ((this.lo >>> 1 | this.hi << 31) ^ t) >>> 0, + this.hi = (this.hi >>> 1 ^ t) >>> 0, + this + } + , + r.prototype.length = function() { + var t = this.lo + , e = (this.lo >>> 28 | this.hi << 4) >>> 0 + , n = this.hi >>> 24; + return 0 === n ? 0 === e ? t < 16384 ? t < 128 ? 1 : 2 : t < 2097152 ? 3 : 4 : e < 16384 ? e < 128 ? 5 : 6 : e < 2097152 ? 7 : 8 : n < 128 ? 9 : 10 + } + } + , { + 15: 15 + }], + 15: [function(t, e, n) { + var r = n; + function o(t, e, n) { + for (var r = Object.keys(e), o = 0; o < r.length; ++o) + t[r[o]] !== b && n || (t[r[o]] = e[r[o]]); + return t + } + function i(t) { + function e(t, n) { + if (!(this instanceof e)) + return new e(t,n); + Object.defineProperty(this, "message", { + get: function() { + return t + } + }), + Error.captureStackTrace ? Error.captureStackTrace(this, e) : Object.defineProperty(this, "stack", { + value: Error().stack || "" + }), + n && o(this, n) + } + return (e.prototype = Object.create(Error.prototype)).constructor = e, + Object.defineProperty(e.prototype, "name", { + get: function() { + return t + } + }), + e.prototype.toString = function() { + return this.name + ": " + this.message + } + , + e + } + r.asPromise = t(1), + r.base64 = t(2), + r.EventEmitter = t(3), + r.float = t(4), + r.inquire = t(5), + r.utf8 = t(7), + r.pool = t(6), + r.LongBits = t(14), + r.global = "undefined" != typeof window && window || void 0 !== global && global || "undefined" != typeof self && self || this, + r.emptyArray = Object.freeze ? Object.freeze([]) : [], + r.emptyObject = Object.freeze ? Object.freeze({}) : {}, + r.isNode = !!(r.global.process && r.global.process.versions && r.global.process.versions.node), + r.isInteger = Number.isInteger || function(t) { + return "number" == typeof t && isFinite(t) && Math.floor(t) === t + } + , + r.isString = function(t) { + return "string" == typeof t || t instanceof String + } + , + r.isObject = function(t) { + return t && "object" == _typeof(t) + } + , + r.isset = r.isSet = function(t, e) { + var n = t[e]; + return !(null == n || !t.hasOwnProperty(e)) && ("object" != _typeof(n) || 0 < (Array.isArray(n) ? n.length : Object.keys(n).length)) + } + , + r.Buffer = function() { + try { + var t = r.inquire("buffer").Buffer; + return t.prototype.utf8Write ? t : null + } catch (t) { + return null + } + }(), + r.r = null, + r.u = null, + r.newBuffer = function(t) { + return "number" == typeof t ? r.Buffer ? r.u(t) : new r.Array(t) : r.Buffer ? r.r(t) : "undefined" == typeof Uint8Array ? t : new Uint8Array(t) + } + , + r.Array = "undefined" != typeof Uint8Array ? Uint8Array : Array, + r.Long = r.global.dcodeIO && r.global.dcodeIO.Long || r.global.Long || r.inquire("long"), + r.key2Re = /^true|false|0|1$/, + r.key32Re = /^-?(?:0|[1-9][0-9]*)$/, + r.key64Re = /^(?:[\\x00-\\xff]{8}|-?(?:0|[1-9][0-9]*))$/, + r.longToHash = function(t) { + return t ? r.LongBits.from(t).toHash() : r.LongBits.zeroHash + } + , + r.longFromHash = function(t, e) { + var n = r.LongBits.fromHash(t); + return r.Long ? r.Long.fromBits(n.lo, n.hi, e) : n.toNumber(!!e) + } + , + r.merge = o, + r.lcFirst = function(t) { + return t.charAt(0).toLowerCase() + t.substring(1) + } + , + r.newError = i, + r.ProtocolError = i("ProtocolError"), + r.oneOfGetter = function(t) { + for (var e = {}, n = 0; n < t.length; ++n) + e[t[n]] = 1; + return function() { + for (var t = Object.keys(this), n = t.length - 1; -1 < n; --n) + if (1 === e[t[n]] && this[t[n]] !== b && null !== this[t[n]]) + return t[n] + } + } + , + r.oneOfSetter = function(t) { + return function(e) { + for (var n = 0; n < t.length; ++n) + t[n] !== e && delete this[t[n]] + } + } + , + r.toJSONOptions = { + longs: String, + enums: String, + bytes: String, + json: !0 + }, + r.n = function() { + var t = r.Buffer; + t ? (r.r = t.from !== Uint8Array.from && t.from || function(e, n) { + return new t(e,n) + } + , + r.u = t.allocUnsafe || function(e) { + return new t(e) + } + ) : r.r = r.u = null + } + } + , { + 1: 1, + 14: 14, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7 + }], + 16: [function(t, e) { + e.exports = f; + var n, r = t(15), o = r.LongBits, i = r.base64, a = r.utf8; + function s(t, e, n) { + this.fn = t, + this.len = e, + this.next = b, + this.val = n + } + function u() {} + function c(t) { + this.head = t.head, + this.tail = t.tail, + this.len = t.len, + this.next = t.states + } + function f() { + this.len = 0, + this.head = new s(u,0,0), + this.tail = this.head, + this.states = null + } + function d(t, e, n) { + e[n] = 255 & t + } + function l(t, e) { + this.len = t, + this.next = b, + this.val = e + } + function p(t, e, n) { + for (; t.hi; ) + e[n++] = 127 & t.lo | 128, + t.lo = (t.lo >>> 7 | t.hi << 25) >>> 0, + t.hi >>>= 7; + for (; 127 < t.lo; ) + e[n++] = 127 & t.lo | 128, + t.lo = t.lo >>> 7; + e[n++] = t.lo + } + function h(t, e, n) { + e[n] = 255 & t, + e[n + 1] = t >>> 8 & 255, + e[n + 2] = t >>> 16 & 255, + e[n + 3] = t >>> 24 + } + f.create = false ? function() { + return (f.create = function() { + return new n + } + )() + } + : function() { + return new f + } + , + f.alloc = function(t) { + return new r.Array(t) + } + , + r.Array !== Array && (f.alloc = r.pool(f.alloc, r.Array.prototype.subarray)), + f.prototype.e = function(t, e, n) { + return this.tail = this.tail.next = new s(t,e,n), + this.len += e, + this + } + , + (l.prototype = Object.create(s.prototype)).fn = function(t, e, n) { + for (; 127 < t; ) + e[n++] = 127 & t | 128, + t >>>= 7; + e[n] = t + } + , + f.prototype.uint32 = function(t) { + return this.len += (this.tail = this.tail.next = new l((t >>>= 0) < 128 ? 1 : t < 16384 ? 2 : t < 2097152 ? 3 : t < 268435456 ? 4 : 5,t)).len, + this + } + , + f.prototype.int32 = function(t) { + return t < 0 ? this.e(p, 10, o.fromNumber(t)) : this.uint32(t) + } + , + f.prototype.sint32 = function(t) { + return this.uint32((t << 1 ^ t >> 31) >>> 0) + } + , + f.prototype.int64 = f.prototype.uint64 = function(t) { + var e = o.from(t); + return this.e(p, e.length(), e) + } + , + f.prototype.sint64 = function(t) { + var e = o.from(t).zzEncode(); + return this.e(p, e.length(), e) + } + , + f.prototype.bool = function(t) { + return this.e(d, 1, t ? 1 : 0) + } + , + f.prototype.sfixed32 = f.prototype.fixed32 = function(t) { + return this.e(h, 4, t >>> 0) + } + , + f.prototype.sfixed64 = f.prototype.fixed64 = function(t) { + var e = o.from(t); + return this.e(h, 4, e.lo).e(h, 4, e.hi) + } + , + f.prototype.float = function(t) { + return this.e(r.float.writeFloatLE, 4, t) + } + , + f.prototype.double = function(t) { + return this.e(r.float.writeDoubleLE, 8, t) + } + ; + var m = r.Array.prototype.set ? function(t, e, n) { + e.set(t, n) + } + : function(t, e, n) { + for (var r = 0; r < t.length; ++r) + e[n + r] = t[r] + } + ; + f.prototype.bytes = function(t) { + var e = t.length >>> 0; + if (!e) + return this.e(d, 1, 0); + if (r.isString(t)) { + var n = f.alloc(e = i.length(t)); + i.decode(t, n, 0), + t = n + } + return this.uint32(e).e(m, e, t) + } + , + f.prototype.string = function(t) { + var e = a.length(t); + return e ? this.uint32(e).e(a.write, e, t) : this.e(d, 1, 0) + } + , + f.prototype.fork = function() { + return this.states = new c(this), + this.head = this.tail = new s(u,0,0), + this.len = 0, + this + } + , + f.prototype.reset = function() { + return this.states ? (this.head = this.states.head, + this.tail = this.states.tail, + this.len = this.states.len, + this.states = this.states.next) : (this.head = this.tail = new s(u,0,0), + this.len = 0), + this + } + , + f.prototype.ldelim = function() { + var t = this.head + , e = this.tail + , n = this.len; + return this.reset().uint32(n), + n && (this.tail.next = t.next, + this.tail = e, + this.len += n), + this + } + , + f.prototype.finish = function() { + for (var t = this.head.next, e = this.constructor.alloc(this.len), n = 0; t; ) + t.fn(t.val, e, n), + n += t.len, + t = t.next; + return e + } + , + f.n = function(t) { + n = t + } + } + , { + 15: 15 + }], + 17: [function(t, e) { + e.exports = i; + var n = t(16); + (i.prototype = Object.create(n.prototype)).constructor = i; + var r = t(15) + , o = r.Buffer; + function i() { + n.call(this) + } + i.alloc = function(t) { + return (i.alloc = r.u)(t) + } + ; + var a = o && o.prototype instanceof Uint8Array && "set" === o.prototype.set.name ? function(t, e, n) { + e.set(t, n) + } + : function(t, e, n) { + if (t.copy) + t.copy(e, n, 0, t.length); + else + for (var r = 0; r < t.length; ) + e[n++] = t[r++] + } + ; + function s(t, e, n) { + t.length < 40 ? r.utf8.write(t, e, n) : e.utf8Write(t, n) + } + i.prototype.bytes = function(t) { + r.isString(t) && (t = r.r(t, "base64")); + var e = t.length >>> 0; + return this.uint32(e), + e && this.e(a, e, t), + this + } + , + i.prototype.string = function(t) { + var e = o.byteLength(t); + return this.uint32(e), + e && this.e(s, e, t), + this + } + } + , { + 15: 15, + 16: 16 + }] + }, + u = {}, + t = [8], + n = function t(e) { + var n = u[e]; + return n || r[e][0].call(n = u[e] = { + exports: {} + }, t, n, n.exports), + n.exports + } + ; + window.nnnnnn = n +}() + +yt = { + Writer: window.nnnnnn(16) +} + + +var zdecode = function(t, n, count) { + window.nnnnnn(16).n(); + if (count == 1){ + var e = { + "1": [ + "titanid", + "string", + "" + ], + "3": [ + "ua", + "string", + "" + ], + "4": [ + "os", + "uint32", + 0 + ], + "5": [ + "uid", + "string", + "" + ], + "11": [ + "repackage", + "bool", + false + ], + "12": [ + "accesstoken", + "string", + "" + ], + "13": [ + "customPayload", + "{string,bytes", + null + ], + "17": [ + "authType", + "uint32", + 0 + ], + "19": [ + "sceneType", + "uint32", + 0 + ] + } + } + else if (count == 2){ + var e = { + "7": [ + "encryptedAppInfo", + "bytes", + [] + ], + "10": [ + "requestType", + "uint32", + 0 + ], + "11": [ + "protocolVersion", + "uint32", + 0 + ], + "12": [ + "isPushConn", + "bool", + false + ] + } + } + else{ + var e = { + "1": [ + "appId", + "uint32", + 0 + ], + "2": [ + "command", + "string", + "" + ], + "3": [ + "protocol", + "uint32", + 0 + ], + "4": [ + "compress", + "uint32", + 0 + ], + "6": [ + "host", + "string", + "" + ], + "7": [ + "appinfo", + "bytes", + [] + ], + "8": [ + "sessionResumptionReq", + "bytes", + [] + ], + "9": [ + "body", + "bytes", + [] + ], + "11": [ + "upstreamSeq", + "uint64", + 0 + ], + "12": [ + "conId", + "uint64", + 0 + ], + "13": [ + "ctxId", + "uint64", + 0 + ], + "14": [ + "keyInfo", + "default.base.msg.MulticastGroupKeyInfo", + null + ] + } + } + for (var i in n = n || yt.Writer.create(), + e) { + var a = e[i][0]; + if ("{" === (f = e[i][1]).charAt(0)) { + if (null != t[a] && t.hasOwnProperty(a)) + for (var s = 0, u = Object.keys(t[a]); s < u.length; ++s) + n.uint32((i << 3 | 2) >> 0).fork(), + zdecode({ + $1: u[s], + $2: t[a][u[s]] + }, n).ldelim() + } else if ("[" === f.charAt(0) || "<" === f.charAt(0)) { + var c = "<" === f.charAt(0) + , f = f.substring(1) + , d = t[a]; + if (null != d && d.length) + if (c && void 0 !== bt[f]) { + for (n.uint32((i << 3 | 2) >> 0).fork(), + s = 0; s < d.length; s++) + window.nnnnnn(16).prototype[f].call(n, d[s]); + n.ldelim() + } else + for (s = 0; s < d.length; s++) + window.nnnnnn(16).prototype[f].call(n, d[s], i) + } else + var t__ = { + "double": 1, + "float": 5, + "int32": 0, + "uint32": 0, + "sint32": 0, + "fixed32": 5, + "sfixed32": 5, + "int64": 0, + "uint64": 0, + "sint64": 0, + "fixed64": 1, + "sfixed64": 1, + "bool": 0, + "string": 2, + "bytes": 2 + }; + var rr = t__[f]; + null != t[a] && t.hasOwnProperty(a) && window.nnnnnn(16).prototype[f].call(n.uint32(i << 3 | rr), t[a]) + } + return n +} + + +function arrayBufferToBase64(buffer) { + let binary = ''; + const bytes = new Uint8Array(buffer); + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]); + } + return btoa(binary); +} + + +function encode_token(titanid, accesstoken){ + aaa = zdecode({ + "titanid": titanid, + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "os": 5, + "uid": titanid, + "repackage": false, + "accesstoken": accesstoken, + "authType": 4, + "sceneType": 1001 + }, undefined, 1).finish() + + zzz = zdecode({ + "encryptedAppInfo": aaa, + "isPushConn": true, + "protocolVersion": 1, + "requestType": 4 + }, undefined, 2).finish() + + ddd = zdecode({ + "appId": 2, + "command": "titan.session", + "compress": 0, + "host": "mms.pinduoduo.com", + "protocol": 1, + "sessionResumptionReq": zzz, + "upstreamSeq": 101 + }, undefined, 3).finish() + + + var i = ddd && ddd.byteLength || 0; + var a = new ArrayBuffer(16 + i); + var gg = new DataView(a); + gg.setInt16(0, 10, !1); + gg.setInt16(2, 102, !1); + gg.setInt32(4, 101, !1); + gg.setInt32(8, 1, !1); + gg.setInt32(12, i, !1); + for (let t = 0; t < i; t++){ + gg.setUint8(16 + t, ddd[t], !1); + } + + // 方法1: 使用循环读取所有字节到数组 + const resultArray1 = []; + for (let offset = 0; offset < gg.byteLength; offset++) { + resultArray1.push(gg.getUint8(offset)); + } + + return resultArray1 +} + + +// console.log(encode_token()) \ No newline at end of file diff --git a/static/js/get_uuid.js b/static/js/get_uuid.js new file mode 100644 index 0000000..0fe3792 --- /dev/null +++ b/static/js/get_uuid.js @@ -0,0 +1,77 @@ +function n(n, o) { + var r = {bw: 1707, bh: 924} + , a = "https://sz.jd.com/szweb/sz/view/productAnalysis/productDetail.html" + , + d = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36" + , + c = "__jdv=122270672|direct|-|none|-|1692254561099; __jdu=1692254561098125451041; wlfstk_smdl=rn7jesxgevs0yntcfsrvjfjbf9aj2dsu; 3AB9D23F7A4B3C9B=BYLR4QCYOYVQIQXRCKH3XB4O527FC3NKDAZ5PPDA5IJXSVN4CP5EFUHUOGB5PH3EXMGZ22JDTYS4DYHMPBHQVEYMG4; TrackID=1PQ9rNMOyjMYOPORod42pcTTsm8qhbKU7seozK_5G2_kuSCeqHl8UUPY3sAceTY_7QTKUv5aNu389rgQyTIrARUZi05BEmI_p9bHTugk8-KU; pinId=MOUYfPJVXga1ffsfn98I-w; pin=%E4%B8%B8%E7%BE%8EIT; unick=%E4%B8%B8%E7%BE%8EIT; ceshi3.com=000; _tp=FSAH7V3VJiXcG2VMtstR1QteqtxBRgaiAg%2FWx4nnI2A%3D; b-sec=JFN3AQWC6KONG2C2JXN4V6Y3D5SHVFAJBDTEQIVPR3QXUB6C6YUBAQXVYUWZI4PW; is_sz_old_version=false; __jda=251704139.1692254561098125451041.1692254561.1692254561.1692254561.1; __jdc=251704139; __jdb=251704139.5.1692254561098125451041|1.1692254561" + , s = 1e9 * Math.random() << 0 + , p = (new Date).getTime() + , m = t(e([r.bw + "" + r.bh, a, d, c, s, p, n].join("-"))).slice(20); + return o ? m : m + "-" + p.toString(16) +} + +function t(n) { + for (var o = "", e = 0; e < n.length; e++) { + var t = n[e].toString(16); + o += t = 1 === t.length ? "0" + t : t + } + return o +} + + +function e(n) { + function o(n, o) { + return n << o | n >>> 32 - o + } + + var e = [1518500249, 1859775393, 2400959708, 3395469782] + , t = [1732584193, 4023233417, 2562383102, 271733878, 3285377520]; + if ("string" == typeof n) { + var i = unescape(encodeURIComponent(n)); + n = new Array(i.length); + for (c = 0; c < i.length; c++) + n[c] = i.charCodeAt(c) + } + n.push(128); + for (var r = n.length / 4 + 2, a = Math.ceil(r / 16), d = new Array(a), c = 0; c < a; c++) { + d[c] = new Array(16); + for (var s = 0; s < 16; s++) + d[c][s] = n[64 * c + 4 * s] << 24 | n[64 * c + 4 * s + 1] << 16 | n[64 * c + 4 * s + 2] << 8 | n[64 * c + 4 * s + 3] + } + d[a - 1][14] = 8 * (n.length - 1) / Math.pow(2, 32), + d[a - 1][14] = Math.floor(d[a - 1][14]), + d[a - 1][15] = 8 * (n.length - 1) & 4294967295; + for (c = 0; c < a; c++) { + for (var p = new Array(80), m = 0; m < 16; m++) + p[m] = d[c][m]; + for (m = 16; m < 80; m++) + p[m] = o(p[m - 3] ^ p[m - 8] ^ p[m - 14] ^ p[m - 16], 1); + for (var w = t[0], f = t[1], g = t[2], u = t[3], _ = t[4], m = 0; m < 80; m++) { + var h = Math.floor(m / 20) + , l = o(w, 5) + function (n, o, e, t) { + switch (n) { + case 0: + return o & e ^ ~o & t; + case 1: + return o ^ e ^ t; + case 2: + return o & e ^ o & t ^ e & t; + case 3: + return o ^ e ^ t + } + }(h, f, g, u) + _ + e[h] + p[m] >>> 0; + _ = u, + u = g, + g = o(f, 30) >>> 0, + f = w, + w = l + } + t[0] = t[0] + w >>> 0, + t[1] = t[1] + f >>> 0, + t[2] = t[2] + g >>> 0, + t[3] = t[3] + u >>> 0, + t[4] = t[4] + _ >>> 0 + } + return [t[0] >> 24 & 255, t[0] >> 16 & 255, t[0] >> 8 & 255, 255 & t[0], t[1] >> 24 & 255, t[1] >> 16 & 255, t[1] >> 8 & 255, 255 & t[1], t[2] >> 24 & 255, t[2] >> 16 & 255, t[2] >> 8 & 255, 255 & t[2], t[3] >> 24 & 255, t[3] >> 16 & 255, t[3] >> 8 & 255, 255 & t[3], t[4] >> 24 & 255, t[4] >> 16 & 255, t[4] >> 8 & 255, 255 & t[4]] +} \ No newline at end of file diff --git a/static/js/pwd_encrypt.js b/static/js/pwd_encrypt.js new file mode 100644 index 0000000..6a982b1 --- /dev/null +++ b/static/js/pwd_encrypt.js @@ -0,0 +1,3867 @@ +/*! JSEncrypt v2.3.1 | https://npmcdn.com/jsencrypt@2.3.1/LICENSE.txt */ +window = this; +window.location = {href: 'https://sz.jd.com/sz/view/index/login.html?ReturnUrl=https%3A%2F%2Fsz.jd.com%2F'} +navigator = { + appName : "Netscape", + userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', + plugins: [], + mimeTypes: [], + cajaVersion: undefined +} + +;;;;;;;;;;;;;; +(function(a, b) { + if (typeof define === "function" && define.amd) { + define(["exports"], b) + } else { + if (typeof exports === "object" && typeof exports.nodeName !== "string") { + b(module.exports) + } else { + b(a) + } + } +} +)(this, function(ap) { + var bE; + var n = 244837814094590; + var aV = ((n & 16777215) == 15715070); + function bf(z, t, L) { + if (z != null) { + if ("number" == typeof z) { + this.fromNumber(z, t, L) + } else { + if (t == null && "string" != typeof z) { + this.fromString(z, 256) + } else { + this.fromString(z, t) + } + } + } + } + function bm() { + return new bf(null) + } + function a7(bX, t, z, bW, bZ, bY) { + while (--bY >= 0) { + var L = t * this[bX++] + z[bW] + bZ; + bZ = Math.floor(L / 67108864); + z[bW++] = L & 67108863 + } + return bZ + } + function a6(bX, b2, b3, bW, b0, t) { + var bZ = b2 & 32767 + , b1 = b2 >> 15; + while (--t >= 0) { + var L = this[bX] & 32767; + var bY = this[bX++] >> 15; + var z = b1 * L + bY * bZ; + L = bZ * L + ((z & 32767) << 15) + b3[bW] + (b0 & 1073741823); + b0 = (L >>> 30) + (z >>> 15) + b1 * bY + (b0 >>> 30); + b3[bW++] = L & 1073741823 + } + return b0 + } + function a5(bX, b2, b3, bW, b0, t) { + var bZ = b2 & 16383 + , b1 = b2 >> 14; + while (--t >= 0) { + var L = this[bX] & 16383; + var bY = this[bX++] >> 14; + var z = b1 * L + bY * bZ; + L = bZ * L + ((z & 16383) << 14) + b3[bW] + b0; + b0 = (L >> 28) + (z >> 14) + b1 * bY; + b3[bW++] = L & 268435455 + } + return b0 + } + if (aV && (navigator.appName == "Microsoft Internet Explorer")) { + bf.prototype.am = a6; + bE = 30 + } else { + if (aV && (navigator.appName != "Netscape")) { + bf.prototype.am = a7; + bE = 26 + } else { + bf.prototype.am = a5; + bE = 28 + } + } + bf.prototype.DB = bE; + bf.prototype.DM = ((1 << bE) - 1); + bf.prototype.DV = (1 << bE); + var bQ = 52; + bf.prototype.FV = Math.pow(2, bQ); + bf.prototype.F1 = bQ - bE; + bf.prototype.F2 = 2 * bE - bQ; + var a = "0123456789abcdefghijklmnopqrstuvwxyz"; + var g = new Array(); + var aH, E; + aH = "0".charCodeAt(0); + for (E = 0; E <= 9; ++E) { + g[aH++] = E + } + aH = "a".charCodeAt(0); + for (E = 10; E < 36; ++E) { + g[aH++] = E + } + aH = "A".charCodeAt(0); + for (E = 10; E < 36; ++E) { + g[aH++] = E + } + function Y(t) { + return a.charAt(t) + } + function aX(z, t) { + var L = g[z.charCodeAt(t)]; + return (L == null) ? -1 : L + } + function d(z) { + for (var t = this.t - 1; t >= 0; --t) { + z[t] = this[t] + } + z.t = this.t; + z.s = this.s + } + function h(t) { + this.t = 1; + this.s = (t < 0) ? -1 : 0; + if (t > 0) { + this[0] = t + } else { + if (t < -1) { + this[0] = t + this.DV + } else { + this.t = 0 + } + } + } + function bi(t) { + var z = bm(); + z.fromInt(t); + return z + } + function bI(bZ, z) { + var bW; + if (z == 16) { + bW = 4 + } else { + if (z == 8) { + bW = 3 + } else { + if (z == 256) { + bW = 8 + } else { + if (z == 2) { + bW = 1 + } else { + if (z == 32) { + bW = 5 + } else { + if (z == 4) { + bW = 2 + } else { + this.fromRadix(bZ, z); + return + } + } + } + } + } + } + this.t = 0; + this.s = 0; + var bY = bZ.length + , L = false + , bX = 0; + while (--bY >= 0) { + var t = (bW == 8) ? bZ[bY] & 255 : aX(bZ, bY); + if (t < 0) { + if (bZ.charAt(bY) == "-") { + L = true + } + continue + } + L = false; + if (bX == 0) { + this[this.t++] = t + } else { + if (bX + bW > this.DB) { + this[this.t - 1] |= (t & ((1 << (this.DB - bX)) - 1)) << bX; + this[this.t++] = (t >> (this.DB - bX)) + } else { + this[this.t - 1] |= t << bX + } + } + bX += bW; + if (bX >= this.DB) { + bX -= this.DB + } + } + if (bW == 8 && (bZ[0] & 128) != 0) { + this.s = -1; + if (bX > 0) { + this[this.t - 1] |= ((1 << (this.DB - bX)) - 1) << bX + } + } + this.clamp(); + if (L) { + bf.ZERO.subTo(this, this) + } + } + function bA() { + var t = this.s & this.DM; + while (this.t > 0 && this[this.t - 1] == t) { + --this.t + } + } + function u(z) { + if (this.s < 0) { + return "-" + this.negate().toString(z) + } + var L; + if (z == 16) { + L = 4 + } else { + if (z == 8) { + L = 3 + } else { + if (z == 2) { + L = 1 + } else { + if (z == 32) { + L = 5 + } else { + if (z == 4) { + L = 2 + } else { + return this.toRadix(z) + } + } + } + } + } + var bX = (1 << L) - 1, b0, t = false, bY = "", bW = this.t; + var bZ = this.DB - (bW * this.DB) % L; + if (bW-- > 0) { + if (bZ < this.DB && (b0 = this[bW] >> bZ) > 0) { + t = true; + bY = Y(b0) + } + while (bW >= 0) { + if (bZ < L) { + b0 = (this[bW] & ((1 << bZ) - 1)) << (L - bZ); + b0 |= this[--bW] >> (bZ += this.DB - L) + } else { + b0 = (this[bW] >> (bZ -= L)) & bX; + if (bZ <= 0) { + bZ += this.DB; + --bW + } + } + if (b0 > 0) { + t = true + } + if (t) { + bY += Y(b0) + } + } + } + return t ? bY : "0" + } + function bC() { + var t = bm(); + bf.ZERO.subTo(this, t); + return t + } + function bB() { + return (this.s < 0) ? this.negate() : this + } + function bN(t) { + var L = this.s - t.s; + if (L != 0) { + return L + } + var z = this.t; + L = z - t.t; + if (L != 0) { + return (this.s < 0) ? -L : L + } + while (--z >= 0) { + if ((L = this[z] - t[z]) != 0) { + return L + } + } + return 0 + } + function q(z) { + var bW = 1, L; + if ((L = z >>> 16) != 0) { + z = L; + bW += 16 + } + if ((L = z >> 8) != 0) { + z = L; + bW += 8 + } + if ((L = z >> 4) != 0) { + z = L; + bW += 4 + } + if ((L = z >> 2) != 0) { + z = L; + bW += 2 + } + if ((L = z >> 1) != 0) { + z = L; + bW += 1 + } + return bW + } + function bt() { + if (this.t <= 0) { + return 0 + } + return this.DB * (this.t - 1) + q(this[this.t - 1] ^ (this.s & this.DM)) + } + function bv(L, z) { + var t; + for (t = this.t - 1; t >= 0; --t) { + z[t + L] = this[t] + } + for (t = L - 1; t >= 0; --t) { + z[t] = 0 + } + z.t = this.t + L; + z.s = this.s + } + function a2(L, z) { + for (var t = L; t < this.t; ++t) { + z[t - L] = this[t] + } + z.t = Math.max(this.t - L, 0); + z.s = this.s + } + function s(b0, bW) { + var z = b0 % this.DB; + var t = this.DB - z; + var bY = (1 << t) - 1; + var bX = Math.floor(b0 / this.DB), bZ = (this.s << z) & this.DM, L; + for (L = this.t - 1; L >= 0; --L) { + bW[L + bX + 1] = (this[L] >> t) | bZ; + bZ = (this[L] & bY) << z + } + for (L = bX - 1; L >= 0; --L) { + bW[L] = 0 + } + bW[bX] = bZ; + bW.t = this.t + bX + 1; + bW.s = this.s; + bW.clamp() + } + function bT(bZ, bW) { + bW.s = this.s; + var bX = Math.floor(bZ / this.DB); + if (bX >= this.t) { + bW.t = 0; + return + } + var z = bZ % this.DB; + var t = this.DB - z; + var bY = (1 << z) - 1; + bW[0] = this[bX] >> z; + for (var L = bX + 1; L < this.t; ++L) { + bW[L - bX - 1] |= (this[L] & bY) << t; + bW[L - bX] = this[L] >> z + } + if (z > 0) { + bW[this.t - bX - 1] |= (this.s & bY) << t + } + bW.t = this.t - bX; + bW.clamp() + } + function bs(z, bW) { + var L = 0 + , bX = 0 + , t = Math.min(z.t, this.t); + while (L < t) { + bX += this[L] - z[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + if (z.t < this.t) { + bX -= z.s; + while (L < this.t) { + bX += this[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + bX += this.s + } else { + bX += this.s; + while (L < z.t) { + bX -= z[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + bX -= z.s + } + bW.s = (bX < 0) ? -1 : 0; + if (bX < -1) { + bW[L++] = this.DV + bX + } else { + if (bX > 0) { + bW[L++] = bX + } + } + bW.t = L; + bW.clamp() + } + function bJ(z, bW) { + var t = this.abs() + , bX = z.abs(); + var L = t.t; + bW.t = L + bX.t; + while (--L >= 0) { + bW[L] = 0 + } + for (L = 0; L < bX.t; ++L) { + bW[L + t.t] = t.am(0, bX[L], bW, L, 0, t.t) + } + bW.s = 0; + bW.clamp(); + if (this.s != z.s) { + bf.ZERO.subTo(bW, bW) + } + } + function au(L) { + var t = this.abs(); + var z = L.t = 2 * t.t; + while (--z >= 0) { + L[z] = 0 + } + for (z = 0; z < t.t - 1; ++z) { + var bW = t.am(z, t[z], L, 2 * z, 0, 1); + if ((L[z + t.t] += t.am(z + 1, 2 * t[z], L, 2 * z + 1, bW, t.t - z - 1)) >= t.DV) { + L[z + t.t] -= t.DV; + L[z + t.t + 1] = 1 + } + } + if (L.t > 0) { + L[L.t - 1] += t.am(z, t[z], L, 2 * z, 0, 1) + } + L.s = 0; + L.clamp() + } + function a9(b3, b0, bZ) { + var b9 = b3.abs(); + if (b9.t <= 0) { + return + } + var b1 = this.abs(); + if (b1.t < b9.t) { + if (b0 != null) { + b0.fromInt(0) + } + if (bZ != null) { + this.copyTo(bZ) + } + return + } + if (bZ == null) { + bZ = bm() + } + var bX = bm() + , z = this.s + , b2 = b3.s; + var b8 = this.DB - q(b9[b9.t - 1]); + if (b8 > 0) { + b9.lShiftTo(b8, bX); + b1.lShiftTo(b8, bZ) + } else { + b9.copyTo(bX); + b1.copyTo(bZ) + } + var b5 = bX.t; + var L = bX[b5 - 1]; + if (L == 0) { + return + } + var b4 = L * (1 << this.F1) + ((b5 > 1) ? bX[b5 - 2] >> this.F2 : 0); + var cc = this.FV / b4 + , cb = (1 << this.F1) / b4 + , ca = 1 << this.F2; + var b7 = bZ.t + , b6 = b7 - b5 + , bY = (b0 == null) ? bm() : b0; + bX.dlShiftTo(b6, bY); + if (bZ.compareTo(bY) >= 0) { + bZ[bZ.t++] = 1; + bZ.subTo(bY, bZ) + } + bf.ONE.dlShiftTo(b5, bY); + bY.subTo(bX, bX); + while (bX.t < b5) { + bX[bX.t++] = 0 + } + while (--b6 >= 0) { + var bW = (bZ[--b7] == L) ? this.DM : Math.floor(bZ[b7] * cc + (bZ[b7 - 1] + ca) * cb); + if ((bZ[b7] += bX.am(0, bW, bZ, b6, 0, b5)) < bW) { + bX.dlShiftTo(b6, bY); + bZ.subTo(bY, bZ); + while (bZ[b7] < --bW) { + bZ.subTo(bY, bZ) + } + } + } + if (b0 != null) { + bZ.drShiftTo(b5, b0); + if (z != b2) { + bf.ZERO.subTo(b0, b0) + } + } + bZ.t = b5; + bZ.clamp(); + if (b8 > 0) { + bZ.rShiftTo(b8, bZ) + } + if (z < 0) { + bf.ZERO.subTo(bZ, bZ) + } + } + function bh(t) { + var z = bm(); + this.abs().divRemTo(t, null, z); + if (this.s < 0 && z.compareTo(bf.ZERO) > 0) { + t.subTo(z, z) + } + return z + } + function aT(t) { + this.m = t + } + function aI(t) { + if (t.s < 0 || t.compareTo(this.m) >= 0) { + return t.mod(this.m) + } else { + return t + } + } + function c(t) { + return t + } + function V(t) { + t.divRemTo(this.m, null, t) + } + function p(t, L, z) { + t.multiplyTo(L, z); + this.reduce(z) + } + function aF(t, z) { + t.squareTo(z); + this.reduce(z) + } + aT.prototype.convert = aI; + aT.prototype.revert = c; + aT.prototype.reduce = V; + aT.prototype.mulTo = p; + aT.prototype.sqrTo = aF; + function ab() { + if (this.t < 1) { + return 0 + } + var t = this[0]; + if ((t & 1) == 0) { + return 0 + } + var z = t & 3; + z = (z * (2 - (t & 15) * z)) & 15; + z = (z * (2 - (t & 255) * z)) & 255; + z = (z * (2 - (((t & 65535) * z) & 65535))) & 65535; + z = (z * (2 - t * z % this.DV)) % this.DV; + return (z > 0) ? this.DV - z : -z + } + function K(t) { + this.m = t; + this.mp = t.invDigit(); + this.mpl = this.mp & 32767; + this.mph = this.mp >> 15; + this.um = (1 << (t.DB - 15)) - 1; + this.mt2 = 2 * t.t + } + function by(t) { + var z = bm(); + t.abs().dlShiftTo(this.m.t, z); + z.divRemTo(this.m, null, z); + if (t.s < 0 && z.compareTo(bf.ZERO) > 0) { + this.m.subTo(z, z) + } + return z + } + function bl(t) { + var z = bm(); + t.copyTo(z); + this.reduce(z); + return z + } + function bV(t) { + while (t.t <= this.mt2) { + t[t.t++] = 0 + } + for (var L = 0; L < this.m.t; ++L) { + var z = t[L] & 32767; + var bW = (z * this.mpl + (((z * this.mph + (t[L] >> 15) * this.mpl) & this.um) << 15)) & t.DM; + z = L + this.m.t; + t[z] += this.m.am(0, bW, t, L, 0, this.m.t); + while (t[z] >= t.DV) { + t[z] -= t.DV; + t[++z]++ + } + } + t.clamp(); + t.drShiftTo(this.m.t, t); + if (t.compareTo(this.m) >= 0) { + t.subTo(this.m, t) + } + } + function ac(t, z) { + t.squareTo(z); + this.reduce(z) + } + function bz(t, L, z) { + t.multiplyTo(L, z); + this.reduce(z) + } + K.prototype.convert = by; + K.prototype.revert = bl; + K.prototype.reduce = bV; + K.prototype.mulTo = bz; + K.prototype.sqrTo = ac; + function ad() { + return ((this.t > 0) ? (this[0] & 1) : this.s) == 0 + } + function am(b0, b1) { + if (b0 > 4294967295 || b0 < 1) { + return bf.ONE + } + var bZ = bm() + , L = bm() + , bY = b1.convert(this) + , bX = q(b0) - 1; + bY.copyTo(bZ); + while (--bX >= 0) { + b1.sqrTo(bZ, L); + if ((b0 & (1 << bX)) > 0) { + b1.mulTo(L, bY, bZ) + } else { + var bW = bZ; + bZ = L; + L = bW + } + } + return b1.revert(bZ) + } + function aG(L, t) { + var bW; + if (L < 256 || t.isEven()) { + bW = new aT(t) + } else { + bW = new K(t) + } + return this.exp(L, bW) + } + bf.prototype.copyTo = d; + bf.prototype.fromInt = h; + bf.prototype.fromString = bI; + bf.prototype.clamp = bA; + bf.prototype.dlShiftTo = bv; + bf.prototype.drShiftTo = a2; + bf.prototype.lShiftTo = s; + bf.prototype.rShiftTo = bT; + bf.prototype.subTo = bs; + bf.prototype.multiplyTo = bJ; + bf.prototype.squareTo = au; + bf.prototype.divRemTo = a9; + bf.prototype.invDigit = ab; + bf.prototype.isEven = ad; + bf.prototype.exp = am; + bf.prototype.toString = u; + bf.prototype.negate = bC; + bf.prototype.abs = bB; + bf.prototype.compareTo = bN; + bf.prototype.bitLength = bt; + bf.prototype.mod = bh; + bf.prototype.modPowInt = aG; + bf.ZERO = bi(0); + bf.ONE = bi(1); + function f() { + var t = bm(); + this.copyTo(t); + return t + } + function b() { + if (this.s < 0) { + if (this.t == 1) { + return this[0] - this.DV + } else { + if (this.t == 0) { + return -1 + } + } + } else { + if (this.t == 1) { + return this[0] + } else { + if (this.t == 0) { + return 0 + } + } + } + return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0] + } + function bF() { + return (this.t == 0) ? this.s : (this[0] << 24) >> 24 + } + function ag() { + return (this.t == 0) ? this.s : (this[0] << 16) >> 16 + } + function aU(t) { + return Math.floor(Math.LN2 * this.DB / Math.log(t)) + } + function aZ() { + if (this.s < 0) { + return -1 + } else { + if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) { + return 0 + } else { + return 1 + } + } + } + function I(t) { + if (t == null) { + t = 10 + } + if (this.signum() == 0 || t < 2 || t > 36) { + return "0" + } + var bW = this.chunkSize(t); + var L = Math.pow(t, bW); + var bZ = bi(L) + , b0 = bm() + , bY = bm() + , bX = ""; + this.divRemTo(bZ, b0, bY); + while (b0.signum() > 0) { + bX = (L + bY.intValue()).toString(t).substr(1) + bX; + b0.divRemTo(bZ, b0, bY) + } + return bY.intValue().toString(t) + bX + } + function av(b1, bY) { + this.fromInt(0); + if (bY == null) { + bY = 10 + } + var bW = this.chunkSize(bY); + var bX = Math.pow(bY, bW) + , L = false + , t = 0 + , b0 = 0; + for (var z = 0; z < b1.length; ++z) { + var bZ = aX(b1, z); + if (bZ < 0) { + if (b1.charAt(z) == "-" && this.signum() == 0) { + L = true + } + continue + } + b0 = bY * b0 + bZ; + if (++t >= bW) { + this.dMultiply(bX); + this.dAddOffset(b0, 0); + t = 0; + b0 = 0 + } + } + if (t > 0) { + this.dMultiply(Math.pow(bY, t)); + this.dAddOffset(b0, 0) + } + if (L) { + bf.ZERO.subTo(this, this) + } + } + function aP(bW, L, bY) { + if ("number" == typeof L) { + if (bW < 2) { + this.fromInt(1) + } else { + this.fromNumber(bW, bY); + if (!this.testBit(bW - 1)) { + this.bitwiseTo(bf.ONE.shiftLeft(bW - 1), ak, this) + } + if (this.isEven()) { + this.dAddOffset(1, 0) + } + while (!this.isProbablePrime(L)) { + this.dAddOffset(2, 0); + if (this.bitLength() > bW) { + this.subTo(bf.ONE.shiftLeft(bW - 1), this) + } + } + } + } else { + var z = new Array() + , bX = bW & 7; + z.length = (bW >> 3) + 1; + L.nextBytes(z); + if (bX > 0) { + z[0] &= ((1 << bX) - 1) + } else { + z[0] = 0 + } + this.fromString(z, 256) + } + } + function aK() { + var z = this.t + , L = new Array(); + L[0] = this.s; + var bW = this.DB - (z * this.DB) % 8, bX, t = 0; + if (z-- > 0) { + if (bW < this.DB && (bX = this[z] >> bW) != (this.s & this.DM) >> bW) { + L[t++] = bX | (this.s << (this.DB - bW)) + } + while (z >= 0) { + if (bW < 8) { + bX = (this[z] & ((1 << bW) - 1)) << (8 - bW); + bX |= this[--z] >> (bW += this.DB - 8) + } else { + bX = (this[z] >> (bW -= 8)) & 255; + if (bW <= 0) { + bW += this.DB; + --z + } + } + if ((bX & 128) != 0) { + bX |= -256 + } + if (t == 0 && (this.s & 128) != (bX & 128)) { + ++t + } + if (t > 0 || bX != this.s) { + L[t++] = bX + } + } + } + return L + } + function bG(t) { + return (this.compareTo(t) == 0) + } + function W(t) { + return (this.compareTo(t) < 0) ? this : t + } + function bu(t) { + return (this.compareTo(t) > 0) ? this : t + } + function aJ(z, bY, bW) { + var L, bX, t = Math.min(z.t, this.t); + for (L = 0; L < t; ++L) { + bW[L] = bY(this[L], z[L]) + } + if (z.t < this.t) { + bX = z.s & this.DM; + for (L = t; L < this.t; ++L) { + bW[L] = bY(this[L], bX) + } + bW.t = this.t + } else { + bX = this.s & this.DM; + for (L = t; L < z.t; ++L) { + bW[L] = bY(bX, z[L]) + } + bW.t = z.t + } + bW.s = bY(this.s, z.s); + bW.clamp() + } + function o(t, z) { + return t & z + } + function bO(t) { + var z = bm(); + this.bitwiseTo(t, o, z); + return z + } + function ak(t, z) { + return t | z + } + function aS(t) { + var z = bm(); + this.bitwiseTo(t, ak, z); + return z + } + function aa(t, z) { + return t ^ z + } + function B(t) { + var z = bm(); + this.bitwiseTo(t, aa, z); + return z + } + function i(t, z) { + return t & ~z + } + function aD(t) { + var z = bm(); + this.bitwiseTo(t, i, z); + return z + } + function T() { + var z = bm(); + for (var t = 0; t < this.t; ++t) { + z[t] = this.DM & ~this[t] + } + z.t = this.t; + z.s = ~this.s; + return z + } + function aN(z) { + var t = bm(); + if (z < 0) { + this.rShiftTo(-z, t) + } else { + this.lShiftTo(z, t) + } + return t + } + function R(z) { + var t = bm(); + if (z < 0) { + this.lShiftTo(-z, t) + } else { + this.rShiftTo(z, t) + } + return t + } + function bc(t) { + if (t == 0) { + return -1 + } + var z = 0; + if ((t & 65535) == 0) { + t >>= 16; + z += 16 + } + if ((t & 255) == 0) { + t >>= 8; + z += 8 + } + if ((t & 15) == 0) { + t >>= 4; + z += 4 + } + if ((t & 3) == 0) { + t >>= 2; + z += 2 + } + if ((t & 1) == 0) { + ++z + } + return z + } + function aq() { + for (var t = 0; t < this.t; ++t) { + if (this[t] != 0) { + return t * this.DB + bc(this[t]) + } + } + if (this.s < 0) { + return this.t * this.DB + } + return -1 + } + function bj(t) { + var z = 0; + while (t != 0) { + t &= t - 1; + ++z + } + return z + } + function ao() { + var L = 0 + , t = this.s & this.DM; + for (var z = 0; z < this.t; ++z) { + L += bj(this[z] ^ t) + } + return L + } + function aL(z) { + var t = Math.floor(z / this.DB); + if (t >= this.t) { + return (this.s != 0) + } + return ((this[t] & (1 << (z % this.DB))) != 0) + } + function U(L, z) { + var t = bf.ONE.shiftLeft(L); + this.bitwiseTo(t, z, t); + return t + } + function a1(t) { + return this.changeBit(t, ak) + } + function ah(t) { + return this.changeBit(t, i) + } + function aO(t) { + return this.changeBit(t, aa) + } + function S(z, bW) { + var L = 0 + , bX = 0 + , t = Math.min(z.t, this.t); + while (L < t) { + bX += this[L] + z[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + if (z.t < this.t) { + bX += z.s; + while (L < this.t) { + bX += this[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + bX += this.s + } else { + bX += this.s; + while (L < z.t) { + bX += z[L]; + bW[L++] = bX & this.DM; + bX >>= this.DB + } + bX += z.s + } + bW.s = (bX < 0) ? -1 : 0; + if (bX > 0) { + bW[L++] = bX + } else { + if (bX < -1) { + bW[L++] = this.DV + bX + } + } + bW.t = L; + bW.clamp() + } + function bg(t) { + var z = bm(); + this.addTo(t, z); + return z + } + function aA(t) { + var z = bm(); + this.subTo(t, z); + return z + } + function bH(t) { + var z = bm(); + this.multiplyTo(t, z); + return z + } + function bU() { + var t = bm(); + this.squareTo(t); + return t + } + function bd(t) { + var z = bm(); + this.divRemTo(t, z, null); + return z + } + function bP(t) { + var z = bm(); + this.divRemTo(t, null, z); + return z + } + function bk(t) { + var L = bm() + , z = bm(); + this.divRemTo(t, L, z); + return new Array(L,z) + } + function e(t) { + this[this.t] = this.am(0, t - 1, this, 0, 0, this.t); + ++this.t; + this.clamp() + } + function aR(z, t) { + if (z == 0) { + return + } + while (this.t <= t) { + this[this.t++] = 0 + } + this[t] += z; + while (this[t] >= this.DV) { + this[t] -= this.DV; + if (++t >= this.t) { + this[this.t++] = 0 + } + ++this[t] + } + } + function Z() {} + function bw(t) { + return t + } + function bK(t, L, z) { + t.multiplyTo(L, z) + } + function ai(t, z) { + t.squareTo(z) + } + Z.prototype.convert = bw; + Z.prototype.revert = bw; + Z.prototype.mulTo = bK; + Z.prototype.sqrTo = ai; + function Q(t) { + return this.exp(t, new Z()) + } + function aQ(t, bX, bW) { + var L = Math.min(this.t + t.t, bX); + bW.s = 0; + bW.t = L; + while (L > 0) { + bW[--L] = 0 + } + var z; + for (z = bW.t - this.t; L < z; ++L) { + bW[L + this.t] = this.am(0, t[L], bW, L, 0, this.t) + } + for (z = Math.min(t.t, bX); L < z; ++L) { + this.am(0, t[L], bW, L, 0, bX - L) + } + bW.clamp() + } + function a0(t, bW, L) { + --bW; + var z = L.t = this.t + t.t - bW; + L.s = 0; + while (--z >= 0) { + L[z] = 0 + } + for (z = Math.max(bW - this.t, 0); z < t.t; ++z) { + L[this.t + z - bW] = this.am(bW - z, t[z], L, 0, 0, this.t + z - bW) + } + L.clamp(); + L.drShiftTo(1, L) + } + function bR(t) { + this.r2 = bm(); + this.q3 = bm(); + bf.ONE.dlShiftTo(2 * t.t, this.r2); + this.mu = this.r2.divide(t); + this.m = t + } + function H(t) { + if (t.s < 0 || t.t > 2 * this.m.t) { + return t.mod(this.m) + } else { + if (t.compareTo(this.m) < 0) { + return t + } else { + var z = bm(); + t.copyTo(z); + this.reduce(z); + return z + } + } + } + function bM(t) { + return t + } + function D(t) { + t.drShiftTo(this.m.t - 1, this.r2); + if (t.t > this.m.t + 1) { + t.t = this.m.t + 1; + t.clamp() + } + this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3); + this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2); + while (t.compareTo(this.r2) < 0) { + t.dAddOffset(1, this.m.t + 1) + } + t.subTo(this.r2, t); + while (t.compareTo(this.m) >= 0) { + t.subTo(this.m, t) + } + } + function aM(t, z) { + t.squareTo(z); + this.reduce(z) + } + function x(t, L, z) { + t.multiplyTo(L, z); + this.reduce(z) + } + bR.prototype.convert = H; + bR.prototype.revert = bM; + bR.prototype.reduce = D; + bR.prototype.mulTo = x; + bR.prototype.sqrTo = aM; + function N(b4, bZ) { + var b2 = b4.bitLength(), b0, bW = bi(1), b7; + if (b2 <= 0) { + return bW + } else { + if (b2 < 18) { + b0 = 1 + } else { + if (b2 < 48) { + b0 = 3 + } else { + if (b2 < 144) { + b0 = 4 + } else { + if (b2 < 768) { + b0 = 5 + } else { + b0 = 6 + } + } + } + } + } + if (b2 < 8) { + b7 = new aT(bZ) + } else { + if (bZ.isEven()) { + b7 = new bR(bZ) + } else { + b7 = new K(bZ) + } + } + var b3 = new Array() + , bY = 3 + , b5 = b0 - 1 + , L = (1 << b0) - 1; + b3[1] = b7.convert(this); + if (b0 > 1) { + var ca = bm(); + b7.sqrTo(b3[1], ca); + while (bY <= L) { + b3[bY] = bm(); + b7.mulTo(ca, b3[bY - 2], b3[bY]); + bY += 2 + } + } + var b1 = b4.t - 1, b8, b6 = true, bX = bm(), b9; + b2 = q(b4[b1]) - 1; + while (b1 >= 0) { + if (b2 >= b5) { + b8 = (b4[b1] >> (b2 - b5)) & L + } else { + b8 = (b4[b1] & ((1 << (b2 + 1)) - 1)) << (b5 - b2); + if (b1 > 0) { + b8 |= b4[b1 - 1] >> (this.DB + b2 - b5) + } + } + bY = b0; + while ((b8 & 1) == 0) { + b8 >>= 1; + --bY + } + if ((b2 -= bY) < 0) { + b2 += this.DB; + --b1 + } + if (b6) { + b3[b8].copyTo(bW); + b6 = false + } else { + while (bY > 1) { + b7.sqrTo(bW, bX); + b7.sqrTo(bX, bW); + bY -= 2 + } + if (bY > 0) { + b7.sqrTo(bW, bX) + } else { + b9 = bW; + bW = bX; + bX = b9 + } + b7.mulTo(bX, b3[b8], bW) + } + while (b1 >= 0 && (b4[b1] & (1 << b2)) == 0) { + b7.sqrTo(bW, bX); + b9 = bW; + bW = bX; + bX = b9; + if (--b2 < 0) { + b2 = this.DB - 1; + --b1 + } + } + } + return b7.revert(bW) + } + function aB(L) { + var z = (this.s < 0) ? this.negate() : this.clone(); + var bZ = (L.s < 0) ? L.negate() : L.clone(); + if (z.compareTo(bZ) < 0) { + var bX = z; + z = bZ; + bZ = bX + } + var bW = z.getLowestSetBit() + , bY = bZ.getLowestSetBit(); + if (bY < 0) { + return z + } + if (bW < bY) { + bY = bW + } + if (bY > 0) { + z.rShiftTo(bY, z); + bZ.rShiftTo(bY, bZ) + } + while (z.signum() > 0) { + if ((bW = z.getLowestSetBit()) > 0) { + z.rShiftTo(bW, z) + } + if ((bW = bZ.getLowestSetBit()) > 0) { + bZ.rShiftTo(bW, bZ) + } + if (z.compareTo(bZ) >= 0) { + z.subTo(bZ, z); + z.rShiftTo(1, z) + } else { + bZ.subTo(z, bZ); + bZ.rShiftTo(1, bZ) + } + } + if (bY > 0) { + bZ.lShiftTo(bY, bZ) + } + return bZ + } + function aj(bW) { + if (bW <= 0) { + return 0 + } + var L = this.DV % bW + , z = (this.s < 0) ? bW - 1 : 0; + if (this.t > 0) { + if (L == 0) { + z = this[0] % bW + } else { + for (var t = this.t - 1; t >= 0; --t) { + z = (L * z + this[t]) % bW + } + } + } + return z + } + function bS(z) { + var bY = z.isEven(); + if ((this.isEven() && bY) || z.signum() == 0) { + return bf.ZERO + } + var bX = z.clone() + , bW = this.clone(); + var L = bi(1) + , t = bi(0) + , b0 = bi(0) + , bZ = bi(1); + while (bX.signum() != 0) { + while (bX.isEven()) { + bX.rShiftTo(1, bX); + if (bY) { + if (!L.isEven() || !t.isEven()) { + L.addTo(this, L); + t.subTo(z, t) + } + L.rShiftTo(1, L) + } else { + if (!t.isEven()) { + t.subTo(z, t) + } + } + t.rShiftTo(1, t) + } + while (bW.isEven()) { + bW.rShiftTo(1, bW); + if (bY) { + if (!b0.isEven() || !bZ.isEven()) { + b0.addTo(this, b0); + bZ.subTo(z, bZ) + } + b0.rShiftTo(1, b0) + } else { + if (!bZ.isEven()) { + bZ.subTo(z, bZ) + } + } + bZ.rShiftTo(1, bZ) + } + if (bX.compareTo(bW) >= 0) { + bX.subTo(bW, bX); + if (bY) { + L.subTo(b0, L) + } + t.subTo(bZ, t) + } else { + bW.subTo(bX, bW); + if (bY) { + b0.subTo(L, b0) + } + bZ.subTo(t, bZ) + } + } + if (bW.compareTo(bf.ONE) != 0) { + return bf.ZERO + } + if (bZ.compareTo(z) >= 0) { + return bZ.subtract(z) + } + if (bZ.signum() < 0) { + bZ.addTo(z, bZ) + } else { + return bZ + } + if (bZ.signum() < 0) { + return bZ.add(z) + } else { + return bZ + } + } + var az = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]; + var k = (1 << 26) / az[az.length - 1]; + function bL(bY) { + var bX, L = this.abs(); + if (L.t == 1 && L[0] <= az[az.length - 1]) { + for (bX = 0; bX < az.length; ++bX) { + if (L[0] == az[bX]) { + return true + } + } + return false + } + if (L.isEven()) { + return false + } + bX = 1; + while (bX < az.length) { + var z = az[bX] + , bW = bX + 1; + while (bW < az.length && z < k) { + z *= az[bW++] + } + z = L.modInt(z); + while (bX < bW) { + if (z % az[bX++] == 0) { + return false + } + } + } + return L.millerRabin(bY) + } + function aE(bY) { + var bZ = this.subtract(bf.ONE); + var L = bZ.getLowestSetBit(); + if (L <= 0) { + return false + } + var b0 = bZ.shiftRight(L); + bY = (bY + 1) >> 1; + if (bY > az.length) { + bY = az.length + } + var z = bm(); + for (var bX = 0; bX < bY; ++bX) { + z.fromInt(az[Math.floor(Math.random() * az.length)]); + var b1 = z.modPow(b0, this); + if (b1.compareTo(bf.ONE) != 0 && b1.compareTo(bZ) != 0) { + var bW = 1; + while (bW++ < L && b1.compareTo(bZ) != 0) { + b1 = b1.modPowInt(2, this); + if (b1.compareTo(bf.ONE) == 0) { + return false + } + } + if (b1.compareTo(bZ) != 0) { + return false + } + } + } + return true + } + bf.prototype.chunkSize = aU; + bf.prototype.toRadix = I; + bf.prototype.fromRadix = av; + bf.prototype.fromNumber = aP; + bf.prototype.bitwiseTo = aJ; + bf.prototype.changeBit = U; + bf.prototype.addTo = S; + bf.prototype.dMultiply = e; + bf.prototype.dAddOffset = aR; + bf.prototype.multiplyLowerTo = aQ; + bf.prototype.multiplyUpperTo = a0; + bf.prototype.modInt = aj; + bf.prototype.millerRabin = aE; + bf.prototype.clone = f; + bf.prototype.intValue = b; + bf.prototype.byteValue = bF; + bf.prototype.shortValue = ag; + bf.prototype.signum = aZ; + bf.prototype.toByteArray = aK; + bf.prototype.equals = bG; + bf.prototype.min = W; + bf.prototype.max = bu; + bf.prototype.and = bO; + bf.prototype.or = aS; + bf.prototype.xor = B; + bf.prototype.andNot = aD; + bf.prototype.not = T; + bf.prototype.shiftLeft = aN; + bf.prototype.shiftRight = R; + bf.prototype.getLowestSetBit = aq; + bf.prototype.bitCount = ao; + bf.prototype.testBit = aL; + bf.prototype.setBit = a1; + bf.prototype.clearBit = ah; + bf.prototype.flipBit = aO; + bf.prototype.add = bg; + bf.prototype.subtract = aA; + bf.prototype.multiply = bH; + bf.prototype.divide = bd; + bf.prototype.remainder = bP; + bf.prototype.divideAndRemainder = bk; + bf.prototype.modPow = N; + bf.prototype.modInverse = bS; + bf.prototype.pow = Q; + bf.prototype.gcd = aB; + bf.prototype.isProbablePrime = bL; + bf.prototype.square = bU; + function bp() { + this.i = 0; + this.j = 0; + this.S = new Array() + } + function af(bX) { + var bW, z, L; + for (bW = 0; bW < 256; ++bW) { + this.S[bW] = bW + } + z = 0; + for (bW = 0; bW < 256; ++bW) { + z = (z + this.S[bW] + bX[bW % bX.length]) & 255; + L = this.S[bW]; + this.S[bW] = this.S[z]; + this.S[z] = L + } + this.i = 0; + this.j = 0 + } + function be() { + var z; + this.i = (this.i + 1) & 255; + this.j = (this.j + this.S[this.i]) & 255; + z = this.S[this.i]; + this.S[this.i] = this.S[this.j]; + this.S[this.j] = z; + return this.S[(z + this.S[this.i]) & 255] + } + bp.prototype.init = af; + bp.prototype.next = be; + function P() { + return new bp() + } + var y = 256; + var j; + var l; + var C; + if (l == null) { + l = new Array(); + C = 0; + var ba; + if (window.crypto && window.crypto.getRandomValues) { + var a8 = new Uint32Array(256); + window.crypto.getRandomValues(a8); + for (ba = 0; ba < a8.length; ++ba) { + l[C++] = a8[ba] & 255 + } + } + var F = function(z) { + this.count = this.count || 0; + if (this.count >= 256 || C >= y) { + if (window.removeEventListener) { + window.removeEventListener("mousemove", F, false) + } else { + if (window.detachEvent) { + window.detachEvent("onmousemove", F) + } + } + return + } + try { + var t = z.x + z.y; + l[C++] = t & 255; + this.count += 1 + } catch (L) {} + }; + if (window.addEventListener) { + window.addEventListener("mousemove", F, false) + } else { + if (window.attachEvent) { + window.attachEvent("onmousemove", F) + } + } + } + function bb() { + if (j == null) { + j = P(); + while (C < y) { + var t = Math.floor(65536 * Math.random()); + l[C++] = t & 255 + } + j.init(l); + for (C = 0; C < l.length; ++C) { + l[C] = 0 + } + C = 0 + } + return j.next() + } + function aY(z) { + var t; + for (t = 0; t < z.length; ++t) { + z[t] = bb() + } + } + function G() {} + G.prototype.nextBytes = aY; + function w(z, t) { + return new bf(z,t) + } + function m(L, bW) { + var t = ""; + var z = 0; + while (z + bW < L.length) { + t += L.substring(z, z + bW) + "\n"; + z += bW + } + return t + L.substring(z, L.length) + } + function br(t) { + if (t < 16) { + return "0" + t.toString(16) + } else { + return t.toString(16) + } + } + function bD(bW, bZ) { + if (bZ < bW.length + 11) { + console.error("Message too long for RSA"); + return null + } + var bY = new Array(); + var L = bW.length - 1; + while (L >= 0 && bZ > 0) { + var bX = bW.charCodeAt(L--); + if (bX < 128) { + bY[--bZ] = bX + } else { + if ((bX > 127) && (bX < 2048)) { + bY[--bZ] = (bX & 63) | 128; + bY[--bZ] = (bX >> 6) | 192 + } else { + bY[--bZ] = (bX & 63) | 128; + bY[--bZ] = ((bX >> 6) & 63) | 128; + bY[--bZ] = (bX >> 12) | 224 + } + } + } + bY[--bZ] = 0; + var z = new G(); + var t = new Array(); + while (bZ > 2) { + t[0] = 0; + while (t[0] == 0) { + z.nextBytes(t) + } + bY[--bZ] = t[0] + } + bY[--bZ] = 2; + bY[--bZ] = 0; + return new bf(bY) + } + function A() { + this.n = null; + this.e = 0; + this.d = null; + this.p = null; + this.q = null; + this.dmp1 = null; + this.dmq1 = null; + this.coeff = null + } + function an(z, t) { + if (z != null && t != null && z.length > 0 && t.length > 0) { + this.n = w(z, 16); + this.e = parseInt(t, 16) + } else { + console.error("Invalid RSA public key") + } + } + function bq(t) { + return t.modPowInt(this.e, this.n) + } + function al(L) { + var t = bD(L, (this.n.bitLength() + 7) >> 3); + if (t == null) { + return null + } + var bW = this.doPublic(t); + if (bW == null) { + return null + } + var z = bW.toString(16); + if ((z.length & 1) == 0) { + return z + } else { + return "0" + z + } + } + A.prototype.doPublic = bq; + A.prototype.setPublic = an; + A.prototype.encrypt = al; + function bo(bW, bY) { + var t = bW.toByteArray(); + var L = 0; + while (L < t.length && t[L] == 0) { + ++L + } + if (t.length - L != bY - 1 || t[L] != 2) { + return null + } + ++L; + while (t[L] != 0) { + if (++L >= t.length) { + return null + } + } + var z = ""; + while (++L < t.length) { + var bX = t[L] & 255; + if (bX < 128) { + z += String.fromCharCode(bX) + } else { + if ((bX > 191) && (bX < 224)) { + z += String.fromCharCode(((bX & 31) << 6) | (t[L + 1] & 63)); + ++L + } else { + z += String.fromCharCode(((bX & 15) << 12) | ((t[L + 1] & 63) << 6) | (t[L + 2] & 63)); + L += 2 + } + } + } + return z + } + function aC(L, t, z) { + if (L != null && t != null && L.length > 0 && t.length > 0) { + this.n = w(L, 16); + this.e = parseInt(t, 16); + this.d = w(z, 16) + } else { + console.error("Invalid RSA private key") + } + } + function O(bZ, bW, bX, L, z, t, b0, bY) { + if (bZ != null && bW != null && bZ.length > 0 && bW.length > 0) { + this.n = w(bZ, 16); + this.e = parseInt(bW, 16); + this.d = w(bX, 16); + this.p = w(L, 16); + this.q = w(z, 16); + this.dmp1 = w(t, 16); + this.dmq1 = w(b0, 16); + this.coeff = w(bY, 16) + } else { + console.error("Invalid RSA private key") + } + } + function ax(L, b2) { + var z = new G(); + var bZ = L >> 1; + this.e = parseInt(b2, 16); + var bW = new bf(b2,16); + for (; ; ) { + for (; ; ) { + this.p = new bf(L - bZ,1,z); + if (this.p.subtract(bf.ONE).gcd(bW).compareTo(bf.ONE) == 0 && this.p.isProbablePrime(10)) { + break + } + } + for (; ; ) { + this.q = new bf(bZ,1,z); + if (this.q.subtract(bf.ONE).gcd(bW).compareTo(bf.ONE) == 0 && this.q.isProbablePrime(10)) { + break + } + } + if (this.p.compareTo(this.q) <= 0) { + var b1 = this.p; + this.p = this.q; + this.q = b1 + } + var b0 = this.p.subtract(bf.ONE); + var bX = this.q.subtract(bf.ONE); + var bY = b0.multiply(bX); + if (bY.gcd(bW).compareTo(bf.ONE) == 0) { + this.n = this.p.multiply(this.q); + this.d = bW.modInverse(bY); + this.dmp1 = this.d.mod(b0); + this.dmq1 = this.d.mod(bX); + this.coeff = this.q.modInverse(this.p); + break + } + } + } + function ay(t) { + if (this.p == null || this.q == null) { + return t.modPow(this.d, this.n) + } + var L = t.mod(this.p).modPow(this.dmp1, this.p); + var z = t.mod(this.q).modPow(this.dmq1, this.q); + while (L.compareTo(z) < 0) { + L = L.add(this.p) + } + return L.subtract(z).multiply(this.coeff).mod(this.p).multiply(this.q).add(z) + } + function r(z) { + var L = w(z, 16); + var t = this.doPrivate(L); + if (t == null) { + return null + } + return bo(t, (this.n.bitLength() + 7) >> 3) + } + A.prototype.doPrivate = ay; + A.prototype.setPrivate = aC; + A.prototype.setPrivateEx = O; + A.prototype.generate = ax; + A.prototype.decrypt = r; + (function() { + var z = function(b3, b1, b2) { + var bZ = new G(); + var bW = b3 >> 1; + this.e = parseInt(b1, 16); + var bY = new bf(b1,16); + var b0 = this; + var bX = function() { + var b5 = function() { + if (b0.p.compareTo(b0.q) <= 0) { + var b8 = b0.p; + b0.p = b0.q; + b0.q = b8 + } + var ca = b0.p.subtract(bf.ONE); + var b7 = b0.q.subtract(bf.ONE); + var b9 = ca.multiply(b7); + if (b9.gcd(bY).compareTo(bf.ONE) == 0) { + b0.n = b0.p.multiply(b0.q); + b0.d = bY.modInverse(b9); + b0.dmp1 = b0.d.mod(ca); + b0.dmq1 = b0.d.mod(b7); + b0.coeff = b0.q.modInverse(b0.p); + setTimeout(function() { + b2() + }, 0) + } else { + setTimeout(bX, 0) + } + }; + var b6 = function() { + b0.q = bm(); + b0.q.fromNumberAsync(bW, 1, bZ, function() { + b0.q.subtract(bf.ONE).gcda(bY, function(b7) { + if (b7.compareTo(bf.ONE) == 0 && b0.q.isProbablePrime(10)) { + setTimeout(b5, 0) + } else { + setTimeout(b6, 0) + } + }) + }) + }; + var b4 = function() { + b0.p = bm(); + b0.p.fromNumberAsync(b3 - bW, 1, bZ, function() { + b0.p.subtract(bf.ONE).gcda(bY, function(b7) { + if (b7.compareTo(bf.ONE) == 0 && b0.p.isProbablePrime(10)) { + setTimeout(b6, 0) + } else { + setTimeout(b4, 0) + } + }) + }) + }; + setTimeout(b4, 0) + }; + setTimeout(bX, 0) + }; + A.prototype.generateAsync = z; + var t = function(bX, b3) { + var bW = (this.s < 0) ? this.negate() : this.clone(); + var b2 = (bX.s < 0) ? bX.negate() : bX.clone(); + if (bW.compareTo(b2) < 0) { + var bZ = bW; + bW = b2; + b2 = bZ + } + var bY = bW.getLowestSetBit() + , b0 = b2.getLowestSetBit(); + if (b0 < 0) { + b3(bW); + return + } + if (bY < b0) { + b0 = bY + } + if (b0 > 0) { + bW.rShiftTo(b0, bW); + b2.rShiftTo(b0, b2) + } + var b1 = function() { + if ((bY = bW.getLowestSetBit()) > 0) { + bW.rShiftTo(bY, bW) + } + if ((bY = b2.getLowestSetBit()) > 0) { + b2.rShiftTo(bY, b2) + } + if (bW.compareTo(b2) >= 0) { + bW.subTo(b2, bW); + bW.rShiftTo(1, bW) + } else { + b2.subTo(bW, b2); + b2.rShiftTo(1, b2) + } + if (!(bW.signum() > 0)) { + if (b0 > 0) { + b2.lShiftTo(b0, b2) + } + setTimeout(function() { + b3(b2) + }, 0) + } else { + setTimeout(b1, 0) + } + }; + setTimeout(b1, 10) + }; + bf.prototype.gcda = t; + var L = function(b0, bX, b3, b2) { + if ("number" == typeof bX) { + if (b0 < 2) { + this.fromInt(1) + } else { + this.fromNumber(b0, b3); + if (!this.testBit(b0 - 1)) { + this.bitwiseTo(bf.ONE.shiftLeft(b0 - 1), ak, this) + } + if (this.isEven()) { + this.dAddOffset(1, 0) + } + var bZ = this; + var bY = function() { + bZ.dAddOffset(2, 0); + if (bZ.bitLength() > b0) { + bZ.subTo(bf.ONE.shiftLeft(b0 - 1), bZ) + } + if (bZ.isProbablePrime(bX)) { + setTimeout(function() { + b2() + }, 0) + } else { + setTimeout(bY, 0) + } + }; + setTimeout(bY, 0) + } + } else { + var bW = new Array() + , b1 = b0 & 7; + bW.length = (b0 >> 3) + 1; + bX.nextBytes(bW); + if (b1 > 0) { + bW[0] &= ((1 << b1) - 1) + } else { + bW[0] = 0 + } + this.fromString(bW, 256) + } + }; + bf.prototype.fromNumberAsync = L + } + )(); + var a4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var J = "="; + function ae(L) { + var z; + var bW; + var t = ""; + for (z = 0; z + 3 <= L.length; z += 3) { + bW = parseInt(L.substring(z, z + 3), 16); + t += a4.charAt(bW >> 6) + a4.charAt(bW & 63) + } + if (z + 1 == L.length) { + bW = parseInt(L.substring(z, z + 1), 16); + t += a4.charAt(bW << 2) + } else { + if (z + 2 == L.length) { + bW = parseInt(L.substring(z, z + 2), 16); + t += a4.charAt(bW >> 2) + a4.charAt((bW & 3) << 4) + } + } + while ((t.length & 3) > 0) { + t += J + } + return t + } + function aW(bX) { + var L = ""; + var bW; + var t = 0; + var z; + for (bW = 0; bW < bX.length; ++bW) { + if (bX.charAt(bW) == J) { + break + } + v = a4.indexOf(bX.charAt(bW)); + if (v < 0) { + continue + } + if (t == 0) { + L += Y(v >> 2); + z = v & 3; + t = 1 + } else { + if (t == 1) { + L += Y((z << 2) | (v >> 4)); + z = v & 15; + t = 2 + } else { + if (t == 2) { + L += Y(z); + L += Y(v >> 2); + z = v & 3; + t = 3 + } else { + L += Y((z << 2) | (v >> 4)); + L += Y(v & 15); + t = 0 + } + } + } + } + if (t == 1) { + L += Y(z << 2) + } + return L + } + function M(bW) { + var L = aW(bW); + var z; + var t = new Array(); + for (z = 0; 2 * z < L.length; ++z) { + t[z] = parseInt(L.substring(2 * z, 2 * z + 2), 16) + } + return t + } + /*! asn1-1.0.2.js (c) 2013 Kenji Urushima | kjur.github.com/jsrsasign/license + */ + ;var at = at || {}; + at.env = at.env || {}; + var bn = at + , aw = Object.prototype + , ar = "[object Function]" + , X = ["toString", "valueOf"]; + at.env.parseUA = function(bW) { + var bX = function(b1) { + var b2 = 0; + return parseFloat(b1.replace(/\./g, function() { + return (b2++ == 1) ? "" : "." + })) + }, b0 = navigator, bZ = { + ie: 0, + opera: 0, + gecko: 0, + webkit: 0, + chrome: 0, + mobile: null, + air: 0, + ipad: 0, + iphone: 0, + ipod: 0, + ios: null, + android: 0, + webos: 0, + caja: b0 && b0.cajaVersion, + secure: false, + os: null + }, L = bW || (navigator && navigator.userAgent), bY = window && window.location, z = bY && bY.href, t; + bZ.secure = z && (z.toLowerCase().indexOf("https") === 0); + if (L) { + if ((/windows|win32/i).test(L)) { + bZ.os = "windows" + } else { + if ((/macintosh/i).test(L)) { + bZ.os = "macintosh" + } else { + if ((/rhino/i).test(L)) { + bZ.os = "rhino" + } + } + } + if ((/KHTML/).test(L)) { + bZ.webkit = 1 + } + t = L.match(/AppleWebKit\/([^\s]*)/); + if (t && t[1]) { + bZ.webkit = bX(t[1]); + if (/ Mobile\//.test(L)) { + bZ.mobile = "Apple"; + t = L.match(/OS ([^\s]*)/); + if (t && t[1]) { + t = bX(t[1].replace("_", ".")) + } + bZ.ios = t; + bZ.ipad = bZ.ipod = bZ.iphone = 0; + t = L.match(/iPad|iPod|iPhone/); + if (t && t[0]) { + bZ[t[0].toLowerCase()] = bZ.ios + } + } else { + t = L.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/); + if (t) { + bZ.mobile = t[0] + } + if (/webOS/.test(L)) { + bZ.mobile = "WebOS"; + t = L.match(/webOS\/([^\s]*);/); + if (t && t[1]) { + bZ.webos = bX(t[1]) + } + } + if (/ Android/.test(L)) { + bZ.mobile = "Android"; + t = L.match(/Android ([^\s]*);/); + if (t && t[1]) { + bZ.android = bX(t[1]) + } + } + } + t = L.match(/Chrome\/([^\s]*)/); + if (t && t[1]) { + bZ.chrome = bX(t[1]) + } else { + t = L.match(/AdobeAIR\/([^\s]*)/); + if (t) { + bZ.air = t[0] + } + } + } + if (!bZ.webkit) { + t = L.match(/Opera[\s\/]([^\s]*)/); + if (t && t[1]) { + bZ.opera = bX(t[1]); + t = L.match(/Version\/([^\s]*)/); + if (t && t[1]) { + bZ.opera = bX(t[1]) + } + t = L.match(/Opera Mini[^;]*/); + if (t) { + bZ.mobile = t[0] + } + } else { + t = L.match(/MSIE\s([^;]*)/); + if (t && t[1]) { + bZ.ie = bX(t[1]) + } else { + t = L.match(/Gecko\/([^\s]*)/); + if (t) { + bZ.gecko = 1; + t = L.match(/rv:([^\s\)]*)/); + if (t && t[1]) { + bZ.gecko = bX(t[1]) + } + } + } + } + } + } + return bZ + } + ; + at.env.ua = at.env.parseUA(); + at.isFunction = function(t) { + return (typeof t === "function") || aw.toString.apply(t) === ar + } + ; + at._IEEnumFix = (at.env.ua.ie) ? function(L, z) { + var t, bX, bW; + for (t = 0; t < X.length; t = t + 1) { + bX = X[t]; + bW = z[bX]; + if (bn.isFunction(bW) && bW != aw[bX]) { + L[bX] = bW + } + } + } + : function() {} + ; + at.extend = function(bW, bX, L) { + if (!bX || !bW) { + throw new Error("extend failed, please check that all dependencies are included.") + } + var z = function() {}, t; + z.prototype = bX.prototype; + bW.prototype = new z(); + bW.prototype.constructor = bW; + bW.superclass = bX.prototype; + if (bX.prototype.constructor == aw.constructor) { + bX.prototype.constructor = bX + } + if (L) { + for (t in L) { + if (bn.hasOwnProperty(L, t)) { + bW.prototype[t] = L[t] + } + } + bn._IEEnumFix(bW.prototype, L) + } + } + ; + if (typeof KJUR == "undefined" || !KJUR) { + KJUR = {} + } + if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) { + KJUR.asn1 = {} + } + KJUR.asn1.ASN1Util = new function() { + this.integerToByteHex = function(t) { + var z = t.toString(16); + if ((z.length % 2) == 1) { + z = "0" + z + } + return z + } + ; + this.bigIntToMinTwosComplementsHex = function(b0) { + var bY = b0.toString(16); + if (bY.substr(0, 1) != "-") { + if (bY.length % 2 == 1) { + bY = "0" + bY + } else { + if (!bY.match(/^[0-7]/)) { + bY = "00" + bY + } + } + } else { + var t = bY.substr(1); + var bX = t.length; + if (bX % 2 == 1) { + bX += 1 + } else { + if (!bY.match(/^[0-7]/)) { + bX += 2 + } + } + var bZ = ""; + for (var bW = 0; bW < bX; bW++) { + bZ += "f" + } + var L = new bf(bZ,16); + var z = L.xor(b0).add(bf.ONE); + bY = z.toString(16).replace(/^-/, "") + } + return bY + } + ; + this.getPEMStringFromHex = function(t, z) { + var bX = CryptoJS.enc.Hex.parse(t); + var L = CryptoJS.enc.Base64.stringify(bX); + var bW = L.replace(/(.{64})/g, "$1\r\n"); + bW = bW.replace(/\r\n$/, ""); + return "-----BEGIN " + z + "-----\r\n" + bW + "\r\n-----END " + z + "-----\r\n" + } + } + ; + KJUR.asn1.ASN1Object = function() { + var L = true; + var z = null; + var bW = "00"; + var bX = "00"; + var t = ""; + this.getLengthHexFromValue = function() { + if (typeof this.hV == "undefined" || this.hV == null) { + throw "this.hV is null or undefined." + } + if (this.hV.length % 2 == 1) { + throw "value hex must be even length: n=" + t.length + ",v=" + this.hV + } + var b1 = this.hV.length / 2; + var b0 = b1.toString(16); + if (b0.length % 2 == 1) { + b0 = "0" + b0 + } + if (b1 < 128) { + return b0 + } else { + var bZ = b0.length / 2; + if (bZ > 15) { + throw "ASN.1 length too long to represent by 8x: n = " + b1.toString(16) + } + var bY = 128 + bZ; + return bY.toString(16) + b0 + } + } + ; + this.getEncodedHex = function() { + if (this.hTLV == null || this.isModified) { + this.hV = this.getFreshValueHex(); + this.hL = this.getLengthHexFromValue(); + this.hTLV = this.hT + this.hL + this.hV; + this.isModified = false + } + return this.hTLV + } + ; + this.getValueHex = function() { + this.getEncodedHex(); + return this.hV + } + ; + this.getFreshValueHex = function() { + return "" + } + } + ; + KJUR.asn1.DERAbstractString = function(L) { + KJUR.asn1.DERAbstractString.superclass.constructor.call(this); + var z = null; + var t = null; + this.getString = function() { + return this.s + } + ; + this.setString = function(bW) { + this.hTLV = null; + this.isModified = true; + this.s = bW; + this.hV = stohex(this.s) + } + ; + this.setStringHex = function(bW) { + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = bW + } + ; + this.getFreshValueHex = function() { + return this.hV + } + ; + if (typeof L != "undefined") { + if (typeof L.str != "undefined") { + this.setString(L.str) + } else { + if (typeof L.hex != "undefined") { + this.setStringHex(L.hex) + } + } + } + } + ; + at.extend(KJUR.asn1.DERAbstractString, KJUR.asn1.ASN1Object); + KJUR.asn1.DERAbstractTime = function(L) { + KJUR.asn1.DERAbstractTime.superclass.constructor.call(this); + var z = null; + var t = null; + this.localDateToUTC = function(bX) { + utc = bX.getTime() + (bX.getTimezoneOffset() * 60000); + var bW = new Date(utc); + return bW + } + ; + this.formatDate = function(b1, b3) { + var bW = this.zeroPadding; + var b2 = this.localDateToUTC(b1); + var b4 = String(b2.getFullYear()); + if (b3 == "utc") { + b4 = b4.substr(2, 2) + } + var b0 = bW(String(b2.getMonth() + 1), 2); + var b5 = bW(String(b2.getDate()), 2); + var bX = bW(String(b2.getHours()), 2); + var bY = bW(String(b2.getMinutes()), 2); + var bZ = bW(String(b2.getSeconds()), 2); + return b4 + b0 + b5 + bX + bY + bZ + "Z" + } + ; + this.zeroPadding = function(bX, bW) { + if (bX.length >= bW) { + return bX + } + return new Array(bW - bX.length + 1).join("0") + bX + } + ; + this.getString = function() { + return this.s + } + ; + this.setString = function(bW) { + this.hTLV = null; + this.isModified = true; + this.s = bW; + this.hV = stohex(this.s) + } + ; + this.setByDateValue = function(b0, b2, bX, bW, bY, bZ) { + var b1 = new Date(Date.UTC(b0, b2 - 1, bX, bW, bY, bZ, 0)); + this.setByDate(b1) + } + ; + this.getFreshValueHex = function() { + return this.hV + } + } + ; + at.extend(KJUR.asn1.DERAbstractTime, KJUR.asn1.ASN1Object); + KJUR.asn1.DERAbstractStructured = function(z) { + KJUR.asn1.DERAbstractString.superclass.constructor.call(this); + var t = null; + this.setByASN1ObjectArray = function(L) { + this.hTLV = null; + this.isModified = true; + this.asn1Array = L + } + ; + this.appendASN1Object = function(L) { + this.hTLV = null; + this.isModified = true; + this.asn1Array.push(L) + } + ; + this.asn1Array = new Array(); + if (typeof z != "undefined") { + if (typeof z.array != "undefined") { + this.asn1Array = z.array + } + } + } + ; + at.extend(KJUR.asn1.DERAbstractStructured, KJUR.asn1.ASN1Object); + KJUR.asn1.DERBoolean = function() { + KJUR.asn1.DERBoolean.superclass.constructor.call(this); + this.hT = "01"; + this.hTLV = "0101ff" + } + ; + at.extend(KJUR.asn1.DERBoolean, KJUR.asn1.ASN1Object); + KJUR.asn1.DERInteger = function(t) { + KJUR.asn1.DERInteger.superclass.constructor.call(this); + this.hT = "02"; + this.setByBigInteger = function(z) { + this.hTLV = null; + this.isModified = true; + this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(z) + } + ; + this.setByInteger = function(L) { + var z = new bf(String(L),10); + this.setByBigInteger(z) + } + ; + this.setValueHex = function(z) { + this.hV = z + } + ; + this.getFreshValueHex = function() { + return this.hV + } + ; + if (typeof t != "undefined") { + if (typeof t.bigint != "undefined") { + this.setByBigInteger(t.bigint) + } else { + if (typeof t["int"] != "undefined") { + this.setByInteger(t["int"]) + } else { + if (typeof t.hex != "undefined") { + this.setValueHex(t.hex) + } + } + } + } + } + ; + at.extend(KJUR.asn1.DERInteger, KJUR.asn1.ASN1Object); + KJUR.asn1.DERBitString = function(t) { + KJUR.asn1.DERBitString.superclass.constructor.call(this); + this.hT = "03"; + this.setHexValueIncludingUnusedBits = function(z) { + this.hTLV = null; + this.isModified = true; + this.hV = z + } + ; + this.setUnusedBitsAndHexValue = function(z, bW) { + if (z < 0 || 7 < z) { + throw "unused bits shall be from 0 to 7: u = " + z + } + var L = "0" + z; + this.hTLV = null; + this.isModified = true; + this.hV = L + bW + } + ; + this.setByBinaryString = function(bW) { + bW = bW.replace(/0+$/, ""); + var bX = 8 - bW.length % 8; + if (bX == 8) { + bX = 0 + } + for (var bY = 0; bY <= bX; bY++) { + bW += "0" + } + var bZ = ""; + for (var bY = 0; bY < bW.length - 1; bY += 8) { + var L = bW.substr(bY, 8); + var z = parseInt(L, 2).toString(16); + if (z.length == 1) { + z = "0" + z + } + bZ += z + } + this.hTLV = null; + this.isModified = true; + this.hV = "0" + bX + bZ + } + ; + this.setByBooleanArray = function(bW) { + var L = ""; + for (var z = 0; z < bW.length; z++) { + if (bW[z] == true) { + L += "1" + } else { + L += "0" + } + } + this.setByBinaryString(L) + } + ; + this.newFalseArray = function(bW) { + var z = new Array(bW); + for (var L = 0; L < bW; L++) { + z[L] = false + } + return z + } + ; + this.getFreshValueHex = function() { + return this.hV + } + ; + if (typeof t != "undefined") { + if (typeof t.hex != "undefined") { + this.setHexValueIncludingUnusedBits(t.hex) + } else { + if (typeof t.bin != "undefined") { + this.setByBinaryString(t.bin) + } else { + if (typeof t.array != "undefined") { + this.setByBooleanArray(t.array) + } + } + } + } + } + ; + at.extend(KJUR.asn1.DERBitString, KJUR.asn1.ASN1Object); + KJUR.asn1.DEROctetString = function(t) { + KJUR.asn1.DEROctetString.superclass.constructor.call(this, t); + this.hT = "04" + } + ; + at.extend(KJUR.asn1.DEROctetString, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERNull = function() { + KJUR.asn1.DERNull.superclass.constructor.call(this); + this.hT = "05"; + this.hTLV = "0500" + } + ; + at.extend(KJUR.asn1.DERNull, KJUR.asn1.ASN1Object); + KJUR.asn1.DERObjectIdentifier = function(L) { + var z = function(bW) { + var bX = bW.toString(16); + if (bX.length == 1) { + bX = "0" + bX + } + return bX + }; + var t = function(b1) { + var b0 = ""; + var bX = new bf(b1,10); + var bW = bX.toString(2); + var bY = 7 - bW.length % 7; + if (bY == 7) { + bY = 0 + } + var b3 = ""; + for (var bZ = 0; bZ < bY; bZ++) { + b3 += "0" + } + bW = b3 + bW; + for (var bZ = 0; bZ < bW.length - 1; bZ += 7) { + var b2 = bW.substr(bZ, 7); + if (bZ != bW.length - 7) { + b2 = "1" + b2 + } + b0 += z(parseInt(b2, 2)) + } + return b0 + }; + KJUR.asn1.DERObjectIdentifier.superclass.constructor.call(this); + this.hT = "06"; + this.setValueHex = function(bW) { + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = bW + } + ; + this.setValueOidString = function(bY) { + if (!bY.match(/^[0-9.]+$/)) { + throw "malformed oid string: " + bY + } + var bZ = ""; + var bW = bY.split("."); + var b0 = parseInt(bW[0]) * 40 + parseInt(bW[1]); + bZ += z(b0); + bW.splice(0, 2); + for (var bX = 0; bX < bW.length; bX++) { + bZ += t(bW[bX]) + } + this.hTLV = null; + this.isModified = true; + this.s = null; + this.hV = bZ + } + ; + this.setValueName = function(bX) { + if (typeof KJUR.asn1.x509.OID.name2oidList[bX] != "undefined") { + var bW = KJUR.asn1.x509.OID.name2oidList[bX]; + this.setValueOidString(bW) + } else { + throw "DERObjectIdentifier oidName undefined: " + bX + } + } + ; + this.getFreshValueHex = function() { + return this.hV + } + ; + if (typeof L != "undefined") { + if (typeof L.oid != "undefined") { + this.setValueOidString(L.oid) + } else { + if (typeof L.hex != "undefined") { + this.setValueHex(L.hex) + } else { + if (typeof L.name != "undefined") { + this.setValueName(L.name) + } + } + } + } + } + ; + at.extend(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object); + KJUR.asn1.DERUTF8String = function(t) { + KJUR.asn1.DERUTF8String.superclass.constructor.call(this, t); + this.hT = "0c" + } + ; + at.extend(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERNumericString = function(t) { + KJUR.asn1.DERNumericString.superclass.constructor.call(this, t); + this.hT = "12" + } + ; + at.extend(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERPrintableString = function(t) { + KJUR.asn1.DERPrintableString.superclass.constructor.call(this, t); + this.hT = "13" + } + ; + at.extend(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERTeletexString = function(t) { + KJUR.asn1.DERTeletexString.superclass.constructor.call(this, t); + this.hT = "14" + } + ; + at.extend(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERIA5String = function(t) { + KJUR.asn1.DERIA5String.superclass.constructor.call(this, t); + this.hT = "16" + } + ; + at.extend(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString); + KJUR.asn1.DERUTCTime = function(t) { + KJUR.asn1.DERUTCTime.superclass.constructor.call(this, t); + this.hT = "17"; + this.setByDate = function(z) { + this.hTLV = null; + this.isModified = true; + this.date = z; + this.s = this.formatDate(this.date, "utc"); + this.hV = stohex(this.s) + } + ; + if (typeof t != "undefined") { + if (typeof t.str != "undefined") { + this.setString(t.str) + } else { + if (typeof t.hex != "undefined") { + this.setStringHex(t.hex) + } else { + if (typeof t.date != "undefined") { + this.setByDate(t.date) + } + } + } + } + } + ; + at.extend(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime); + KJUR.asn1.DERGeneralizedTime = function(t) { + KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, t); + this.hT = "18"; + this.setByDate = function(z) { + this.hTLV = null; + this.isModified = true; + this.date = z; + this.s = this.formatDate(this.date, "gen"); + this.hV = stohex(this.s) + } + ; + if (typeof t != "undefined") { + if (typeof t.str != "undefined") { + this.setString(t.str) + } else { + if (typeof t.hex != "undefined") { + this.setStringHex(t.hex) + } else { + if (typeof t.date != "undefined") { + this.setByDate(t.date) + } + } + } + } + } + ; + at.extend(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime); + KJUR.asn1.DERSequence = function(t) { + KJUR.asn1.DERSequence.superclass.constructor.call(this, t); + this.hT = "30"; + this.getFreshValueHex = function() { + var L = ""; + for (var z = 0; z < this.asn1Array.length; z++) { + var bW = this.asn1Array[z]; + L += bW.getEncodedHex() + } + this.hV = L; + return this.hV + } + } + ; + at.extend(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured); + KJUR.asn1.DERSet = function(t) { + KJUR.asn1.DERSet.superclass.constructor.call(this, t); + this.hT = "31"; + this.getFreshValueHex = function() { + var z = new Array(); + for (var L = 0; L < this.asn1Array.length; L++) { + var bW = this.asn1Array[L]; + z.push(bW.getEncodedHex()) + } + z.sort(); + this.hV = z.join(""); + return this.hV + } + } + ; + at.extend(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured); + KJUR.asn1.DERTaggedObject = function(t) { + KJUR.asn1.DERTaggedObject.superclass.constructor.call(this); + this.hT = "a0"; + this.hV = ""; + this.isExplicit = true; + this.asn1Object = null; + this.setASN1Object = function(z, L, bW) { + this.hT = L; + this.isExplicit = z; + this.asn1Object = bW; + if (this.isExplicit) { + this.hV = this.asn1Object.getEncodedHex(); + this.hTLV = null; + this.isModified = true + } else { + this.hV = null; + this.hTLV = bW.getEncodedHex(); + this.hTLV = this.hTLV.replace(/^../, L); + this.isModified = false + } + } + ; + this.getFreshValueHex = function() { + return this.hV + } + ; + if (typeof t != "undefined") { + if (typeof t.tag != "undefined") { + this.hT = t.tag + } + if (typeof t.explicit != "undefined") { + this.isExplicit = t.explicit + } + if (typeof t.obj != "undefined") { + this.asn1Object = t.obj; + this.setASN1Object(this.isExplicit, this.hT, this.asn1Object) + } + } + } + ; + at.extend(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object); + (function(z) { + var t = {}, L; + t.decode = function(bW) { + var bY; + if (L === z) { + var bZ = "0123456789ABCDEF" + , b3 = " \f\n\r\t\u00A0\u2028\u2029"; + L = []; + for (bY = 0; bY < 16; ++bY) { + L[bZ.charAt(bY)] = bY + } + bZ = bZ.toLowerCase(); + for (bY = 10; bY < 16; ++bY) { + L[bZ.charAt(bY)] = bY + } + for (bY = 0; bY < b3.length; ++bY) { + L[b3.charAt(bY)] = -1 + } + } + var bX = [] + , b0 = 0 + , b2 = 0; + for (bY = 0; bY < bW.length; ++bY) { + var b1 = bW.charAt(bY); + if (b1 == "=") { + break + } + b1 = L[b1]; + if (b1 == -1) { + continue + } + if (b1 === z) { + throw "Illegal character at offset " + bY + } + b0 |= b1; + if (++b2 >= 2) { + bX[bX.length] = b0; + b0 = 0; + b2 = 0 + } else { + b0 <<= 4 + } + } + if (b2) { + throw "Hex encoding incomplete: 4 bits missing" + } + return bX + } + ; + window.Hex = t + } + )(); + (function(z) { + var t = {}, L; + t.decode = function(bW) { + var bZ; + if (L === z) { + var bY = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + , b3 = "= \f\n\r\t\u00A0\u2028\u2029"; + L = []; + for (bZ = 0; bZ < 64; ++bZ) { + L[bY.charAt(bZ)] = bZ + } + for (bZ = 0; bZ < b3.length; ++bZ) { + L[b3.charAt(bZ)] = -1 + } + } + var bX = []; + var b0 = 0 + , b2 = 0; + for (bZ = 0; bZ < bW.length; ++bZ) { + var b1 = bW.charAt(bZ); + if (b1 == "=") { + break + } + b1 = L[b1]; + if (b1 == -1) { + continue + } + if (b1 === z) { + throw "Illegal character at offset " + bZ + } + b0 |= b1; + if (++b2 >= 4) { + bX[bX.length] = (b0 >> 16); + bX[bX.length] = (b0 >> 8) & 255; + bX[bX.length] = b0 & 255; + b0 = 0; + b2 = 0 + } else { + b0 <<= 6 + } + } + switch (b2) { + case 1: + throw "Base64 encoding incomplete: at least 2 bits missing"; + case 2: + bX[bX.length] = (b0 >> 10); + break; + case 3: + bX[bX.length] = (b0 >> 16); + bX[bX.length] = (b0 >> 8) & 255; + break + } + return bX + } + ; + t.re = /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/; + t.unarmor = function(bX) { + var bW = t.re.exec(bX); + if (bW) { + if (bW[1]) { + bX = bW[1] + } else { + if (bW[2]) { + bX = bW[2] + } else { + throw "RegExp out of sync" + } + } + } + return t.decode(bX) + } + ; + window.Base64 = t + } + )(); + (function(bY) { + var z = 100 + , t = "\u2026" + , L = { + tag: function(b0, b1) { + var bZ = document.createElement(b0); + bZ.className = b1; + return bZ + }, + text: function(bZ) { + return document.createTextNode(bZ) + } + }; + function bX(bZ, b0) { + if (bZ instanceof bX) { + this.enc = bZ.enc; + this.pos = bZ.pos + } else { + this.enc = bZ; + this.pos = b0 + } + } + bX.prototype.get = function(bZ) { + if (bZ === bY) { + bZ = this.pos++ + } + if (bZ >= this.enc.length) { + throw "Requesting byte offset " + bZ + " on a stream of length " + this.enc.length + } + return this.enc[bZ] + } + ; + bX.prototype.hexDigits = "0123456789ABCDEF"; + bX.prototype.hexByte = function(bZ) { + return this.hexDigits.charAt((bZ >> 4) & 15) + this.hexDigits.charAt(bZ & 15) + } + ; + bX.prototype.hexDump = function(b3, bZ, b0) { + var b2 = ""; + for (var b1 = b3; b1 < bZ; ++b1) { + b2 += this.hexByte(this.get(b1)); + if (b0 !== true) { + switch (b1 & 15) { + case 7: + b2 += " "; + break; + case 15: + b2 += "\n"; + break; + default: + b2 += " " + } + } + } + return b2 + } + ; + bX.prototype.parseStringISO = function(b2, bZ) { + var b1 = ""; + for (var b0 = b2; b0 < bZ; ++b0) { + b1 += String.fromCharCode(this.get(b0)) + } + return b1 + } + ; + bX.prototype.parseStringUTF = function(b3, bZ) { + var b1 = ""; + for (var b0 = b3; b0 < bZ; ) { + var b2 = this.get(b0++); + if (b2 < 128) { + b1 += String.fromCharCode(b2) + } else { + if ((b2 > 191) && (b2 < 224)) { + b1 += String.fromCharCode(((b2 & 31) << 6) | (this.get(b0++) & 63)) + } else { + b1 += String.fromCharCode(((b2 & 15) << 12) | ((this.get(b0++) & 63) << 6) | (this.get(b0++) & 63)) + } + } + } + return b1 + } + ; + bX.prototype.parseStringBMP = function(b4, b0) { + var b3 = ""; + for (var b2 = b4; b2 < b0; b2 += 2) { + var bZ = this.get(b2); + var b1 = this.get(b2 + 1); + b3 += String.fromCharCode((bZ << 8) + b1) + } + return b3 + } + ; + bX.prototype.reTime = /^((?:1[89]|2\d)?\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/; + bX.prototype.parseTime = function(b2, b0) { + var b1 = this.parseStringISO(b2, b0) + , bZ = this.reTime.exec(b1); + if (!bZ) { + return "Unrecognized time: " + b1 + } + b1 = bZ[1] + "-" + bZ[2] + "-" + bZ[3] + " " + bZ[4]; + if (bZ[5]) { + b1 += ":" + bZ[5]; + if (bZ[6]) { + b1 += ":" + bZ[6]; + if (bZ[7]) { + b1 += "." + bZ[7] + } + } + } + if (bZ[8]) { + b1 += " UTC"; + if (bZ[8] != "Z") { + b1 += bZ[8]; + if (bZ[9]) { + b1 += ":" + bZ[9] + } + } + } + return b1 + } + ; + bX.prototype.parseInteger = function(b4, b0) { + var bZ = b0 - b4; + if (bZ > 4) { + bZ <<= 3; + var b2 = this.get(b4); + if (b2 === 0) { + bZ -= 8 + } else { + while (b2 < 128) { + b2 <<= 1; + --bZ + } + } + return "(" + bZ + " bit)" + } + var b3 = 0; + for (var b1 = b4; b1 < b0; ++b1) { + b3 = (b3 << 8) | this.get(b1) + } + return b3 + } + ; + bX.prototype.parseBitString = function(bZ, b0) { + var b4 = this.get(bZ) + , b2 = ((b0 - bZ - 1) << 3) - b4 + , b7 = "(" + b2 + " bit)"; + if (b2 <= 20) { + var b6 = b4; + b7 += " "; + for (var b3 = b0 - 1; b3 > bZ; --b3) { + var b5 = this.get(b3); + for (var b1 = b6; b1 < 8; ++b1) { + b7 += (b5 >> b1) & 1 ? "1" : "0" + } + b6 = 0 + } + } + return b7 + } + ; + bX.prototype.parseOctetString = function(b3, b0) { + var bZ = b0 - b3 + , b2 = "(" + bZ + " byte) "; + if (bZ > z) { + b0 = b3 + z + } + for (var b1 = b3; b1 < b0; ++b1) { + b2 += this.hexByte(this.get(b1)) + } + if (bZ > z) { + b2 += t + } + return b2 + } + ; + bX.prototype.parseOID = function(b6, b0) { + var b3 = "" + , b5 = 0 + , b4 = 0; + for (var b2 = b6; b2 < b0; ++b2) { + var b1 = this.get(b2); + b5 = (b5 << 7) | (b1 & 127); + b4 += 7; + if (!(b1 & 128)) { + if (b3 === "") { + var bZ = b5 < 80 ? b5 < 40 ? 0 : 1 : 2; + b3 = bZ + "." + (b5 - bZ * 40) + } else { + b3 += "." + ((b4 >= 31) ? "bigint" : b5) + } + b5 = b4 = 0 + } + } + return b3 + } + ; + function bW(b2, b3, b1, bZ, b0) { + this.stream = b2; + this.header = b3; + this.length = b1; + this.tag = bZ; + this.sub = b0 + } + bW.prototype.typeName = function() { + if (this.tag === bY) { + return "unknown" + } + var b1 = this.tag >> 6 + , bZ = (this.tag >> 5) & 1 + , b0 = this.tag & 31; + switch (b1) { + case 0: + switch (b0) { + case 0: + return "EOC"; + case 1: + return "BOOLEAN"; + case 2: + return "INTEGER"; + case 3: + return "BIT_STRING"; + case 4: + return "OCTET_STRING"; + case 5: + return "NULL"; + case 6: + return "OBJECT_IDENTIFIER"; + case 7: + return "ObjectDescriptor"; + case 8: + return "EXTERNAL"; + case 9: + return "REAL"; + case 10: + return "ENUMERATED"; + case 11: + return "EMBEDDED_PDV"; + case 12: + return "UTF8String"; + case 16: + return "SEQUENCE"; + case 17: + return "SET"; + case 18: + return "NumericString"; + case 19: + return "PrintableString"; + case 20: + return "TeletexString"; + case 21: + return "VideotexString"; + case 22: + return "IA5String"; + case 23: + return "UTCTime"; + case 24: + return "GeneralizedTime"; + case 25: + return "GraphicString"; + case 26: + return "VisibleString"; + case 27: + return "GeneralString"; + case 28: + return "UniversalString"; + case 30: + return "BMPString"; + default: + return "Universal_" + b0.toString(16) + } + case 1: + return "Application_" + b0.toString(16); + case 2: + return "[" + b0 + "]"; + case 3: + return "Private_" + b0.toString(16) + } + } + ; + bW.prototype.reSeemsASCII = /^[ -~]+$/; + bW.prototype.content = function() { + if (this.tag === bY) { + return null + } + var b3 = this.tag >> 6 + , b0 = this.tag & 31 + , b2 = this.posContent() + , bZ = Math.abs(this.length); + if (b3 !== 0) { + if (this.sub !== null) { + return "(" + this.sub.length + " elem)" + } + var b1 = this.stream.parseStringISO(b2, b2 + Math.min(bZ, z)); + if (this.reSeemsASCII.test(b1)) { + return b1.substring(0, 2 * z) + ((b1.length > 2 * z) ? t : "") + } else { + return this.stream.parseOctetString(b2, b2 + bZ) + } + } + switch (b0) { + case 1: + return (this.stream.get(b2) === 0) ? "false" : "true"; + case 2: + return this.stream.parseInteger(b2, b2 + bZ); + case 3: + return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseBitString(b2, b2 + bZ); + case 4: + return this.sub ? "(" + this.sub.length + " elem)" : this.stream.parseOctetString(b2, b2 + bZ); + case 6: + return this.stream.parseOID(b2, b2 + bZ); + case 16: + case 17: + return "(" + this.sub.length + " elem)"; + case 12: + return this.stream.parseStringUTF(b2, b2 + bZ); + case 18: + case 19: + case 20: + case 21: + case 22: + case 26: + return this.stream.parseStringISO(b2, b2 + bZ); + case 30: + return this.stream.parseStringBMP(b2, b2 + bZ); + case 23: + case 24: + return this.stream.parseTime(b2, b2 + bZ) + } + return null + } + ; + bW.prototype.toString = function() { + return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub === null) ? "null" : this.sub.length) + "]" + } + ; + bW.prototype.print = function(b0) { + if (b0 === bY) { + b0 = "" + } + document.writeln(b0 + this); + if (this.sub !== null) { + b0 += " "; + for (var b1 = 0, bZ = this.sub.length; b1 < bZ; ++b1) { + this.sub[b1].print(b0) + } + } + } + ; + bW.prototype.toPrettyString = function(b0) { + if (b0 === bY) { + b0 = "" + } + var b2 = b0 + this.typeName() + " @" + this.stream.pos; + if (this.length >= 0) { + b2 += "+" + } + b2 += this.length; + if (this.tag & 32) { + b2 += " (constructed)" + } else { + if (((this.tag == 3) || (this.tag == 4)) && (this.sub !== null)) { + b2 += " (encapsulates)" + } + } + b2 += "\n"; + if (this.sub !== null) { + b0 += " "; + for (var b1 = 0, bZ = this.sub.length; b1 < bZ; ++b1) { + b2 += this.sub[b1].toPrettyString(b0) + } + } + return b2 + } + ; + bW.prototype.toDOM = function() { + var b0 = L.tag("div", "node"); + b0.asn1 = this; + var b6 = L.tag("div", "head"); + var b8 = this.typeName().replace(/_/g, " "); + b6.innerHTML = b8; + var b4 = this.content(); + if (b4 !== null) { + b4 = String(b4).replace(/"; + b8 += "Length: " + this.header + "+"; + if (this.length >= 0) { + b8 += this.length + } else { + b8 += (-this.length) + " (undefined)" + } + if (this.tag & 32) { + b8 += "
(constructed)" + } else { + if (((this.tag == 3) || (this.tag == 4)) && (this.sub !== null)) { + b8 += "
(encapsulates)" + } + } + if (b4 !== null) { + b8 += "
Value:
" + b4 + ""; + if ((typeof oids === "object") && (this.tag == 6)) { + var b1 = oids[b4]; + if (b1) { + if (b1.d) { + b8 += "
" + b1.d + } + if (b1.c) { + b8 += "
" + b1.c + } + if (b1.w) { + b8 += "
(warning!)" + } + } + } + } + b7.innerHTML = b8; + b0.appendChild(b7); + var bZ = L.tag("div", "sub"); + if (this.sub !== null) { + for (var b2 = 0, b5 = this.sub.length; b2 < b5; ++b2) { + bZ.appendChild(this.sub[b2].toDOM()) + } + } + b0.appendChild(bZ); + b6.onclick = function() { + b0.className = (b0.className == "node collapsed") ? "node" : "node collapsed" + } + ; + return b0 + } + ; + bW.prototype.posStart = function() { + return this.stream.pos + } + ; + bW.prototype.posContent = function() { + return this.stream.pos + this.header + } + ; + bW.prototype.posEnd = function() { + return this.stream.pos + this.header + Math.abs(this.length) + } + ; + bW.prototype.fakeHover = function(bZ) { + this.node.className += " hover"; + if (bZ) { + this.head.className += " hover" + } + } + ; + bW.prototype.fakeOut = function(b0) { + var bZ = / ?hover/; + this.node.className = this.node.className.replace(bZ, ""); + if (b0) { + this.head.className = this.head.className.replace(bZ, "") + } + } + ; + bW.prototype.toHexDOM_sub = function(b2, b1, b3, b4, bZ) { + if (b4 >= bZ) { + return + } + var b0 = L.tag("span", b1); + b0.appendChild(L.text(b3.hexDump(b4, bZ))); + b2.appendChild(b0) + } + ; + bW.prototype.toHexDOM = function(b0) { + var b3 = L.tag("span", "hex"); + if (b0 === bY) { + b0 = b3 + } + this.head.hexNode = b3; + this.head.onmouseover = function() { + this.hexNode.className = "hexCurrent" + } + ; + this.head.onmouseout = function() { + this.hexNode.className = "hex" + } + ; + b3.asn1 = this; + b3.onmouseover = function() { + var b5 = !b0.selected; + if (b5) { + b0.selected = this.asn1; + this.className = "hexCurrent" + } + this.asn1.fakeHover(b5) + } + ; + b3.onmouseout = function() { + var b5 = (b0.selected == this.asn1); + this.asn1.fakeOut(b5); + if (b5) { + b0.selected = null; + this.className = "hex" + } + } + ; + this.toHexDOM_sub(b3, "tag", this.stream, this.posStart(), this.posStart() + 1); + this.toHexDOM_sub(b3, (this.length >= 0) ? "dlen" : "ulen", this.stream, this.posStart() + 1, this.posContent()); + if (this.sub === null) { + b3.appendChild(L.text(this.stream.hexDump(this.posContent(), this.posEnd()))) + } else { + if (this.sub.length > 0) { + var b4 = this.sub[0]; + var b2 = this.sub[this.sub.length - 1]; + this.toHexDOM_sub(b3, "intro", this.stream, this.posContent(), b4.posStart()); + for (var b1 = 0, bZ = this.sub.length; b1 < bZ; ++b1) { + b3.appendChild(this.sub[b1].toHexDOM(b0)) + } + this.toHexDOM_sub(b3, "outro", this.stream, b2.posEnd(), this.posEnd()) + } + } + return b3 + } + ; + bW.prototype.toHexString = function(bZ) { + return this.stream.hexDump(this.posStart(), this.posEnd(), true) + } + ; + bW.decodeLength = function(b2) { + var b0 = b2.get() + , bZ = b0 & 127; + if (bZ == b0) { + return bZ + } + if (bZ > 3) { + throw "Length over 24 bits not supported at position " + (b2.pos - 1) + } + if (bZ === 0) { + return -1 + } + b0 = 0; + for (var b1 = 0; b1 < bZ; ++b1) { + b0 = (b0 << 8) | b2.get() + } + return b0 + } + ; + bW.hasContent = function(b0, bZ, b5) { + if (b0 & 32) { + return true + } + if ((b0 < 3) || (b0 > 4)) { + return false + } + var b4 = new bX(b5); + if (b0 == 3) { + b4.get() + } + var b3 = b4.get(); + if ((b3 >> 6) & 1) { + return false + } + try { + var b2 = bW.decodeLength(b4); + return ((b4.pos - b5.pos) + b2 == bZ) + } catch (b1) { + return false + } + } + ; + bW.decode = function(b6) { + if (!(b6 instanceof bX)) { + b6 = new bX(b6,0) + } + var b5 = new bX(b6) + , b8 = b6.get() + , b3 = bW.decodeLength(b6) + , b2 = b6.pos - b5.pos + , bZ = null; + if (bW.hasContent(b8, b3, b6)) { + var b0 = b6.pos; + if (b8 == 3) { + b6.get() + } + bZ = []; + if (b3 >= 0) { + var b1 = b0 + b3; + while (b6.pos < b1) { + bZ[bZ.length] = bW.decode(b6) + } + if (b6.pos != b1) { + throw "Content size is not correct for container starting at offset " + b0 + } + } else { + try { + for (; ; ) { + var b7 = bW.decode(b6); + if (b7.tag === 0) { + break + } + bZ[bZ.length] = b7 + } + b3 = b0 - b6.pos + } catch (b4) { + throw "Exception while decoding undefined length content: " + b4 + } + } + } else { + b6.pos += b3 + } + return new bW(b5,b2,b3,b8,bZ) + } + ; + bW.test = function() { + var b4 = [{ + value: [39], + expected: 39 + }, { + value: [129, 201], + expected: 201 + }, { + value: [131, 254, 220, 186], + expected: 16702650 + }]; + for (var b1 = 0, bZ = b4.length; b1 < bZ; ++b1) { + var b3 = 0 + , b2 = new bX(b4[b1].value,0) + , b0 = bW.decodeLength(b2); + if (b0 != b4[b1].expected) { + document.write("In test[" + b1 + "] expected " + b4[b1].expected + " got " + b0 + "\n") + } + } + } + ; + window.ASN1 = bW + } + )(); + ASN1.prototype.getHexStringValue = function() { + var t = this.toHexString(); + var L = this.header * 2; + var z = this.length * 2; + return t.substr(L, z) + } + ; + A.prototype.parseKey = function(b1) { + try { + var b6 = 0; + var bW = 0; + var t = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/; + var b5 = t.test(b1) ? Hex.decode(b1) : Base64.unarmor(b1); + var bX = ASN1.decode(b5); + if (bX.sub.length === 3) { + bX = bX.sub[2].sub[0] + } + if (bX.sub.length === 9) { + b6 = bX.sub[1].getHexStringValue(); + this.n = w(b6, 16); + bW = bX.sub[2].getHexStringValue(); + this.e = parseInt(bW, 16); + var z = bX.sub[3].getHexStringValue(); + this.d = w(z, 16); + var b0 = bX.sub[4].getHexStringValue(); + this.p = w(b0, 16); + var bZ = bX.sub[5].getHexStringValue(); + this.q = w(bZ, 16); + var b3 = bX.sub[6].getHexStringValue(); + this.dmp1 = w(b3, 16); + var b2 = bX.sub[7].getHexStringValue(); + this.dmq1 = w(b2, 16); + var L = bX.sub[8].getHexStringValue(); + this.coeff = w(L, 16) + } else { + if (bX.sub.length === 2) { + var b7 = bX.sub[1]; + var bY = b7.sub[0]; + b6 = bY.sub[0].getHexStringValue(); + this.n = w(b6, 16); + bW = bY.sub[1].getHexStringValue(); + this.e = parseInt(bW, 16) + } else { + return false + } + } + return true + } catch (b4) { + return false + } + } + ; + A.prototype.getPrivateBaseKey = function() { + var z = { + array: [new KJUR.asn1.DERInteger({ + "int": 0 + }), new KJUR.asn1.DERInteger({ + bigint: this.n + }), new KJUR.asn1.DERInteger({ + "int": this.e + }), new KJUR.asn1.DERInteger({ + bigint: this.d + }), new KJUR.asn1.DERInteger({ + bigint: this.p + }), new KJUR.asn1.DERInteger({ + bigint: this.q + }), new KJUR.asn1.DERInteger({ + bigint: this.dmp1 + }), new KJUR.asn1.DERInteger({ + bigint: this.dmq1 + }), new KJUR.asn1.DERInteger({ + bigint: this.coeff + })] + }; + var t = new KJUR.asn1.DERSequence(z); + return t.getEncodedHex() + } + ; + A.prototype.getPrivateBaseKeyB64 = function() { + return ae(this.getPrivateBaseKey()) + } + ; + A.prototype.getPublicBaseKey = function() { + var L = { + array: [new KJUR.asn1.DERObjectIdentifier({ + oid: "1.2.840.113549.1.1.1" + }), new KJUR.asn1.DERNull()] + }; + var t = new KJUR.asn1.DERSequence(L); + L = { + array: [new KJUR.asn1.DERInteger({ + bigint: this.n + }), new KJUR.asn1.DERInteger({ + "int": this.e + })] + }; + var bX = new KJUR.asn1.DERSequence(L); + L = { + hex: "00" + bX.getEncodedHex() + }; + var bW = new KJUR.asn1.DERBitString(L); + L = { + array: [t, bW] + }; + var z = new KJUR.asn1.DERSequence(L); + return z.getEncodedHex() + } + ; + A.prototype.getPublicBaseKeyB64 = function() { + return ae(this.getPublicBaseKey()) + } + ; + A.prototype.wordwrap = function(L, t) { + t = t || 64; + if (!L) { + return L + } + var z = "(.{1," + t + "})( +|$\n?)|(.{1," + t + "})"; + return L.match(RegExp(z, "g")).join("\n") + } + ; + A.prototype.getPrivateKey = function() { + var t = "-----BEGIN RSA PRIVATE KEY-----\n"; + t += this.wordwrap(this.getPrivateBaseKeyB64()) + "\n"; + t += "-----END RSA PRIVATE KEY-----"; + return t + } + ; + A.prototype.getPublicKey = function() { + var t = "-----BEGIN PUBLIC KEY-----\n"; + t += this.wordwrap(this.getPublicBaseKeyB64()) + "\n"; + t += "-----END PUBLIC KEY-----"; + return t + } + ; + A.prototype.hasPublicKeyProperty = function(t) { + t = t || {}; + return (t.hasOwnProperty("n") && t.hasOwnProperty("e")) + } + ; + A.prototype.hasPrivateKeyProperty = function(t) { + t = t || {}; + return (t.hasOwnProperty("n") && t.hasOwnProperty("e") && t.hasOwnProperty("d") && t.hasOwnProperty("p") && t.hasOwnProperty("q") && t.hasOwnProperty("dmp1") && t.hasOwnProperty("dmq1") && t.hasOwnProperty("coeff")) + } + ; + A.prototype.parsePropertiesFrom = function(t) { + this.n = t.n; + this.e = t.e; + if (t.hasOwnProperty("d")) { + this.d = t.d; + this.p = t.p; + this.q = t.q; + this.dmp1 = t.dmp1; + this.dmq1 = t.dmq1; + this.coeff = t.coeff + } + } + ; + var bx = function(t) { + A.call(this); + if (t) { + if (typeof t === "string") { + this.parseKey(t) + } else { + if (this.hasPrivateKeyProperty(t) || this.hasPublicKeyProperty(t)) { + this.parsePropertiesFrom(t) + } + } + } + }; + bx.prototype = new A(); + bx.prototype.constructor = bx; + var a3 = function(t) { + t = t || {}; + this.default_key_size = parseInt(t.default_key_size) || 1024; + this.default_public_exponent = t.default_public_exponent || "010001"; + this.log = t.log || false; + this.key = null + }; + a3.prototype.setKey = function(t) { + if (this.log && this.key) { + console.warn("A key was already set, overriding existing.") + } + this.key = new bx(t) + } + ; + a3.prototype.setPrivateKey = function(t) { + this.setKey(t) + } + ; + a3.prototype.setPublicKey = function(t) { + this.setKey(t) + } + ; + a3.prototype.decrypt = function(t) { + try { + return this.getKey().decrypt(aW(t)) + } catch (z) { + return false + } + } + ; + a3.prototype.encrypt = function(t) { + try { + return ae(this.getKey().encrypt(t)) + } catch (z) { + return false + } + } + ; + a3.prototype.getKey = function(t) { + if (!this.key) { + this.key = new bx(); + if (t && {}.toString.call(t) === "[object Function]") { + this.key.generateAsync(this.default_key_size, this.default_public_exponent, t); + return + } + this.key.generate(this.default_key_size, this.default_public_exponent) + } + return this.key + } + ; + a3.prototype.getPrivateKey = function() { + return this.getKey().getPrivateKey() + } + ; + a3.prototype.getPrivateKeyB64 = function() { + return this.getKey().getPrivateBaseKeyB64() + } + ; + a3.prototype.getPublicKey = function() { + return this.getKey().getPublicKey() + } + ; + a3.prototype.getPublicKeyB64 = function() { + return this.getKey().getPublicBaseKeyB64() + } + ; + a3.version = "2.3.1"; + ap.JSEncrypt = a3 +}); + +function encrypt_pwd(pubKey, pwd){ + var encrypt = new window.JSEncrypt(); + encrypt.setPublicKey(pubKey); + return encrypt.encrypt(pwd); +} + +// console.log(encrypt_pwd('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB', '11111')) \ No newline at end of file diff --git a/static/js/track_encrypt.js b/static/js/track_encrypt.js new file mode 100644 index 0000000..ad66178 --- /dev/null +++ b/static/js/track_encrypt.js @@ -0,0 +1,1371 @@ +var JDJRValidate = function(a, b) { + this['params'] = a; + this['callback'] = b; + this['init'](); +}; +JDJRValidate['prototype'] = { + 'init': function() { + this['lang'] = this['params'] == undefined ? null : this['params']['lang']; + this['slideTimer'] = null; + this['mousePos'] = []; + this['clickProductData'] = []; + this['disX'] = 0x0; + this['passValidate'] = ![]; + this['validateID'] = null; + this['isDraging'] = ![]; + this['warp'] = this['getByID'](this['params']['id']); + this['clickResult'] = ![]; + this['i18nParams'] = this['i18n'](this['lang']); + this['protocol'] = this['params']['protocol'] ? this['params']['protocol'] + ':' : ''; + this['apiServer'] = this['protocol'] + (this['lang'] && this['lang'] != 'zh_CN' ? '//iv.joybuy.com' : '//iv.jd.com'); + this['bottomSlide'] = this['params']['bottomSlide'] !== ![]; + this['initHtml'](); + this['getInstance'](); + }, + 'i18n': function(a) { + var b = {}; + b['zh_CN'] = { + 'default-placeholder': '向右滑动完成拼图', + 'default-title': '完成拼图验证', + 'default-refresh': '换一张', + 'default-click': '点击完成验证', + 'default-slide-success': '拼接成功', + 'default-suspend-success': '验证成功', + 'default-action-block': '操作过于频繁', + 'default-slide-fail': '没有对齐,请再来一次' + }; + b['en_US'] = { + 'default-placeholder': 'Swipe\x20to\x20complete\x20puzzle', + 'default-title': 'Complete\x20the\x20image', + 'default-refresh': 'Refresh', + 'default-click': 'Confirm\x20registration', + 'default-slide-success': 'Verification\x20complete', + 'default-suspend-success': 'Verification\x20complete', + 'default-action-block': 'You\x20have\x20performed\x20this\x20action\x20too\x20many\x20times.', + 'default-slide-fail': 'Incorrect.\x20Please\x20try\x20again.' + }; + b['ru_RU'] = { + 'default-placeholder': 'Проведите\x20вправо', + 'default-title': 'Завершите\x20пазл', + 'default-refresh': 'Обновить', + 'default-click': 'Подтверждение\x20регистрации', + 'default-slide-success': 'Проверка\x20успешно', + 'default-suspend-success': 'Проверка\x20успешно', + 'default-action-block': 'Превышено\x20допустимое\x20количество\x20попыток.', + 'default-slide-fail': 'Ошибка.\x20Попробуйте\x20еще\x20раз.' + }; + b['es_ES'] = { + 'default-placeholder': 'completar\x20la\x20pieza', + 'default-title': 'Completar\x20la\x20imagen', + 'default-refresh': 'Actualizar', + 'default-click': 'Haga\x20clic\x20para\x20la\x20verificación', + 'default-slide-success': 'Verificado\x20con\x20éxito', + 'default-suspend-success': 'Verificado\x20con\x20éxito', + 'default-action-block': 'Has\x20realizado\x20esta\x20acción\x20muchas\x20veces.', + 'default-slide-fail': 'Incorrecto.\x20Inténtalo\x20de\x20nuevo.' + }; + b['th_TH'] = { + 'default-placeholder': 'เลื่อนชิ้นส่วนจิ๊กซอว์ให้เข้าที่', + 'default-title': 'เล่มเกมเพื่อลงทะเบียน', + 'default-refresh': 'เปลี่ยนรูป', + 'default-click': 'ถัดไป', + 'default-slide-success': 'ยินดีด้วย!', + 'default-suspend-success': 'ยินดีด้วย!', + 'default-action-block': 'You\x20have\x20performed\x20this\x20action\x20too\x20many\x20times.', + 'default-slide-fail': 'Incorrect.\x20Please\x20try\x20again.' + }; + b['en_TH'] = { + 'default-placeholder': 'Swipe\x20to\x20complete\x20puzzle', + 'default-title': 'Complete\x20the\x20puzzle', + 'default-refresh': 'Change', + 'default-click': 'Next', + 'default-slide-success': 'Congratulations!', + 'default-suspend-success': 'Congratulations!', + 'default-action-block': 'You\x20have\x20performed\x20this\x20action\x20too\x20many\x20times.', + 'default-slide-fail': 'Incorrect.\x20Please\x20try\x20again.' + }; + b['id_ID'] = { + 'default-placeholder': 'Geser\x20untuk\x20teka-teki', + 'default-title': 'Lengkapi\x20gambarnya', + 'default-refresh': 'Refresh', + 'default-click': 'Klik\x20verifikasi', + 'default-slide-success': 'Verifikasi\x20selesai', + 'default-suspend-success': 'Verifikasi\x20selesai', + 'default-action-block': 'You\x20have\x20performed\x20this\x20action\x20too\x20many\x20times.', + 'default-slide-fail': 'Incorrect.\x20Please\x20try\x20again.' + }; + b['zh_TW'] = { + 'default-placeholder': '向右滑動完成拼圖', + 'default-title': '完成拼圖驗證', + 'default-refresh': '換一張', + 'default-click': '點擊完成驗證', + 'default-slide-success': '拼接成功', + 'default-suspend-success': '驗證成功', + 'default-action-block': '操作過於頻繁', + 'default-slide-fail': '沒有對齊,請再來一次' + }; + if (b['hasOwnProperty'](a)) { + return b[a]; + } else { + return b['zh_CN']; + } + }, + 'getByID': function(a) { + return document['getElementById'](a); + }, + 'initGetElementsByName': function(a) { + a['getElementsByClassName'] = function(b) { + var c = (a || document)['getElementsByTagName']('*'); + var e = new Array(); + for (var f = 0x0; f < c['length']; f++) { + var g = c[f]; + var h = g['className']['split']('\x20'); + for (var k = 0x0; k < h['length']; k++) { + if (h[k] == b) { + e['push'](g); + break; + } + } + } + return e; + } + ; + }, + 'initHtml': function() { + var a = this; + var b = 'JDJRV-' + (this['params']['product'] ? this['params']['product'] : 'embed'); + var c = this['params']['width'] ? this['params']['width'] : '100%'; + var d = this['params']['placeholder'] ? this['params']['placeholder'] : a['i18nParams']['default-placeholder']; + var e = this['params']['refreshRight'] ? this['params']['refreshRight'] : '0px'; + var f = a['lang'] && a['lang'] != 'zh_CN' ? 'JDJRV-joybuy' : ''; + var g = this['protocol'] + (a['lang'] && a['lang'] != 'zh_CN' ? '//static.joybuy.com/risk-cdn/iv/images/wait.gif' : '//ivs.jd.com/slide/i/wait.gif'); + var i = navigator['userAgent']['indexOf']('compatible') > -0x1 && navigator['userAgent']['indexOf']('MSIE') > -0x1; + var j = ''; + if (this['params']['product'] == 'bind' || this['params']['product'] == 'popup' || this['params']['product'] == 'click-popup' || this['params']['product'] == 'e-pic-popup') { + j += ''; + e = '15px'; + } + if (this['params']['product'] == 'click-suspend') { + j += ''; + e = '15px'; + } + if (this['params']['product'] == 'click-bind-suspend') { + var m = this['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var p = this['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + c = c['indexOf']('%') > 0x0 ? c['replace']('%', '') * 0.01 * this['clickWarp']['offsetWidth'] + 'px' : c; + if (c['indexOf']('px') > 0x0) { + p -= 0x8c / (0x168 / (c['replace']('px', '') - 0x18)) + 0x78; + } + j += '' + (typeof this['params']['top'] != 'undefined' ? '' : ''); + e = '15px'; + } + if (this['params']['product'] == 'i-dsc') { + var m = this['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var p = this['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + c = c['indexOf']('%') > 0x0 ? c['replace']('%', '') * 0.01 * this['clickWarp']['offsetWidth'] + 'px' : c; + if (c['indexOf']('px') > 0x0) { + p -= 0x8c / (0x168 / (c['replace']('px', '') - 0x18)) + 0x78; + } + j += '' + (typeof this['params']['top'] != 'undefined' ? '' : ''); + e = '15px'; + } else if (this['params']['product'] == 'i-pic-click') { + var m = this['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var p = this['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + c = c['indexOf']('%') > 0x0 ? c['replace']('%', '') * 0.01 * this['clickWarp']['offsetWidth'] + 'px' : c; + if (c['indexOf']('px') > 0x0) { + p -= 0x14d / (0x280 / (c['replace']('px', '') - 0x18)) + 0x46; + } + j += '' + (typeof this['params']['top'] != 'undefined' ? '' : ''); + e = '15px'; + } + if (this['params']['product'] != 'click' && this['params']['product'] != 'click-bind' && this['params']['product'] != 'suspend' && this['params']['product'] != 'bind-suspend' && this['params']['product'] != 'dsc' && this['params']['product'] != 'i-dsc' && this['params']['product'] != 'pic-click' && this['params']['product'] != 'i-pic-click' && this['params']['product'] != 'e-pic-popup') { + var q = c; + if (this['params']['product'] == 'bind' || this['params']['product'] == 'popup' || this['params']['product'] == 'click-popup' || this['params']['product'] == 'click-suspend' || this['params']['product'] == 'click-bind-suspend') { + q = 'auto'; + } + j += '' + '' + '' + a['i18nParams']['default-title'] + '' + a['i18nParams']['default-refresh'] + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + d + '' + '' + '' + '' + '' + ''; + } + if (this['params']['product'] == 'dsc' || this['params']['product'] == 'i-dsc') { + if (this['params']['product'] == 'i-dsc') + c = '100%'; + j += '' + '' + '' + a['i18nParams']['default-refresh'] + '
' + '' + '' + '' + '' + '' + ''; + } + if (this['params']['product'] == 'pic-click' || this['params']['product'] == 'i-pic-click' || this['params']['product'] == 'e-pic-popup') { + if (this['params']['product'] == 'i-pic-click') + c = '100%'; + j += '' + '' + '' + a['i18nParams']['default-refresh'] + '
' + '' + '' + '' + '1' + '2' + '3' + '4' + '5' + '6' + '7' + '8' + '9' + '' + '' + '' + '' + ''; + } + if (this['params']['product'] == 'bind' || this['params']['product'] == 'popup' || this['params']['product'] == 'click-popup' || this['params']['product'] == 'e-pic-popup') { + j += ''; + var s = document['createElement']('div'); + s['innerHTML'] = j; + var u = document['createDocumentFragment'](); + while (s['firstChild']) { + u['appendChild'](s['firstChild']); + } + var w = this['getByID']('JDJRV-wrap-' + this['params']['id']); + if (w) { + document['body']['removeChild'](w); + } + document['body']['appendChild'](u); + this['warp'] = this['getByID']('JDJRV-wrap-' + this['params']['id']); + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + this['closeBtn'] = this['warp']['getElementsByClassName']('JDJRV-close')[0x0]; + this['popContent'] = this['warp']['getElementsByClassName']('JDJRV-pop-content')[0x0]; + if (this['params']['product'] == 'popup') { + this['clickWarp'] = this['getByID'](this['params']['id']); + var B = '' + a['i18nParams']['default-click'] + ''; + this['clickWarp']['innerHTML'] = B; + if (!this['clickWarp']['getElementsByClassName']) + this['initGetElementsByName'](this['clickWarp']); + this['clickContent'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-warp')[0x0]; + this['clickImg'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-img')[0x0]; + this['clickText'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-text')[0x0]; + } + } else if (this['params']['product'] == 'click') { + this['clickWarp'] = this['getByID'](this['params']['id']); + var B = '' + a['i18nParams']['default-click'] + ''; + this['clickWarp']['innerHTML'] = B; + if (!this['clickWarp']['getElementsByClassName']) + this['initGetElementsByName'](this['clickWarp']); + this['clickContent'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-warp')[0x0]; + this['clickImg'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-img')[0x0]; + this['clickText'] = this['clickWarp']['getElementsByClassName']('JDJRV-click-text')[0x0]; + } else if (this['params']['product'] == 'click-bind' || this['params']['product'] == 'bind-suspend') { + this['clickWarp'] = this['getByID'](this['params']['id']); + if (!this['clickWarp']['getElementsByClassName']) + this['initGetElementsByName'](this['clickWarp']); + } else if (this['params']['product'] == 'suspend') { + this['warp'] = this['getByID'](this['params']['id']); + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + var C = this['params']['height'] || '40px'; + var B = '' + a['i18nParams']['default-click'] + ''; + this['warp']['innerHTML'] = B; + this['clickWarp'] = this['warp']['getElementsByClassName']('JDJRV-suspend-click')[0x0]; + this['clickContent'] = this['warp']['getElementsByClassName']('JDJRV-suspend-click')[0x0]; + this['clickText'] = this['warp']['getElementsByClassName']('JDJRV-suspend-click')[0x0]; + this['suspendSlideWarp'] = this['warp']['getElementsByClassName']('JDJRV-suspend-slide')[0x0]; + this['suspendSlideWarp']['style']['bottom'] = this['clickWarp']['offsetHeight'] + 0x6 + 'px'; + } else if (this['params']['product'] == 'click-suspend') { + j += ''; + this['suspendSlideWarp']['innerHTML'] = j; + this['suspendSlideWarp']['style']['display'] = 'block'; + this['closeBtn'] = this['warp']['getElementsByClassName']('JDJRV-close')[0x0]; + } else if (this['params']['product'] == 'click-bind-suspend' || this['params']['product'] == 'i-dsc' || this['params']['product'] == 'i-pic-click') { + j += ''; + var s = document['createElement']('div'); + s['innerHTML'] = j; + var u = document['createDocumentFragment'](); + while (s['firstChild']) { + u['appendChild'](s['firstChild']); + } + var w = this['getByID']('JDJRV-wrap-' + this['params']['id']); + if (w) { + document['body']['removeChild'](w); + } + document['body']['appendChild'](u); + this['warp'] = this['getByID']('JDJRV-wrap-' + this['params']['id']); + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + this['closeBtn'] = this['warp']['getElementsByClassName']('JDJRV-close')[0x0]; + if (this['params']['product'] == 'click-bind-suspend' || this['params']['product'] == 'i-dsc') { + this['suspendSlideWarp'] = this['warp']['getElementsByClassName']('JDJRV-suspend-slide')[0x0]; + } else if (this['params']['product'] == 'i-pic-click') { + this['suspendPicClickWarp'] = this['warp']['getElementsByClassName']('JDJRV-suspend-pic-click')[0x0]; + } + } else { + this['warp']['innerHTML'] = j; + } + if (this['params']['product'] != 'click' && this['params']['product'] != 'click-bind' && this['params']['product'] != 'suspend' && this['params']['product'] != 'bind-suspend' && this['params']['product'] != 'dsc' && this['params']['product'] != 'i-dsc' && this['params']['product'] != 'pic-click' && this['params']['product'] != 'i-pic-click' && this['params']['product'] != 'e-pic-popup') { + if (this['params']['product'] == 'click-popup' || this['params']['product'] == 'click-suspend' || this['params']['product'] == 'click-bind-suspend') { + a['initSlideWrap'](); + } else { + setTimeout(function() { + a['initSlideWrap'](); + }, 0x32); + } + } else if (this['params']['product'] == 'dsc' || this['params']['product'] == 'i-dsc') { + setTimeout(function() { + a['initDscWrap'](); + }, 0x32); + } else if (this['params']['product'] == 'pic-click' || this['params']['product'] == 'i-pic-click' || this['params']['product'] == 'e-pic-popup') { + setTimeout(function() { + a['initPicClickWrap'](); + }, 0x32); + } else { + setTimeout(function() { + a['initClickWrap'](); + }, 0x32); + } + }, + 'initSlideWrap': function() { + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + this['slideWrap'] = this['warp']['getElementsByClassName']('JDJRV-slide')[0x0]; + this['width'] = this['slideWrap']['offsetWidth']; + this['imgRatio'] = this['slideWrap']['offsetWidth'] ? 0x168 / this['slideWrap']['offsetWidth'] : 0x1; + this['slideBar'] = this['warp']['getElementsByClassName']('JDJRV-slide-bg')[0x0]; + this['slideBtn'] = this['warp']['getElementsByClassName']('JDJRV-slide-btn')[0x0]; + this['slideGreenBar'] = this['warp']['getElementsByClassName']('JDJRV-slide-bar')[0x0]; + this['slideGreenBarCenter'] = this['warp']['getElementsByClassName']('JDJRV-slide-bar-center')[0x0]; + this['slideSmallImg'] = this['warp']['getElementsByClassName']('JDJRV-smallimg')[0x0]; + this['slideBigImg'] = this['warp']['getElementsByClassName']('JDJRV-bigimg')[0x0]; + this['slideImgWrap'] = this['warp']['getElementsByClassName']('JDJRV-img-panel')[0x0]; + this['slideCenter'] = this['warp']['getElementsByClassName']('JDJRV-slide-center')[0x0]; + if (!this['slideImgWrap']['getElementsByClassName']) + this['initGetElementsByName'](this['slideImgWrap']); + this['refreshBtn'] = this['slideImgWrap']['getElementsByClassName']('JDJRV-img-refresh')[0x0]; + this['slideText'] = this['warp']['getElementsByClassName']('JDJRV-slide-text')[0x0]; + this['slideBigImg']['style']['height'] = 0x8c / (0x168 / this['slideWrap']['offsetWidth']) + 'px'; + this['getValidateImage'](); + this['bindEvent'](); + }, + 'initClickWrap': function() { + var a = this; + a['getValidateImage'](); + if (a['params']['eventListener'] == ![] || a['params']['eventListener'] == 'false') { + a['verify'] = c; + } else { + a['clickWarp']['onclick'] = c; + if (a['params']['formId']) { + document['getElementById'](a['params']['formId'])['onsubmit'] = function() { + c(); + return ![]; + } + ; + } + } + document['onmousemove'] = b; + document['ontouchmove'] = b; + function b(d) { + if (a['params']['product'] == 'click' || a['params']['product'] == 'click-bind' || a['params']['product'] == 'suspend' || a['params']['product'] == 'bind-suspend') { + var e = d || event; + if (e['touches']) + e = e['touches'][0x0]; + a['clickProductData']['push']([e['clientX']['toFixed'](0x0), e['clientY']['toFixed'](0x0), new Date()['getTime']()]); + } + } + function c() { + if (!a['clickResult']) { + if (a['params']['product'] == 'click-popup' || a['params']['product'] == 'e-pic-popup') { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } else if (a['params']['product'] == 'click-suspend') { + a['suspendSlideWarp']['style']['display'] = 'block'; + a['resetSize'](); + } else if (a['params']['product'] == 'click-bind-suspend') { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } else if (a['params']['product'] == 'i-dsc') { + a['warp']['style']['display'] = 'block'; + } else if (a['params']['product'] == 'i-pic-click') { + a['warp']['style']['display'] = 'block'; + } else { + if (a['validateID']) { + a['submit'](); + } + } + } + } + }, + 'initDscWrap': function() { + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + this['dscWrap'] = this['warp']['getElementsByClassName']('JDJRV-dsc')[0x0]; + this['width'] = this['dscWrap']['offsetWidth']; + this['imgRatio'] = this['dscWrap']['offsetWidth'] ? 0x168 / this['dscWrap']['offsetWidth'] : 0x1; + this['dscBigImg'] = this['warp']['getElementsByClassName']('JDJRV-bigimg')[0x0]; + this['dscResult'] = this['warp']['getElementsByClassName']('JDJRV-dsc-result')[0x0]; + this['dscWrapImgWrap'] = this['warp']['getElementsByClassName']('JDJRV-img-panel')[0x0]; + if (!this['dscWrapImgWrap']['getElementsByClassName']) + this['initGetElementsByName'](this['dscWrapImgWrap']); + this['refreshBtn'] = this['dscWrapImgWrap']['getElementsByClassName']('JDJRV-question-refresh')[0x0]; + this['dscBigImg']['style']['height'] = 0xbe / (0x168 / this['dscWrap']['offsetWidth']) + 'px'; + this['questionLable'] = this['warp']['getElementsByClassName']('JDJRV-question-lable')[0x0]; + this['getValidateImage'](); + this['bindDscEvent'](); + }, + 'initPicClickWrap': function() { + if (!this['warp']['getElementsByClassName']) + this['initGetElementsByName'](this['warp']); + this['picClickWrap'] = this['warp']['getElementsByClassName']('JDJRV-pic-click')[0x0]; + this['width'] = this['picClickWrap']['offsetWidth']; + this['imgRatio'] = this['picClickWrap']['offsetWidth'] ? 0x280 / this['picClickWrap']['offsetWidth'] : 0x1; + this['picClickBigImg'] = this['warp']['getElementsByClassName']('JDJRV-bigimg')[0x0]; + this['picClickSmallImg'] = this['warp']['getElementsByClassName']('JDJRV-smallimg')[0x0]; + this['picClickResult'] = this['warp']['getElementsByClassName']('JDJRV-pic-click-result')[0x0]; + this['picClickImgWrap'] = this['warp']['getElementsByClassName']('JDJRV-img-panel')[0x0]; + if (!this['picClickImgWrap']['getElementsByClassName']) + this['initGetElementsByName'](this['picClickImgWrap']); + this['refreshBtn'] = this['picClickImgWrap']['getElementsByClassName']('JDJRV-question-refresh')[0x0]; + this['picClickBigImg']['style']['height'] = 0x14d / (0x280 / this['picClickWrap']['offsetWidth']) + 'px'; + this['questionLable'] = this['warp']['getElementsByClassName']('JDJRV-question-lable')[0x0]; + this['operWrap'] = this['warp']['getElementsByClassName']('JDJRV-oper')[0x0]; + this['operSeqs'] = this['warp']['getElementsByClassName']('JDJRV-seq'); + this['getValidateImage'](); + this['bindPicClickEvent'](); + }, + 'bindEvent': function() { + var a = this; + if (a['params']['product'] == 'click-popup') { + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + if (a['params']['product'] == 'click-suspend') { + a['closeBtn']['onclick'] = function() { + a['suspendSlideWarp']['style']['display'] = 'none'; + } + ; + } + if (a['params']['product'] == 'click-bind-suspend') { + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + if (a['params']['product'] == 'popup') { + a['clickWarp']['onclick'] = function() { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + ; + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + if (a['params']['product'] == 'bind') { + if (a['params']['eventListener'] == ![] || a['params']['eventListener'] == 'false') { + a['verify'] = function() { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + ; + } else { + document['getElementById'](a['params']['id'])['onclick'] = function() { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + ; + } + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + a['slideBtn']['onmousedown'] = b; + a['slideBtn']['ontouchstart'] = b; + a['slideSmallImg']['onmousedown'] = b; + a['slideSmallImg']['ontouchstart'] = b; + function b(f) { + if (a['passValidate']) + return; + a['isDraging'] = !![]; + var g = f || event; + if (document['all']) { + window['event']['returnValue'] = ![]; + window['event']['cancelBubble'] = !![]; + } else { + g['preventDefault'](); + g['stopPropagation'](); + g['returnValue'] = ![]; + } + ;if (g['touches']) + g = g['touches'][0x0]; + a['disX'] = g['clientX']; + a['slideGreenBar']['style']['display'] = 'block'; + a['mousePos'] = []; + a['mousePos']['push']([a['getLeft'](a['slideBtn'])['toFixed'](0x0), a['getTop'](a['slideBtn'])['toFixed'](0x0), new Date()['getTime']()]); + a['mousePos']['push']([g['clientX']['toFixed'](0x0), g['clientY']['toFixed'](0x0), new Date()['getTime']()]); + document['onmousemove'] = h; + document['ontouchmove'] = h; + document['onmouseup'] = j; + document['ontouchend'] = j; + function h(k) { + var l = k || event; + if (document['all']) { + window['event']['returnValue'] = ![]; + window['event']['cancelBubble'] = !![]; + } else { + l['preventDefault'](); + l['stopPropagation'](); + l['returnValue'] = ![]; + } + ;if (l['touches']) + l = l['touches'][0x0]; + var m = l['clientX'] - a['disX'] + 0x28; + var n = l['clientX'] - a['disX']; + var o = l['clientX'] - a['disX']; + if (o < 0x0) { + o = 0x0; + } else if (o > a['width'] - 0x32 / a['imgRatio']) { + o = a['width'] - 0x32 / a['imgRatio']; + } + if (n < 0x0) { + n = 0x0; + } else if (n > a['width'] - 0x28) { + n = a['width'] - 0x28; + } + if (m < 0x2c) { + m = 0x2c; + } else if (m > a['width']) { + m = a['width']; + } + a['mousePos']['push']([l['clientX']['toFixed'](0x0), l['clientY']['toFixed'](0x0), new Date()['getTime']()]); + a['slideBtn']['style']['left'] = n + 'px'; + a['slideSmallImg']['style']['left'] = o + 'px'; + a['slideGreenBar']['style']['width'] = m + 'px'; + return ![]; + } + ;function j(k) { + var l = k || event; + if (l['changedTouches']) + l = l['changedTouches'][0x0]; + a['isDraging'] = ![]; + a['mousePos']['push']([l['clientX']['toFixed'](0x0), l['clientY']['toFixed'](0x0), new Date()['getTime']()]); + document['onmousemove'] = null; + document['ontouchmove'] = null; + document['onmouseup'] = null; + document['ontouchend'] = null; + if (a['mousePos']['length'] <= 0x3) { + a['slideGreenBar']['style']['display'] = 'none'; + a['slideText']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-text'); + a['slideText']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-text'); + return; + } + a['submit'](); + } + } + ;if (this['params']['product'] == 'float') { + var c = ![]; + var d = ![]; + this['slideImgWrap']['onmouseover'] = function() { + c = !![]; + } + ; + this['slideImgWrap']['onmouseout'] = function() { + c = ![]; + a['slideTimer'] = setTimeout(function() { + if (c || d) + return; + a['slideImgWrap']['setAttribute']('class', 'JDJRV-img-panel\x20JDJRV-float'); + a['slideImgWrap']['setAttribute']('className', 'JDJRV-img-panel\x20JDJRV-float\x20'); + }, 0x12c); + } + ; + this['slideBar']['onmouseover'] = function() { + d = !![]; + if (a['passValidate'] || a['isDraging']) + return; + clearTimeout(a['slideTimer']); + a['slideImgWrap']['setAttribute']('class', 'JDJRV-img-panel\x20JDJRV-float\x20JDJRV-float-hover'); + a['slideImgWrap']['setAttribute']('className', 'JDJRV-img-panel\x20JDJRV-float\x20JDJRV-float-hover'); + } + ; + this['slideBar']['onmouseout'] = function() { + d = ![]; + if (a['isDraging']) + return; + a['slideTimer'] = setTimeout(function() { + if (c) + return; + a['slideImgWrap']['setAttribute']('class', 'JDJRV-img-panel\x20JDJRV-float'); + a['slideImgWrap']['setAttribute']('className', 'JDJRV-img-panel\x20JDJRV-float\x20'); + }, 0x12c); + } + ; + } + this['refreshBtn']['onclick'] = function() { + if (a['passValidate'] || a['isDraging']) + return; + a['getValidateImage'](); + if (a['params']['refreshCallback']) { + a['callback']({ + 'getSuccess': function() { + return '2'; + }, + 'getMessage': function() { + return 'refresh'; + }, + 'getValidate': function() { + return ''; + } + }); + } + } + ; + var e = 0x0; + window['onresize'] = function() { + a['resetSize'](); + } + ; + }, + 'bindDscEvent': function() { + var a = this; + if (a['params']['product'] == 'i-dsc') { + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + document['onmousemove'] = b; + document['ontouchmove'] = b; + a['dscBigImg']['onmousedown'] = c; + function b(d) { + var e = d || event; + if (document['all']) { + window['event']['returnValue'] = ![]; + window['event']['cancelBubble'] = !![]; + } else { + e['preventDefault'](); + e['stopPropagation'](); + e['returnValue'] = ![]; + } + ;if (e['touches']) + e = e['touches'][0x0]; + a['mousePos']['push']([e['clientX']['toFixed'](0x0), e['clientY']['toFixed'](0x0), new Date()['getTime']()]); + return ![]; + } + ;function c(d) { + var e = d || event; + if (e['changedTouches']) + e = e['changedTouches'][0x0]; + a['isDraging'] = ![]; + a['mousePos']['push']([e['clientX']['toFixed'](0x0), e['clientY']['toFixed'](0x0), new Date()['getTime']()]); + a['mousePos']['push']([a['getLeft'](a['dscBigImg'])['toFixed'](0x0), a['getTop'](a['dscBigImg'])['toFixed'](0x0), new Date()['getTime']()]); + var f = e['offsetX'] || e['clientX'] - a['dscBigImg']['getBoundingClientRect']()['left']; + var g = e['offsetY'] || e['clientY'] - a['dscBigImg']['getBoundingClientRect']()['top']; + a['mousePos']['push']([f['toFixed'](0x0), g['toFixed'](0x0), new Date()['getTime']()]); + a['mousePos']['push']([0x0, 0x0, new Date()['getTime']()]); + document['onmousemove'] = null; + document['ontouchmove'] = null; + a['dscBigImg']['onmousedown'] = null; + a['submit'](); + } + this['refreshBtn']['onclick'] = function() { + if (a['passValidate'] || a['isDraging']) + return; + a['getValidateImage'](); + if (a['params']['refreshCallback']) { + a['callback']({ + 'getSuccess': function() { + return '2'; + }, + 'getMessage': function() { + return 'refresh'; + }, + 'getValidate': function() { + return ''; + } + }); + } + } + ; + window['onresize'] = function() { + a['resetSize'](); + } + ; + }, + 'bindPicClickEvent': function() { + var a = this; + if (a['params']['product'] == 'i-pic-click') { + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + if (a['params']['product'] == 'e-pic-popup') { + if (a['params']['eventListener'] == ![] || a['params']['eventListener'] == 'false') { + a['verify'] = function() { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + ; + } else { + document['getElementById'](a['params']['id'])['onclick'] = function() { + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + ; + } + a['closeBtn']['onclick'] = function() { + a['warp']['style']['display'] = 'none'; + } + ; + } + a['picClickBigImg']['onmousedown'] = b; + function b(e) { + var f = e || event; + if (f['changedTouches']) + f = f['changedTouches'][0x0]; + a['isDraging'] = ![]; + var g = f['offsetX'] || f['clientX'] - a['dscBigImg']['getBoundingClientRect']()['left']; + var h = f['offsetY'] || f['clientY'] - a['dscBigImg']['getBoundingClientRect']()['top']; + a['mousePos']['push']([g['toFixed'](0x0), h['toFixed'](0x0), new Date()['getTime']()]); + var j = a['operSeqs'][a['mousePos']['length'] - 0x1]; + j['style']['top'] = h - 0xd + 'px'; + j['style']['left'] = g - 0xd + 'px'; + j['style']['display'] = 'block'; + if (a['mousePos']['length'] == (a['operLimit'] || 0x4)) { + a['picClickBigImg']['onmousedown'] = null; + a['submit'](); + } + } + for (var c = 0x0; c < a['operSeqs']['length']; c++) { + var d = a['operSeqs'][c]; + d['onmousedown'] = function() { + var e = this['getAttribute']('data-i') * 0x1; + a['mousePos'] = a['mousePos']['slice'](0x0, e - 0x1); + for (var f = a['operSeqs']['length']; f > e - 0x1; f--) { + a['operSeqs'][f - 0x1]['style']['display'] = 'none'; + } + } + ; + } + this['refreshBtn']['onclick'] = function() { + if (a['passValidate'] || a['isDraging']) + return; + a['mousePos'] = new Array(); + for (var e = 0x0; e < a['operSeqs']['length']; e++) { + a['operSeqs'][e]['style']['display'] = 'none'; + } + a['getValidateImage'](); + if (a['params']['refreshCallback']) { + a['callback']({ + 'getSuccess': function() { + return '2'; + }, + 'getMessage': function() { + return 'refresh'; + }, + 'getValidate': function() { + return ''; + } + }); + } + } + ; + window['onresize'] = function() { + a['resetSize'](); + } + ; + }, + 'getInstance': function() { + var a = this; + if (a['params']['getInstance']) { + a['params']['getInstance'](a); + } + }, + 'resetSize': function() { + var a = this; + if (a['y']) { + a['width'] = a['slideWrap']['offsetWidth']; + var b = a['imgRatio']; + a['imgRatio'] = a['slideWrap']['offsetWidth'] ? 0x168 / a['slideWrap']['offsetWidth'] : 0x0; + a['slideSmallImg']['style']['top'] = a['y'] / a['imgRatio'] + 'px'; + a['slideSmallImg']['style']['width'] = 0x32 / a['imgRatio'] + 'px'; + a['slideBigImg']['style']['height'] = 0x8c / (0x168 / a['slideWrap']['offsetWidth']) + 'px'; + a['slideSmallImg']['style']['left'] = a['slideSmallImg']['offsetLeft'] * b / a['imgRatio'] + 'px'; + } + if (a['params']['product'] == 'bind' || a['params']['product'] == 'popup' || a['params']['product'] == 'click-popup' || a['params']['product'] == 'e-pic-popup') { + a['popContent']['style']['marginLeft'] = a['popContent']['offsetWidth'] < 0x168 ? document['body']['clientWidth'] * -0.432 + 'px' : a['popContent']['offsetWidth'] / 0x2 * -0x1 + 'px'; + } + if (a['params']['product'] == 'click-bind-suspend' && a['slideWrap']) { + var e = a['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var h = a['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + h -= 0x8c / (0x168 / a['slideWrap']['offsetWidth']) + 0x78; + a['warp']['style']['top'] = typeof a['params']['top'] != 'undefined' ? a['params']['top'] : h + 'px'; + a['warp']['style']['left'] = e + 'px'; + } + if (a['params']['product'] == 'i-dsc' && a['dscWrap']) { + var e = a['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var h = a['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + h -= 0xbe / (0x168 / a['dscWrap']['offsetWidth']) + 0x46; + a['warp']['style']['top'] = typeof a['params']['top'] != 'undefined' ? a['params']['top'] : h + 'px'; + a['warp']['style']['left'] = e + 'px'; + a['width'] = a['dscWrap']['offsetWidth']; + } + if (a['params']['product'] == 'i-pic-click' && a['picClickWrap']) { + var e = a['clickWarp']['getBoundingClientRect']()['left'] + document['documentElement']['scrollLeft']; + var h = a['clickWarp']['getBoundingClientRect']()['top'] + document['documentElement']['scrollTop']; + h -= 0x14d / (0x280 / a['picClickWrap']['offsetWidth']) + 0x46; + a['warp']['style']['top'] = typeof a['params']['top'] != 'undefined' ? a['params']['top'] : h + 'px'; + a['warp']['style']['left'] = e + 'px'; + a['width'] = a['picClickWrap']['offsetWidth']; + } + if (a['params']['product'] == 'e-pic-popup' && a['picClickWrap']) { + this['width'] = this['picClickWrap']['offsetWidth']; + this['picClickBigImg']['style']['height'] = 0x14d / (0x280 / this['picClickWrap']['offsetWidth']) + 'px'; + } + }, + 'resetValidate': function() { + var a = this; + setTimeout(function() { + a['slideBtn']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-btn\x20JRJRV-animate-el'); + a['slideBtn']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-btn\x20JRJRV-animate-el'); + a['slideGreenBar']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-bar\x20JRJRV-animate-el'); + a['slideGreenBar']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-bar\x20JRJRV-animate-el'); + a['slideWrap']['setAttribute']('class', 'JDJRV-slide'); + a['slideWrap']['setAttribute']('className', 'JDJRV-slide'); + a['slideBtn']['style']['left'] = '0px'; + a['slideGreenBar']['style']['width'] = '0'; + a['slideText']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-text'); + a['slideText']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-text'); + setTimeout(function() { + a['slideBtn']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-btn'); + a['slideBtn']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-btn'); + a['slideGreenBar']['setAttribute']('class', 'JDJRV-slide-inner\x20JDJRV-slide-bar'); + a['slideGreenBar']['setAttribute']('className', 'JDJRV-slide-inner\x20JDJRV-slide-bar'); + }, 0x190); + }, 0x258); + }, + 'getValidateImage': function() { + var a = this; + a['jsonp'](a['apiServer'] + '/slide/g.html', { + 'appId': a['params']['appId'], + 'scene': a['params']['scene'], + 'product': a['params']['product'], + 'e': a['getEid'](), + 'j': a['getJsTk'](), + 'lang': a['lang'] ? a['lang'] : 'zh_CN' + }, 'callback', function(b) { + if (a['params']['product'] != 'click' && a['params']['product'] != 'click-bind' && a['params']['product'] != 'suspend' && a['params']['product'] != 'bind-suspend' && a['params']['product'] != 'dsc' && a['params']['product'] != 'i-dsc' && a['params']['product'] != 'pic-click' && a['params']['product'] != 'i-pic-click' && a['params']['product'] != 'e-pic-popup') { + a['slideBigImg']['innerHTML'] = ''; + a['slideSmallImg']['innerHTML'] = ''; + a['y'] = b['y']; + a['slideSmallImg']['style']['top'] = b['y'] / a['imgRatio'] + 'px'; + a['slideSmallImg']['style']['width'] = 0x32 / a['imgRatio'] + 'px'; + a['slideSmallImg']['style']['left'] = 0x0 + 'px'; + } else if (a['params']['product'] == 'dsc' || a['params']['product'] == 'i-dsc') { + a['dscBigImg']['innerHTML'] = ''; + a['questionLable']['innerHTML'] = b['desc']; + } else if (a['params']['product'] == 'pic-click' || a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + a['picClickBigImg']['innerHTML'] = ''; + a['questionLable']['innerHTML'] = b['desc'] + ''; + a['operLimit'] = b['n']; + a['picClickResult']['style']['bottom'] = '-30px'; + } + a['validateID'] = b['challenge']; + a['o'] = b['o']; + setTimeout(function() { + a['resetSize'](); + }, 0x3c); + setTimeout(function() { + a['resetSize'](); + }, 0x3e8); + }); + }, + 'submit': function() { + var a = this; + var b; + if (a['params']['product'] == 'click' || a['params']['product'] == 'click-bind' || a['params']['product'] == 'suspend' || a['params']['product'] == 'bind-suspend') { + b = a['clickProductData']; + var f = b['length']; + if (f > 0x12c) { + b = a['clickProductData']['slice'](f - 0x12c, f); + } + } else if (a['params']['product'] == 'dsc' || a['params']['product'] == 'i-dsc') { + b = a['mousePos']; + var f = b['length']; + if (f > 0x12c) { + b = a['mousePos']['slice'](f - 0x12c, f); + } + } else { + b = a['mousePos']; + } + var g = ''; + if (a['o']) { + try { + var h = a['getByID'](a['o']); + if (h) { + g = encodeURIComponent(h['value']); + } + } catch (i) {} + } + a['jsonp'](a['apiServer'] + '/slide/s.html', { + 'd': a['getCoordinate'](b), + 'c': a['validateID'], + 'w': a['width'] ? a['width']['toFixed'](0x0) : 0x0, + 'appId': a['params']['appId'], + 'scene': a['params']['scene'], + 'product': a['params']['product'], + 'e': a['getEid'](), + 'j': a['getJsTk'](), + 's': a['getSessionId'](), + 'o': g, + 'o1': a['getSelenium'](), + 'u': a['getUrl'](), + 'lang': a['lang'] ? a['lang'] : 'zh_CN' + }, 'callback', function(j) { + if (a['params']['product'] == 'click' || a['params']['product'] == 'click-bind' || a['params']['product'] == 'suspend' || a['params']['product'] == 'bind-suspend') { + if (j['success'] == 0x0) { + if (a['params']['product'] == 'suspend') { + a['params']['product'] = 'click-suspend'; + } else if (a['params']['product'] == 'bind-suspend') { + if (j['nextVerify'] == 'DSC_VERIFY') { + a['params']['product'] = 'i-dsc'; + } else if (j['nextVerify'] == 'PIC_CLICK_VERIFY') { + a['params']['product'] = 'i-pic-click'; + } else { + a['params']['product'] = 'click-bind-suspend'; + } + } else { + a['params']['product'] = 'click-popup'; + } + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + setTimeout(function() { + a['resetSize'](); + }, 0x3c); + setTimeout(function() { + a['resetSize'](); + }, 0x3e8); + } else { + a['clickSuccess'](); + } + } else if (a['params']['product'] == 'dsc' || a['params']['product'] == 'i-dsc') { + var k = a['mousePos'][a['mousePos']['length'] - 0x1]; + var m = a['mousePos'][a['mousePos']['length'] - 0x2]; + a['dscResult']['style']['top'] = m[0x1] - k[0x1] - 0x14 + 'px'; + a['dscResult']['style']['left'] = m[0x0] - k[0x0] - 0x14 + 'px'; + a['dscResult']['style']['display'] = 'block'; + if (j['success'] == 0x0) { + a['dscResult']['setAttribute']('class', 'JDJRV-dsc-result\x20JDJRV-dsc-result-err'); + a['dscResult']['setAttribute']('className', 'JDJRV-dsc-result\x20JDJRV-dsc-result-err'); + if (a['params']['product'] == 'i-dsc') { + a['params']['product'] = j['nextVerify'] == 'SLIDE_VERIFY' ? 'click-bind-suspend' : 'i-dsc'; + } + setTimeout(function() { + if (a['params']['product'] == 'i-dsc') { + a['dscResult']['style']['display'] = 'none'; + a['getValidateImage'](); + a['bindDscEvent'](); + a['resetSize'](); + } else { + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + }, 0x1f4); + } else { + a['dscResult']['setAttribute']('class', 'JDJRV-dsc-result\x20JDJRV-dsc-result-succ'); + a['dscResult']['setAttribute']('className', 'JDJRV-dsc-result\x20JDJRV-dsc-result-succ'); + a['refreshBtn']['style']['display'] = 'none'; + if (a['params']['product'] == 'i-dsc') { + setTimeout(function() { + a['warp']['style']['display'] = 'none'; + }, 0x320); + } + } + } else if (a['params']['product'] == 'pic-click' || a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + a['picClickResult']['style']['display'] = 'block'; + if (j['success'] == 0x0) { + a['picClickResult']['setAttribute']('class', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-err'); + a['picClickResult']['setAttribute']('className', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-err'); + a['picClickResult']['innerHTML'] = '验证失败,请重试'; + setTimeout(function() { + a['picClickResult']['style']['bottom'] = '0px'; + }, 0xa); + a['mousePos'] = new Array(); + for (var p = 0x0; p < a['operSeqs']['length']; p++) { + a['operSeqs'][p]['style']['display'] = 'none'; + } + if (a['params']['product'] == 'i-pic-click') { + a['params']['product'] = j['nextVerify'] == 'SLIDE_VERIFY' ? 'click-bind-suspend' : 'i-pic-click'; + } + setTimeout(function() { + if (a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + a['picClickResult']['style']['display'] = 'none'; + a['getValidateImage'](); + a['bindPicClickEvent'](); + a['resetSize'](); + } else { + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + }, 0x3e8); + } else { + a['picClickResult']['setAttribute']('class', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-succ'); + a['picClickResult']['setAttribute']('className', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-succ'); + a['picClickResult']['innerHTML'] = '验证成功'; + a['picClickResult']['style']['bottom'] = '0px'; + a['refreshBtn']['style']['display'] = 'none'; + for (var p = 0x0; p < a['operSeqs']['length']; p++) { + a['operSeqs'][p]['onmousedown'] = null; + } + if (a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + setTimeout(function() { + a['warp']['style']['display'] = 'none'; + }, 0x320); + } + } + } else { + if (j['success'] == 0x0) { + a['slideWrap']['setAttribute']('class', 'JDJRV-slide\x20JDJRV-slide-err'); + a['slideWrap']['setAttribute']('className', 'JDJRV-slide\x20JDJRV-slide-err'); + if (a['params']['product'] == 'click-bind-suspend' && j['nextVerify'] == 'DSC_VERIFY') { + a['params']['product'] = j['nextVerify'] == 'DSC_VERIFY' ? 'i-dsc' : 'click-bind-suspend'; + setTimeout(function() { + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + }, 0x1f4); + } else { + setTimeout(function() { + a['getValidateImage'](); + }, 0x1f4); + a['resetValidate'](); + } + } else { + a['passValidate'] = !![]; + a['slideWrap']['setAttribute']('class', 'JDJRV-slide\x20JDJRV-slide-succ'); + a['slideWrap']['setAttribute']('className', 'JDJRV-slide\x20JDJRV-slide-succ'); + a['slideGreenBar']['style']['width'] = '100%'; + a['slideGreenBarCenter']['innerHTML'] = a['params']['successMess'] ? a['params']['successMess'] : a['i18nParams']['default-slide-success']; + a['refreshBtn']['style']['display'] = 'none'; + if (a['params']['product'] == 'float') { + a['slideTimer'] = setTimeout(function() { + a['slideImgWrap']['setAttribute']('class', 'JDJRV-img-panel\x20JDJRV-float'); + a['slideImgWrap']['setAttribute']('className', 'JDJRV-img-panel\x20JDJRV-float'); + }, 0x12c); + } + if (a['params']['product'] == 'bind' || a['params']['product'] == 'popup' || a['params']['product'] == 'click-popup' || a['params']['product'] == 'click-bind-suspend') { + setTimeout(function() { + a['warp']['style']['display'] = 'none'; + }, 0x320); + } + if (a['params']['product'] == 'popup' || a['params']['product'] == 'click-popup' || a['params']['product'] == 'click-suspend') { + a['clickSuccess'](); + } + } + } + a['submitCallback'](j); + }, function() { + if (a['params']['product'] == 'click' || a['params']['product'] == 'click-bind') { + a['params']['product'] = 'click-popup'; + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + setTimeout(function() { + a['resetSize'](); + }, 0x32); + } else if (a['params']['product'] == 'dsc') { + a['dscResult']['setAttribute']('class', 'JDJRV-dsc-result\x20JDJRV-dsc-result-err'); + a['dscResult']['setAttribute']('className', 'JDJRV-dsc-result\x20JDJRV-dsc-result-err'); + setTimeout(function() { + a['initHtml'](); + }, 0x1f4); + } else if (a['params']['product'] == 'pic-click' || a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + a['picClickResult']['setAttribute']('class', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-err'); + a['picClickResult']['setAttribute']('className', 'JDJRV-pic-click-result\x20JDJRV-pic-click-result-err'); + a['picClickResult']['innerHTML'] = '验证失败,请重试'; + setTimeout(function() { + a['picClickResult']['style']['bottom'] = '0px'; + }, 0xa); + a['mousePos'] = new Array(); + for (var j = 0x0; j < a['operSeqs']['length']; j++) { + a['operSeqs'][j]['style']['display'] = 'none'; + } + if (a['params']['product'] == 'i-pic-click') { + a['params']['product'] = data['nextVerify'] == 'SLIDE_VERIFY' ? 'click-bind-suspend' : 'i-pic-click'; + } + setTimeout(function() { + if (a['params']['product'] == 'i-pic-click' || a['params']['product'] == 'e-pic-popup') { + a['picClickResult']['style']['display'] = 'none'; + a['getValidateImage'](); + a['bindPicClickEvent'](); + a['resetSize'](); + } else { + a['initHtml'](); + a['warp']['style']['display'] = 'block'; + a['resetSize'](); + } + }, 0x3e8); + } else { + a['slideWrap']['setAttribute']('class', 'JDJRV-slide\x20JDJRV-slide-err'); + a['slideWrap']['setAttribute']('className', 'JDJRV-slide\x20JDJRV-slide-err'); + setTimeout(function() { + a['getValidateImage'](); + }, 0x1f4); + a['resetValidate'](); + } + }); + }, + 'submitCallback': function(a) { + var b = this; + var c = {}; + c['getSuccess'] = function() { + return a['success']; + } + ; + c['getMessage'] = function() { + return a['message']; + } + ; + c['getValidate'] = function() { + return ''; + } + ; + if (a['success'] == 0x0) { + if (b['params']['failCallback']) { + b['callback'](c); + } + } else { + c['getValidate'] = function() { + return a['validate']; + } + ; + b['callback'](c); + } + }, + 'clickSuccess': function() { + var a = this; + if (a['clickContent']) { + if (a['params']['product'] == 'suspend') { + a['clickContent']['setAttribute']('class', 'JDJRV-suspend-click\x20JDJRV-suspend-click-success'); + a['clickContent']['setAttribute']('className', 'JDJRV-suspend-click\x20JDJRV-suspend-click-success'); + a['clickText']['innerHTML'] = a['params']['successMess'] ? a['params']['successMess'] : a['i18nParams']['default-suspend-success']; + } else if (a['params']['product'] == 'click-suspend') { + a['clickContent']['setAttribute']('class', 'JDJRV-suspend-click\x20JDJRV-suspend-click-success'); + a['clickContent']['setAttribute']('className', 'JDJRV-suspend-click\x20JDJRV-suspend-click-success'); + a['clickText']['innerHTML'] = a['params']['successMess'] ? a['params']['successMess'] : a['i18nParams']['default-suspend-success']; + a['suspendSlideWarp']['style']['display'] = 'none'; + } else { + a['clickContent']['setAttribute']('class', 'JDJRV-click-warp\x20JDJRV-click-success'); + a['clickContent']['setAttribute']('className', 'JDJRV-click-warp\x20JDJRV-click-success'); + a['clickImg']['src'] = this['protocol'] + (a['lang'] && a['lang'] != 'zh_CN' ? '//static.joybuy.com/risk-cdn/iv/images/slide-succ.png' : '//ivs.jd.com/slide/i/slide-succ.png'); + a['clickText']['innerHTML'] = a['params']['successMess'] ? a['params']['successMess'] : a['i18nParams']['default-suspend-success']; + } + } + a['clickResult'] = !![]; + }, + 'getImgSrc': function(a, b) { + return (b['lastIndexOf']('.png') > 0x0 || b['lastIndexOf']('.jpg') > 0x0 || b['lastIndexOf']('.webp') > 0x0 ? this['protocol'] + a : 'data:image/png;base64,') + b; + }, + 'jsonp': function(a, b, c, d, e) { + var f = 'jsonp_' + Math['random'](); + f = f['replace']('.', ''); + window[f] = function(n) { + clearTimeout(g); + window[f] = null; + m['removeChild'](l); + d(n); + } + ; + var g = setTimeout(function() { + window[f] = null; + m['removeChild'](l); + e && e(); + }, 0x1388); + b[c] = f; + var h = []; + for (var j in b) { + h['push'](j + '=' + b[j]); + } + var k = a + '?' + h['join']('&'); + var l = document['createElement']('script'); + l['src'] = k; + l['type'] = 'text/javascript'; + l['setAttribute']('ignore', 'true'); + var m = document['getElementsByTagName']('head')[0x0]; + m['appendChild'](l); + }, + 'ajax': function(a) { + a = a || {}; + a['type'] = (a['type'] || 'GET')['toUpperCase'](); + a['dataType'] = a['dataType'] || 'json'; + var b = this['formatParams'](a['data']); + if (window['XMLHttpRequest']) { + var d = new XMLHttpRequest(); + } else { + var d = new ActiveXObject('Microsoft.XMLHTTP'); + } + d['onreadystatechange'] = function() { + if (d['readyState'] == 0x4) { + var e = d['status']; + if (e >= 0xc8 && e < 0x12c) { + a['success'] && a['success'](d['responseText'], d['responseXML']); + } else { + a['fail'] && a['fail'](e); + } + } + } + ; + if (a['type'] == 'GET') { + d['open']('GET', a['url'] + '?' + b, !![]); + d['send'](null); + } else if (a['type'] == 'POST') { + d['open']('POST', a['url'], !![]); + d['setRequestHeader']('Content-Type', 'application/x-www-form-urlencoded'); + d['send'](b); + } + }, + 'formatParams': function(a) { + var b = []; + for (var c in a) { + b['push'](encodeURIComponent(c) + '=' + encodeURIComponent(a[c])); + } + b['push'](('v=' + Math['random']())['replace']('.', '')); + return b['join']('&'); + }, + 'string10to64': function(a) { + var b = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-~'['split']('') + , c = b['length'] + , d = +a + , e = []; + do { + mod = d % c; + d = (d - mod) / c; + e['unshift'](b[mod]); + } while (d); + return e['join'](''); + }, + 'prefixInteger': function(a, b) { + return (Array(b)['join'](0x0) + a)['slice'](-b); + }, + 'pretreatment': function(a, b, c) { + var d = this; + var e = d['string10to64'](Math['abs'](a)); + var f = ''; + if (!c) { + f += a > 0x0 ? '1' : '0'; + } + f += d['prefixInteger'](e, b); + return f; + }, + 'getCoordinate': function(a) { + var b = this; + var c = new Array(); + for (var d = 0x0; d < a['length']; d++) { + if (d == 0x0) { + c['push'](b['pretreatment'](a[d][0x0] < 0x3ffff ? a[d][0x0] : 0x3ffff, 0x3, !![])); + c['push'](b['pretreatment'](a[d][0x1] < 0xffffff ? a[d][0x1] : 0xffffff, 0x4, !![])); + c['push'](b['pretreatment'](a[d][0x2] < 0x3ffffffffff ? a[d][0x2] : 0x3ffffffffff, 0x7, !![])); + } else { + var e = a[d][0x0] - a[d - 0x1][0x0]; + var f = a[d][0x1] - a[d - 0x1][0x1]; + var g = a[d][0x2] - a[d - 0x1][0x2]; + c['push'](b['pretreatment'](e < 0xfff ? e : 0xfff, 0x2, ![])); + c['push'](b['pretreatment'](f < 0xfff ? f : 0xfff, 0x2, ![])); + c['push'](b['pretreatment'](g < 0xffffff ? g : 0xffffff, 0x4, !![])); + } + } + return c['join'](''); + }, + 'getEid': function() { + var a = ''; + try { + a = getJdEid()['eid']; + } catch (b) {} + try { + if (a == '') { + if (typeof eval('getJdEid;') == 'function') { + getJdEid(function(c, d, f) { + a = c; + }); + } + } + } catch (c) {} + return a; + }, + 'getJsTk': function() { + var a = ''; + try { + if (typeof eval('getJsToken;') == 'function') { + getJsToken(function(b) { + a = b['jsToken']; + }, 0xbb8); + } + } catch (b) {} + return a; + }, + 'getSessionId': function() { + var a = ''; + try { + if ('undefined' != typeof _jdtdmap_sessionId) + a = _jdtdmap_sessionId; + } catch (b) { + console['error']('sessionId\x20err;'); + } + return a; + }, + 'getSelenium': function() { + var a = '0'; + try { + if (window['navigator']['webdriver']) + a = '1'; + } catch (b) {} + return a; + }, + 'getUrl': function() { + var a = 'NULL'; + try { + a = encodeURIComponent(window['location']['href']); + } catch (b) { + a = 'ERROR'; + } + return a; + }, + 'getLeft': function(a) { + var b = a; + var c = 0x0; + var d = 0x0; + if (document['getElementById'] || document['all']) { + do { + d += a['offsetLeft'] - a['scrollLeft']; + c += a['offsetTop'] - a['scrollTop']; + a = a['offsetParent']; + b = b['parentNode']; + while (b != a) { + d -= b['scrollLeft']; + c -= b['scrollTop']; + b = b['parentNode']; + } + } while (a['offsetParent']); + } else if (document['layers']) { + c += a['y']; + d += a['x']; + } + if (document['compatMode'] == 'BackCompat') { + var g = document['body']['scrollLeft']; + } else { + var g = document['documentElement']['scrollLeft']; + } + return d - g; + }, + 'getTop': function(a) { + var b = a; + var c = 0x0; + var d = 0x0; + if (document['getElementById'] || document['all']) { + do { + d += a['offsetLeft'] - a['scrollLeft']; + c += a['offsetTop'] - a['scrollTop']; + a = a['offsetParent']; + b = b['parentNode']; + while (b != a) { + d -= b['scrollLeft']; + c -= b['scrollTop']; + b = b['parentNode']; + } + } while (a['offsetParent']); + } else if (document['layers']) { + c += a['y']; + d += a['x']; + } + if (document['compatMode'] == 'BackCompat') { + var g = document['body']['scrollTop']; + } else { + var g = document['documentElement']['scrollTop']; + } + return c - g; + } +}; + +function get_slide(data){ + return JDJRValidate['prototype'].getCoordinate(data) +} +