- socketio 2017-03-19T16:58:15+01:00 https://fadeit.dk/blog/tag/socketio.html Socket.io with AngularJS boilerplate 2015-05-29T13:18:15+02:00 https://fadeit.dk/blog /2015/05/29/socketio-angular-ultra-simple-boilerplate <p><a href="http://socket.io">Socket.io</a> has truly been a godsend to making realtime applicaions. What used to require writing complex code, ajax polling and other tricks of the trade is now a few lines of code. And it’s fast too - in fact we have a situation where client sends a POST request to python server, which in turn is passed to node server via <a href="http://redis.io">redis</a> <a href="http://redis.io/topics/pubsub">pub/sub</a> and that in turn send a message to the client with socket.io. The interesting bit is that although the socket.io round-trip involves more components, it delivers the message back to client before the response is received. While pure HTTP implementation with network latency in the mix might win the race, it is still a valid contender.</p> <p>I often find myself experimenting on some concept where I need a quick and simple boilerplate to get me going - setting it all up takes time after-all. There are great demos out there, but they often cover more ground than necessary, what I am mostly interested in is the bare minimum working backbone that I can build upon. So here is a stripped-down chat application in just 2 files, doesn’t even contain an http server!</p> <h2 id="serverjs">Server.js</h2> <div class="language-javascript highlighter-rouge"><pre class="highlight"><code><span class="kd">var</span> <span class="nx">io</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'socket.io'</span><span class="p">).</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span> <span class="nx">io</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'connection'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">socket</span><span class="p">){</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">msg</span><span class="p">){</span> <span class="nx">io</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="nx">msg</span><span class="p">);</span> <span class="p">});</span> <span class="p">});</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">"Server up!"</span><span class="p">);</span> </code></pre> </div> <h2 id="indexhtml">Index.html</h2> <p>Since Angular is not aware of socket receiving a message, we need to wrap the <code class="highlighter-rouge">$scope</code> update in an <code class="highlighter-rouge">$apply</code> function so that angular would pick it up.</p> <div class="language-html highlighter-rouge"><pre class="highlight"><code><span class="cp">&lt;!doctype html&gt;</span> <span class="nt">&lt;html</span> <span class="na">ng-app=</span><span class="s">"myApp"</span><span class="nt">&gt;</span> <span class="nt">&lt;head&gt;</span> <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.5/socket.io.js"</span><span class="nt">&gt;&lt;/script&gt;</span> <span class="nt">&lt;script </span><span class="na">src=</span><span class="s">"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.min.js"</span><span class="nt">&gt;&lt;/script&gt;</span> <span class="nt">&lt;/head&gt;</span> <span class="nt">&lt;body</span> <span class="na">ng-controller=</span><span class="s">"myAppCtrl"</span><span class="nt">&gt;</span> <span class="nt">&lt;textarea</span> <span class="na">ng-model=</span><span class="s">"messages"</span> <span class="na">rows=</span><span class="s">15</span> <span class="na">cols=</span><span class="s">80</span><span class="nt">&gt;&lt;/textarea&gt;&lt;br/&gt;</span> <span class="nt">&lt;input</span> <span class="na">ng-model=</span><span class="s">"message"</span><span class="nt">&gt;&lt;/input&gt;</span> <span class="nt">&lt;button</span> <span class="na">ng-click=</span><span class="s">"send()"</span><span class="nt">&gt;</span>Send<span class="nt">&lt;/button&gt;</span> <span class="nt">&lt;script&gt;</span> <span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s2">"myApp"</span><span class="p">,</span> <span class="p">[]);</span> <span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s2">"myAppCtrl"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$scope</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">io</span><span class="p">(</span><span class="s1">'http://localhost:3000'</span><span class="p">);</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">messages</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">send</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">message</span><span class="p">);</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">message</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span> <span class="p">}</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">message</span><span class="p">){</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">$apply</span><span class="p">(</span><span class="kd">function</span><span class="p">(){</span> <span class="nx">$scope</span><span class="p">.</span><span class="nx">messages</span> <span class="o">+=</span> <span class="nx">message</span> <span class="o">+</span> <span class="s2">"\n"</span><span class="p">;</span> <span class="p">});</span> <span class="p">});</span> <span class="p">});</span> <span class="nt">&lt;/script&gt;</span> <span class="nt">&lt;/body&gt;</span> <span class="nt">&lt;/html&gt;</span> </code></pre> </div> <h2 id="setup">Setup</h2> <div class="language-bash highlighter-rouge"><pre class="highlight"><code>npm install socket.io node server.js </code></pre> </div> Proxy Custom Socket.IO Namespaces with NGINX 2015-05-21T22:30:00+02:00 https://fadeit.dk/blog /2015/05/21/socketio-namespaces-and-nginx <p>A while ago I implemented a chat server based on <a href="http://socket.io/">Socket.IO</a> for <a href="https://hopper.dk">hopper.dk</a>. In addition to the chat server, the system already had 2 HTTP servers: <a href="http://gunicorn.org/">Gunicorn</a> for our RESTful API and <a href="http://nginx.org/">NGINX</a> for serving <a href="https://angularjs.org/">AngularJS</a> frontend. To make SSL management easier I decided to put all 3 servers behind a single NGINX host. It all went pretty smoothly except for 1 thing- my chat server with a custom namespace was unreachable through NGINX.</p> <p>Let’s illustrate this with some code</p> <h2 id="socketio-server">Socket.IO Server</h2> <div class="language-javascript highlighter-rouge"><pre class="highlight"><code><span class="nx">io</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'socket.io'</span><span class="p">)();</span> <span class="nx">io</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">3000</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">myNamespace</span> <span class="o">=</span> <span class="nx">io</span><span class="p">.</span><span class="nx">of</span><span class="p">(</span><span class="s1">'/my-namespace'</span><span class="p">);</span> <span class="nx">myNamespace</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">'connection'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">socket</span><span class="p">){</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'someone connected'</span><span class="p">);</span> <span class="nx">socket</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">'news'</span><span class="p">,</span> <span class="s1">'Hi there!!'</span><span class="p">);</span> <span class="nx">myNamespace</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">'news'</span><span class="p">,</span> <span class="s1">'Someone joined the party!'</span><span class="p">);</span> <span class="p">});</span> </code></pre> </div> <h2 id="nginx-host">NGINX Host</h2> <div class="language-bash highlighter-rouge"><pre class="highlight"><code>server <span class="o">{</span> listen 8080; server_name localhost; location ~/<span class="o">(</span>my-namespace<span class="o">)</span>.<span class="k">*</span><span class="nv">$ </span><span class="o">{</span> proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade <span class="nv">$http_upgrade</span>; proxy_set_header Connection <span class="s2">"upgrade"</span>; <span class="o">}</span> <span class="o">}</span> </code></pre> </div> <h2 id="connection-attempts-fail-with-http-404">Connection attempts fail with HTTP 404</h2> <p><img src="/blog/assets/socketio-namespaces-and-nginx/fail.png" alt="Client connection attempts fail" /></p> <p>This setup results in Socket.IO client trying to establish a connection to the server with no success. After a bit of furious <em>DuckDuckGoing</em> and <em>Googling</em>, I gave up and decided to look for answers in <a href="https://github.com/Automattic/socket.io">Socket.IO’s code</a>.</p> <p>The solution is simple: in addition to proxying your custom namespace, you also have to proxy <code class="highlighter-rouge">/socket.io</code> resource to the Socket.IO server:</p> <div class="language-bash highlighter-rouge"><pre class="highlight"><code>server <span class="o">{</span> listen 8080; server_name localhost; location ~/<span class="o">(</span>my-namespace|socket<span class="se">\.</span>io<span class="o">)</span>.<span class="k">*</span><span class="nv">$ </span><span class="o">{</span> proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade <span class="nv">$http_upgrade</span>; proxy_set_header Connection <span class="s2">"upgrade"</span>; <span class="o">}</span> <span class="o">}</span> </code></pre> </div> <h2 id="success">Success</h2> <p><img src="/blog/assets/socketio-namespaces-and-nginx/success.png" alt="Client connection successfully established" /></p> <p>I hope this helps.</p>