From e204cc74226b02c83e343408551a97b4befafe18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Thu, 2 May 2019 15:07:13 +0200 Subject: [PATCH 1/8] Make event_handler_main shutdown gracefully on SIGTERM and SIGINT --- solvable/src/event_handler_main.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/solvable/src/event_handler_main.py b/solvable/src/event_handler_main.py index 9ff99e5..a4f231a 100644 --- a/solvable/src/event_handler_main.py +++ b/solvable/src/event_handler_main.py @@ -1,9 +1,10 @@ from ast import literal_eval from functools import partial +from signal import signal, SIGTERM, SIGINT from tornado.ioloop import IOLoop -from tfw import YamlFSM, FSMAwareEventHandler +from tfw import YamlFSM, FSMAwareEventHandler, EventHandlerBase from tfw.components import IdeEventHandler, TerminalEventHandler from tfw.components import ProcessManagingEventHandler, BashMonitor from tfw.components import TerminalCommands, LogMonitoringEventHandler @@ -136,9 +137,12 @@ if __name__ == '__main__': # Example terminal command callback terminal.historymonitor.subscribe_callback(cenator) - try: - IOLoop.instance().start() - finally: - eventhandlers = {fsm, ide, terminal, processmanager, logmonitor, message_fsm_steps} - for eh in eventhandlers: + event_handlers = EventHandlerBase.get_local_instances() + def cleanup(sig, frame): + for eh in event_handlers: eh.cleanup() + exit(0) + signal(SIGTERM, cleanup) + signal(SIGINT, cleanup) + + IOLoop.instance().start() From 31d8161379fd03afade3826b1ffcaf914d9ce996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Thu, 2 May 2019 15:59:20 +0200 Subject: [PATCH 2/8] Add example process with PipeIO event handlers --- solvable/src/pipe_io_main.py | 24 ++++++++++++++++++++++++ solvable/supervisor/pipe_io_main.conf | 4 ++++ 2 files changed, 28 insertions(+) create mode 100644 solvable/src/pipe_io_main.py create mode 100644 solvable/supervisor/pipe_io_main.conf diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py new file mode 100644 index 0000000..e0b0f83 --- /dev/null +++ b/solvable/src/pipe_io_main.py @@ -0,0 +1,24 @@ +from signal import signal, SIGTERM, SIGINT + +from tornado.ioloop import IOLoop + +from tfw import EventHandlerBase +from tfw.components import PipeIOEventHandler + + +if __name__ == '__main__': + ide_pipeio = PipeIOEventHandler( + 'ide', + '/tmp/ide_send', + '/tmp/ide_recv' + ) + + event_handlers = EventHandlerBase.get_local_instances() + def cleanup(sig, frame): + for eh in event_handlers: + eh.cleanup() + exit(0) + signal(SIGTERM, cleanup) + signal(SIGINT, cleanup) + + IOLoop.instance().start() diff --git a/solvable/supervisor/pipe_io_main.conf b/solvable/supervisor/pipe_io_main.conf new file mode 100644 index 0000000..bdf8a1a --- /dev/null +++ b/solvable/supervisor/pipe_io_main.conf @@ -0,0 +1,4 @@ +[program:pipe_io_main] +user=root +directory=%(ENV_TFW_EHMAIN_DIR)s +command=python3 pipe_io_main.py From fe49e61f82b1396cf9ed4b6d08056c7fc1e7cba8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Sun, 5 May 2019 21:29:39 +0200 Subject: [PATCH 3/8] Generalize pipeio by subscribing to all keys in pipe_io_main --- solvable/src/pipe_io_main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index e0b0f83..26e7349 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -7,10 +7,10 @@ from tfw.components import PipeIOEventHandler if __name__ == '__main__': - ide_pipeio = PipeIOEventHandler( - 'ide', - '/tmp/ide_send', - '/tmp/ide_recv' + pipe_io = PipeIOEventHandler( + '', + '/tmp/tfw_send', + '/tmp/tfw_recv' ) event_handlers = EventHandlerBase.get_local_instances() From 6edc8d8bd53b90fca63d84bd14a25afa2241e8fa Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Mon, 13 May 2019 16:58:24 +0200 Subject: [PATCH 4/8] Implement simple pipe-based event handlers --- solvable/src/pipe_io_auxlib.py | 154 +++++++++++++++++++++++++++++++++ solvable/src/pipe_io_main.py | 79 ++++++++++++++++- 2 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 solvable/src/pipe_io_auxlib.py diff --git a/solvable/src/pipe_io_auxlib.py b/solvable/src/pipe_io_auxlib.py new file mode 100644 index 0000000..37bb1a8 --- /dev/null +++ b/solvable/src/pipe_io_auxlib.py @@ -0,0 +1,154 @@ +from json import dumps, loads +from tfw.crypto import KeyManager, sign_message, verify_message +from tfw.components import PipeIOEventHandlerBase +from tfw.components.pipe_io_event_handler import DEFAULT_PERMISSIONS + +class DeployPipeIOEventHandler(PipeIOEventHandlerBase): + # pylint: disable=too-many-arguments + def __init__( + self, in_pipe_path, out_pipe_path, process, + permissions=DEFAULT_PERMISSIONS + ): + self.expected = False + self.process = process + + self.onsuccess = { + 'key': 'processmanager', + 'data': { + 'process_name': process, + 'command': 'restart' + } + } + self.onerror = { + 'key': 'processmanager', + 'data': { + 'process_name': process, + 'error': True + } + } + + super().__init__('processmanager', in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + if message == self.onsuccess: + self.expected = True + self.pipe_io.send_message(b'deploy') + + def handle_pipe_event(self, message_bytes): + if not self.expected: + raise ValueError( + f'{self.pipe_io.in_pipe}: There is nothing to deploy.' + ) + + self.expected = False + if message_bytes == b'true': + self.server_connector.send(self.onsuccess) + elif message_bytes == b'false': + self.server_connector.send(self.onerror) + else: + raise ValueError( + f'{self.pipe_io.in_pipe}: Expected "true" or "false".' + ) + +class IdePipeIOEventHandler(PipeIOEventHandlerBase): + # pylint: disable=too-many-arguments + def __init__( + self, in_pipe_path, out_pipe_path, filename, + permissions=DEFAULT_PERMISSIONS, + selected=True + ): + self.selected = selected + self.filename = filename + super().__init__('ide', in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + data = message['data'] + + if data['command'] == 'select': + self.selected = data['filename'] == self.filename + elif data['command'] == 'write' and self.selected: + clean = data['content'].replace('\n', '\\n') + self.pipe_io.send_message(clean.encode()) + + def handle_pipe_event(self, message_bytes): + if not self.selected: + self.server_connector.send({ + 'key': 'mirror', + 'data': { + 'key': 'ide', + 'data': { + 'command': 'select', + 'filename': self.filename + } + } + }) + + self.server_connector.send({ + 'key': 'mirror', + 'data': { + 'key': 'ide', + 'data': { + 'command': 'write', + 'content': message_bytes.decode().replace('\\n', '\n') + } + } + }) + self.server_connector.send({ + 'key': 'mirror', + 'data': { + 'key': 'ide', + 'data': { + 'command': 'read' + } + } + }) + +class FSMPipeIOEventHandler(PipeIOEventHandlerBase): + def __init__(self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): + super().__init__( + ['fsm', 'fsm_update'], + in_pipe_path, out_pipe_path, permissions + ) + + def handle_event(self, message): + if 'current_state' in message['data']: + self.pipe_io.send_message(message['data']['current_state'].encode()) + + def handle_pipe_event(self, message_bytes): + self.server_connector.send({ + 'key': '', + 'trigger': message_bytes.decode() + }) + +class MsgSignPipeIOEventHandler(PipeIOEventHandlerBase): + def __init__( + self, in_pipe_path, out_pipe_path, + permissions=DEFAULT_PERMISSIONS, + forwarding=True + ): + self.forwarding = forwarding + self.auth_key = KeyManager().auth_key + super().__init__(None, in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + return + + def handle_pipe_event(self, message_bytes): + message = loads(message_bytes) + sign_message(self.auth_key, message) + if self.forwarding: + self.server_connector.send(message) + self.pipe_io.send_message(dumps(message).encode()) + +class MsgVerifyPipeIOEventHandler(PipeIOEventHandlerBase): + def __init__(self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): + self.auth_key = KeyManager().auth_key + super().__init__(None, in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + return + + def handle_pipe_event(self, message_bytes): + message = loads(message_bytes) + validity = verify_message(self.auth_key, message) + self.pipe_io.send_message(str(validity).lower().encode()) diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index 26e7349..31e3271 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -5,12 +5,85 @@ from tornado.ioloop import IOLoop from tfw import EventHandlerBase from tfw.components import PipeIOEventHandler +from pipe_io_auxlib import ( + MsgSignPipeIOEventHandler, MsgVerifyPipeIOEventHandler, + DeployPipeIOEventHandler, IdePipeIOEventHandler, + FSMPipeIOEventHandler +) + if __name__ == '__main__': - pipe_io = PipeIOEventHandler( + ''' + Creates general purpose pipes. + You can send/receive JSON messages to/from the TFW server as any user. + ''' + json_pipe = PipeIOEventHandler( '', - '/tmp/tfw_send', - '/tmp/tfw_recv' + '/tmp/tfw_json_send', + '/tmp/tfw_json_recv', + permissions=0o666 + ) + + ''' + Signs a valid TFW message with HMAC. + Note that this process needs root permissions in order to read the + authentication key. + When forwarding is true, it will send the signed message to the TFW + server before writing it into the output pipe. + ''' + sign_pipe = MsgSignPipeIOEventHandler( + '/tmp/tfw_sign_send', + '/tmp/tfw_sign_recv', + forwarding=True + ) + + ''' + Verifies a signed TFW message. + This pipe also needs root permissions. Send the serialized JSON object + to the pipe, then wait for its boolean response. + ''' + verify_pipe = MsgVerifyPipeIOEventHandler( + '/tmp/tfw_verify_send', + '/tmp/tfw_verify_recv' + ) + + ''' + Manages deployment in the IDE. + When you receive "deploy", then you have to answer with a "true" or + "false" depending whether you are satisfied with the result or not. + The third parameter is the name of the supervised service. + ''' + deploy_pipe = DeployPipeIOEventHandler( + '/tmp/tfw_deploy_send', + '/tmp/tfw_deploy_recv', + 'webservice' + ) + + ''' + Manipulates the content of the IDE. + You can observe a file, and when the user edits it, you will receive + the new contents where newlines are escaped as "\\n". + In order to overwrite the file, send an escaped text back to the pipe. + Since the pipe doesn't know if the file is selected initially in the IDE, + you have to provide this information by yourself, but it will track it + later on. + ''' + ide_pipe = IdePipeIOEventHandler( + '/tmp/tfw_ide_send', + '/tmp/tfw_ide_recv', + 'user_ops.py', + selected=True + ) + + ''' + Handles FSM steps. + When the FSM enters the next state, you will receive a line containing + its name. + To trigger a state change, send the name of the transition to the pipe. + ''' + fsm_pipe = FSMPipeIOEventHandler( + '/tmp/tfw_fsm_send', + '/tmp/tfw_fsm_recv' ) event_handlers = EventHandlerBase.get_local_instances() From a82a0d68cf858c666d589c212c8deff6b3744872 Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Tue, 14 May 2019 08:47:29 +0200 Subject: [PATCH 5/8] Explain subscription --- solvable/src/pipe_io_main.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index 31e3271..bef89a9 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -15,7 +15,14 @@ from pipe_io_auxlib import ( if __name__ == '__main__': ''' Creates general purpose pipes. - You can send/receive JSON messages to/from the TFW server as any user. + The first parameter associates the receiving pipe with a key, which is + an empty string in this case. It has a special meaning, you can + subscribe to every kind of message with this key. + If you wish to filter incoming data, specify a single or more keys in + a list, eg.: processmanager, ide, key... + You can send/receive JSON messages to/from the TFW server as any user, + because we gave read+write permissions, without that parameter, only + the owner has access to the pipes. ''' json_pipe = PipeIOEventHandler( '', From 769a87e0df0330a50bb8eeb666c6da5a18fa0f5c Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Thu, 16 May 2019 14:29:34 +0200 Subject: [PATCH 6/8] Move docstrings --- solvable/src/pipe_io_auxlib.py | 110 +++++++++++++++++++++++---------- solvable/src/pipe_io_main.py | 33 ---------- 2 files changed, 77 insertions(+), 66 deletions(-) diff --git a/solvable/src/pipe_io_auxlib.py b/solvable/src/pipe_io_auxlib.py index 37bb1a8..75c831e 100644 --- a/solvable/src/pipe_io_auxlib.py +++ b/solvable/src/pipe_io_auxlib.py @@ -1,9 +1,67 @@ from json import dumps, loads + from tfw.crypto import KeyManager, sign_message, verify_message from tfw.components import PipeIOEventHandlerBase from tfw.components.pipe_io_event_handler import DEFAULT_PERMISSIONS + +class SignMessagePipeIOEventHandler(PipeIOEventHandlerBase): + """ + Signs a valid TFW message with HMAC. + Note that the running process needs root permissions in order to read + the authentication key. + When forwarding is true, it will send the signed message to the TFW + server before writing it into the output pipe. + """ + + def __init__( + self, in_pipe_path, out_pipe_path, + permissions=DEFAULT_PERMISSIONS, + forwarding=True + ): + self.forwarding = forwarding + self.auth_key = KeyManager().auth_key + super().__init__(None, in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + return + + def handle_pipe_event(self, message_bytes): + message = loads(message_bytes) + sign_message(self.auth_key, message) + if self.forwarding: + self.server_connector.send(message) + self.pipe_io.send_message(dumps(message).encode()) + + +class VerifyMessagePipeIOEventHandler(PipeIOEventHandlerBase): + """ + Verifies a signed TFW message. + This pipe also needs root permissions. Send the serialized JSON object + to the pipe, then wait for its boolean response. + """ + + def __init__(self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): + self.auth_key = KeyManager().auth_key + super().__init__(None, in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + return + + def handle_pipe_event(self, message_bytes): + message = loads(message_bytes) + validity = verify_message(self.auth_key, message) + self.pipe_io.send_message(str(validity).lower().encode()) + + class DeployPipeIOEventHandler(PipeIOEventHandlerBase): + """ + Manages deployment in the IDE. + When you receive "deploy", then you have to answer with a "true" or + "false" depending whether you are satisfied with the result or not. + The @process parameter is the name of the supervised service. + """ + # pylint: disable=too-many-arguments def __init__( self, in_pipe_path, out_pipe_path, process, @@ -50,7 +108,18 @@ class DeployPipeIOEventHandler(PipeIOEventHandlerBase): f'{self.pipe_io.in_pipe}: Expected "true" or "false".' ) + class IdePipeIOEventHandler(PipeIOEventHandlerBase): + """ + Manipulates the content of the IDE. + You can observe a file, and when the user edits it, you will receive + the new contents where newlines are escaped as "\\n". + In order to overwrite the file, send an escaped text back to the pipe. + Since the pipe doesn't know if the file is selected initially in the IDE, + you have to provide this information by yourself with @selected, + but it will track it later on. + """ + # pylint: disable=too-many-arguments def __init__( self, in_pipe_path, out_pipe_path, filename, @@ -103,7 +172,15 @@ class IdePipeIOEventHandler(PipeIOEventHandlerBase): } }) + class FSMPipeIOEventHandler(PipeIOEventHandlerBase): + """ + Handles FSM steps. + When the FSM enters the next state, you will receive a line containing + its name. To trigger a state change, send the name of the transition to + the pipe. + """ + def __init__(self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): super().__init__( ['fsm', 'fsm_update'], @@ -119,36 +196,3 @@ class FSMPipeIOEventHandler(PipeIOEventHandlerBase): 'key': '', 'trigger': message_bytes.decode() }) - -class MsgSignPipeIOEventHandler(PipeIOEventHandlerBase): - def __init__( - self, in_pipe_path, out_pipe_path, - permissions=DEFAULT_PERMISSIONS, - forwarding=True - ): - self.forwarding = forwarding - self.auth_key = KeyManager().auth_key - super().__init__(None, in_pipe_path, out_pipe_path, permissions) - - def handle_event(self, message): - return - - def handle_pipe_event(self, message_bytes): - message = loads(message_bytes) - sign_message(self.auth_key, message) - if self.forwarding: - self.server_connector.send(message) - self.pipe_io.send_message(dumps(message).encode()) - -class MsgVerifyPipeIOEventHandler(PipeIOEventHandlerBase): - def __init__(self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS): - self.auth_key = KeyManager().auth_key - super().__init__(None, in_pipe_path, out_pipe_path, permissions) - - def handle_event(self, message): - return - - def handle_pipe_event(self, message_bytes): - message = loads(message_bytes) - validity = verify_message(self.auth_key, message) - self.pipe_io.send_message(str(validity).lower().encode()) diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index bef89a9..61fb547 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -31,50 +31,23 @@ if __name__ == '__main__': permissions=0o666 ) - ''' - Signs a valid TFW message with HMAC. - Note that this process needs root permissions in order to read the - authentication key. - When forwarding is true, it will send the signed message to the TFW - server before writing it into the output pipe. - ''' sign_pipe = MsgSignPipeIOEventHandler( '/tmp/tfw_sign_send', '/tmp/tfw_sign_recv', forwarding=True ) - ''' - Verifies a signed TFW message. - This pipe also needs root permissions. Send the serialized JSON object - to the pipe, then wait for its boolean response. - ''' verify_pipe = MsgVerifyPipeIOEventHandler( '/tmp/tfw_verify_send', '/tmp/tfw_verify_recv' ) - ''' - Manages deployment in the IDE. - When you receive "deploy", then you have to answer with a "true" or - "false" depending whether you are satisfied with the result or not. - The third parameter is the name of the supervised service. - ''' deploy_pipe = DeployPipeIOEventHandler( '/tmp/tfw_deploy_send', '/tmp/tfw_deploy_recv', 'webservice' ) - ''' - Manipulates the content of the IDE. - You can observe a file, and when the user edits it, you will receive - the new contents where newlines are escaped as "\\n". - In order to overwrite the file, send an escaped text back to the pipe. - Since the pipe doesn't know if the file is selected initially in the IDE, - you have to provide this information by yourself, but it will track it - later on. - ''' ide_pipe = IdePipeIOEventHandler( '/tmp/tfw_ide_send', '/tmp/tfw_ide_recv', @@ -82,12 +55,6 @@ if __name__ == '__main__': selected=True ) - ''' - Handles FSM steps. - When the FSM enters the next state, you will receive a line containing - its name. - To trigger a state change, send the name of the transition to the pipe. - ''' fsm_pipe = FSMPipeIOEventHandler( '/tmp/tfw_fsm_send', '/tmp/tfw_fsm_recv' From bcf4f35e6191ecc67d6f911ca49abe3c5aa0bda6 Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Tue, 21 May 2019 10:22:07 +0200 Subject: [PATCH 7/8] Rename signature handling classes --- solvable/src/pipe_io_main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index 61fb547..f39fabd 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -6,7 +6,7 @@ from tfw import EventHandlerBase from tfw.components import PipeIOEventHandler from pipe_io_auxlib import ( - MsgSignPipeIOEventHandler, MsgVerifyPipeIOEventHandler, + SignMessagePipeIOEventHandler, VerifyMessagePipeIOEventHandler, DeployPipeIOEventHandler, IdePipeIOEventHandler, FSMPipeIOEventHandler ) @@ -31,13 +31,13 @@ if __name__ == '__main__': permissions=0o666 ) - sign_pipe = MsgSignPipeIOEventHandler( + sign_pipe = SignMessagePipeIOEventHandler( '/tmp/tfw_sign_send', '/tmp/tfw_sign_recv', forwarding=True ) - verify_pipe = MsgVerifyPipeIOEventHandler( + verify_pipe = VerifyMessagePipeIOEventHandler( '/tmp/tfw_verify_send', '/tmp/tfw_verify_recv' ) From 6c383102727c3470c985648ce7175399270cc659 Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Tue, 28 May 2019 14:46:09 +0200 Subject: [PATCH 8/8] Add message sender pipe --- solvable/src/pipe_io_auxlib.py | 41 ++++++++++++++++++++++++++++++++-- solvable/src/pipe_io_main.py | 10 +++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/solvable/src/pipe_io_auxlib.py b/solvable/src/pipe_io_auxlib.py index 75c831e..a06ce06 100644 --- a/solvable/src/pipe_io_auxlib.py +++ b/solvable/src/pipe_io_auxlib.py @@ -24,7 +24,7 @@ class SignMessagePipeIOEventHandler(PipeIOEventHandlerBase): super().__init__(None, in_pipe_path, out_pipe_path, permissions) def handle_event(self, message): - return + pass def handle_pipe_event(self, message_bytes): message = loads(message_bytes) @@ -46,7 +46,7 @@ class VerifyMessagePipeIOEventHandler(PipeIOEventHandlerBase): super().__init__(None, in_pipe_path, out_pipe_path, permissions) def handle_event(self, message): - return + pass def handle_pipe_event(self, message_bytes): message = loads(message_bytes) @@ -54,6 +54,43 @@ class VerifyMessagePipeIOEventHandler(PipeIOEventHandlerBase): self.pipe_io.send_message(str(validity).lower().encode()) +class BotPipeIOEventHandler(PipeIOEventHandlerBase): + """ + Sends bot messages to the frontend. + If you assign @originator, it will be the default message sender. + When you write a line to the pipe, it will be considered as a single + message and gets appended to the queue until an empty line is received, + which triggers forwarding the messages to the TFW server. + """ + + def __init__( + self, in_pipe_path, out_pipe_path, permissions=DEFAULT_PERMISSIONS, + originator='avataobot' + ): + self.queue = [] + self.originator = originator + super().__init__(None, in_pipe_path, out_pipe_path, permissions) + + def handle_event(self, message): + pass + + def handle_pipe_event(self, message_bytes): + if message_bytes == b"": + if self.queue: + self.server_connector.send({ + 'key': 'queueMessages', + 'data': { + 'messages': self.queue + } + }) + self.queue = [] + else: + self.queue.append({ + 'originator': self.originator, + 'message': message_bytes.decode().replace('\\n', '\n') + }) + + class DeployPipeIOEventHandler(PipeIOEventHandlerBase): """ Manages deployment in the IDE. diff --git a/solvable/src/pipe_io_main.py b/solvable/src/pipe_io_main.py index f39fabd..056b152 100644 --- a/solvable/src/pipe_io_main.py +++ b/solvable/src/pipe_io_main.py @@ -7,13 +7,14 @@ from tfw.components import PipeIOEventHandler from pipe_io_auxlib import ( SignMessagePipeIOEventHandler, VerifyMessagePipeIOEventHandler, + BotPipeIOEventHandler, DeployPipeIOEventHandler, IdePipeIOEventHandler, FSMPipeIOEventHandler ) if __name__ == '__main__': - ''' + """ Creates general purpose pipes. The first parameter associates the receiving pipe with a key, which is an empty string in this case. It has a special meaning, you can @@ -23,7 +24,7 @@ if __name__ == '__main__': You can send/receive JSON messages to/from the TFW server as any user, because we gave read+write permissions, without that parameter, only the owner has access to the pipes. - ''' + """ json_pipe = PipeIOEventHandler( '', '/tmp/tfw_json_send', @@ -42,6 +43,11 @@ if __name__ == '__main__': '/tmp/tfw_verify_recv' ) + bot_pipe = BotPipeIOEventHandler( + '/tmp/tfw_bot_send', + '/tmp/tfw_bot_recv' + ) + deploy_pipe = DeployPipeIOEventHandler( '/tmp/tfw_deploy_send', '/tmp/tfw_deploy_recv',