import ctypes
import asyncio
import websockets
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  # WS以及HTTP的请求端口，默认3030
web_socket = True  # 是否开启WebSocket
http_server = True  # 是否开启HTTP请求
remote = False  # 是否开启远程请求
log = True  # 是否开启日志功能
ws_max = 0  # 设置WS客户端最大连接数，0 = 不限制
sign_key = b'111111'  # 签名key，留空表示无需签名请求 调试时建议修改为空 
sha256 = True  # sign签名方式，假 = md5，真 = hmac - sha256
version_tip = True  # 是否开启SDK版本与DLL不一致时的刷新提示

# 启动服务器
result = sainiu_api.Access_ServerStart(
    port,
    web_socket,
    http_server,
    remote,
    log,
    ws_max,
    sign_key,
    sha256,
    version_tip
)

print(f"Access_ServerStart 服务器启动: {result.decode('gbk')}")

# 计算sign值
def sign_GetSign(signKey, post, time, sha256=False):
    # 拼接字符串
    data = post + str(time) + signKey
    
    # 将字符串转换为字节集
    byte_data = data.encode('utf-8')
    
    # 根据sha256参数选择哈希算法
    if sha256:
        hash_object = hashlib.sha256(byte_data)
    else:
        hash_object = hashlib.md5(byte_data)
    
    # 获取十六进制表示并转换为小写
    sign = hash_object.hexdigest().lower()
    
    return sign

async def connect_to_websocket():
    while True:
        try:
            # 获取当前的13位时间戳（毫秒级）
            current_time_ws = int(time.time() * 1000)
            
            # 计算签名，参数post参数为"ws"不可修改，signKey为自定义密匙，sha256参数为True选择sha256算法,为False则选择md5算法，需要与Access_StartServer的参数一致
            ws_sign = sign_GetSign(sign_key.decode('utf-8'), "ws", current_time_ws, sha256)
            
            # 构建URI
            uri = f"ws://127.0.0.1:{port}?time={current_time_ws}&sign={ws_sign}"
            
            async with websockets.connect(uri) as websocket:
                print("已连接到ws服务器")
 
                # 再次获取当前的13位时间戳（毫秒级）以避免签名超时
                current_time_json = int(time.time() * 1000)
                
                # 计算JSON数据的签名，参数post参数为"init"
                json_sign = sign_GetSign(sign_key.decode('utf-8'), "Init", current_time_json, sha256)
                
                # 发送JSON数据
                message = {
                    "type": "Invoke_SaiNiu",
                    "traceId": "Access_Init",
                    "codeType": "Access",
                    "post": "Init",
                    "data": {
                        "AccessType": 0,
                        "AccessId": "AccessId", #替换成授权的AccessId,
                        "AccessKey": "AccessKey", #替换成授权的AccessKey
                        "ForceLogin": True
                    },
                    "time": current_time_json,
                    "sign": json_sign
                }
                
                await websocket.send(json.dumps(message))
                print(f"Sent message: {message}")

                try:
                    while True:
                        # 接收来自服务器的消息
                        response = await websocket.recv()
                        print(f"接收来自服务器的消息: {response}")
                        
                        # 解析响应消息
                        response_data = json.loads(response)
                        
                        # 判断traceId是否匹配
                        if response_data.get("traceId") == "Access_Init":
                            # 再次获取当前的13位时间戳（毫秒级）以避免签名超时
                            current_time_sys_init = int(time.time() * 1000)
                            
                            # 计算新的JSON数据的签名，参数post参数为"SysInit"
                            sys_init_sign = sign_GetSign(sign_key.decode('utf-8'), "SysInit", current_time_sys_init, sha256)
                            
                            # 发送新的JSON数据
                            new_message = {
                                "type": "Invoke_SaiNiu",
                                "traceId": "0470bf9489729b2e8a2126a04ab3e272",#自定义返回的traceId
                                "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_sys_init,
                                "sign": sys_init_sign
                            }
                            
                            await websocket.send(json.dumps(new_message))
                            print(f"Sent message: {new_message}")
                except websockets.ConnectionClosed:
                    print("服务器关闭连接")
                except Exception as e:
                    print(f"出现错误：{e}")
        except websockets.InvalidURI as e:
            print(f"ws地址无效: {e} 请检查WebSocket地址")
            break
        except ConnectionRefusedError as e:
            print(f"连接被拒绝： {e} 服务器可能未运行或URI不正确。5秒后重试..")
            await asyncio.sleep(5)
        except OSError as e:
            print(f"操作系统错误: {e} 服务器可能无法访问。5秒后重试..")
            await asyncio.sleep(5)
        except Exception as e:
            print(f"发生意外错误：{e} Sign验证错误。5秒后重试..")
            await asyncio.sleep(5)

# 运行异步主函数
if __name__ == "__main__":
    asyncio.run(connect_to_websocket())



