Skip to content

Commit

Permalink
Merge pull request #1068 from leeAx/feat/lark_http
Browse files Browse the repository at this point in the history
feat(lark):enable lark callback
  • Loading branch information
RockChinQ authored Feb 12, 2025
2 parents 5311e78 + dc93b37 commit 2776a95
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 15 deletions.
5 changes: 4 additions & 1 deletion pkg/core/migrations/m021_lark_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ async def run(self):
"enable": False,
"app_id": "cli_abcdefgh",
"app_secret": "XXXXXXXXXX",
"bot_name": "LangBot"
"bot_name": "LangBot",
"enable-webhook": False,
"port": 2285,
"encrypt-key": "xxxxxxxxx"
})

await self.ap.platform_cfg.dump_config()
31 changes: 31 additions & 0 deletions pkg/core/migrations/m030_lark_config_cmpl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from .. import migration


@migration.migration_class("lark-config-cmpl", 30)
class LarkConfigCmplMigration(migration.Migration):
"""迁移"""

async def need_migrate(self) -> bool:
"""判断当前环境是否需要运行此迁移"""

for adapter in self.ap.platform_cfg.data['platform-adapters']:
if adapter['adapter'] == 'lark':
if 'enable-webhook' not in adapter:
return True

return False

async def run(self):
"""执行迁移"""
for adapter in self.ap.platform_cfg.data['platform-adapters']:
if adapter['adapter'] == 'lark':
if 'enable-webhook' not in adapter:
adapter['enable-webhook'] = False
if 'port' not in adapter:
adapter['port'] = 2285
if 'encrypt-key' not in adapter:
adapter['encrypt-key'] = "xxxxxxxxx"

await self.ap.platform_cfg.dump_config()
3 changes: 1 addition & 2 deletions pkg/core/stages/migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
from ..migrations import m015_gitee_ai_config, m016_dify_service_api, m017_dify_api_timeout_params, m018_xai_config, m019_zhipuai_config
from ..migrations import m020_wecom_config, m021_lark_config, m022_lmstudio_config, m023_siliconflow_config, m024_discord_config, m025_gewechat_config
from ..migrations import m026_qqofficial_config, m027_wx_official_account_config, m028_aliyun_requester_config
from ..migrations import m029_dashscope_app_api_config, m030_lark_config_cmpl


from ..migrations import m029_dashscope_app_api_config

@stage.stage_class("MigrationStage")
class MigrationStage(stage.BootingStage):
"""迁移阶段
Expand Down
108 changes: 97 additions & 11 deletions pkg/platform/sources/lark.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
import uuid
import json
import datetime
import hashlib
import base64
from Crypto.Cipher import AES

import aiohttp
import lark_oapi.ws.exception
import quart
from flask import jsonify
from lark_oapi.api.im.v1 import *
from lark_oapi.api.verification.v1 import GetVerificationRequest

from .. import adapter
from ...pipeline.longtext.strategies import forward
Expand All @@ -25,6 +31,28 @@
from ...utils import image


class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key=hashlib.sha256(AESCipher.str_to_bytes(key)).digest()
@staticmethod
def str_to_bytes(data):
u_type = type(b"".decode('utf8'))
if isinstance(data, u_type):
return data.encode('utf8')
return data
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
def decrypt(self, enc):
iv = enc[:AES.block_size]
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:]))
def decrypt_string(self, enc):
enc = base64.b64decode(enc)
return self.decrypt(enc).decode('utf8')


class LarkMessageConverter(adapter.MessageConverter):

@staticmethod
Expand Down Expand Up @@ -288,12 +316,57 @@ class LarkMessageSourceAdapter(adapter.MessageSourceAdapter):
] = {}

config: dict

quart_app: quart.Quart
ap: app.Application

def __init__(self, config: dict, ap: app.Application):
self.config = config
self.ap = ap
self.quart_app = quart.Quart(__name__)

@self.quart_app.route('/lark/callback', methods=['POST'])
async def lark_callback():
try:
data = await quart.request.json

if 'encrypt' in data:
cipher = AESCipher(self.config['encrypt-key'])
data = cipher.decrypt_string(data['encrypt'])
data = json.loads(data)

type = data.get("type")
if type is None :
context = EventContext(data)
type = context.header.event_type

if 'url_verification' == type:
print(data.get("challenge"))
# todo 验证verification token
return {
"challenge": data.get("challenge")
}
context = EventContext(data)
type = context.header.event_type
p2v1 = P2ImMessageReceiveV1()
p2v1.header = context.header
event = P2ImMessageReceiveV1Data()
event.message = EventMessage(context.event['message'])
event.sender = EventSender(context.event['sender'])
p2v1.event = event
p2v1.schema = context.schema
if 'im.message.receive_v1' == type:
try:
event = await self.event_converter.target2yiri(p2v1, self.api_client)
except Exception as e:
traceback.print_exc()

if event.__class__ in self.listeners:
await self.listeners[event.__class__](event, self)

return {"code": 200, "message": "ok"}
except Exception as e:
traceback.print_exc()
return {"code": 500, "message": "error"}

async def on_message(event: lark_oapi.im.v1.P2ImMessageReceiveV1):

Expand Down Expand Up @@ -392,16 +465,29 @@ def unregister_listener(
self.listeners.pop(event_type)

async def run_async(self):
try:
await self.bot._connect()
except lark_oapi.ws.exception.ClientException as e:
raise e
except Exception as e:
await self.bot._disconnect()
if self.bot._auto_reconnect:
await self.bot._reconnect()
else:
raise e
port = self.config['port']
enable_webhook = self.config['enable-webhook']

if not enable_webhook:
try:
await self.bot._connect()
except lark_oapi.ws.exception.ClientException as e:
raise e
except Exception as e:
await self.bot._disconnect()
if self.bot._auto_reconnect:
await self.bot._reconnect()
else:
raise e
else:
async def shutdown_trigger_placeholder():
while True:
await asyncio.sleep(1)

await self.quart_app.run_task(
host='0.0.0.0',
port=port,
shutdown_trigger=shutdown_trigger_placeholder,
)
async def kill(self) -> bool:
return False
5 changes: 4 additions & 1 deletion templates/platform.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
"enable": false,
"app_id": "cli_abcdefgh",
"app_secret": "XXXXXXXXXX",
"bot_name": "LangBot"
"bot_name": "LangBot",
"enable-webhook": false,
"port": 2285,
"encrypt-key": "xxxxxxxxx"
},
{
"adapter": "discord",
Expand Down
15 changes: 15 additions & 0 deletions templates/schema/platform.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,21 @@
"type": "string",
"default": "",
"description": "飞书的bot_name"
},
"enable-webhook": {
"type": "boolean",
"default": false,
"description": "是否启用webhook模式"
},
"port": {
"type": "integer",
"description": "设置监听的端口,开启callback event时需要设置",
"default": 2285
},
"encrypt-key": {
"type": "string",
"default": "",
"description": "设置加密密钥"
}
}
},
Expand Down

0 comments on commit 2776a95

Please sign in to comment.