From 2c73c302f4c9ff543b96a36125eebc198676c087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=91=E8=B4=A8?= Date: Sat, 2 Dec 2023 00:24:31 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B1=B3=E6=B8=B8=E7=A4=BE=E5=A4=A7=E5=88=AB?= =?UTF-8?q?=E9=87=8E=E5=9F=BA=E6=9C=AC=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OlivOS/API.py | 10 + OlivOS/messageAPI.py | 8 + OlivOS/mhyVilaLinkServerAPI.py | 107 +++++-- OlivOS/mhyVilaSDK.py | 292 ++++++++++++++++-- OlivOS/thirdPartyModule/__init__.py | 1 + .../thirdPartyModule/mhyVilaProto/__init__.py | 1 + OlivOS/thirdPartyModule/mhyVilaProto/tools.py | 1 + 7 files changed, 382 insertions(+), 38 deletions(-) create mode 100644 OlivOS/thirdPartyModule/mhyVilaProto/tools.py diff --git a/OlivOS/API.py b/OlivOS/API.py index 1ff6a4ad..920c41af 100644 --- a/OlivOS/API.py +++ b/OlivOS/API.py @@ -197,6 +197,8 @@ def get_Event_from_SDK(self): OlivOS.contentAPI.get_Event_from_fake_SDK(self) elif self.sdk_event_type is OlivOS.kaiheilaSDK.event: OlivOS.kaiheilaSDK.get_Event_from_SDK(self) + elif self.sdk_event_type is OlivOS.mhyVilaSDK.event: + OlivOS.mhyVilaSDK.get_Event_from_SDK(self) elif self.sdk_event_type is OlivOS.qqRedSDK.event: OlivOS.qqRedSDK.get_Event_from_SDK(self) elif self.sdk_event_type is OlivOS.hackChatSDK.event: @@ -894,6 +896,14 @@ def __send(self, send_type, target_id, message, host_id=None, flag_log=True): OlivOS.kaiheilaSDK.event_action.send_msg(self, target_id, tmp_message, flag_direct=False) elif flag_type == 'private': OlivOS.kaiheilaSDK.event_action.send_msg(self, target_id, tmp_message, flag_direct=True) + elif self.platform['sdk'] == 'mhyVila_link': + if flag_type == 'group': + if host_id is not None: + OlivOS.mhyVilaSDK.event_action.send_group_msg(self, target_id, tmp_message, host_id=host_id) + elif 'host_id' in self.data.__dict__: + OlivOS.mhyVilaSDK.event_action.send_group_msg(self, target_id, tmp_message, host_id=self.data.host_id) + elif flag_type == 'private': + pass elif self.platform['sdk'] == 'hackChat_link': OlivOS.hackChatSDK.event_action.send_msg(self, tmp_message, self.plugin_info['control_queue']) elif self.platform['sdk'] == 'biliLive_link': diff --git a/OlivOS/messageAPI.py b/OlivOS/messageAPI.py index cfc55137..598bd5b4 100644 --- a/OlivOS/messageAPI.py +++ b/OlivOS/messageAPI.py @@ -83,6 +83,14 @@ 'text': 'olivos_para' } }, + 'mhyVila': { + 'mhyVila_link': { + 'default': 'olivos_string', + 'public': 'olivos_string', + 'private': 'olivos_string', + 'sandbox': 'olivos_string' + } + }, 'discord': { 'discord_link': { 'default': 'olivos_para' diff --git a/OlivOS/mhyVilaLinkServerAPI.py b/OlivOS/mhyVilaLinkServerAPI.py index 4bf6536d..89213b08 100644 --- a/OlivOS/mhyVilaLinkServerAPI.py +++ b/OlivOS/mhyVilaLinkServerAPI.py @@ -46,46 +46,111 @@ def __init__(self, Proc_name, scan_interval=0.001, dead_interval=1, rx_queue=Non 'pulse_interval': None, 'last_s': None, 'ws_obj': None, - 'ws_item': None + 'ws_item': None, + 'ws_PLogin': { + 'uid': 0, + 'token': '', + 'platform': 3, + 'app_id': 104, + 'device_id': '' + } } self.Proc_data['platform_bot_info_dict'] = None def run(self): - self.log(2, 'OlivOS kaiheila link server [' + self.Proc_name + '] is running') + self.log(2, 'OlivOS mhyVila link server [' + self.Proc_name + '] is running') while True: - api_obj = OlivOS.mhyVilaSDK.API.getWebsocketInfo( - OlivOS.mhyVilaSDK.get_SDK_bot_info_from_Plugin_bot_info( - self.Proc_data['bot_info_dict'] - ) + sdk_bot_info = OlivOS.mhyVilaSDK.get_SDK_bot_info_from_Plugin_bot_info( + self.Proc_data['bot_info_dict'] ) + api_obj = OlivOS.mhyVilaSDK.API.getWebsocketInfo(sdk_bot_info) try: api_obj.do_api('GET') api_obj_json = json.loads(api_obj.res) if api_obj_json['retcode'] == 0: + self.Proc_data['extend_data']['ws_PLogin']['uid'] = int(api_obj_json['data']['uid']) + self.Proc_data['extend_data']['ws_PLogin']['token'] = '%s.%s.%s' % ( + str(sdk_bot_info.vila_id), + OlivOS.mhyVilaSDK.get_bot_secret(sdk_bot_info), + str(sdk_bot_info.bot_id) + ) + self.Proc_data['extend_data']['ws_PLogin']['platform'] = int(api_obj_json['data']['platform']) + self.Proc_data['extend_data']['ws_PLogin']['app_id'] = int(api_obj_json['data']['app_id']) + self.Proc_data['extend_data']['ws_PLogin']['device_id'] = str(api_obj_json['data']['device_id']) self.Proc_data['extend_data']['websocket_url'] = api_obj_json['data']['websocket_url'] else: self.Proc_data['extend_data']['websocket_url'] = None except: self.Proc_data['extend_data']['websocket_url'] = None - print(self.Proc_data['extend_data']['websocket_url']) - #if self.Proc_data['extend_data']['websocket_url'] is not None: - # self.run_websocket_rx_connect_start() + if self.Proc_data['extend_data']['websocket_url'] is not None: + self.run_websocket_rx_connect_start() time.sleep(10) - def on_message(self, ws, message): + def on_data(self, ws:websocket.WebSocketApp, data, opcode, FIN): + #print([data, opcode, FIN]) + pass + + def on_message(self, ws:websocket.WebSocketApp, message): try: - print(message) - except: - pass + #print(message) + messageObj = OlivOS.mhyVilaSDK.PAYLOAD.rxPacket(message) + if messageObj.dataHeader.BizType in [ + OlivOS.mhyVilaSDK.protoEnum.Model_ROBOTEVENT.value + ]: + sdk_event = OlivOS.mhyVilaSDK.event( + messageObj.dataHeader.BizType, + messageObj.dataTable, + self.Proc_data['bot_info_dict'] + ) + tx_packet_data = OlivOS.pluginAPI.shallow.rx_packet(sdk_event) + self.Proc_info.tx_queue.put(tx_packet_data, block=False) + except Exception as e: + traceback.print_exc() + + def on_error(self, ws:websocket.WebSocketApp, error): + self.log(0, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket link error') + + def on_close(self, ws:websocket.WebSocketApp, close_status_code, close_msg): + self.log(0, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket link close') - def on_error(self, ws, error): - self.log(0, 'OlivOS kaiheila link server [' + self.Proc_name + '] websocket link error') + def on_open(self, ws:websocket.WebSocketApp): + self.send_PLogin(ws) + threading.Thread( + target=self.run_pulse, + args=() + ).start() + self.log(2, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket link start') - def on_close(self, ws, close_status_code, close_msg): - self.log(0, 'OlivOS kaiheila link server [' + self.Proc_name + '] websocket link close') + def run_pulse(self): + tmp_ws_item = self.Proc_data['extend_data']['ws_item'] + while self.Proc_data['extend_data']['pulse_interval'] is not None: + tmp_pulse_interval = self.Proc_data['extend_data']['pulse_interval'] + time.sleep(tmp_pulse_interval) + tmp_data = OlivOS.mhyVilaSDK.PAYLOAD.PHeartBeat().dump() + if tmp_ws_item != self.Proc_data['extend_data']['ws_item'] or self.Proc_data['extend_data']['ws_item'] is None: + self.log(0, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket pulse giveup') + return + if self.Proc_data['extend_data']['ws_obj'] is not None: + try: + self.Proc_data['extend_data']['ws_obj'].send(tmp_data, opcode=websocket.ABNF.OPCODE_BINARY) + self.log(0, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket pulse send') + except: + break + else: + break + self.log(0, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket pulse lost') + return - def on_open(self, ws): - self.log(2, 'OlivOS kaiheila link server [' + self.Proc_name + '] websocket link start') + def send_PLogin(self, ws:websocket.WebSocketApp): + tmp_data = OlivOS.mhyVilaSDK.PAYLOAD.PLogin() + tmp_data.data.uid = self.Proc_data['extend_data']['ws_PLogin']['uid'] + tmp_data.data.token = self.Proc_data['extend_data']['ws_PLogin']['token'] + tmp_data.data.platform = self.Proc_data['extend_data']['ws_PLogin']['platform'] + tmp_data.data.app_id = self.Proc_data['extend_data']['ws_PLogin']['app_id'] + tmp_data.data.device_id = self.Proc_data['extend_data']['ws_PLogin']['device_id'] + tmp_data.dump() + #print(tmp_data) + ws.send(tmp_data.raw, opcode=websocket.ABNF.OPCODE_BINARY) def run_websocket_rx_connect_start(self): websocket.enableTrace(False) @@ -93,13 +158,15 @@ def run_websocket_rx_connect_start(self): self.Proc_data['extend_data']['websocket_url'], on_open=self.on_open, on_message=self.on_message, + on_data=self.on_data, on_error=self.on_error, on_close=self.on_close ) self.Proc_data['extend_data']['ws_obj'] = ws self.Proc_data['extend_data']['ws_item'] = uuid.uuid4() + self.Proc_data['extend_data']['pulse_interval'] = 20 ws.run_forever() self.Proc_data['extend_data']['pulse_interval'] = None self.Proc_data['extend_data']['ws_obj'] = None self.Proc_data['extend_data']['ws_item'] = None - self.log(2, 'OlivOS kaiheila link server [' + self.Proc_name + '] websocket link lost') + self.log(2, 'OlivOS mhyVila link server [' + self.Proc_name + '] websocket link lost') diff --git a/OlivOS/mhyVilaSDK.py b/OlivOS/mhyVilaSDK.py index 544139b4..57becc9a 100644 --- a/OlivOS/mhyVilaSDK.py +++ b/OlivOS/mhyVilaSDK.py @@ -18,6 +18,7 @@ import json import requests as req import time +from datetime import datetime, timezone, timedelta from requests_toolbelt import MultipartEncoder import uuid import traceback @@ -26,9 +27,11 @@ import hashlib import hmac import struct +import enum import OlivOS import OlivOS.thirdPartyModule.mhyVilaProto as mhyVilaProto +from OlivOS.thirdPartyModule.mhyVilaProto.tools import MessageToDict sdkAPIHost = { 'default': 'https://bbs-api.miyoushe.com' @@ -38,10 +41,13 @@ 'platform': '/vila/api/bot/platform' } +sdkIDCount = {} + sdkAPIRouteTemp = {} sdkSubSelfInfo = {} +sdkNameDict = {} class bot_info_T(object): def __init__( @@ -71,11 +77,189 @@ def get_SDK_bot_info_from_Plugin_bot_info(plugin_bot_info): def get_SDK_bot_info_from_Event(target_event): return get_SDK_bot_info_from_Plugin_bot_info(target_event.bot_info) +class event(object): + def __init__(self, BizType:int, dataTable:dict, botInfo): + self.payload = dataTable + self.BizType = BizType + self.platform = botInfo.platform + self.active = False + if self.payload is not None: + self.active = True + self.base_info = {} + if self.active: + self.base_info['time'] = int(time.time()) + self.base_info['self_id'] = botInfo.id + self.base_info['post_type'] = None + +def set_name(id:str, name:str): + global sdkNameDict + sdkNameDict[str(id)] = str(name) + +def get_name(id:str): + global sdkNameDict + return sdkNameDict.get(str(id), str(id)) + +def get_message(contentData:dict): + msg = contentData.get('content', {}).get('text', '') + res_msg = '' + count = 0 + atTable = contentData.get('content', {}).get('entities', []) + if type(atTable) is list: + for atTable_this in atTable: + if type(atTable_this) is dict: + i_offset = atTable_this.get('offset', None) + i_length = atTable_this.get('length', None) + s_type = atTable_this.get('entity', {}).get('type', None) + if type(i_offset) is int \ + and type(i_length) is int \ + and type(s_type) is str \ + and i_offset + i_length <= len(msg): + if s_type == 'mentioned_robot': + s_bot_id = atTable_this.get('entity', {}).get('bot_id', None) + if type(s_bot_id) is str: + res_msg += msg[count:i_offset] + res_msg += f'[OP:at,id={s_bot_id}] ' + set_name(s_bot_id, msg[i_offset + 1:i_offset + i_length - 1]) + count = i_offset + i_length + if s_type == 'mentioned_user': + s_user_id = atTable_this.get('entity', {}).get('user_id', None) + if type(s_user_id) is str: + res_msg += msg[count:i_offset] + res_msg += f'[OP:at,id={s_user_id}] ' + set_name(s_user_id, msg[i_offset + 1:i_offset + i_length - 1]) + count = i_offset + i_length + if count <= len(msg): + res_msg += msg[count:] + return res_msg + + +def release_message(msg:str): + res = { + 'content': { + 'text': '', + 'entities': [] + } + } + message_obj = OlivOS.messageAPI.Message_templet( + 'olivos_string', + msg + ) + for message_obj_this in message_obj.data: + if type(message_obj_this) is OlivOS.messageAPI.PARA.at: + i_offset = len(res['content']['text']) + res['content']['text'] += f"@{get_name(message_obj_this.data['id'])}" + i_length = len(res['content']['text']) - i_offset + obj_this = { + 'offset': i_offset, + 'length': i_length + } + if str(message_obj_this.data['id']).isdecimal(): + obj_this['entity'] = { + 'type': 'mentioned_user', + 'user_id': message_obj_this.data['id'] + } + else: + obj_this['entity'] = { + 'type': 'mentioned_robot', + 'bot_id': message_obj_this.data['id'] + } + res['content']['entities'].append(obj_this) + elif type(message_obj_this) is OlivOS.messageAPI.PARA.text: + res['content']['text'] += message_obj_this.data['text'] + return res + +def get_Event_from_SDK(target_event): + global sdkSubSelfInfo + #print(json.dumps(target_event.sdk_event.__dict__, ensure_ascii=False, indent=4)) + target_event.base_info['time'] = target_event.sdk_event.base_info['time'] + target_event.base_info['self_id'] = str(target_event.sdk_event.base_info['self_id']) + target_event.base_info['type'] = target_event.sdk_event.base_info['post_type'] + target_event.platform['sdk'] = target_event.sdk_event.platform['sdk'] + target_event.platform['platform'] = target_event.sdk_event.platform['platform'] + target_event.platform['model'] = target_event.sdk_event.platform['model'] + target_event.plugin_info['message_mode_rx'] = 'olivos_string' + plugin_event_bot_hash = OlivOS.API.getBotHash( + bot_id=target_event.base_info['self_id'], + platform_sdk=target_event.platform['sdk'], + platform_platform=target_event.platform['platform'], + platform_model=target_event.platform['model'] + ) + #print(type(target_event.sdk_event.payload)) + if target_event.sdk_event.BizType == protoEnum.Model_ROBOTEVENT.value \ + and type(target_event.sdk_event.payload) is dict \ + and target_event.sdk_event.payload.get('type', None) == 'SendMessage' \ + and type(target_event.sdk_event.payload.get('extendData', None)) is dict: + messageData = target_event.sdk_event.payload.get('extendData', {}).get('sendMessage', None) + if type(messageData) is dict: + contentData_str = messageData.get('content', None) + if type(contentData_str) is str \ + and messageData.get('objectName', None) == 'Text': + villaId = messageData.get('villaId', None) + roomId = messageData.get('roomId', None) + msgUid = messageData.get('msgUid', None) + nickname = messageData.get('nickname', None) + fromUserId = messageData.get('fromUserId', None) + contentData = json.loads(contentData_str) + #print(json.dumps(contentData, ensure_ascii=False, indent=4)) + if type(villaId) is str \ + and type(roomId) is str \ + and type(msgUid) is str \ + and type(nickname) is str \ + and type(fromUserId) is str: + msg = get_message(contentData) + target_event.active = True + target_event.plugin_info['func_type'] = 'group_message' + target_event.data = target_event.group_message( + roomId, + fromUserId, + msg, + 'group' + ) + target_event.data.message_sdk = OlivOS.messageAPI.Message_templet( + 'olivos_string', + msg + ) + target_event.data.message_id = msgUid + target_event.data.raw_message = target_event.data.message + target_event.data.raw_message_sdk = target_event.data.message_sdk + target_event.data.host_id = villaId + target_event.data.font = None + target_event.data.sender['name'] = nickname + target_event.data.sender['id'] = fromUserId + target_event.data.sender['nickname'] = target_event.data.sender['name'] + target_event.data.sender['user_id'] = target_event.data.sender['id'] ''' 对于WEBSOCKET接口的PAYLOAD实现 ''' +def getIDCount(botId:str) -> int: + global sdkIDCount + if type(sdkIDCount.get(str(botId), None)) is not int: + sdkIDCount[str(botId)] = 0 + res:int = sdkIDCount[str(botId)] + 1 + sdkIDCount[str(botId)] = res + return res + +class protoEnum(enum.Enum): + Command_P_HEARTBEAT = mhyVilaProto.command.Command.P_HEARTBEAT + Command_P_LOGIN = mhyVilaProto.command.Command.P_LOGIN + Command_P_LOGOUT = mhyVilaProto.command.Command.P_LOGOUT + Model_ROBOTEVENT = 30001 + +recvProtoDict = { + protoEnum.Command_P_HEARTBEAT.value: mhyVilaProto.command.PHeartBeatReply, + protoEnum.Command_P_LOGIN.value: mhyVilaProto.command.PLoginReply, + protoEnum.Command_P_LOGOUT.value: mhyVilaProto.command.PLogoutReply, + protoEnum.Model_ROBOTEVENT.value: mhyVilaProto.model.RobotEvent, +} + +sendProtoDict = { + protoEnum.Command_P_HEARTBEAT.value: mhyVilaProto.command.PHeartBeat, + protoEnum.Command_P_LOGIN.value: mhyVilaProto.command.PLogin, + protoEnum.Command_P_LOGOUT.value: mhyVilaProto.command.PLogout, +} + class payload_template(object): def __init__(self, raw:'bytearray|None'=None): self.active = True @@ -87,18 +271,20 @@ def __init__(self, raw:'bytearray|None'=None): self.dataHeader = self.dataHeader_T() self.dataDataBody:bytearray = b'' self.data = None + self.dataTable = {} self.dataProto = None + if self.is_rx: + self.load() class magicHeader_T(object): def __init__(self): - self.HeaderLen:int = 8 - self.Magic:bytearray = b'\xBA\xBE\xFA\xCE' + self.Magic:int = 0xBABEFACE self.DataLen:int = 0 class dataHeader_T(object): def __init__(self): self.HeaderLen:int = 24 # uint32 变长头总长度,变长头部分所有字段(包括HeaderLen本身)的总长度。 注:也就是说这玩意每个版本是固定的 - self.ID:int = 0 # uint64 协议包序列ID,同一条连接上的发出的协议包应该单调递增,相同序列ID且Flag字段相同的包应该被认为是同一个包 + self.ID:int = 1 # uint64 协议包序列ID,同一条连接上的发出的协议包应该单调递增,相同序列ID且Flag字段相同的包应该被认为是同一个包 self.Flag:int = 1 # uint32 配合bizType使用,用于标识同一个bizType协议的方向。 # 用 1 代表主动发到服务端的request包 # 用 2 代表针对某个request包回应的response包 @@ -106,23 +292,25 @@ def __init__(self): self.AppId:int = 104 # int32 应用标识。固定为 104 def __dump_dataDataBody(self): - if self.data is not None \ - and self.dataProto is not None: - self.dataDataBody = self.dataProto(**self.data.__dict__).SerializeToString() + if self.data is not None: + self.dataTable = self.data.__dict__ + if self.dataProto is not None: + self.dataDataBody = self.dataProto(**self.dataTable).SerializeToString() return self.dataDataBody def __update_DataLen(self): - self.magicHeader.DataLen = self.magicHeader.HeaderLen + self.dataHeader.HeaderLen + len(self.dataDataBody) + self.magicHeader.DataLen = self.dataHeader.HeaderLen + len(self.dataDataBody) return self.magicHeader.DataLen def __dump_magicHeader(self): return struct.pack( - '<4sI', + '= 32: + self.magicHeader.Magic, \ + self.magicHeader.DataLen = struct.unpack( + '' class PAYLOAD(object): class rxPacket(payload_template): def __init__(self, raw): - payload_template.__init__(self, raw, True) + payload_template.__init__(self, raw) # 登录命令 class PLogin(payload_template): def __init__(self): payload_template.__init__(self) + self.dataHeader.Flag = 1 + self.dataHeader.BizType = protoEnum.Command_P_LOGIN.value self.data = self.data_T() - self.dataProto = mhyVilaProto.command.PLogin + self.dataProto = sendProtoDict[self.dataHeader.BizType] class data_T(object): def __init__(self): @@ -164,12 +384,33 @@ def __init__(self): self.app_id:int = 0 self.device_id:str = '' self.region:str = '' + self.meta:dict = {} + + # 心跳命令 + class PHeartBeat(payload_template): + def __init__(self): + payload_template.__init__(self) + self.dataHeader.Flag = 1 + self.dataHeader.BizType = protoEnum.Command_P_HEARTBEAT.value + self.data = self.data_T() + self.dataProto = sendProtoDict[self.dataHeader.BizType] + + class data_T(object): + def __init__(self): + self.client_timestamp:str = str(int(datetime.now(timezone.utc).timestamp() * 1000)) ''' 对于POST接口的实现 ''' +def get_bot_secret(bot_info:bot_info_T): + return str(hmac.new( + str(bot_info.pub_key).encode('utf-8'), + str(bot_info.secret).encode('utf-8'), + hashlib.sha256 + ).hexdigest()) + class api_templet(object): def __init__(self): self.bot_info:'bot_info_T|None' = None @@ -201,11 +442,7 @@ def do_api(self, req_type='POST'): headers = { 'Content-Type': 'application/json', 'User-Agent': OlivOS.infoAPI.OlivOS_Header_UA, - 'x-rpc-bot_secret': '%s' % str(hmac.new( - str(self.bot_info.pub_key).encode('utf-8'), - str(self.bot_info.secret).encode('utf-8'), - hashlib.sha256 - ).hexdigest()), + 'x-rpc-bot_secret': '%s' % get_bot_secret(self.bot_info), 'x-rpc-bot_id': '%s' % str(self.bot_info.bot_id) } if self.headdata.vila_id is not None: @@ -218,6 +455,7 @@ def do_api(self, req_type='POST'): msg_res = req.request("GET", send_url, headers=headers) self.res = msg_res.text + #print(self.res) return msg_res.text except: return None @@ -241,3 +479,21 @@ def __init__(self): self.room_id = -1 self.object_name = 'MHY:Text' self.msg_content = '' + + +# 支持OlivOS API调用的方法实现 +class event_action(object): + def send_group_msg(target_event, chat_id, message, host_id = None): + if host_id is None: + try: + host_id = target_event.data.host_id + except: + pass + sdk_bot_info = get_SDK_bot_info_from_Event(target_event) + api_obj = API.sendMessage(sdk_bot_info) + api_obj.headdata.vila_id = host_id + api_obj.data.room_id = chat_id + api_obj.data.msg_content = json.dumps(release_message(message)) + api_obj.data.object_name = 'MHY:Text' + api_obj.do_api('POST') + return None diff --git a/OlivOS/thirdPartyModule/__init__.py b/OlivOS/thirdPartyModule/__init__.py index e44b8ad5..b674ca78 100644 --- a/OlivOS/thirdPartyModule/__init__.py +++ b/OlivOS/thirdPartyModule/__init__.py @@ -17,3 +17,4 @@ # here put the import lib from . import blivedm +from . import mhyVilaProto diff --git a/OlivOS/thirdPartyModule/mhyVilaProto/__init__.py b/OlivOS/thirdPartyModule/mhyVilaProto/__init__.py index e3af63f0..3bb3d891 100644 --- a/OlivOS/thirdPartyModule/mhyVilaProto/__init__.py +++ b/OlivOS/thirdPartyModule/mhyVilaProto/__init__.py @@ -2,3 +2,4 @@ from . import command_pb2 as command from . import model_pb2 as model from . import robot_event_message_pb2 as robot_event_message +from . import tools diff --git a/OlivOS/thirdPartyModule/mhyVilaProto/tools.py b/OlivOS/thirdPartyModule/mhyVilaProto/tools.py new file mode 100644 index 00000000..b1e25c0f --- /dev/null +++ b/OlivOS/thirdPartyModule/mhyVilaProto/tools.py @@ -0,0 +1 @@ +from google.protobuf.json_format import MessageToDict