All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.dirigible.components.terminal.endpoint.TerminalWebsocketHandler Maven / Gradle / Ivy

/*
 * Copyright (c) 2024 Eclipse Dirigible contributors
 *
 * All rights reserved. This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v2.0 which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v20.html
 *
 * SPDX-FileCopyrightText: Eclipse Dirigible contributors SPDX-License-Identifier: EPL-2.0
 */
package org.eclipse.dirigible.components.terminal.endpoint;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.dirigible.components.terminal.client.TerminalWebsocketClientEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.SubProtocolCapable;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.BinaryWebSocketHandler;

/**
 * The Console Websocket Handler.
 */
public class TerminalWebsocketHandler extends BinaryWebSocketHandler implements SubProtocolCapable {

    /** The Constant TERMINAL_PREFIX. */
    private static final String TERMINAL_PREFIX = "[ws:terminal] ";

    /** The Constant logger. */
    private static final Logger logger = LoggerFactory.getLogger(TerminalWebsocketHandler.class);

    /** The open sessions. */
    private static Map OPEN_SESSIONS = new ConcurrentHashMap();

    /** The session to client. */
    private static Map SESSION_TO_CLIENT =
            new ConcurrentHashMap();


    /**
     * After connection established.
     *
     * @param session the session
     * @throws Exception the exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // if (Configuration.isAnonymousModeEnabled() || !Configuration.isTerminalEnabled()) {
        // try {
        // session.getBasicRemote().sendText(FEATURE_TERMINAL_IS_DISABLED_IN_THIS_MODE, true);
        // if (logger.isWarnEnabled()) {logger.warn(FEATURE_TERMINAL_IS_DISABLED_IN_THIS_MODE);}
        // } catch (IOException e) {
        // logger.error(TERMINAL_PREFIX + e.getMessage(), e);
        // }
        // try {
        // session.close();
        // } catch (IOException e) {
        // logger.error(TERMINAL_PREFIX + e.getMessage(), e);
        // }
        // return;
        // }

        if (logger.isDebugEnabled()) {
            logger.debug("[ws:terminal] onOpen: " + session.getId());
        }
        try {
            TerminalWebsocketClientEndpoint clientEndPoint = startClientWebsocket(session);
            SESSION_TO_CLIENT.put(session.getId(), clientEndPoint);
        } catch (Exception e) {
            logger.error(TERMINAL_PREFIX + e.getMessage(), e);
            try {
                session.close();
            } catch (Exception e1) {
                logger.error(TERMINAL_PREFIX + e.getMessage(), e);
            }
        }
        OPEN_SESSIONS.put(session.getId(), session);
    }

    /**
     * Handle text message.
     *
     * @param session the session
     * @param message the message
     * @throws Exception the exception
     */
    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        if (logger.isTraceEnabled()) {
            logger.trace("[ws:terminal] onMessage: " + new String(message.getPayload()
                                                                         .array()));
        }

        TerminalWebsocketClientEndpoint clientEndPoint = SESSION_TO_CLIENT.get(session.getId());

        if (clientEndPoint != null) {
            synchronized (clientEndPoint) {
                // send message to websocket
                clientEndPoint.sendMessage(message.getPayload());
            }
        }
    }

    /**
     * Handle transport error.
     *
     * @param session the session
     * @param throwable the throwable
     * @throws Exception the exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception {
        if (logger.isInfoEnabled()) {
            logger.info(String.format("[ws:terminal] Session %s error %s", session.getId(), throwable.getMessage()));
        }
        // logger.error(TERMINAL_PREFIX + throwable.getMessage(), throwable);
    }

    /**
     * After connection closed.
     *
     * @param session the session
     * @param status the status
     * @throws Exception the exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        if (logger.isTraceEnabled()) {
            logger.trace(String.format("[ws:terminal] Session %s closed because of %s", session.getId(), status.getReason()));
        }
        OPEN_SESSIONS.remove(session.getId());
        TerminalWebsocketClientEndpoint clientEndPoint = SESSION_TO_CLIENT.remove(session.getId());
        try {
            if (clientEndPoint != null && clientEndPoint.getSession() != null) {
                clientEndPoint.getSession()
                              .close();
            }
        } catch (Exception e) {
            logger.error(TERMINAL_PREFIX + e.getMessage(), e);
        }
    }

    /**
     * Gets the sub protocols.
     *
     * @return the sub protocols
     */
    @Override
    public List getSubProtocols() {
        return Arrays.asList("tty");
    }

    /**
     * Start the WebSocket proxy.
     *
     * @param session the source session
     * @return the x terminal websocket client endpoint
     * @throws URISyntaxException the URI syntax exception
     */
    private TerminalWebsocketClientEndpoint startClientWebsocket(WebSocketSession session) throws URISyntaxException {

        final TerminalWebsocketClientEndpoint clientEndPoint = new TerminalWebsocketClientEndpoint(new URI("ws://localhost:9000/ws"));

        // add listener
        clientEndPoint.addMessageHandler(new TerminalWebsocketClientEndpoint.MessageHandler() {
            public void handleMessage(ByteBuffer message) throws IOException {
                session.sendMessage(new BinaryMessage(message));
            }
        });

        return clientEndPoint;
    }

    /**
     * The Process Runnable.
     */
    static class ProcessRunnable implements Runnable {

        /** The command. */
        private String command;

        /** The process. */
        private Process process;

        /**
         * Instantiates a new process runnable.
         *
         * @param command the command
         */
        ProcessRunnable(String command) {
            this.command = command;
        }

        /**
         * Gets the process.
         *
         * @return the process
         */
        public Process getProcess() {
            return process;
        }

        /**
         * Run.
         */
        @Override
        public void run() {
            try {
                this.process = Runtime.getRuntime()
                                      .exec(this.command);

                Thread reader = new Thread(new Runnable() {
                    public void run() {
                        try {
                            try (BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                                String line;

                                while ((line = input.readLine()) != null) {
                                    if (logger.isDebugEnabled()) {
                                        logger.debug(TERMINAL_PREFIX + line);
                                    }
                                }
                            }
                        } catch (IOException e) {
                            logger.error(TERMINAL_PREFIX + e.getMessage(), e);
                        }
                    }
                });
                reader.start();


                Thread error = new Thread(new Runnable() {
                    public void run() {
                        try {
                            try (BufferedReader input = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                                String line;

                                while ((line = input.readLine()) != null) {
                                    logger.error(TERMINAL_PREFIX + line);
                                }
                            }
                        } catch (IOException e) {
                            logger.error(TERMINAL_PREFIX + e.getMessage(), e);
                        }
                    }
                });
                error.start();

                // logger.info("[ws:terminal] " + process.exitValue());
            } catch (IOException e) {
                logger.error(TERMINAL_PREFIX + e.getMessage(), e);
            }

        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy