Module socialization.ccs
Expand source code
from .base_god_service import BaseGodService
from .base_goddess_service import BaseGoddessService
from .json_ws_active_service import JSONWebsocketActiveService
from .json_ws_passive_service import JSONWebsocketPassiveService
from .wrapped_god_service import WrappedGodService
from .wrapped_goddess_service import WrappedGoddessService
from .wrapped_goddess_db_agent import WrappedGoddessDBAgent
from ..import codes
__all__ = ["BaseGodService", "BaseGoddessService", "JSONWebsocketActiveService", "JSONWebsocketPassiveService", "WrappedGodService", "WrappedGoddessService", "WrappedGoddessDBAgent", "codes"]
Sub-modules
socialization.ccs.base_god_service
socialization.ccs.base_goddess_service
socialization.ccs.json_ws_active_service
socialization.ccs.json_ws_passive_service
socialization.ccs.wrapped_god_service
socialization.ccs.wrapped_goddess_db_agent
socialization.ccs.wrapped_goddess_service
Classes
-
Expand source code
class BaseGodService(JSONWebsocketActiveService): def __init__(self): super().__init__() self.codes = codes self.path = '' # possible new route path for websocket def on_open(self, ws): print('BaseGodService opened') # override this function to handle data def _handle_data_dict(self, data, ws): # print(f'BaseGodService: _handle_data_dict received {data} at websocket {ws}') if data['code'] == self.codes.MESSAGE_TO_CCS: self._handle_message_to_ccs(data, ws, self.path) elif data['code'] == self.codes.COMMAND_TO_CCS: self._handle_command_to_ccs(data, ws, self.path) else: pass def _handle_message_to_ccs(self, data, ws, path): data['extra']['origin'] = self.__class__.__name__ data['extra']['type_code'] += 20000 # 3xxxx to 5xxxx self._send_data_to_ws(ws, self.codes.MESSAGE_FROM_CCS, **data['extra']) def _handle_command_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] if 20000 <= type_code <= 29999: self._handle_basic_command(data, ws, path) elif 80000 <= type_code <= 89999: self._handle_notice(data, ws, path) elif 90000 <= type_code <= 99999: self._handle_feature(data, ws, path) else: pass def _handle_basic_command(self, data, ws, path): pass def _handle_notice(self, data, ws, path): pass def _handle_feature(self, data, ws, path): pass def _send_ccs_operation(self, data, ws, path): code = data['code'] if code == self.codes.COPERATION_GOD_RECONNECT: user_id = data['extra']['user_id'] password = data['extra']['password'] self._send_data_to_ws(ws, code, user_id=user_id, password=password) else: pass # # print('BaseGoddessService ccs_operation: ', data) # code = data['code'] # password = data['extra']['password'] # ccs_id = data['extra']['ccs_id'] # if code == self.codes.COPERATION_LOGIN: # self._send_data_to_ws(ws, self.codes.COPERATION_LOGIN, ccs_id=ccs_id, password=password) # else: # pass def _send_command_down(self, ws, type_code, **kwargs): self._send_data_to_ws(ws, self.codes.COMMAND_FROM_CCS, type_code=type_code, **kwargs)
Ancestors
Subclasses
Methods
-
Expand source code
def on_open(self, ws): print('BaseGodService opened')
-
-
Expand source code
class BaseGoddessService(JSONWebsocketPassiveService): def __init__(self, port=9000): super().__init__(port=port) self.codes = codes async def _handle_data_dict(self, data, ws, path): # print('BaseGoddessService _handle_data_dict: ', data) if data['code'] == self.codes.MESSAGE_TO_CCS: await self._handle_message_to_ccs(data, ws, path) elif data['code'] == self.codes.COMMAND_TO_CCS: await self._handle_command_to_ccs(data, ws, path) # elif data['code'] == self.codes.QUERY_RESPOND_TO_CCS: # await self._handle_query_respond_to_ccs(data, ws, path) else: pass async def _handle_message_to_ccs(self, data, ws, path): data['extra']['origin'] = self.__class__.__name__ data['extra']['type_code'] += 20000 # 3xxxx to 5xxxx await self._send_data_to_ws(ws, self.codes.MESSAGE_FROM_CCS, **data['extra']) async def _handle_command_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] # print('BaseGoddessService _handle_command_to_ccs: ', data) if 20000 <= type_code <= 29999: await self._handle_basic_command(data, ws, path) elif 80000 <= type_code <= 89999: await self._handle_notice(data, ws, path) elif 90000 <= type_code <= 99999: await self._handle_feature(data, ws, path) else: pass async def _handle_basic_command(self, data, ws, path): pass async def _handle_notice(self, data, ws, path): pass async def _handle_feature(self, data, ws, path): pass async def _send_command_down(self, ws, type_code, **kwargs): await self._send_data_to_ws(ws, self.codes.COMMAND_FROM_CCS, type_code=type_code, **kwargs) async def _send_ccs_operation(self, data, ws, path): pass
Ancestors
Subclasses
-
Expand source code
class JSONWebsocketActiveService: def __init__(self) -> None: pass # new websocket, do not try to connect def create_websocket(self, uri, on_open=None, on_message=None, on_error=None, on_close=None): print('create_websocket') ws = websocket.WebSocketApp(uri, on_open=on_open or self.on_open, on_message=on_message or self.on_message, on_error=on_error or self.on_error, on_close=on_close or self.on_close ) return ws # new connections could be created in response to on_XXX following same rules def create_connection(self, uri, on_open=None, on_message=None, on_error=None, on_close=None): print('create_connection') # ws = websocket.WebSocketApp(uri, # on_open=on_open or self.on_open, # on_message=on_message or self.on_message, # on_error=on_error or self.on_error, # on_close=on_close or self.on_close # ) ws = self.create_websocket(uri, on_open, on_message, on_error, on_close) # ws.run_forever(reconnect=5) ws.run_forever(skip_utf8_validation=True, dispatcher=rel, reconnect=5) # print('before yield ws run_forever') # yield ws # print('start run_forever') # keep_on = True # use the return of run_forever to capture KeyboardInterrupt # while keep_on: # try: # keep_on = ws.run_forever(skip_utf8_validation=True, ping_interval=10, ping_timeout=8) # except Exception as e: # gc.collect() # print("Websocket connection Error : {e}") # print("Reconnecting websocket after 5 sec") # time.sleep(5) return ws def on_message(self, ws, message): import datetime ct = datetime.datetime.now() print("on_message on_message on_message", ct) self._safe_handle(ws, message) def on_error(self, ws, error): print(f'Male.on_error: {error}') def on_close(self, ws, close_status_code, close_msg): print(f"Male.on_close: {ws} closed with status code {close_status_code} and message {close_msg}") # print ("Retry connection: %s" % time.ctime()) # time.sleep(5) # self.run() # retry per 5 seconds # override this function to do something when connection is established def on_open(self, ws): pass @staticmethod def _make_data_dict(code, **extra_args): return { 'code': code, 'extra': extra_args } def _send_data_to_ws(self, ws, code, **extra_args): data_dict = self._make_data_dict(code=code, **extra_args) self._safe_send(ws, data_dict) def _safe_send(self, ws, data): try: if isinstance(data, dict): data = json.dumps(data) else: pass import datetime; ct = datetime.datetime.now() print("active send", ct) ws.send(data) return True except websocket.WebSocketConnectionClosedException as e: print('Male: _safe_send: Connection Closed Exception.', e) return False except Exception as e: traceback.print_exc() print('Male: self._safe_send: Exception Occurs', e) return False def echo(self, ws, message): print(f'echo() received message: {message}') message = "I got your message: {}".format(message) self._safe_send(ws, message) def _safe_handle(self, ws, message): import datetime; # # ct stores current time try: ct = datetime.datetime.now() print("before social active _safe_handle current time:-", ct) data = json.loads(message) # ct = datetime.datetime.now() # print('data', data, ct) self._handle_data_dict(data, ws) except ValueError as e: # traceback.print_exc() print(f'Male: _safe_handle received non-json message {message}') except Exception as e: print('Male: Server function error!') traceback.print_exc() # import datetime; # # ct stores current time # ct = datetime.datetime.now() # print("after social active _safe_handle current time:-", ct) # override this function to handle data def _handle_data_dict(self, data, ws): print(f'Male default: _handle_data_dict received {data} at websocket {ws}') def run(self): uri = 'wss://frog.4fun.chat/social' self.create_connection(uri) # print("after create_connection") rel.signal(2, rel.abort) # Keyboard Interrupt, one for all connections # print("after signal") rel.dispatch() # print("after everything in run") # def run(self): # uri = 'wss://frog.4fun.chat/social' # ws = self.create_connection(uri) # # _thread.start_new_thread(self.create_connection, (uri,)) # # # ws = websocket.WebSocketApp("ws://127.0.0.1:3000", on_open = on_open, on_close = on_close) # # wst = threading.Thread(target=ws.run_forever()) # # wst.daemon = True # # print('before start') # # wst.start() # # print('after start')
Subclasses
Methods
-
Expand source code
def create_connection(self, uri, on_open=None, on_message=None, on_error=None, on_close=None): print('create_connection') # ws = websocket.WebSocketApp(uri, # on_open=on_open or self.on_open, # on_message=on_message or self.on_message, # on_error=on_error or self.on_error, # on_close=on_close or self.on_close # ) ws = self.create_websocket(uri, on_open, on_message, on_error, on_close) # ws.run_forever(reconnect=5) ws.run_forever(skip_utf8_validation=True, dispatcher=rel, reconnect=5) # print('before yield ws run_forever') # yield ws # print('start run_forever') # keep_on = True # use the return of run_forever to capture KeyboardInterrupt # while keep_on: # try: # keep_on = ws.run_forever(skip_utf8_validation=True, ping_interval=10, ping_timeout=8) # except Exception as e: # gc.collect() # print("Websocket connection Error : {e}") # print("Reconnecting websocket after 5 sec") # time.sleep(5) return ws
-
Expand source code
def create_websocket(self, uri, on_open=None, on_message=None, on_error=None, on_close=None): print('create_websocket') ws = websocket.WebSocketApp(uri, on_open=on_open or self.on_open, on_message=on_message or self.on_message, on_error=on_error or self.on_error, on_close=on_close or self.on_close ) return ws
-
Expand source code
def echo(self, ws, message): print(f'echo() received message: {message}') message = "I got your message: {}".format(message) self._safe_send(ws, message)
-
Expand source code
def on_close(self, ws, close_status_code, close_msg): print(f"Male.on_close: {ws} closed with status code {close_status_code} and message {close_msg}") # print ("Retry connection: %s" % time.ctime()) # time.sleep(5) # self.run() # retry per 5 seconds
-
Expand source code
def on_error(self, ws, error): print(f'Male.on_error: {error}')
-
Expand source code
def on_message(self, ws, message): import datetime ct = datetime.datetime.now() print("on_message on_message on_message", ct) self._safe_handle(ws, message)
-
Expand source code
def on_open(self, ws): pass
-
Expand source code
def run(self): uri = 'wss://frog.4fun.chat/social' self.create_connection(uri) # print("after create_connection") rel.signal(2, rel.abort) # Keyboard Interrupt, one for all connections # print("after signal") rel.dispatch() # print("after everything in run")
-
-
Expand source code
class JSONWebsocketPassiveService: def __init__(self, port=7654): self.port = port @property def _timestamp(self): now = datetime.now(timezone.utc) epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) # use POSIX epoch return (now - epoch) // timedelta(microseconds=1) # or `/ 1e3` for float @staticmethod def _make_data_dict(code, **extra_args): return { 'code': code, 'extra': extra_args } async def _safe_send(self, ws, data): # import datetime; # ct stores current time # ct = datetime.datetime.now() # print("before social passive _safe_sendcurrent time:-", ct, data) try: if isinstance(data, dict): data = json.dumps(data) else: pass await ws.send(data) # ct stores current time # ct = datetime.datetime.now() # print("after social passive _safe_sendcurrent time:-", ct) return True except websockets.ConnectionClosedOK as e: print('_safe_send: Connection Closed OK Exception.', e) return False except websockets.ConnectionClosed as e: print('_safe_send: Connection Closed Exception.', e) return False except Exception as e: traceback.print_exc() print('self._safe_send: Exception Occurs', e) return False async def _send_data_to_ws(self, ws, code, **extra_args): data_dict = self._make_data_dict(code=code, **extra_args) await self._safe_send(ws, data_dict) async def echo(self, ws, message): print(f'echo() received message: {message}') message = "I got your message: {}".format(message) await self._safe_send(ws, message) async def _safe_handle(self, ws, path): # import datetime; # ct stores current time # ct = datetime.datetime.now() # print("before social passive _safe_handle current time:-", ct) try: # This websocket may be closed async for message in ws: try: import datetime ct = datetime.datetime.now() print("passive handle", ct, message) data = json.loads(message) await self._handle_data_dict(data, ws, path) except Exception as e: traceback.print_exc() await self._handle_internal_error(e, ws, path) # ct = datetime.datetime.now() # print("after social passive _safe_handle current time:-", ct) except Exception as e: print('Exception in handle(): ', e) async def _handle_data_dict(self, data, ws, path): await self._safe_send(ws, 'Female: _handle_data_dict Not Implemented') async def _handle_internal_error(self, e, ws, path): await self._safe_send(ws, f'Female._handle_internal_error: {e}') # call this for the coroutine to start def get_server_coroutine(self): return websockets.serve(self._safe_handle, 'localhost', self.port)
Subclasses
Methods
-
Expand source code
async def echo(self, ws, message): print(f'echo() received message: {message}') message = "I got your message: {}".format(message) await self._safe_send(ws, message)
-
Expand source code
def get_server_coroutine(self): return websockets.serve(self._safe_handle, 'localhost', self.port)
-
-
This is the wrapped God service. CCS provides a various of features for users in corresponding channels to use.
Expand source code
class WrappedGodService(BaseGodService): """ This is the wrapped God service. CCS provides a various of features for users in corresponding channels to use. """ def __init__(self, name='WrappedGodService'): super().__init__() self.agent = WrappedGoddessDBAgent(name+".json") self.uri = None self.name = 'WrappedGodService' self.feature_commands = [] self.basic_command_func_map = {} self.notice_func_map = {} self.feature_func_map = {} self.prompt = {} self.message_func_map = {} self.temp_msg_map = {} def on_open(self, ws): """ Default behavior "on_open" for websocket. You can override this method to customize your own behavior. Also applies to "on_message", "on_error" and "on_close". """ data = {'code': self.codes.COPERATION_GOD_RECONNECT, 'extra': { 'user_id': self.user_id, 'password': self.password}} print('SocialGodService send query: run: ', data) self._send_ccs_operation(data, ws, None) print(self.name, 'opened') def add_feature(self, name, code, prompts, func=None): """ Add a feature to the service. Every feature contains a name, a code and a prompt. The code is always a five-digited int, and the first number must be 9, like 90001. The prompt here will be replaced by "params" in the future. Now it's the string that shows to the user in the input bar. You do not need to specify a handler func to the feature, but it's recommended to do so. If one feature with no handler is triggered, an exception will be raised. You can use set_feature_handle to set a handler for a feature. """ self.feature_commands.append( {'name': name, 'code': code, 'prompts': [prompts] if prompts else []}) self.prompt[code] = prompts if func: self.feature_func_map[code] = func def remove_feature(self, code): """ Remove a feature from the service. The feature is specified by its code. """ self.feature_commands = list( filter(lambda x: x['code'] != code, self.feature_commands)) self.feature_func_map.pop(code, None) def set_basic_command_handle(self, code, func): """ Set a handler for a basic command. The command is specified by its code. Some commands will be like "help", "quit". """ self.basic_command_func_map[code] = func def set_notice_handle(self, code, func): """ Set a handler for a notice. The notice is specified by its code. Some notices will be like "user joined the channel", "user left the channel". """ self.notice_func_map[code] = func def set_feature_handle(self, code, func): """ Set a handler for a feature. The feature is specified by its code. """ self.feature_func_map[code] = func def set_message_handle(self, code, func): """ Set a handler for a message. This code is always MESSAGE_TO_CCS. """ self.message_func_map[code] = func def _handle_data_dict(self, data, ws): print( f'WrappedGodService: _handle_data_dict received {data} at websocket {ws}') if data['code'] == self.codes.MESSAGE_TO_CCS: try: self._handle_message_to_ccs(data, ws, self.path) except Exception as e: print('WrappedGodService: _handle_message_to_ccs error: ', e) elif data['code'] == self.codes.COMMAND_TO_CCS: try: self._handle_command_to_ccs(data, ws, self.path) except Exception as e: print('WrappedGodService: _handle_command_to_ccs error: ', e) else: raise Exception('no handler for code', data['code']) def _handle_message_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.message_func_map: self.message_func_map[type_code](self, data, ws, path) else: raise Exception('no message function for code', type_code) def _handle_command_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] if 20000 <= type_code <= 29999: self._handle_basic_command(data, ws, path) elif 80000 <= type_code <= 89999: self._handle_notice(data, ws, path) elif 90000 <= type_code <= 99999: self._handle_feature(data, ws, path) else: raise Exception('no command function for code', type_code) def _handle_basic_command(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.basic_command_func_map: self.basic_command_func_map[type_code](self, data, ws, path) else: raise Exception('no basic command function for code', type_code) def _handle_notice(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.notice_func_map: self.notice_func_map[type_code](self, data, ws, path) else: raise Exception('no notice function for code', type_code) def _handle_feature(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.feature_func_map: self.feature_func_map[type_code](self, data, ws, path) else: raise Exception('no feature function for code', type_code) def _send_ccs_operation(self, data, ws, path): print('WrappedGodService ccs_operation: ', data) code = data['code'] password = data['extra']['password'] user_id = data['extra']['user_id'] if code == self.codes.COPERATION_GOD_RECONNECT: self._send_data_to_ws( ws, self.codes.COPERATION_GOD_RECONNECT, user_id=user_id, password=password) else: raise Exception('no ccs operation for code', code) def _send_command_down(self, ws, type_code, **kwargs): self._send_data_to_ws(ws, self.codes.COMMAND_FROM_CCS, type_code=type_code, **kwargs) def _send_message_down(self, ws, type_code, channel_id, to_user_ids, origin, **kwargs): self._send_data_to_ws(ws, self.codes.MESSAGE_FROM_CCS, type_code=type_code, channel_id=channel_id, to_user_ids=to_user_ids, origin=origin, **kwargs) def broadcast_command_text(self, data, ws, text, clear=False): """ Broadcast a text to all users in a channel. """ channel_id = data['extra']['channel_id'] self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'text': text, 'clear': clear} ) def broadcast_command_image(self, data, ws, url): """ Broadcast an image to all users in a channel. """ channel_id = data['extra']['channel_id'] self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={ 'type': 'url', 'image': url } ) def reply_command_text(self, data, ws, text, clear=False): """ Reply a text to a single user. """ self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=data['extra']['channel_id'], to_user_ids=[data['extra']['user_id']], args={'text': text, 'clear': clear} ) def reply_command_image(self, data, ws, url): """ Reply an image to a single user. """ self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=data['extra']['channel_id'], to_user_ids=[data['extra']['user_id']], args={'type': 'url', 'image': url} ) def whistle_sender_command_text( self, data, ws, *, text_to_sender, text_to_others, clear_sender=False, clear_others=False ): """ Dog whistle. """ channel_id = data['extra']['channel_id'] # to sender self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=[data['extra']['user_id']], args={'text': text_to_sender, 'clear': clear_sender} ) # to others self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=list(set(self.agent.get_channel_user_list( channel_id)) - {data['extra']['user_id']}), args={'text': text_to_others, 'clear': clear_others} ) def set_account(self, user_id, password): """ Set the account for the service. Fetch these in CH0000. """ self.user_id = user_id self.password = password def run(self): """ Run the service. """ uri = 'wss://frog.4fun.chat/social' if self.uri is None else self.uri ws = self.create_connection( uri, self.on_open, self.on_message, self.on_error, self.on_close) rel.signal(2, rel.abort) # Keyboard Interrupt, one for all connections rel.dispatch()
Ancestors
Methods
-
Add a feature to the service. Every feature contains a name, a code and a prompt. The code is always a five-digited int, and the first number must be 9, like 90001. The prompt here will be replaced by "params" in the future. Now it's the string that shows to the user in the input bar. You do not need to specify a handler func to the feature, but it's recommended to do so. If one feature with no handler is triggered, an exception will be raised. You can use set_feature_handle to set a handler for a feature.
Expand source code
def add_feature(self, name, code, prompts, func=None): """ Add a feature to the service. Every feature contains a name, a code and a prompt. The code is always a five-digited int, and the first number must be 9, like 90001. The prompt here will be replaced by "params" in the future. Now it's the string that shows to the user in the input bar. You do not need to specify a handler func to the feature, but it's recommended to do so. If one feature with no handler is triggered, an exception will be raised. You can use set_feature_handle to set a handler for a feature. """ self.feature_commands.append( {'name': name, 'code': code, 'prompts': [prompts] if prompts else []}) self.prompt[code] = prompts if func: self.feature_func_map[code] = func
-
Broadcast an image to all users in a channel.
Expand source code
def broadcast_command_image(self, data, ws, url): """ Broadcast an image to all users in a channel. """ channel_id = data['extra']['channel_id'] self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={ 'type': 'url', 'image': url } )
-
Broadcast a text to all users in a channel.
Expand source code
def broadcast_command_text(self, data, ws, text, clear=False): """ Broadcast a text to all users in a channel. """ channel_id = data['extra']['channel_id'] self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'text': text, 'clear': clear} )
-
Default behavior "on_open" for websocket. You can override this method to customize your own behavior. Also applies to "on_message", "on_error" and "on_close".
Expand source code
def on_open(self, ws): """ Default behavior "on_open" for websocket. You can override this method to customize your own behavior. Also applies to "on_message", "on_error" and "on_close". """ data = {'code': self.codes.COPERATION_GOD_RECONNECT, 'extra': { 'user_id': self.user_id, 'password': self.password}} print('SocialGodService send query: run: ', data) self._send_ccs_operation(data, ws, None) print(self.name, 'opened')
-
Remove a feature from the service. The feature is specified by its code.
Expand source code
def remove_feature(self, code): """ Remove a feature from the service. The feature is specified by its code. """ self.feature_commands = list( filter(lambda x: x['code'] != code, self.feature_commands)) self.feature_func_map.pop(code, None)
-
Reply an image to a single user.
Expand source code
def reply_command_image(self, data, ws, url): """ Reply an image to a single user. """ self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=data['extra']['channel_id'], to_user_ids=[data['extra']['user_id']], args={'type': 'url', 'image': url} )
-
Reply a text to a single user.
Expand source code
def reply_command_text(self, data, ws, text, clear=False): """ Reply a text to a single user. """ self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=data['extra']['channel_id'], to_user_ids=[data['extra']['user_id']], args={'text': text, 'clear': clear} )
-
Run the service.
Expand source code
def run(self): """ Run the service. """ uri = 'wss://frog.4fun.chat/social' if self.uri is None else self.uri ws = self.create_connection( uri, self.on_open, self.on_message, self.on_error, self.on_close) rel.signal(2, rel.abort) # Keyboard Interrupt, one for all connections rel.dispatch()
-
Set the account for the service. Fetch these in CH0000.
Expand source code
def set_account(self, user_id, password): """ Set the account for the service. Fetch these in CH0000. """ self.user_id = user_id self.password = password
-
Set a handler for a basic command. The command is specified by its code. Some commands will be like "help", "quit".
Expand source code
def set_basic_command_handle(self, code, func): """ Set a handler for a basic command. The command is specified by its code. Some commands will be like "help", "quit". """ self.basic_command_func_map[code] = func
-
Set a handler for a feature. The feature is specified by its code.
Expand source code
def set_feature_handle(self, code, func): """ Set a handler for a feature. The feature is specified by its code. """ self.feature_func_map[code] = func
-
Set a handler for a message. This code is always MESSAGE_TO_CCS.
Expand source code
def set_message_handle(self, code, func): """ Set a handler for a message. This code is always MESSAGE_TO_CCS. """ self.message_func_map[code] = func
-
Set a handler for a notice. The notice is specified by its code. Some notices will be like "user joined the channel", "user left the channel".
Expand source code
def set_notice_handle(self, code, func): """ Set a handler for a notice. The notice is specified by its code. Some notices will be like "user joined the channel", "user left the channel". """ self.notice_func_map[code] = func
-
Dog whistle.
Expand source code
def whistle_sender_command_text( self, data, ws, *, text_to_sender, text_to_others, clear_sender=False, clear_others=False ): """ Dog whistle. """ channel_id = data['extra']['channel_id'] # to sender self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=[data['extra']['user_id']], args={'text': text_to_sender, 'clear': clear_sender} ) # to others self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=list(set(self.agent.get_channel_user_list( channel_id)) - {data['extra']['user_id']}), args={'text': text_to_others, 'clear': clear_others} )
-
-
Expand source code
class WrappedGoddessDBAgent: def __init__(self, path): self.path = path # create if not exist if not os.path.exists(self.path): with open(self.path, 'w') as f: json.dump({}, f) def leave_channel(self, channel_id, user_id): with open(self.path, 'r') as f: data = json.load(f) data["user_list"][channel_id].remove(user_id) # write with open(self.path, 'w') as f: json.dump(data, f) def join_channel(self, channel_id, user_id): with open(self.path, 'r') as f: data = json.load(f) if not channel_id in data: data["user_list"][channel_id] = [] data["user_list"][channel_id].append(user_id) # write with open(self.path, 'w') as f: json.dump(data, f) def get_channel_user_list(self, channel_id): with open(self.path, 'r') as f: data = json.load(f) if not ("user_list" in data and channel_id in data["user_list"]): return [] return data["user_list"][channel_id] def init_user_id_list(self, channel_id, user_ids): with open(self.path, 'r') as f: data = json.load(f) data["user_list"][channel_id] = user_ids or [] with open(self.path, 'w') as f: json.dump(data, f) def init_dog_whistle(self, channel_id): with open(self.path, 'r') as f: data = json.load(f) data["dog_whistle"][channel_id] = [] with open(self.path, 'w') as f: json.dump(data, f) def add_whistle_msg(self, channel_id, msg, recipients): with open(self.path, 'r') as f: data = json.load(f) data["dog_whistle"][channel_id].append({msg, recipients}) with open(self.path, 'w') as f: json.dump(data, f) def get_whistle_recipients(self, channel_id, msg): with open(self.path, 'r') as f: data = json.load(f) if not ("dog_whistle" in data and channel_id in data["dog_whistle"] and msg in data["dog_whistle"][channel_id]): return [] return data["dog_whistle"][channel_id][msg]
Methods
-
Expand source code
def add_whistle_msg(self, channel_id, msg, recipients): with open(self.path, 'r') as f: data = json.load(f) data["dog_whistle"][channel_id].append({msg, recipients}) with open(self.path, 'w') as f: json.dump(data, f)
-
Expand source code
def get_channel_user_list(self, channel_id): with open(self.path, 'r') as f: data = json.load(f) if not ("user_list" in data and channel_id in data["user_list"]): return [] return data["user_list"][channel_id]
-
Expand source code
def get_whistle_recipients(self, channel_id, msg): with open(self.path, 'r') as f: data = json.load(f) if not ("dog_whistle" in data and channel_id in data["dog_whistle"] and msg in data["dog_whistle"][channel_id]): return [] return data["dog_whistle"][channel_id][msg]
-
Expand source code
def init_dog_whistle(self, channel_id): with open(self.path, 'r') as f: data = json.load(f) data["dog_whistle"][channel_id] = [] with open(self.path, 'w') as f: json.dump(data, f)
-
Expand source code
def init_user_id_list(self, channel_id, user_ids): with open(self.path, 'r') as f: data = json.load(f) data["user_list"][channel_id] = user_ids or [] with open(self.path, 'w') as f: json.dump(data, f)
-
Expand source code
def join_channel(self, channel_id, user_id): with open(self.path, 'r') as f: data = json.load(f) if not channel_id in data: data["user_list"][channel_id] = [] data["user_list"][channel_id].append(user_id) # write with open(self.path, 'w') as f: json.dump(data, f)
-
Expand source code
def leave_channel(self, channel_id, user_id): with open(self.path, 'r') as f: data = json.load(f) data["user_list"][channel_id].remove(user_id) # write with open(self.path, 'w') as f: json.dump(data, f)
-
-
Expand source code
class WrappedGoddessService(BaseGoddessService): def __init__(self, port, uri, token, name='WrappedGoddessService'): super().__init__(port) self.agent = WrappedGoddessDBAgent('/home/ubuntu/social_backend/yellow502goddess.json') self.uri = uri self.token = token self.name = name self.feature_commands = [] self.basic_command_func_map = { self.codes.COMMAND_UP_FETCH_CHANNEL_USER_LIST: handle_command_fetch_user_list, self.codes.COMMAND_UP_FETCH_RECIPIENT_LIST: handle_command_fetch_recipient_list, self.codes.COMMAND_UP_FETCH_CCS_COMMAND_LIST: handle_command_fetch_cmd_list, } self.notice_func_map = { self.codes.NOTICE_ASK_AUTH_TOKEN: handle_notice_auth_token, self.codes.NOTICE_TAKE_OVER: handle_notice_take_over, self.codes.NOTICE_RELEASE: handle_notice_release, self.codes.NOTICE_USER_JOINED: handle_notice_user_joined, } self.feature_func_map = {} self.prompt = {} self.message_func_map = {} def add_feature(self, name, code, prompts, func=None): self.feature_commands.append( {'name': name, 'code': code, 'prompts': [prompts]}) self.prompt[code] = prompts if func: self.feature_func_map[code] = func def set_basic_command_handle(self, code, func): self.basic_command_func_map[code] = func def set_notice_handle(self, code, func): self.notice_func_map[code] = func def set_feature_handle(self, code, func): self.feature_func_map[code] = func def set_message_handle(self, code, func): self.message_func_map[code] = func async def _handle_data_dict_core(self, data, ws, path): print(f'WrappedGoddessService: _handle_data_dict received {data}.') if data['code'] == self.codes.MESSAGE_TO_CCS: await self._handle_message_to_ccs(data, ws, path) elif data['code'] == self.codes.COMMAND_TO_CCS: await self._handle_command_to_ccs(data, ws, path) else: pass async def _handle_data_dict(self, data, ws, path): asyncio.ensure_future(self._handle_data_dict_core(data, ws, path)) async def _handle_message_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.message_func_map: await self.message_func_map[type_code](self, data, ws, path) else: print('no message function for code', type_code) async def _handle_command_to_ccs(self, data, ws, path): type_code = data['extra']['type_code'] if 20000 <= type_code <= 29999: await self._handle_basic_command(data, ws, path) elif 80000 <= type_code <= 89999: await self._handle_notice(data, ws, path) elif 90000 <= type_code <= 99999: await self._handle_feature(data, ws, path) else: pass async def _handle_basic_command(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.basic_command_func_map: await self.basic_command_func_map[type_code](self, data, ws, path) else: print('no basic_command function for code', type_code) async def _handle_notice(self, data, ws, path): type_code = data['extra']['type_code'] print('receive notice:' + str(data)) if type_code in self.notice_func_map: await self.notice_func_map[type_code](self, data, ws, path) else: if type_code == self.codes.NOTICE_USER_LEFT: channel_id = data['extra']['channel_id'] # Here the CCS database may want to update to delete the new user # In the case of Social default Goddess, the database has been updated on OPERATION_JOIN user_id = data['extra']['user_id'] self.agent.leave_channel(channel_id, user_id) user_ids = self.agent.get_channel_user_list(channel_id) print('user_ids', user_ids) # serial_numbers= self.agent.user_id_list_to_serial_number_list(user_ids) # alias = [self.serial_number_to_alias(serial_number) for serial_number in serial_numbers] # print('alias', alias) # await self._send_command_down(ws, self.codes.COMMAND_DOWN_UPDATE_CHANNEL_USER_LIST, # channel_id=channel_id, to_user_ids=user_ids) # await self._send_command_down(ws, self.codes.COMMAND_DOWN_UPDATE_CCS_COMMAND_LIST, # channel_id=channel_id, to_user_ids=user_ids) await self._send_command_down(ws, self.codes.COMMAND_DOWN_UPDATE_CHANNEL_USER_LIST, channel_id=channel_id, to_user_ids=user_ids, user_ids=user_ids) # await self._send_command_down(ws, self.codes.COMMAND_DOWN_UPDATE_CCS_COMMAND_LIST, # channel_id=channel_id, to_user_ids=user_ids, commands=self.feature_commands) elif type_code == self.codes.NOTICE_GET_CHANNEL_USER_LIST: print('ccs yellowbear notice get channel user list', data) else: raise Exception('yellowbear goddess Unknown type_code: {}'.format(type_code)) ''' else: print('no notice function for code', type_code) ''' async def _handle_feature(self, data, ws, path): type_code = data['extra']['type_code'] if type_code in self.feature_func_map: await self.feature_func_map[type_code](self, data, ws, path) else: print('no feature function for code', type_code) async def _send_ccs_operation(self, data, ws, path): print('WrappedGoddessService ccs_operation: ', data) code = data['code'] password = data['extra']['password'] ccs_id = data['extra']['ccs_id'] if code == self.codes.OPERATION_CCS_LOGIN: await self._send_data_to_ws( ws, self.codes.OPERATION_CCS_LOGIN, ccs_id=ccs_id, password=password) else: pass async def _send_command_down(self, ws, type_code, **kwargs): await self._send_data_to_ws(ws, self.codes.COMMAND_FROM_CCS, type_code=type_code, **kwargs) ### Some wrapped functions, use them to make your work easier! # broadcast to all users async def broadcast_command_text(self, channel_id, ws, text, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'text': text, 'clear': clear} ) async def broadcast_command_image(self, channel_id, ws, url, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'type':'url', 'image': url} ) # only reply to the sender async def reply_command_text(self, data, ws, text, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = [data['extra']['user_id']], args = {'text': text, 'clear': clear} ) # two texts, one for sender, one for others async def whistle_sender_command_text( self, data, ws, *, text_to_sender, text_to_others, clear_sender=False, clear_others=False ): # to sender await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = [data['extra']['user_id']], args = {'text': text_to_sender, 'clear': clear_sender} ) # to others user_ids = self.agent.get_channel_user_list(data['extra']['channel_id']) await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = list(set(user_ids) - {data['extra']['user_id']}), args = {'text': text_to_others, 'clear': clear_others} )
Ancestors
Methods
-
Expand source code
def add_feature(self, name, code, prompts, func=None): self.feature_commands.append( {'name': name, 'code': code, 'prompts': [prompts]}) self.prompt[code] = prompts if func: self.feature_func_map[code] = func
-
Expand source code
async def broadcast_command_image(self, channel_id, ws, url, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_IMAGE, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'type':'url', 'image': url} )
-
Expand source code
async def broadcast_command_text(self, channel_id, ws, text, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id=channel_id, to_user_ids=self.agent.get_channel_user_list(channel_id), args={'text': text, 'clear': clear} )
-
Expand source code
async def reply_command_text(self, data, ws, text, clear=False): await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = [data['extra']['user_id']], args = {'text': text, 'clear': clear} )
-
Expand source code
def set_basic_command_handle(self, code, func): self.basic_command_func_map[code] = func
-
Expand source code
def set_feature_handle(self, code, func): self.feature_func_map[code] = func
-
Expand source code
def set_message_handle(self, code, func): self.message_func_map[code] = func
-
Expand source code
def set_notice_handle(self, code, func): self.notice_func_map[code] = func
-
Expand source code
async def whistle_sender_command_text( self, data, ws, *, text_to_sender, text_to_others, clear_sender=False, clear_others=False ): # to sender await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = [data['extra']['user_id']], args = {'text': text_to_sender, 'clear': clear_sender} ) # to others user_ids = self.agent.get_channel_user_list(data['extra']['channel_id']) await self._send_command_down( ws, self.codes.COMMAND_DOWN_DISPLAY_TEXT, channel_id = data['extra']['channel_id'], to_user_ids = list(set(user_ids) - {data['extra']['user_id']}), args = {'text': text_to_others, 'clear': clear_others} )
-