Mrs4s / go-cqhttp

cqhttp的golang实现,轻量、原生跨平台.
GNU Affero General Public License v3.0
10.4k stars 1.63k forks source link

[求赐教]关于反向WS的python实现 #418

Closed NagaseYami closed 3 years ago

NagaseYami commented 3 years ago

说明

大佬好,我是程序方面的小白。特别是对网络这块的知识非常缺乏。 目前在尝试实现反向WS的时候遇到了一些问题,在此提问,如果可以的话,劳烦您回答。 ※第一次接触python和websocket,一边查找资料一边写的,还请多多包涵 ※如果在Issues里不允许咨询此类问题或有冒犯到您,请关闭此Issue

go-cqhttp的配置文件

除了QQ号,密码,和反向WS的服务器设置以外都是维持默认的。

{
    "uin": <QQ号>,
    "password": <QQ密码>,
    "encrypt_password": false,
    "password_encrypted": "",
    "enable_db": true,
    "access_token": "",
    "relogin": {
        "enabled": true,
        "relogin_delay": 3,
        "max_relogin_times": 0
    },
    "_rate_limit": {
        "enabled": false,
        "frequency": 1,
        "bucket_size": 1
    },
    "ignore_invalid_cqcode": false,
    "force_fragmented": false,
    "heartbeat_interval": 0,
    "http_config": {
        "enabled": true,
        "host": "0.0.0.0",
        "port": 5700,
        "timeout": 0,
        "post_urls": {}
    },
    "ws_config": {
        "enabled": true,
        "host": "0.0.0.0",
        "port": 6700
    },
    "ws_reverse_servers": [
        {
            "enabled": true,
            "reverse_url": "",
            "reverse_api_url": "ws://localhost:8765/api",
            "reverse_event_url": "ws://localhost:8765/event",
            "reverse_reconnect_interval": 3000
        }
    ],
    "post_message_format": "string",
    "use_sso_address": false,
    "debug": false,
    "log_level": "",
    "web_ui": {
        "enabled": true,
        "host": "127.0.0.1",
        "web_ui_port": 9999,
        "web_input": false
    }
}

WS服务器的实现

第一次写python,也许很丑,请见谅

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from websocket_server import WebsocketServer
import json

class CqServer(object):
    def __init__(self):
        self.server = WebsocketServer(port=8765, host="localhost")

        self.server.set_fn_new_client(self.new_client)
        self.server.set_fn_client_left(self.client_left)
        self.server.set_fn_message_received(self.message_received)

        self.server.run_forever()

    def new_client(self, client, server):
        print(
            "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
        )

    def client_left(self, client, server):
        print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

    def message_received(self, client, server, message):
        print(message)
        dic = {
            "action": "send_private_msg",
            "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
        }
        server.send_message(client, json.dumps(dic).encode("utf-8"))

一个很基础的ws服务器,在任何ws客户端连接,断开,以及收到任何客户端的消息时会打印一些信息。 以及在收到任意消息之后,往我自己的QQ发一个Hello World!

遇到的问题

在go-cqhttp连接到ws服务器,以及发送heartbeat的时候,ws服务器都打印出了正确的内容

New Client Join.
IP : ('127.0.0.1', 1960)
ID : 1
New Client Join.
IP : ('127.0.0.1', 1959)
ID : 2

{"meta_event_type":"lifecycle","post_type":"meta_event","self_id":<Bot的QQ号>,"sub_type":"connect","time":1605411254}
{"interval":5000,"meta_event_type":"heartbeat","post_type":"meta_event","self_id":<Bot的QQ号>,"status":null,"time":1605411256}
// 然后不断重复上面这一行heartbeat

问题是server.send_message(client, json.dumps(dic).encode("utf-8"))这一行仿佛没有起作用一般,go-cqhttp那边一点反应都没有。 我后来尝试将go-cqhttp的repo直接clone下来debug, 然后发现websocket.go的listenApi在我每次send_message后并无任何反应。 https://github.com/Mrs4s/go-cqhttp/blob/a52ae1c828f6c1f1506c8ed2a00d2faa87b3eb31/server/websocket.go#L171-L189

一些其他的疑问

我有查看onebot上的关于反向WS的说明,但是没能理解的是,

连接建立后,使用方式同 正向 WebSocket。

这难道意味着,当反向连接成功之后,我需要再正向WS连接go-cqhttp的ws服务器吗?

undefined-moe commented 3 years ago

