title: NGROK + WEB-SERVER + NODE.JS + WEBSOCKET + NPM
body: <p>I have a web server on localhost and I connect to this server with my phone via ngrock. Up here very well, since ngrock creates a url, for example <a href="http://94815c96.ngrok.io" rel="nofollow noreferrer">http://94815c96.ngrok.io</a> that redirects me to localhost:8888, where I can see my project and files.</p>
  
  <p>Then I need to connect my web-server through websocket and make a chat application, for this I have installed npm and node.js and I run the command node filename.js, which this filename.js file creates a socket that listens on port 1337 and on the side of the web-server opens the websocket on port 1337. If i do it via web-browser on my local device it works, but when I try it via mobile phone with the ngrock url it return an error that cannot connect to WebSocket Server.</p>
  
  <p>The code that I use is simple. I have one html called frontend.html to view and output the chat application, another file called chat-client.js that opens the connection to websocket on port 1337 and the last file is called chat-server.js that listens on port 1337. The code for each file is this one below here:</p>
  
  <p>frontend.html:</p>
  
  <pre><code>    &lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;meta charset="utf-8"&gt;
          &lt;title&gt;WebSockets - Simple chat&lt;/title&gt;
  
          &lt;style&gt;
          * { font-family:tahoma; font-size:12px; padding:0px; margin:0px; }
          p { line-height:18px; }
          div { width:500px; margin-left:auto; margin-right:auto;}
          #content { padding:5px; background:#ddd; border-radius:5px; overflow-y: scroll;
                     border:1px solid #CCC; margin-top:10px; height: 160px; }
          #input { border-radius:2px; border:1px solid #ccc;
                   margin-top:10px; padding:5px; width:400px;  }
          #status { width:88px; display:block; float:left; margin-top:15px; }
          &lt;/style&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;div id="content"&gt;&lt;/div&gt;
          &lt;div&gt;
              &lt;span id="status"&gt;Connecting...&lt;/span&gt;
              &lt;input type="text" id="input" disabled="disabled" /&gt;
          &lt;/div&gt;
  
          &lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"&gt;&lt;/script&gt;
          &lt;script src="./chat-frontend.js"&gt;&lt;/script&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>chat-client.js:</p>
  
  <pre><code>$(function () {
  "use strict";
  
  // for better performance - to avoid searching in DOM
  var content = $('#content');
  var input = $('#input');
  var status = $('#status');
  
  // my color assigned by the server
  var myColor = false;
  // my name sent to the server
  var myName = false;
  
  // if user is running mozilla then use it's built-in WebSocket
  window.WebSocket = window.WebSocket || window.MozWebSocket;
  
  // if browser doesn't support WebSocket, just show some notification and exit
  if (!window.WebSocket) {
      content.html($('&lt;p&gt;', { text: 'Sorry, but your browser doesn\'t '
                                  + 'support WebSockets.'} ));
      input.hide();
      $('span').hide();
      return;
  }
  
  // open connection
  var connection = new WebSocket('ws://127.0.0.1:1337');
  
  connection.onopen = function () {
      // first we want users to enter their names
      input.removeAttr('disabled');
      status.text('Choose name:');
  };
  
  connection.onerror = function (error) {
      // just in there were some problems with conenction...
      content.html($('&lt;p&gt;', { text: 'Sorry, but there\'s some problem with your '
                                  + 'connection or the server is down.' } ));
  };
  
  // most important part - incoming messages
  connection.onmessage = function (message) {
      // try to parse JSON message. Because we know that the server always returns
      // JSON this should work without any problem but we should make sure that
      // the massage is not chunked or otherwise damaged.
      try {
          var json = JSON.parse(message.data);
      } catch (e) {
          console.log('This doesn\'t look like a valid JSON: ', message.data);
          return;
      }
  
      // NOTE: if you're not sure about the JSON structure
      // check the server source code above
      if (json.type === 'color') { // first response from the server with user's color
          myColor = json.data;
          status.text(myName + ': ').css('color', myColor);
          input.removeAttr('disabled').focus();
          // from now user can start sending messages
      } else if (json.type === 'history') { // entire message history
          // insert every single message to the chat window
          for (var i=0; i &lt; json.data.length; i++) {
              addMessage(json.data[i].author, json.data[i].text,
                         json.data[i].color, new Date(json.data[i].time));
          }
      } else if (json.type === 'message') { // it's a single message
          input.removeAttr('disabled'); // let the user write another message
          addMessage(json.data.author, json.data.text,
                     json.data.color, new Date(json.data.time));
      } else {
          console.log('Hmm..., I\'ve never seen JSON like this: ', json);
      }
  };
  
  /**
   * Send mesage when user presses Enter key
   */
  input.keydown(function(e) {
      if (e.keyCode === 13) {
          var msg = $(this).val();
          if (!msg) {
              return;
          }
          // send the message as an ordinary text
          connection.send(msg);
          $(this).val('');
          // disable the input field to make the user wait until server
          // sends back response
          input.attr('disabled', 'disabled');
  
          // we know that the first message sent from a user their name
          if (myName === false) {
              myName = msg;
          }
      }
  });
  
  /**
   * This method is optional. If the server wasn't able to respond to the
   * in 3 seconds then show some error message to notify the user that
   * something is wrong.
   */
  setInterval(function() {
      if (connection.readyState !== 1) {
          status.text('Error');
          input.attr('disabled', 'disabled').val('Unable to comminucate '
                                               + 'with the WebSocket server.');
      }
  }, 3000);
  
  /**
   * Add message to the chat window
   */
  function addMessage(author, message, color, dt) {
      content.prepend('&lt;p&gt;&lt;span style="color:' + color + '"&gt;' + author + '&lt;/span&gt; @ ' +
           + (dt.getHours() &lt; 10 ? '0' + dt.getHours() : dt.getHours()) + ':'
           + (dt.getMinutes() &lt; 10 ? '0' + dt.getMinutes() : dt.getMinutes())
           + ': ' + message + '&lt;/p&gt;');
  }
  });
  </code></pre>
  
  <p>chat-server.js</p>
  
  <pre><code>// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
  "use strict";
  
  // Optional. You will see this name in eg. 'ps' or 'top' command
  process.title = 'node-chat';
  
  // Port where we'll run the websocket server
  var webSocketsServerPort = 1337;
  
  // websocket and http servers
  var webSocketServer = require('websocket').server;
  var http = require('http');
  
  /**
   * Global variables
   */
  // latest 100 messages
  var history = [ ];
  // list of currently connected clients (users)
  var clients = [ ];
  
  /**
   * Helper function for escaping input strings
   */
  function htmlEntities(str) {
      return String(str).replace(/&amp;/g, '&amp;amp;').replace(/&lt;/g, '&amp;lt;')
                        .replace(/&gt;/g, '&amp;gt;').replace(/"/g, '&amp;quot;');
  }
  
  // Array with some colors
  var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
  // ... in random order
  colors.sort(function(a,b) { return Math.random() &gt; 0.5; } );
  
  /**
   * HTTP server
   */
  var server = http.createServer(function(request, response) {
      // Not important for us. We're writing WebSocket server, not HTTP server
  });
  server.listen(webSocketsServerPort, function() {
      console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
  });
  
  /**
   * WebSocket server
   */
  var wsServer = new webSocketServer({
      // WebSocket server is tied to a HTTP server. WebSocket request is just
      // an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
      httpServer: server
  });
  
  // This callback function is called every time someone
  // tries to connect to the WebSocket server
  wsServer.on('request', function(request) {
      console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
  
      // accept connection - you should check 'request.origin' to make sure that
      // client is connecting from your website
      // (http://en.wikipedia.org/wiki/Same_origin_policy)
      var connection = request.accept(null, request.origin); 
      // we need to know client index to remove them on 'close' event
      var index = clients.push(connection) - 1;
      var userName = false;
      var userColor = false;
  console.log((new Date()) + ' Connection accepted.');
  
  // send back chat history
  if (history.length &gt; 0) {
      connection.sendUTF(JSON.stringify( { type: 'history', data: history} ));
  }
  
  // user sent some message
  connection.on('message', function(message) {
      if (message.type === 'utf8') { // accept only text
          if (userName === false) { // first message sent by user is their name
              // remember user name
              userName = htmlEntities(message.utf8Data);
              // get random color and send it back to the user
              userColor = colors.shift();
              connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
              console.log((new Date()) + ' User is known as: ' + userName
                          + ' with ' + userColor + ' color.');
  
          } else { // log and broadcast the message
              console.log((new Date()) + ' Received Message from '
                          + userName + ': ' + message.utf8Data);
  
              // we want to keep history of all sent messages
              var obj = {
                  time: (new Date()).getTime(),
                  text: htmlEntities(message.utf8Data),
                  author: userName,
                  color: userColor
              };
              history.push(obj);
              history = history.slice(-100);
  
              // broadcast message to all connected clients
              var json = JSON.stringify({ type:'message', data: obj });
              for (var i=0; i &lt; clients.length; i++) {
                  clients[i].sendUTF(json);
              }
          }
      }
  });
  
  // user disconnected
  connection.on('close', function(connection) {
      if (userName !== false &amp;&amp; userColor !== false) {
          console.log((new Date()) + " Peer "
              + connection.remoteAddress + " disconnected.");
          // remove user from the list of connected clients
          clients.splice(index, 1);
          // push back user's color to be reused by another user
          colors.push(userColor);
      }
  });
  
  });
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/qnEZG.png" rel="nofollow noreferrer">Command to execute ngrok</a></p>
  
  <p><a href="https://i.stack.imgur.com/jG5FU.png" rel="nofollow noreferrer">Execute node with chat-server.js</a></p>
  
  <p><a href="https://i.stack.imgur.com/Pid8H.png" rel="nofollow noreferrer">Error returned by ngrok</a></p>