Support CoolQHttpApi message source

This commit is contained in:
Richard Chien 2017-02-15 23:39:37 +08:00
parent 74b3bad931
commit 318d642c90
8 changed files with 122 additions and 17 deletions

View File

@ -6,7 +6,7 @@
[![QQ](https://img.shields.io/badge/qq-1647869577-orange.svg)](#)
[![WeChat](https://img.shields.io/badge/wechat-cczu__xiaokai-brightgreen.svg)](#)
用 Python 编写的即时聊天平台机器人,通过适配器模式支持使用多种 bot 框架/平台作为消息源(目前支持 Mojo-Webqq、Mojo-Weixin支持自定义插件。
用 Python 编写的即时聊天平台机器人,通过适配器模式支持使用多种 bot 框架/平台作为消息源(目前支持 [Mojo-Webqq](https://github.com/sjdy521/Mojo-Webqq)[Mojo-Weixin](https://github.com/sjdy521/Mojo-Weixin)、[CoolQ HTTP API](https://github.com/richardchien/coolq-http-api)),支持自定义插件。
请注意区分此程序和其它模拟登录或封装接口的聊天平台**客户端**,此程序不负责登录或维护即时聊天平台的账号的状态,而只负责收到消息之后对消息的分析、处理、回复等逻辑,本程序通过适配器来与所支持的聊天平台客户端进行通讯,通常包括上报数据的统一化、调用接口获取额外信息、发送消息等,而这些聊天平台客户端(很多时候它们的项目名称也是「某某 bot」相当于机器人的前端需要你自行运行。

View File

@ -2,8 +2,8 @@
「消息源」在文档的某些位置可能还称为「消息平台」「聊天平台客户端」「消息源客户端」「机器人前端」等。比如网上很多开源的 SmartQQ 封装或网页微信封装,我们这里就称他们为「消息源」,他们的功能通常是模拟登录账号、维护登录状态、上报接收到的消息、通过某种方式调用接口发送消息等。通过适配器,本程序可以支持多种消息源,下面是目前所支持的消息源列表:
| 消息源名称 | 官网/项目地址 | 配置文件中定义时填项 |
| -------------------- | ---------------------------------------- | ----------------- |
| mojo_webqq | https://github.com/sjdy521/Mojo-Webqq | `api_url`API 根地址 |
| mojo_weixin | https://github.com/sjdy521/Mojo-Weixin | `api_url`API 根地址 |
| coolq_http_api(即将支持) | https://github.com/richardchien/coolq-http-api | |
| 消息源名称 | 官网/项目地址 | 配置文件中定义时填 |
| -------------- | ---------------------------------------- | ---------------------------------------- |
| mojo_webqq | https://github.com/sjdy521/Mojo-Webqq | `api_url`API 根地址(必填) |
| mojo_weixin | https://github.com/sjdy521/Mojo-Weixin | `api_url`API 根地址(必填) |
| coolq_http_api | https://github.com/richardchien/coolq-http-api | `api_url`API 根地址(必填);`token`:发送请求时的 token设置了的情况下必填 |

View File

@ -7,10 +7,10 @@ from filter import as_filter
@as_filter(priority=1000)
def _log_message(ctx_msg):
log = ctx_msg.get('sender') or ctx_msg.get('sender_id') or '未知用户'
log = ctx_msg.get('sender') or ctx_msg.get('sender_name') or ctx_msg.get('sender_id') or '未知用户'
if ctx_msg.get('msg_type') == 'group':
log += '@' + ctx_msg.get('group') or ctx_msg.get('group_id') or '未知群组'
log += '@' + (ctx_msg.get('group') or ctx_msg.get('group_id') or '未知群组')
if ctx_msg.get('msg_type') == 'discuss':
log += '@' + ctx_msg.get('discuss') or ctx_msg.get('discuss_id') or '未知讨论组'
log += '@' + (ctx_msg.get('discuss') or ctx_msg.get('discuss_id') or '未知讨论组')
log += ': ' + ctx_msg.get('content', '')
print(log)

View File

@ -15,12 +15,10 @@ def _split_at_xiaokai(ctx_msg):
if ctx_msg.get('msg_type') == 'group' or ctx_msg.get('msg_type') == 'discuss':
text = ctx_msg.get('text', '')
if text.startswith('@'):
my_group_nick = ctx_msg.get('receiver')
if not my_group_nick:
return False
my_group_nick = ctx_msg.get('receiver') or ctx_msg.get('receiver_name') or ''
at_me = '@' + my_group_nick
if not text.startswith(at_me):
user_info = get_adapter_by_ctx(ctx_msg).get_login_info(ctx_msg)
if not my_group_nick or not text.startswith(at_me):
user_info = get_adapter_by_ctx(ctx_msg).get_login_info()
my_nick = user_info.get('nickname')
if not my_nick:
return False

View File

@ -46,7 +46,7 @@ class Adapter(object):
if 'user_tid' in target and 'sender_tid' in target:
del target['user_tid']
def get_login_info(self, ctx_msg: dict):
def get_login_info(self):
return {}
def is_sender_superuser(self, ctx_msg: dict):

View File

@ -0,0 +1,107 @@
import requests
from flask import request as flask_req
from msg_src_adapter import Adapter, as_adapter, ConfigurationError
@as_adapter(via='coolq_http_api')
class CoolQHttpApiAdapter(Adapter):
def __init__(self, config: dict):
super().__init__(config)
if not config.get('api_url'):
raise ConfigurationError
self.api_url = config['api_url']
self.token = config.get('token')
self.session = requests.Session()
if self.token:
self.session.headers['Authorization'] = 'token ' + self.token
def unitize_context(self, ctx_msg: dict):
# Check token
if self.token:
if flask_req.headers.get('Authorization', '') != 'token ' + self.token:
return None
new_ctx = {'raw_ctx': ctx_msg, 'post_type': ctx_msg['post_type'], 'via': ctx_msg['via'],
'login_id': ctx_msg['login_id']}
if new_ctx['post_type'] != 'message':
return new_ctx
new_ctx['time'] = ctx_msg['time']
new_ctx['msg_type'] = ctx_msg['message_type']
new_ctx['format'] = 'text'
new_ctx['content'] = ctx_msg['message']
login_info = self.get_login_info()
new_ctx['receiver_name'] = login_info['nickname']
new_ctx['receiver_id'] = login_info['user_id']
new_ctx['receiver_tid'] = login_info['user_id']
new_ctx['sender_id'] = str(ctx_msg.get('user_id', ''))
new_ctx['sender_tid'] = new_ctx['sender_id']
json = self.session.get(self.api_url + '/get_stranger_info',
params={'user_id': new_ctx['sender_id']}).json()
if json and json.get('data'):
new_ctx['sender_name'] = json['data']['nickname']
if new_ctx['msg_type'] == 'group':
new_ctx['group_id'] = str(ctx_msg.get('group_id', ''))
new_ctx['group_tid'] = new_ctx['group_id']
if new_ctx['msg_type'] == 'discuss':
new_ctx['discuss_id'] = str(ctx_msg.get('discuss_id', ''))
new_ctx['discuss_tid'] = new_ctx['discuss_id']
import re
if re.search('\\[CQ:at,qq=%s\\]' % new_ctx['receiver_id'], new_ctx['content']):
new_ctx['content'] = re.sub('\\[CQ:at,qq=%s\\]' % new_ctx['receiver_id'], '', new_ctx['content']).lstrip()
new_ctx['is_at_me'] = True
return new_ctx
def get_login_info(self):
json = self.session.get(self.api_url + '/get_login_info').json()
if json and json.get('data'):
json['user_id'] = str(json['data'].get('user_id', ''))
json['user_tid'] = json['data']['user_id']
json['nickname'] = json['data'].get('nickname', '')
return json
def get_sender_group_role(self, ctx_msg: dict):
json = self.session.get(
self.api_url + '/get_group_member_info',
params={'group_id': ctx_msg.get('group_id'), 'user_id': ctx_msg.get('sender_id')}
).json()
if json and json.get('data'):
return json['data']['role']
return 'member'
def send_private_message(self, target: dict, content: str):
params = None
if target.get('user_id'):
params = {'user_id': target.get('user_id')}
if params:
params['message'] = content
params['is_raw'] = True
self.session.get(self.api_url + '/send_private_msg', params=params)
def send_group_message(self, target: dict, content: str):
params = None
if target.get('group_id'):
params = {'group_id': target.get('group_id')}
if params:
params['message'] = content
params['is_raw'] = True
self.session.get(self.api_url + '/send_group_msg', params=params)
def send_discuss_message(self, target: dict, content: str):
params = None
if target.get('discuss_id'):
params = {'discuss_id': target.get('discuss_id')}
if params:
params['message'] = content
params['is_raw'] = True
self.session.get(self.api_url + '/send_discuss_msg', params=params)

View File

@ -49,7 +49,7 @@ class MojoWebqqAdapter(Adapter):
return new_ctx
def get_login_info(self, ctx_msg: dict):
def get_login_info(self):
json = requests.get(self.api_url + '/get_user_info').json()
if json:
json['user_tid'] = json.get('id')

View File

@ -52,7 +52,7 @@ class MojoWeixinAdapter(Adapter):
return new_ctx
def get_login_info(self, ctx_msg: dict):
def get_login_info(self):
json = requests.get(self.api_url + '/get_user_info').json()
if json:
json['user_tid'] = json.get('id')