先推荐一波 koishijs/koishi ;
当反向连接成功之后,不需要正向WS连接。
请尝试通过HTTP POST提交send_private_msg事件(?

NagaseYami commented 3 years ago

@undefined-moe

先推荐一波 koishijs/koishi

感谢推荐,已Star。 不过我主要还是想在周末自学一些python和golang,所以还是想把当前的问题搞懂

当反向连接成功之后,不需要正向WS连接。 请尝试通过HTTP POST提交send_private_msg事件(?

抱歉,没能理解,意思是反向WS之后没法从已经建立的连接提交api事件吗?

undefined-moe commented 3 years ago

理论上是可以(我没试过),只是测试一下问题出在哪

NagaseYami commented 3 years ago

我先尝试用golang写一个等价的ws服务器试一试吧

NagaseYami commented 3 years ago

好吧,问题解决了,我仔细参考了websocket.go的代码,发现handshake是把string转换成了bytes发送的 https://github.com/Mrs4s/go-cqhttp/blob/a52ae1c828f6c1f1506c8ed2a00d2faa87b3eb31/server/websocket.go#L290 所以python那边的正确写法是 server.send_message(client, bytes(json.dumps(dic).encode('utf-8'))) 为什么我之前send了一堆奇怪的东西都没有任何地方报错的。。。

borgeens commented 3 years ago

!/usr/bin/env python

-- coding: utf-8 --

from websocket_server import WebsocketServer import json

class CqServer(object): def init(self): self.server = WebsocketServer(port=8765, host="localhost")

    self.server.set_fn_new_client(self.new_client)
    self.server.set_fn_client_left(self.client_left)
    self.server.set_fn_message_received(self.message_received)

    self.server.run_forever()

def new_client(self, client, server):
    print(
        "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
    )

def client_left(self, client, server):
    print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

def message_received(self, client, server, message):
    print(message)
    dic = {
        "action": "send_private_msg",
        "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
    }
    server.send_message(client, json.dumps(dic).encode("utf-8"))

python反向websocket怎么写的?可以分享一下吗?

Ink-33 commented 3 years ago

!/usr/bin/env python

-- coding: utf-8 --

from websocket_server import WebsocketServer import json class CqServer(object): def init(self): self.server = WebsocketServer(port=8765, host="localhost")

    self.server.set_fn_new_client(self.new_client)
    self.server.set_fn_client_left(self.client_left)
    self.server.set_fn_message_received(self.message_received)

    self.server.run_forever()

def new_client(self, client, server):
    print(
        "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
    )

def client_left(self, client, server):
    print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

def message_received(self, client, server, message):
    print(message)
    dic = {
        "action": "send_private_msg",
        "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
    }
    server.send_message(client, json.dumps(dic).encode("utf-8"))

python反向websocket怎么写的?可以分享一下吗?

去参考nonebot,你来错地方了

borgeens commented 3 years ago

!/usr/bin/env python

-- coding: utf-8 --

from websocket_server import WebsocketServer import json class CqServer(object): def init(self): self.server = WebsocketServer(port=8765, host="localhost")

    self.server.set_fn_new_client(self.new_client)
    self.server.set_fn_client_left(self.client_left)
    self.server.set_fn_message_received(self.message_received)

    self.server.run_forever()

def new_client(self, client, server):
    print(
        "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
    )

def client_left(self, client, server):
    print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

def message_received(self, client, server, message):
    print(message)
    dic = {
        "action": "send_private_msg",
        "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
    }
    server.send_message(client, json.dumps(dic).encode("utf-8"))

python反向websocket怎么写的?可以分享一下吗?

去参考nonebot,你来错地方了

nonebot并没有得到答案。

Ink-33 commented 3 years ago

!/usr/bin/env python

-- coding: utf-8 --

from websocket_server import WebsocketServer import json class CqServer(object): def init(self): self.server = WebsocketServer(port=8765, host="localhost")

    self.server.set_fn_new_client(self.new_client)
    self.server.set_fn_client_left(self.client_left)
    self.server.set_fn_message_received(self.message_received)

    self.server.run_forever()

def new_client(self, client, server):
    print(
        "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
    )

def client_left(self, client, server):
    print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

def message_received(self, client, server, message):
    print(message)
    dic = {
        "action": "send_private_msg",
        "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
    }
    server.send_message(client, json.dumps(dic).encode("utf-8"))

python反向websocket怎么写的?可以分享一下吗?

去参考nonebot,你来错地方了

nonebot并没有得到答案。

我的意思是让你去看nonebot源码

yanyongyu commented 3 years ago

nonebot aiocqhttp nonebot2

borgeens commented 3 years ago

!/usr/bin/env python

-- coding: utf-8 --

from websocket_server import WebsocketServer import json class CqServer(object): def init(self): self.server = WebsocketServer(port=8765, host="localhost")

    self.server.set_fn_new_client(self.new_client)
    self.server.set_fn_client_left(self.client_left)
    self.server.set_fn_message_received(self.message_received)

    self.server.run_forever()

def new_client(self, client, server):
    print(
        "New Client Join.\nIP : {}\nID : {}\n".format(client["address"], client["id"])
    )

def client_left(self, client, server):
    print("Client Leave.\nIP : {}\nID : {}\n".format(client["address"], client["id"]))

def message_received(self, client, server, message):
    print(message)
    dic = {
        "action": "send_private_msg",
        "params": {"user_id": <我的QQ号>, "message": "Hello World!"},
    }
    server.send_message(client, json.dumps(dic).encode("utf-8"))

python反向websocket怎么写的?可以分享一下吗?

去参考nonebot,你来错地方了

nonebot并没有得到答案。

我的意思是让你去看nonebot源码

好的,谢谢啦。nonebot+cqhttp这样是可以吗?

QyuJ123456 commented 1 year ago

我好像用不了这个库啊,用的时候获取不到完整信息