]> prime8.dev >> repos - ttyd.git/commitdiff
Add support for the --once option
authorShuanglei Tao <tsl0922@gmail.com>
Mon, 10 Oct 2016 13:39:43 +0000 (21:39 +0800)
committerShuanglei Tao <tsl0922@gmail.com>
Mon, 10 Oct 2016 13:53:03 +0000 (21:53 +0800)
README.md
src/index.html
src/protocol.c
src/server.c
src/server.h

index 8dd375950f0f4998d12cb48d1aa7cc8b3827cd39..117cf00de9cd29848b08b33c0a5cb2ff3899501a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -65,6 +65,7 @@ OPTIONS:
     --gid, -g               Group id to run with
     --signal, -s            Signal to send to the command when exit it (default: SIGHUP)
     --reconnect, -r         Time to reconnect for the client in seconds (default: 10)
+    --once, -o              Accept only one client and exit on disconnection
     --ssl, -S               Enable ssl
     --ssl-cert, -C          Ssl certificate file path
     --ssl-key, -K           Ssl key file path
index 8a15414e2238fc9bbb1496e3c876e7b9dc3397fb..25e5c63864e5d65f02a6fc60853b28d1a7862b54 100644 (file)
                         var io = term.io.push();
 
                         io.onVTKeystroke = function(str) {
-                            ws.send("0" + str);
+                            if (ws.readyState === WebSocket.OPEN) {
+                                ws.send("0" + str);
+                            }
                         };
 
                         io.sendString = io.onVTKeystroke;
 
                         io.onTerminalResize = function(columns, rows) {
-                            ws.send(
-                                    "2" + JSON.stringify(
-                                            {
-                                                columns: columns,
-                                                rows: rows,
-                                            }
-                                    )
-                            )
+                            if (ws.readyState === WebSocket.OPEN) {
+                                ws.send("2" + JSON.stringify({columns: columns, rows: rows}));
+                            }
                         };
 
                         term.installKeyboard();
                             term.setWindowTitle(data);
                             break;
                         case '3':
-                            preferences = JSON.parse(data);
+                            var preferences = JSON.parse(data);
                             Object.keys(preferences).forEach(function(key) {
                                 console.log("Setting " + key + ": " +  preferences[key]);
                                 term.getPrefs().set(key, preferences[key]);
                 ws.onclose = function(event) {
                     if (term) {
                         term.uninstallKeyboard();
-                        term.io.showOverlay("Connection Closed", null);
+                        setTimeout(function(){
+                            term.io.showOverlay("Connection Closed", null);
+                        }, 300);
                     }
                     clearInterval(pingTimer);
                     if (autoReconnect > 0) {
                         setTimeout(openWs, autoReconnect * 1000);
                     }
                 };
+
+                ws.onerror = function(event) {
+                    var errorNode = document.createElement('div');
+                    errorNode.style.cssText = [
+                            "color: red",
+                            "font-size: x-large",
+                            "opacity: 0.75",
+                            "text-align: center",
+                            "margin: 1em",
+                            "padding: 0.2em",
+                            "border: 0.1em dotted #ccc"
+                    ].join(";");
+                    errorNode.textContent = "Websocket handshake failed!";
+                    document.getElementById("terminal").appendChild(errorNode);
+                };
             };
 
 
index 13077c9d78cd9568ac7929d9addd0dfba27fbb22..7218c86102239e63337a91dd393eb8d4da963c7f 100644 (file)
@@ -65,7 +65,7 @@ parse_window_size(const char *json) {
 
 void
 tty_client_destroy(struct tty_client *client) {
-    if (client->exit)
+    if (client->exit || client->pid <= 0)
         return;
 
     // stop event loop
@@ -159,6 +159,12 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
     struct winsize *size;
 
     switch (reason) {
+        case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
+            if (server->once && server->client_count > 0) {
+                lwsl_notice("refuse to serve new client due to the --once option.\n");
+                return -1;
+            }
+            break;
         case LWS_CALLBACK_ESTABLISHED:
             client->exit = false;
             client->initialized = false;
@@ -305,6 +311,12 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
         case LWS_CALLBACK_CLOSED:
             tty_client_destroy(client);
             lwsl_notice("client disconnected from %s (%s), total: %d\n", client->hostname, client->address, server->client_count);
+            if (server->once && server->client_count == 0) {
+                lwsl_notice("exiting due to the --once option.\n");
+                force_exit = true;
+                lws_cancel_service(context);
+                exit(0);
+            }
             break;
 
         default:
index 7792cfa9a65bce94c46e1644bf8542dea0d0d1ba..2f5b41218e6aaec0f93ad742148e3a074f97062f 100644 (file)
@@ -33,12 +33,13 @@ static const struct option options[] = {
         {"ssl-cert", required_argument, NULL, 'C'},
         {"ssl-key", required_argument, NULL, 'K'},
         {"ssl-ca", required_argument, NULL, 'A'},
+        {"once", no_argument, NULL, 'o'},
         {"debug", required_argument, NULL, 'd'},
         {"version", no_argument, NULL, 'v'},
         {"help", no_argument, NULL, 'h'},
         {NULL, 0, 0, 0}
 };
-static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:d:vh";
+static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:od:vh";
 
 void print_help() {
     fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n"
@@ -54,6 +55,7 @@ void print_help() {
                     "    --gid, -g               Group id to run with\n"
                     "    --signal, -s            Signal to send to the command when exit it (default: SIGHUP)\n"
                     "    --reconnect, -r         Time to reconnect for the client in seconds (default: 10)\n"
+                    "    --once, -o              Accept only one client and exit on disconnection\n"
                     "    --ssl, -S               Enable ssl\n"
                     "    --ssl-cert, -C          Ssl certificate file path\n"
                     "    --ssl-key, -K           Ssl key file path\n"
@@ -200,6 +202,9 @@ main(int argc, char **argv) {
             case 'd':
                 debug_level = atoi(optarg);
                 break;
+            case 'o':
+                server->once = true;
+                break;
             case 'p':
                 info.port = atoi(optarg);
                 if (info.port < 0) {
@@ -317,6 +322,8 @@ main(int argc, char **argv) {
     lwsl_notice("  start command: %s\n", server->command);
     lwsl_notice("  reconnect timeout: %ds\n", server->reconnect);
     lwsl_notice("  close signal: %s (%d)\n", server->sig_name, server->sig_code);
+    if (server->once)
+        lwsl_notice("  once: true\n");
 
     // libwebsockets main loop
     while (!force_exit) {
index 2e914518a3420a4701eb313fe36dabb9639e458b..8c197e86c538e0cadfe3edada80c2ec453fe4fe9 100644 (file)
@@ -71,6 +71,7 @@ struct tty_server {
     char **argv;                              // command with arguments
     int sig_code;                             // close signal
     char *sig_name;                           // human readable signal string
+    bool once;                                // whether accept only one client and exit on disconnection
     pthread_mutex_t lock;
 };