diff --git a/Dockerfile b/Dockerfile index cd0ce9f..3f11de4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,10 +34,9 @@ RUN curl -fSL -o pyenv-installer ${PYENV_INSTALLER_URL} &&\ pip install -r /tmp/requirements.txt USER root -WORKDIR /data/ COPY src/frontend /data/ -RUN yarn install --frozen-lockfile -RUN yarn build --no-progress +RUN cd /data && yarn install --frozen-lockfile +RUN cd /data && yarn build --no-progress ENV TFW_PUBLIC_PORT=8888 \ TFW_WEB_PORT=4242 \ @@ -55,7 +54,8 @@ ENV PYTHONPATH="/usr/local/lib/" \ TFW_SUPERVISOR_HTTP_URI="http://localhost:${TFW_SUPERVISOR_HTTP_PORT}" \ TFW_SUPERVISORD_CONF="/etc/supervisor/supervisord.conf" \ TFW_SUPERVISORD_COMPONENTS="/etc/supervisor/conf" \ - TFW_NGINX_CONF="/etc/nginx/sites-enabled/default" \ + TFW_NGINX_CONF="/etc/nginx/nginx.conf" \ + TFW_NGINX_DEFAULT="/etc/nginx/sites-enabled/default" \ TFW_NGINX_COMPONENTS="/etc/nginx/components" \ TFW_LIB_DIR="/usr/local/lib/" \ TFW_CONTROLLER_DIR="/srv/controller" \ @@ -74,17 +74,18 @@ RUN echo "shopt -s cmdhist\n" \ >> /home/${AVATAO_USER}/.bashrc COPY nginx/nginx.conf ${TFW_NGINX_CONF} +COPY nginx/default.conf ${TFW_NGINX_DEFAULT} COPY nginx/components/ ${TFW_NGINX_COMPONENTS} -RUN chown -R ${AVATAO_USER} /var/log/nginx /var/lib/nginx &&\ - sed -i 's#pid /run/nginx.pid;#pid /tmp/nginx.pid;#g' /etc/nginx/nginx.conf &&\ - for f in "${TFW_NGINX_CONF}" ${TFW_NGINX_COMPONENTS}/*.conf; do \ - envsubst "$(printenv | cut -d= -f1 | grep TFW_ | sed -e 's/^/$/g')" < $f > $f ;\ +RUN chown -R ${AVATAO_USER} /var/log/nginx /var/lib/nginx &&\ + for f in "${TFW_NGINX_DEFAULT}" ${TFW_NGINX_COMPONENTS}/*.conf; do \ + envsubst "$(printenv | cut -d= -f1 | grep TFW_ | sed -e 's/^/$/g')" < $f > $f~ && mv $f~ $f ;\ done COPY supervisor/supervisord.conf ${TFW_SUPERVISORD_CONF} COPY supervisor/components/ ${TFW_SUPERVISORD_COMPONENTS} COPY lib ${TFW_LIB_DIR} COPY src/controller ${TFW_CONTROLLER_DIR} +RUN mv /data/dist ${TFW_FRONTEND_DIR} && rm -rf /data ### TFW internals ^ ### DEMO v ############################################################### @@ -93,17 +94,17 @@ ENV TFW_APP_DIR="/srv/app" \ TFW_WEBIDE_WD="/home/${AVATAO_USER}/workdir" \ TFW_TERMINADO_WD="/home/${AVATAO_USER}/workdir" -RUN mv /data/dist ${TFW_FRONTEND_DIR} - COPY src/demo ${TFW_APP_DIR}/ COPY src/demo/source_code_server/server.py ${TFW_LOGIN_APP_DIR}/ COPY src/demo/source_code_server/users.db ${TFW_LOGIN_APP_DIR}/ COPY src/demo/source_code_server/login_component.py ${TFW_WEBIDE_WD}/ -RUN chown -R ${AVATAO_USER} ${TFW_WEBIDE_WD} && chmod -R 755 ${TFW_WEBIDE_WD} +RUN chown -R ${AVATAO_USER} ${TFW_WEBIDE_WD} &&\ + chmod -R 755 ${TFW_WEBIDE_WD} USER ${AVATAO_USER} +VOLUME ["/etc/nginx", "/home/${AVATAO_USER}", "/var/lib/nginx", "/var/log/nginx"] WORKDIR /home/${AVATAO_USER} CMD . "$HOME/.pyenvrc" && exec supervisord --nodaemon diff --git a/lib/tfw/components/source_code_event_handler.py b/lib/tfw/components/source_code_event_handler.py index 4915887..5ff61e8 100644 --- a/lib/tfw/components/source_code_event_handler.py +++ b/lib/tfw/components/source_code_event_handler.py @@ -106,7 +106,7 @@ class SourceCodeEventHandler(TriggerlessEventHandler): except IndexError: data['content'] = 'No files in this directory :(' except EnvironmentError: - log.exception('Failed to select directory "{}"'.format(data['directory'])) + log.error('Failed to select directory "{}"'.format(data['directory'])) return data def attach_fileinfo(self, data): diff --git a/lib/tfw/event_handler_base.py b/lib/tfw/event_handler_base.py index 93172ce..768c1f6 100644 --- a/lib/tfw/event_handler_base.py +++ b/lib/tfw/event_handler_base.py @@ -1,18 +1,7 @@ -from itertools import cycle - from tfw.networking.serialization import deserialize_all from tfw.networking.event_handlers.server_connector import ServerConnector -def cenator(): - yield from [ - '**Your time is up**', - '`My time is now`', - '_You can\'t see me_', - 'My time is now' - ] - - class EventHandlerBase: def __init__(self, key): self.server_connector = ServerConnector() @@ -21,13 +10,9 @@ class EventHandlerBase: self.subscribe(self.key) self.subscribe('reset') self.server_connector.register_callback(self.event_handler_callback) - self.cenerator = cycle(cenator()) def event_handler_callback(self, msg_parts): key, message = deserialize_all(*msg_parts) - from .message_sender import MessageSender - ms = MessageSender() - ms.send('avataobot', next(self.cenerator)) response = self.dispatch_handling(key, message) if response is None: return self.server_connector.send(key, response) diff --git a/lib/tfw/networking/event_handlers/server_connector.py b/lib/tfw/networking/event_handlers/server_connector.py index 7c3fcb3..09290fb 100644 --- a/lib/tfw/networking/event_handlers/server_connector.py +++ b/lib/tfw/networking/event_handlers/server_connector.py @@ -25,6 +25,10 @@ class ServerUplinkConnector(ZMQConnectorBase): self._zmq_push_socket = self._zmq_context.socket(zmq.PUSH) self._zmq_push_socket.connect('tcp://localhost:{}'.format(tfwenv.RECEIVER_PORT)) + def send_to_eventhandler(self, key, response): + response['data']['key'] = key + self.send('mirror', response) + def send(self, key, response): response['key'] = key self._zmq_push_socket.send_multipart(serialize_all(key, response)) diff --git a/lib/tfw/networking/server/zmq_websocket_handler.py b/lib/tfw/networking/server/zmq_websocket_handler.py index de2932e..017040e 100644 --- a/lib/tfw/networking/server/zmq_websocket_handler.py +++ b/lib/tfw/networking/server/zmq_websocket_handler.py @@ -21,12 +21,23 @@ class ZMQWebSocketHandler(WebSocketHandler): log.debug('WebSocket connection initiated') self._event_handler_connector.register_callback(self.zmq_callback) - @staticmethod - def zmq_callback(msg_parts): + @classmethod + def zmq_callback(cls, msg_parts): + keyhandlers = {'mirror': cls.mirror} + key, data = deserialize_all(*msg_parts) log.debug('Received on pull socket: {}'.format(data)) - for instance in ZMQWebSocketHandler.instances: - instance.write_message(data) + if key not in keyhandlers: + for instance in cls.instances: + instance.write_message(data) + else: + try: keyhandlers[key](data['data']) + except KeyError: log.error('Invalid mirror message format! Ignoring.') + + @classmethod + def mirror(cls, data): + key = data['key'] + cls._event_handler_connector.send_message({'data': data}, key) def on_message(self, message): log.debug('Received on WebSocket: {}'.format(message)) diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 0000000..563bced --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,22 @@ +server { + listen ${TFW_PUBLIC_PORT}; + server_name localhost; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + + location = /ws { + proxy_pass http://127.0.0.1:${TFW_WEB_PORT}; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + } + + include ${TFW_NGINX_COMPONENTS}/*.conf; + + location / { + index index.html; + try_files $uri $uri/ /index.html =404; + root ${TFW_FRONTEND_DIR}; + } +} diff --git a/nginx/nginx.conf b/nginx/nginx.conf index ea60388..5d1e5ec 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -1,21 +1,24 @@ -server { - listen ${TFW_PUBLIC_PORT}; - server_name localhost; - proxy_connect_timeout 7d; - proxy_send_timeout 7d; - proxy_read_timeout 7d; +worker_processes auto; +pid /tmp/nginx.pid; - location = /ws { - proxy_pass http://127.0.0.1:${TFW_WEB_PORT}; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - } - - include ${TFW_NGINX_COMPONENTS}/*.conf; - - location / { - root ${TFW_FRONTEND_DIR}; - try_files $uri $uri/ index.html; - } +events +{ + worker_connections 1024; +} + +http +{ + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + access_log /dev/stdout; + error_log /dev/stderr; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; } diff --git a/src/demo/event_handler_main.py b/src/demo/event_handler_main.py index 6cb9c8a..ad5e9ce 100644 --- a/src/demo/event_handler_main.py +++ b/src/demo/event_handler_main.py @@ -4,14 +4,32 @@ from tfw.components.source_code_event_handler import SourceCodeEventHandler from tfw.components.terminado_event_handler import TerminadoEventHandler from tfw.components.process_managing_event_handler import ProcessManagingEventHandler from tfw.config import tfwenv +from tfw.message_sender import MessageSender +from tfw.networking.event_handlers.server_connector import ServerUplinkConnector from tfw.config.logs import logging log = logging.getLogger(__name__) +def cenator(history): + log.debug('User executed command: "{}"'.format(history[-1])) + MessageSender().send('JOHN CENA', 'You\'ve executed "{}"'.format(history[-1])) + + +def selectdir(history): + try: + cmd = history[-1].split() + if cmd[0] == 'selectdir': + ServerUplinkConnector().send_to_eventhandler('webide', + {'data': {'command': 'selectdir', + 'directory': cmd[1]}}) + except Exception: + log.exception('Selectdir failed!') + if __name__ == '__main__': ide = SourceCodeEventHandler(key='webide', directory=tfwenv.WEBIDE_WD, exclude=['__pycache__']) terminado = TerminadoEventHandler(key='shell') - terminado.historymonitor.subscribe_callback(callback=lambda hist: log.debug('User executed command: "{}"'.format(hist[-1]))) + terminado.historymonitor.subscribe_callback(cenator) + terminado.historymonitor.subscribe_callback(selectdir) processmanager = ProcessManagingEventHandler(key='processmanager', dirmonitor=ide.monitor) eventhandlers = {ide, terminado, processmanager}