Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://facundoolano.wordpress.com/feed/

  1. <?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
  2. xmlns:content="http://purl.org/rss/1.0/modules/content/"
  3. xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  4. xmlns:dc="http://purl.org/dc/elements/1.1/"
  5. xmlns:atom="http://www.w3.org/2005/Atom"
  6. xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
  7. xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  8. xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
  9. >
  10.  
  11. <channel>
  12. <title>No silver bullet</title>
  13. <atom:link href="https://facundoolano.wordpress.com/feed/" rel="self" type="application/rss+xml" />
  14. <link>https://facundoolano.wordpress.com</link>
  15. <description>facundoolano&#039;s rants on software development</description>
  16. <lastBuildDate>Sun, 06 Sep 2020 22:51:32 +0000</lastBuildDate>
  17. <language>en</language>
  18. <sy:updatePeriod>
  19. hourly </sy:updatePeriod>
  20. <sy:updateFrequency>
  21. 1 </sy:updateFrequency>
  22. <generator>http://wordpress.com/</generator>
  23. <cloud domain='facundoolano.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
  24. <image>
  25. <url>https://s0.wp.com/i/buttonw-com.png</url>
  26. <title>No silver bullet</title>
  27. <link>https://facundoolano.wordpress.com</link>
  28. </image>
  29. <atom:link rel="search" type="application/opensearchdescription+xml" href="https://facundoolano.wordpress.com/osd.xml" title="No silver bullet" />
  30. <atom:link rel='hub' href='https://facundoolano.wordpress.com/?pushpress=hub'/>
  31. <item>
  32. <title>Squeezing the most out of the server: Erlang Profiling</title>
  33. <link>https://facundoolano.wordpress.com/2020/04/11/squeezing-the-most-out-of-the-server-erlang-profiling/</link>
  34. <comments>https://facundoolano.wordpress.com/2020/04/11/squeezing-the-most-out-of-the-server-erlang-profiling/#respond</comments>
  35. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  36. <pubDate>Sat, 11 Apr 2020 15:17:28 +0000</pubDate>
  37. <category><![CDATA[Uncategorized]]></category>
  38. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=1034</guid>
  39.  
  40. <description><![CDATA[This month I published an article about profiling in Erlang at NextRoll&#8217;s Tech Blog.]]></description>
  41. <content:encoded><![CDATA[<p>This month I published an article about profiling in Erlang at <a href="http://tech.nextroll.com/blog/dev/2020/04/07/erlang-profiling.html" target="_blank" rel="noopener">NextRoll&#8217;s Tech Blog</a>.</p>
  42. ]]></content:encoded>
  43. <wfw:commentRss>https://facundoolano.wordpress.com/2020/04/11/squeezing-the-most-out-of-the-server-erlang-profiling/feed/</wfw:commentRss>
  44. <slash:comments>0</slash:comments>
  45. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  46. <media:title type="html">facundoolano</media:title>
  47. </media:content>
  48. </item>
  49. <item>
  50. <title>Rust, Open-Source and dogs</title>
  51. <link>https://facundoolano.wordpress.com/2019/04/02/rust-open-source-and-dogs/</link>
  52. <comments>https://facundoolano.wordpress.com/2019/04/02/rust-open-source-and-dogs/#respond</comments>
  53. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  54. <pubDate>Tue, 02 Apr 2019 17:16:29 +0000</pubDate>
  55. <category><![CDATA[Uncategorized]]></category>
  56. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=1022</guid>
  57.  
  58. <description><![CDATA[Some years ago I learned a programming language that made a profound impact in the way I think about software; a language that I enjoyed working with, that enabled me to meet some amazing people and pushed me to get more involved in Open-Source and community than I ever did before. I stopped using it [&#8230;]]]></description>
  59. <content:encoded><![CDATA[<p><b>Some years ago</b> I learned a programming language that made a profound impact in the way I think about software; a language that I enjoyed working with, that enabled me to meet some amazing people and pushed me to get more involved in Open-Source and community than I ever did before. I stopped using it because it couldn&#8217;t get me the job I wanted, and I needed to switch my efforts to mastering the tools that could. I later became disenchanted with that language and its ecosystem because of how it is managed; because the interests of the greater community of its users seemed to be secondary —sometimes even opposed— to the needs of the company that owns it.<br />
  60. I made multiple attempts at writing a blog post explaining why I lost interest in that language; a little out of frustration, a little because if had known better I wouldn&#8217;t have invested so much time in it. But I could never shape the text in a way that couldn&#8217;t be perceived as a rant or an attack and so I left it unfinished, popping up from the back of my head every now and then.</p>
  61. <p><b>A couple of months ago</b> me and my girlfriend got a dog. She insisted that we got one ever since we moved together and I kept putting it off because I wasn&#8217;t a dog person and I didn&#8217;t want to be responsible for another living being, not just yet. Eventually, I gave in. One of the things that she first showed me when Cumbia (my dog) got home was that to teach her how I wanted her to behave I shouldn&#8217;t focus on punishing mistakes but rather on rewarding accomplishments. This required (and still requires) an effort from my part; pessimistic as I am, I tend to put more attention to the negative side of things.</p>
  62. <p><img data-attachment-id="1023" data-permalink="https://facundoolano.wordpress.com/2019/04/02/rust-open-source-and-dogs/servo/#main" data-orig-file="https://facundoolano.files.wordpress.com/2019/04/servo.png" data-orig-size="220,220" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="servo" data-image-description="" data-image-caption="" data-medium-file="https://facundoolano.files.wordpress.com/2019/04/servo.png?w=220" data-large-file="https://facundoolano.files.wordpress.com/2019/04/servo.png?w=220" class=" size-full wp-image-1023 aligncenter" src="https://facundoolano.files.wordpress.com/2019/04/servo.png?w=594" alt="servo"   srcset="https://facundoolano.files.wordpress.com/2019/04/servo.png 220w, https://facundoolano.files.wordpress.com/2019/04/servo.png?w=150&amp;h=150 150w" sizes="(max-width: 220px) 100vw, 220px" /></p>
  63. <p style="text-align:center;"><small><i>The servo logo is an instance of Rust+dogs which I include here to make the title sound less arbitrary</i></small></p>
  64. <p><b>The past weekend</b> I took the ferry across the Río de la Plata to Montevideo to assist to the <a href="http://rustlatam.org/" target="_blank" rel="noopener noreferrer">Rust Latam</a> conference, along with <a href="https://twitter.com/unbalancedparen" target="_blank" rel="noopener noreferrer">The Boss</a> and other <a href="https://github.com/lambdaclass/" target="_blank" rel="noopener noreferrer">LambdaClass</a> coworkers. As the talks progressed —following a first day where I took a great <a href="https://sunjay.dev/learn-game-dev/workshop/" target="_blank" rel="noopener noreferrer">game development workshop</a>—, I kept getting this feeling that <i>this</i> is the kind of  Open-Source software community I want to invest myself in. Yes, the people that know better and have put the biggest effort are the ones calling the shots, but the discussions are open and anyone can weigh in. What&#8217;s more, small contributions, beginner contributions are not only welcome but necessary because that&#8217;s how the project grows and the language evolves to become a better tool, one increasingly helpful for an increasing amount of people.<br />
  65. It became apparent to me that the best way to scratch the itch of my previous Open-Source disappointment was to focus on the accomplishments of this community rather than clinging on what I disliked about the other. As when teaching Cumbia, I had more to gain by looking at the good side of things.</p>
  66. <p><b>During his amazing <a href="https://nikomatsakis.github.io/rust-latam-2019/">opening keynote</a></b>, Niko Matsakis said that he was skeptical and pessimistic by nature, and that he was, at first, worried about whether people using Rust also <i>liked</i> it. At that point I looked at The Boss because I knew he would be nodding at me, the company&#8217;s &#8220;designated pessimist&#8221;, the one that always assumes the worst. Niko then moved on to show that a lot of people were, in fact, loving Rust and that this was in part for its features but largely because of the sense of craftsmanship that they enabled and the community that grew around it.</p>
  67. <p>I don&#8217;t hold an especially romantic view of Open-Source. At the end of the day, it&#8217;s just another way of doing business, like most professional activities are. Capitalism has this way of ingesting everything, even what antagonizes it, and turn it into business. I don&#8217;t think Open-Source, nor technology for that matter, can change the world, but I do feel proud about being part of a discipline where there&#8217;s still room for passion and craftsmanship; a discipline that proves that fellowship and collaboration can be the best way of making progress.</p>
  68. ]]></content:encoded>
  69. <wfw:commentRss>https://facundoolano.wordpress.com/2019/04/02/rust-open-source-and-dogs/feed/</wfw:commentRss>
  70. <slash:comments>0</slash:comments>
  71. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  72. <media:title type="html">facundoolano</media:title>
  73. </media:content>
  74.  
  75. <media:content url="https://facundoolano.files.wordpress.com/2019/04/servo.png" medium="image">
  76. <media:title type="html">servo</media:title>
  77. </media:content>
  78. </item>
  79. <item>
  80. <title>Holiday Ping design notes</title>
  81. <link>https://facundoolano.wordpress.com/2017/12/04/holiday-ping-design-notes/</link>
  82. <comments>https://facundoolano.wordpress.com/2017/12/04/holiday-ping-design-notes/#respond</comments>
  83. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  84. <pubDate>Mon, 04 Dec 2017 15:05:56 +0000</pubDate>
  85. <category><![CDATA[Uncategorized]]></category>
  86. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=1029</guid>
  87.  
  88. <description><![CDATA[After joining LambdaClass, I&#8217;ve been working on an Open-Source application using Erlang and ClojureScript. I Published the design notes in two articles at Not A Monad Tutorial: Holiday Ping: how we implemented our first open source app with Erlang and Clojurescript One does not simply build a user interface: our ClojureScript/re-frame app &#160;]]></description>
  89. <content:encoded><![CDATA[<p>After joining <a href="http://lambdaclass.com" target="_blank" rel="noopener">LambdaClass</a>, I&#8217;ve been working on an Open-Source application using Erlang and ClojureScript. I Published the design notes in two articles at Not A Monad Tutorial:</p>
  90. <ul>
  91. <li><a href="https://notamonadtutorial.com/one-does-not-simply-build-a-user-interface-our-clojurescript-re-frame-app-67b1354a2d55" target="_blank" rel="noopener">Holiday Ping: how we implemented our first open source app with Erlang and Clojurescript</a></li>
  92. <li><a href="https://notamonadtutorial.com/one-does-not-simply-build-a-user-interface-our-clojurescript-re-frame-app-67b1354a2d55" target="_blank" rel="noopener">One does not simply build a user interface: our ClojureScript/re-frame app</a></li>
  93. </ul>
  94. <p>&nbsp;</p>
  95. ]]></content:encoded>
  96. <wfw:commentRss>https://facundoolano.wordpress.com/2017/12/04/holiday-ping-design-notes/feed/</wfw:commentRss>
  97. <slash:comments>0</slash:comments>
  98. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  99. <media:title type="html">facundoolano</media:title>
  100. </media:content>
  101. </item>
  102. <item>
  103. <title>Interview for This is not a Monad tutorial</title>
  104. <link>https://facundoolano.wordpress.com/2017/04/14/interview-for-this-is-not-a-monad-tutorial/</link>
  105. <comments>https://facundoolano.wordpress.com/2017/04/14/interview-for-this-is-not-a-monad-tutorial/#respond</comments>
  106. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  107. <pubDate>Fri, 14 Apr 2017 18:56:03 +0000</pubDate>
  108. <category><![CDATA[Uncategorized]]></category>
  109. <category><![CDATA[clojure]]></category>
  110. <category><![CDATA[Java]]></category>
  111. <category><![CDATA[JavaScript]]></category>
  112. <category><![CDATA[Python]]></category>
  113. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=1008</guid>
  114.  
  115. <description><![CDATA[unbalancedparen interviewed me for his blog This is not a Monad tutorial. I elaborated on some of the topics I usually write about in this blog, like Python, Clojure and Open Source programming. Here&#8217;s the link to the interview.]]></description>
  116. <content:encoded><![CDATA[<p><a href="https://twitter.com/unbalancedparen">unbalancedparen</a> interviewed me for his blog <a href="https://notamonadtutorial.com/">This is not a Monad tutorial</a>. I elaborated on some of the topics I usually write about in this blog, like Python, Clojure and Open Source programming.</p>
  117. <p><a href="https://notamonadtutorial.com/a-pythonist-finds-a-new-home-at-clojure-land-761ad8612b47">Here&#8217;s the link to the interview</a>.</p>
  118. ]]></content:encoded>
  119. <wfw:commentRss>https://facundoolano.wordpress.com/2017/04/14/interview-for-this-is-not-a-monad-tutorial/feed/</wfw:commentRss>
  120. <slash:comments>0</slash:comments>
  121. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  122. <media:title type="html">facundoolano</media:title>
  123. </media:content>
  124. </item>
  125. <item>
  126. <title>This is unfortunate and we&#8217;re stuck with it forever</title>
  127. <link>https://facundoolano.wordpress.com/2016/12/09/this-is-unfortunate-and-were-stuck-with-it-forever/</link>
  128. <comments>https://facundoolano.wordpress.com/2016/12/09/this-is-unfortunate-and-were-stuck-with-it-forever/#comments</comments>
  129. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  130. <pubDate>Fri, 09 Dec 2016 15:25:14 +0000</pubDate>
  131. <category><![CDATA[Uncategorized]]></category>
  132. <category><![CDATA[JavaScript]]></category>
  133. <category><![CDATA[Node.js]]></category>
  134. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=976</guid>
  135.  
  136. <description><![CDATA[I. Some weeks ago, at NodeConf Argentina, Mathias Bynens gave a presentation about RegExp and Unicode in JavaScript. At some point he showed a series of examples that yielded counter-intuitive results and said: “This is unfortunate and we’re stuck with it forever”. The phrase immediately resounded in my head, because to me it was a [&#8230;]]]></description>
  137. <content:encoded><![CDATA[<p style="text-align:justify;"><strong>I.</strong> Some weeks ago, at <a href="http://2016.nodeconf.com.ar">NodeConf Argentina</a>, <a href="https://twitter.com/mathias">Mathias Bynens</a> gave a presentation about RegExp and Unicode in JavaScript. At some point he showed a series of examples that yielded counter-intuitive results and said: “This is unfortunate and we’re stuck with it forever”. The phrase immediately resounded in my head, because to me it was a perfect definition of JavaScript, or at least the current state of JavaScript.</p>
  138. <p style="text-align:justify;"><strong>II.</strong> Douglas Crockford published <i>JavaScript: The Good Parts</i> about eight years ago. It’s a masterpiece to me, with a lot of takeaways: JavaScript is loaded with crap (the bad and awful parts); there’s a great functional language somewhere in there, striving to get out; sometimes, a lot of the times, less is more. The book itself is the perfect example: 100 pages long, mostly filled with snippets and examples, and still it had a clearer purpose and communicated it more effectively than most computer books. We can (and we should) make a better language out of JavaScript by subsetting it.</p>
  139. <p style="text-align:justify;"><strong>III.</strong> JavaScript and its ecosystem have been evolving constantly over the last few years; I imagine it mutated faster than any other programming language has done before. And a lot of the changes are genuinely good additions, that make our lives easier and more pleasant. But is JavaScript as a whole getting any better?</p>
  140. <p style="text-align:justify;"><strong>IV.</strong> Unlike any other language, JavaScript runs in browsers. And we can’t control the runtime of the browsers. And we want older browsers to support our new code, and new browsers to support our old code. We can’t break backwards compatibility. We can add (some) stuff to the language but we can’t take stuff out. All the bad and awful parts are still there. JavaScript is like a train wreck with a nose job.</p>
  141. <p style="text-align:justify;"><strong>V.</strong> I always wonder how is it like to learn JavaScript in 2016, for new programmers and for programmers coming from other languages. Do you tell them about <code>var</code>? Or just stick to <code>let</code> and <code>const</code>? And which one of those is preferred? And why the preferred one isn’t just the default? Why do we always have to prepend some operator to define a variable? Yes, we can instruct a linter to forbid this or that keyword (especially this!) but it should be the compiler/interpreter doing it. And we can&#8217;t make the interpreter assume a <code>const</code> declaration by default.</p>
  142. <p style="text-align:justify;"><strong>VI.</strong> Is there really no way to break backwards compatibility? Can’t we just stick a flag in there somewhere? <code>&lt;script language="javascript-good"&gt;</code>? <code>'use non-crappy'</code>? I don’t mind adding the <code>'use strict'</code> on every file and I honestly forgot what it does. Can’t the browsers manage multiple versions of JavaScript? is it worth their save, especially now that this uneven language has crawled its way to the server and the desktop?</p>
  143. <p style="text-align:justify;"><strong>VII.</strong> I know there must be excellent reasons why we can’t break backwards compatibility of JavaScript or why it would be just too expensive to do so. But I can’t help my mind, my syntax-oriented-programmer-with-an-inclination-to-a-less-is-more-kind-of-thinking-type-of-mind, I can’t help it from imagining how would <i>I </i>go about subsetting the language. How would I design my <code>JavaScript--</code>. I can’t help myself from outlining a spec of that imaginary language in my head. I even came up with a name for it, which, unsurprisingly, has already been taken.</p>
  144. ]]></content:encoded>
  145. <wfw:commentRss>https://facundoolano.wordpress.com/2016/12/09/this-is-unfortunate-and-were-stuck-with-it-forever/feed/</wfw:commentRss>
  146. <slash:comments>6</slash:comments>
  147. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  148. <media:title type="html">facundoolano</media:title>
  149. </media:content>
  150. </item>
  151. <item>
  152. <title>From Clojure to ClojureScript</title>
  153. <link>https://facundoolano.wordpress.com/2016/10/16/from-clojure-to-clojurescript/</link>
  154. <comments>https://facundoolano.wordpress.com/2016/10/16/from-clojure-to-clojurescript/#comments</comments>
  155. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  156. <pubDate>Mon, 17 Oct 2016 01:55:49 +0000</pubDate>
  157. <category><![CDATA[Uncategorized]]></category>
  158. <category><![CDATA[clojure]]></category>
  159. <category><![CDATA[clojurescript]]></category>
  160. <category><![CDATA[JavaScript]]></category>
  161. <category><![CDATA[lisp]]></category>
  162. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=930</guid>
  163.  
  164. <description><![CDATA[Ever since I started working on the advenjure engine as a learning project for Clojure, I thought porting it to the browser would make a great excuse to get into ClojureScript as well. I finally took the time to do it a couple of weeks ago and now the engine is fully functional in both environments. The process [&#8230;]]]></description>
  165. <content:encoded><![CDATA[<p style="text-align:justify;">Ever since I started working on the <a href="https://github.com/facundoolano/advenjure">advenjure engine</a> as a learning project for Clojure, I thought porting it to the browser would make a great excuse to get into ClojureScript as well. I finally took the time to do it a couple of weeks ago and now the engine is fully functional in both environments.</p>
  166. <p style="text-align:justify;">The process of going from zero to having some Clojure code running in the browser, source-maps included, was surprisingly easy. Making a fully functional Clojure project target the browser too was a bit more difficult, especially when dealing with JavaScript&#8217;s inherent asynchronous nature and setting up the ClojureScript compiler to bundle the project and its dependencies.</p>
  167. <p style="text-align:justify;">I document here the steps I took, useful reads, issues I found along the way and the sources where I got the solutions. For context, I&#8217;m using version 1.9.229 of ClojureScript.</p>
  168. <h3 style="text-align:justify;">Getting Started</h3>
  169. <p style="text-align:justify;"><a href="https://www.clojurescript.org/about/differences">Differences from Clojure</a> was a good place to start getting an idea of what ClojureScript looks like coming from Clojure. After that, the <a href="http://clojurescript.org/guides/quick-start">Quick Start</a> tutorial was all it took to get my code running in the browser, in Node.js and even in a ClojureScript REPL. With the boilerplate project from the tutorial I was able to start migrating bits of the advenjure codebase and running them in the browser console.</p>
  170. <p style="text-align:justify;">After testing most of the pure-logic parts of the project and being confortable that they could actually run in the browser, I had to deal with the files that were more or less dependant on Java interop. At this point I needed to review the Reader Conditionals documentation, <a href="http://clojure.org/guides/reader_conditionals">here</a> and <a href="http://dev.clojure.org/display/design/Reader+Conditionals">here</a>. The key takeaways where: Clojure specific logic goes in <code>.clj</code> files, ClojureScript in <code>.cljs</code>; shared logic goes in <code>.cljc</code>, using the conditional syntax in the parts that differ from one host to another:</p>
  171. <pre class="brush: clojure; title: ; notranslate">
  172. (defn str-&gt;int [s]
  173.  #?(:clj  (java.lang.Integer/parseInt s)
  174.     :cljs (js/parseInt s)))
  175. </pre>
  176. <p style="text-align:justify;">Because of how macros work in ClojureScript, those needed to go either in <code>.clj</code> or <code>.cljc</code> files, and required using the <code>:require-macros</code> option:</p>
  177. <pre class="brush: clojure; title: ; notranslate">
  178. (ns example.dialogs
  179.  #?(:clj (:require [advenjure.dialogs :refer [dialog]])
  180.     :cljs (:require-macros [advenjure.dialogs :refer [dialog]])))
  181. </pre>
  182. <p style="text-align:justify;">With Reader Conditionals, <code>println</code> and <code>js/prompt</code> I had a fairly functional version of the example game running in the browser. The next step was to include <a href="https://github.com/jcubic/jquery.terminal">jQuery terminal</a> in the web page and use it as the interface for the game.</p>
  183. <h3 style="text-align:justify;">JavaScript interop and asyncrhonous code</h3>
  184. <p style="text-align:justify;">Interop syntax is pretty simple, <a href="http://www.spacjer.com/blog/2014/09/12/clojurescript-javascript-interop/">this article</a> and the <a href="http://cljs.info/cheatsheet/">CloureScript Cheatsheet</a> covered all I needed: the <code>js/</code> namespace to access JavaScript globals and built-ins, <code>js-obj</code> for object literals, <code>aget</code> and <code>aset</code> to access them, dot prefix to invoke methods.</p>
  185. <p style="text-align:justify;">Things got a bit more complicated as I started integrating the jQuery terminal: my library was more or less a REPL, designed around the idea of waiting for user input and then processing it, but the terminal, as most JavaScript libraries, relied on callbacks and asynchronous processing. When the user enters a command, a processing function is called, which is detached from the game loop that holds the current game state and knows how to handle that command.</p>
  186. <p style="text-align:justify;">After googling around, core.async seemed like the most suitable tool to emulate the synchronicity that my codebase required. I&#8217;ve read about it earlier in the <a href="http://www.braveclojure.com/core-async/">Brave Clojure book</a>; <a href="http://ku1ik.com/2015/10/12/sweet-core-async.html">this article</a> was also helpful to get code samples.</p>
  187. <p style="text-align:justify;">My solution was to create an input channel where the jQuery terminal would write the commands:</p>
  188. <pre class="brush: clojure; title: ; notranslate">
  189. (ns advenjure.ui.input
  190.  (:require-macros [cljs.core.async.macros :refer [go]])
  191.  (:require [cljs.core.async :refer [&lt;! &gt;! chan]]))
  192.  
  193. (def input-chan (chan))
  194.  
  195. (defn process-command
  196.  &quot;Callback passed to jQuery terminal upon initialization&quot;
  197.  [command]
  198.  (go (&gt;! input-chan command)))
  199.  
  200. (defn get-input
  201.  &quot;Wait for input to be written in the input channel&quot;
  202.  [state]
  203.  (go (&lt;! input-chan)))
  204. </pre>
  205. <p style="text-align:justify;">The main game loop that used to block waiting for user input now was a <code>go-loop</code> that &#8220;parked&#8221; until data came into the input channel:</p>
  206. <pre class="brush: clojure; title: ; notranslate">
  207. (ns advenjure.game
  208.  (:require [advenjure.ui.input :refer [get-input exit]]
  209.            #?(:cljs [cljs.core.async :refer [&lt;!]]))
  210.  #?(:cljs (:require-macros [cljs.core.async.macros :refer [go-loop]])))
  211.  
  212. #?(:clj
  213.    (defn run
  214.      [game-state finished?]
  215.      (loop [state game-state]
  216.        (let [input (get-input state)
  217.              new-state (process-input state input)]
  218.          (if-not (finished? new-state)
  219.            (recur new-state)
  220.            (exit))))))
  221.  
  222. #?(:cljs
  223.    (defn run
  224.      [game-state finished?]
  225.      (go-loop [state game-state]
  226.        (let [input (&lt;! (get-input state))
  227.              new-state (process-input state input)]
  228.          (if-not (finished? new-state)
  229.            (recur new-state)
  230.            (exit))))))
  231. </pre>
  232. <p style="text-align:justify;">This works well although it requires some amount of duplication between the Clojure and ClojureScript versions of the code. Advenjure dialog trees introduce more sophisticated ways of reading and processing user input, which threatened to leak the core.async logic into other portions of the codebase, thus causing more duplication. I managed to keep that to an acceptable minimum without loosing functionality, but there&#8217;s definitely room for improvement, perhaps coming up with some macro that abstracts host-specific differences behind a common syntax.</p>
  233. <h3>Reading, evaluating and persisting Clojure code</h3>
  234. <p style="text-align:justify;">Some of the features of advenjure, such as dialogs and post/pre conditions, required storing quoted Clojure code in the game state, for later evaluation. I found that some built-ins I used to implement them, like <code>read-string</code> and <code>eval</code>, are not directly available in ClojureScript, but a bit of googling revealed how to bring them back.</p>
  235. <p style="text-align:justify;">Based on <a href="https://yogthos.net/posts/2015-11-12-ClojureScript-Eval.html">this article</a> I came up with the following function to replace the native <code>eval</code>, using the tools in the <code>cljs.js</code> namespace:</p>
  236. <pre class="brush: clojure; title: ; notranslate">
  237. (ns advenjure.eval
  238.  (:require [cljs.js]))
  239.  
  240. (defn eval [form] (cljs.js/eval
  241.                    (cljs.js/empty-state)
  242.                    form
  243.                    {:eval cljs.js/js-eval
  244.                     :source-map true
  245.                     :context :expr}
  246.                    :value))
  247. </pre>
  248. <p style="text-align:justify;">As I learned later on, this snippet comes with one catch: when using <a href="http://clojurescript.org/guides/self-hosting">Self-hosted ClojureScript</a> (which is what <code>cljs.js</code> enables, evaluating ClojureScript code inside ClojureScript), you can&#8217;t use advanced <a href="http://clojurescript.org/reference/compiler-options#optimizations">compiler optimizations</a> in your build.</p>
  249. <p style="text-align:justify;">While it&#8217;s not a built-in, <code>read-string</code> can be found in <code>cljs.reader/read-string</code>. In the Clojure version of my library, I was able to easily save and restore the game state to a file:</p>
  250. <pre class="brush: clojure; title: ; notranslate">
  251. (defn save-game [game-state]
  252. (spit &quot;saved.game&quot; game-state))
  253.  
  254. (defn load-game []
  255. (read-string (slurp &quot;saved.game&quot;)))
  256. </pre>
  257. <p style="text-align:justify;">I intended to do the same in ClojureScript, using the browser localStorage. This didn&#8217;t work right away, though, because the ClojureScript reader doesn&#8217;t know how to read records back from the storage. <a href="https://coderwall.com/p/3xqr7q/clojurescript-read-string-and-records">This script</a> gave me the solution:</p>
  258. <pre class="brush: clojure; title: ; notranslate">
  259. (require '[cljs.reader :refer [read-string register-tag-parser!]]
  260.         '[advenjure.items :refer [map-&gt;Item]]
  261.         '[advenjure.rooms :refer [map-&gt;Room]])
  262.  
  263. (defn save-game [game-state]
  264. (aset js/localStorage &quot;saved.game&quot; (pr-str game-state)))
  265.  
  266. (register-tag-parser! &quot;advenjure.items.Item&quot; map-&gt;Item)
  267. (register-tag-parser! &quot;advenjure.rooms.Room&quot; map-&gt;Room)
  268.  
  269. (defn load-game []
  270. (read-string (aget js/localStorage &quot;saved.game&quot;)))
  271. </pre>
  272. <h3>Leiningen cljsbuild plugin</h3>
  273. <p style="text-align:justify;">So far I was doing all the work inside the hello-world project from the Quick Start tutorial. Now that most of the engine was working in ClojureScript I had to integrate it back into the Clojure project and fix anything I broke to make sure it targeted both platforms. I&#8217;m using Leiningen so I looked into the <a href="https://github.com/emezeske/lein-cljsbuild">lein-cljsbuild</a> plugin. Since advenjure is a library intended to be used as a dependency in other projects, it didn&#8217;t matter much what configuration I put in there; the example project, though, ended up with the following configuration in its project.clj:</p>
  274. <pre class="brush: clojure; title: ; notranslate">
  275. :plugins [[lein-cljsbuild &quot;1.1.4&quot;]]
  276. :cljsbuild
  277.  {:builds
  278.   {:main {:source-paths [&quot;src&quot;]
  279.           :compiler {:output-to &quot;main.js&quot;
  280.                      :main example.core
  281.                      :optimizations :simple
  282.                      :pretty-print false
  283.                      :optimize-constants true
  284.                      :static-fns true}}
  285.  
  286.    :dev {:source-paths [&quot;src&quot;]
  287.          :compiler {:output-to &quot;dev.js&quot;
  288.                     :main example.core
  289.                     :optimizations :none
  290.                     :source-map true
  291.                     :pretty-print true}}}}
  292. </pre>
  293. <p style="text-align:justify;">Then, running <code>lein cljsbuild once</code> would compile development and production versions of the game to be included in the HTML page. Note that, as mentioned, I couldn&#8217;t use <code>:optimizations :advanced</code> in the production build, because I was using the <code>cljs.js</code> namespace in my project.</p>
  294. <h3 style="text-align:justify;">Regular Expressions</h3>
  295. <p style="text-align:justify;">Some of the features of advenjure relied on regular expressions. The Clojure related functions are backed by the host implementation of regexes, and JavaScript <a href="http://stackoverflow.com/q/5367369/993769">doesn&#8217;t support</a> named capturing groups. To overcome this without changing the original code, I resorted to <a href="http://xregexp.com/">XRegExp</a>, which fortunately respects the native JavaScript interfaces for regular expressions:</p>
  296. <pre class="brush: clojure; title: ; notranslate">
  297. (def regexp #?(:clj re-pattern :cljs js/XRegExp))
  298.  
  299. (defn match-verb [verb-pattern input]
  300.  (re-find (regexp verb-pattern) input))
  301. </pre>
  302. <h3 style="text-align:justify;">Bundling foreign libs</h3>
  303. <p style="text-align:justify;">Once everything worked as expected, I needed to figure out how to pack the library so it could be easily included in projects with minimum effort. Particularly, I needed a way to bundle the JavaScript dependencies (jQuery, jQuery terminal, etc.), so the users wouldn&#8217;t need to include them manually in their HTML. This topic can get a bit complex in ClojureScript, especially when dealing with advanced optimizations (which I learned along the way I wasn&#8217;t going to use). <a href="http://clojurescript.org/reference/dependencies">This</a> and <a href="http://lukevanderhart.com/2011/09/30/using-javascript-and-clojurescript.html">this</a> are good references.</p>
  304. <p style="text-align:justify;">The <a href="http://cljsjs.github.io/">CLJSJS project</a> is an initiative that allows to easily require JavaScript libraries like regular Clojure dependencies. The problem is that the amount of supported libraries is limited, and contributing one of your own is <a href="https://github.com/cljsjs/packages/wiki/Creating-Packages">not a trivial process</a> (specifically, it seems to require Boot, and since I was already set up with Leiningen it didn&#8217;t look like an option at the moment).</p>
  305. <p style="text-align:justify;">I had to fallback to using the <a href="http://clojurescript.org/reference/compiler-options#foreign-libs">foreign-libs compiler option</a>. For some reason, I couldn&#8217;t figure out how to make that work from the cljsbuild settings in my project.clj, so after reviewing <a href="http://clojurescript.org/reference/packaging-foreign-deps">this wiki entry</a> I decided to include a <code>deps.cljs</code> file in the root of my source directory:</p>
  306. <pre class="brush: clojure; title: ; notranslate">
  307. {:foreign-libs
  308. [{:file &quot;jquery/jquery-3.1.1.js&quot;
  309. :file-min &quot;jquery/jquery-3.1.1.min.js&quot;
  310. :provides [&quot;jquery&quot;]}
  311. {:file &quot;jquery.terminal/jquery.terminal-0.11.10.js&quot;
  312. :file-min &quot;jquery.terminal/jquery.terminal-0.11.10.min.js&quot;
  313. :requires [&quot;jquery&quot;]
  314. :provides [&quot;jquery.terminal&quot;]}
  315. {:file &quot;jquery.terminal/jquery.mousewheel.js&quot;
  316. :file-min &quot;jquery.terminal/jquery.mousewheel.min.js&quot;
  317. :requires [&quot;jquery&quot;]
  318. :provides [&quot;jquery.mousewheel&quot;]}
  319. {:file &quot;xregexp/xregexp-all.js&quot;
  320. :file-min &quot;xregexp/xregexp-all.min.js&quot;
  321. :provides [&quot;xregexp&quot;]}]
  322. :externs [&quot;jquery/externs.js&quot; &quot;jquery.terminal/externs.js&quot; &quot;xregexp/externs.js&quot;]}
  323. </pre>
  324. <p style="text-align:justify;">Some notes about it:</p>
  325. <ul>
  326. <li style="text-align:justify;">I had to add the files and minified files to the resources folder of the library, to be used in the development and production builds respectively.</li>
  327. <li style="text-align:justify;">I needed to define a <code>:provides</code> name and require it in my codebase (no matter if the library exposes a global value that&#8217;s actually accesible through <code>js/</code>), in order for the compiler to include the library in the generated build.</li>
  328. <li style="text-align:justify;">The <code>:requires</code> is also important to establish dependencies between libraries; without it, the jQuery terminal code can be included before jQuery, which would cause a reference error when running in the browser.</li>
  329. <li style="text-align:justify;">The externs aren&#8217;t really necessary, since I wasn&#8217;t using advanced optimizations, but if I was I found <a href="http://www.dotnetwise.com/Code/Externs/">this tool</a> of great help in generating those files, especially for big libraries like jQuery. Smaller ones, like a jQuery plugin, I could create by hand; the <a href="https://github.com/cljsjs/packages">CLJSJS packages</a> can be a good reference in that case.</li>
  330. </ul>
  331. ]]></content:encoded>
  332. <wfw:commentRss>https://facundoolano.wordpress.com/2016/10/16/from-clojure-to-clojurescript/feed/</wfw:commentRss>
  333. <slash:comments>1</slash:comments>
  334. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  335. <media:title type="html">facundoolano</media:title>
  336. </media:content>
  337. </item>
  338. <item>
  339. <title>Real-world RPC with RabbitMQ and Node.JS</title>
  340. <link>https://facundoolano.wordpress.com/2016/06/26/real-world-rpc-with-rabbitmq-and-node-js/</link>
  341. <comments>https://facundoolano.wordpress.com/2016/06/26/real-world-rpc-with-rabbitmq-and-node-js/#comments</comments>
  342. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  343. <pubDate>Sun, 26 Jun 2016 15:54:16 +0000</pubDate>
  344. <category><![CDATA[Uncategorized]]></category>
  345. <category><![CDATA[JavaScript]]></category>
  346. <category><![CDATA[microservices]]></category>
  347. <category><![CDATA[Node.js]]></category>
  348. <category><![CDATA[RabbitMQ]]></category>
  349. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=824</guid>
  350.  
  351. <description><![CDATA[tl;dr: use the direct reply-to feature to implement RPC in RabbitMQ. I’m currently working on a platform that relies heavily on RPC over RabbitMQ to move incoming requests through a chain of Node.JS worker processes. The high level setup for RPC is well described in RabbitMQ’s documentation; let&#8217;s steal their diagram: We grew our RPC client [&#8230;]]]></description>
  352. <content:encoded><![CDATA[<p style="text-align:justify;"><em><span style="font-weight:400;">tl;dr: use the <a href="https://www.rabbitmq.com/direct-reply-to.html" target="_blank">direct reply-to</a> feature to implement RPC in RabbitMQ.</span></em></p>
  353. <p style="text-align:justify;">I’m currently working on a platform that relies heavily on RPC over RabbitMQ to move incoming requests through a chain of Node.JS worker processes. The high level setup for RPC is well described in RabbitMQ’s documentation; let&#8217;s steal their diagram:</p>
  354. <p style="text-align:justify;"><img data-attachment-id="831" data-permalink="https://facundoolano.wordpress.com/2016/06/26/real-world-rpc-with-rabbitmq-and-node-js/python-six/#main" data-orig-file="https://facundoolano.files.wordpress.com/2016/06/python-six.png" data-orig-size="576,200" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="python-six" data-image-description="" data-image-caption="" data-medium-file="https://facundoolano.files.wordpress.com/2016/06/python-six.png?w=300" data-large-file="https://facundoolano.files.wordpress.com/2016/06/python-six.png?w=576" class=" size-full wp-image-831 aligncenter" src="https://facundoolano.files.wordpress.com/2016/06/python-six.png?w=594" alt="python-six"   srcset="https://facundoolano.files.wordpress.com/2016/06/python-six.png 576w, https://facundoolano.files.wordpress.com/2016/06/python-six.png?w=150&amp;h=52 150w, https://facundoolano.files.wordpress.com/2016/06/python-six.png?w=300&amp;h=104 300w" sizes="(max-width: 576px) 100vw, 576px" /></p>
  355. <p style="text-align:justify;">We grew our RPC client code based on the <a href="https://www.rabbitmq.com/tutorials/tutorial-six-javascript.html" target="_blank">JavaScript tutorial</a>, using the <a href="https://github.com/squaremo/amqp.node" target="_blank">amqp.node</a> module. The first —admittedly naive— implementation just created a new connection, channel and queue per request and killed the connection after getting a reply:</p>
  356. <pre class="brush: jscript; title: ; notranslate">
  357. const sendRPCMessage = (settings, message, rpcQueue) =&gt;
  358.  amqp.connect(settings.url, settings.socketOptions)
  359.    .then((conn) =&gt; conn.createChannel())
  360.    .then((channel) =&gt; channel.assertQueue('', settings.queueOptions)
  361.      .then((replyQueue) =&gt; new Promise((resolve, reject) =&gt; {
  362.        const correlationId = uuid.v4();
  363.        const msgProperties = {
  364.          correlationId,
  365.          replyTo: replyQueue.queue
  366.        };
  367.  
  368.        function consumeAndReply (msg) {
  369.          if (!msg) return reject(Error.create('consumer cancelled by rabbitmq'));
  370.  
  371.          if (msg.properties.correlationId === correlationId) {
  372.            resolve(msg.content);
  373.          }
  374.        }
  375.  
  376.        channel.consume(replyQueue.queue, consumeAndReply, {noAck: true})
  377.        .then(() =&gt; channel.sendToQueue(rpcQueue, new Buffer(message), msgProperties));
  378.      })));
  379. </pre>
  380. <p style="text-align:justify;">That got us a long way during development but obviously failed to perform under non-trivial loads. What was more shocking is that it got dramatically worse when running it on a RabbitMQ cluster.</p>
  381. <p style="text-align:justify;">So we needed to refactor our client code. The problem is that <a href="https://www.rabbitmq.com/tutorials/tutorial-six-javascript.html">most</a> <a href="https://github.com/squaremo/amqp.node/blob/master/examples/tutorials/rpc_client.js">examples</a> show how to send one-off RPC messages, but aren’t that clear on how the approach would be used at scale on a long-lived process. We obviously needed to reuse the connection but how about the channel? Should I create a new callback queue per incoming request or a single one per client?</p>
  382. <h3 style="text-align:justify;">Using a single reply-to queue per client</h3>
  383. <p style="text-align:justify;">Based on the tutorial, I understood that the sensible approach was to reuse the queue from which the client consumed the RPC replies:</p>
  384. <blockquote>
  385. <p style="text-align:justify;">In the method presented above we suggest creating a callback queue for every RPC request. That&#8217;s pretty inefficient, but fortunately there is a better way &#8211; let&#8217;s create a single callback queue per client. That raises a new issue, having received a response in that queue it&#8217;s not clear to which request the response belongs. That&#8217;s when the correlation_id property is used.</p>
  386. </blockquote>
  387. <p style="text-align:justify;">We were already checking the <code>correlationId</code>, and just needed to create the reply-to queue in advance:</p>
  388. <pre class="brush: jscript; title: ; notranslate">
  389. const createClient = (settings) =&gt;
  390.  amqp.connect(settings.url, settings.socketOptions)
  391.    .then((conn) =&gt; conn.createChannel())
  392.    .then((channel) =&gt; channel.assertQueue('', settings.queueOptions)
  393.      .then((replyQueue) =&gt; {
  394.        channel.replyQueue = replyQueue.queue;
  395.        return channel;
  396.      }));
  397. </pre>
  398. <p style="text-align:justify;">I thought that would be enough to make sure the right consumer got the right message, but in practice I found that each message was always delivered to the first consumer. Therefore, I needed to cancel the consumer after the reply was processed:</p>
  399. <pre class="brush: jscript; title: ; notranslate">
  400. const sendRPCMessage = (channel, message, rpcQueue) =&gt;
  401.  new Promise((resolve, reject) =&gt; {
  402.    const correlationId = uuid.v4();
  403.    const msgProperties = {
  404.      correlationId,
  405.      replyTo: channel.replyQueue
  406.    };
  407.  
  408.    function consumeAndReply (msg) {
  409.      if (!msg) return reject(Error.create('consumer cancelled by rabbitmq'));
  410.  
  411.      if (msg.properties.correlationId === correlationId) {
  412.        channel.cancel(correlationId)
  413.          .then(() =&gt; resolve(resolve(msg.content)));
  414.      }
  415.    }
  416.  
  417.    channel.consume(channel.replyQueue, consumeAndReply, {
  418.      noAck: true,
  419.      // use the correlationId as a consumerTag to cancel the consumer later
  420.      consumerTag: correlationId
  421.    })
  422.    .then(() =&gt; channel.sendToQueue(rpcQueue, new Buffer(message), msgProperties));
  423.  });
  424. </pre>
  425. <p style="text-align:justify;">Enough? Only if the client processed one request at a time. As soon as I added some concurrency I saw that some of the messages were not handled at all. They were picked up by the wrong consumer, which ignored them because of the <code>correlationId</code> check, so they were lost. I needed to do something about unexpected message handling.</p>
  426. <h3 style="text-align:justify;">Requeuing unexpected messages</h3>
  427. <p style="text-align:justify;">I tried using <code>nack</code> when a consumer received a reply to a message with an unexpected <code>correlationId</code>:</p>
  428. <pre class="brush: jscript; title: ; notranslate">
  429. function consumeAndReply (msg) {
  430.  if (!msg) return reject(Error.create('consumer cancelled by rabbitmq'));
  431.  
  432.  if (msg.properties.correlationId === correlationId) {
  433.    channel.ack(msg);
  434.    channel.cancel(correlationId)
  435.      .then(() =&gt; resolve(resolve(msg.content)));
  436.  } else {
  437.    channel.nack(msg);
  438.  }
  439. }
  440. </pre>
  441. <p style="text-align:justify;">Now the messages seemed to be handled, eventually. Only they weren’t: when I increased the load I saw message loss again. Further inspection revealed that the consumers were entering a weird infinite loop:</p>
  442. <pre>Consumer A gets message B; message B requeued
  443. Consumer B gets message C; Message C requeued
  444. Consumer C gets message A; Message A requeued</pre>
  445. <p style="text-align:justify;">Repeated ad-infinitum. The same behaviour was reproduced using every possible combination of <code>nack</code>, <code>reject</code> and <code>sendToQueue</code> to send back the message.</p>
  446. <p style="text-align:justify;"><a href="http://rabbitmq.1065348.n5.nabble.com/Push-to-back-of-Queue-on-NAck-td28421.html">Googling the issue</a>, I read about the possibility of using <a href="https://www.rabbitmq.com/dlx.html">Dead letter exchanges</a> to handle those cases. But having to manually requeue unexpected messages felt weird enough; introducing a new exchange and queue sounded like a lot of effort to handle what should be a pretty standard use case for RPC. Better to take a step back.</p>
  447. <h3 style="text-align:justify;">Using a new reply-to queue per request</h3>
  448. <p style="text-align:justify;">So I went back to a reply-to queue per request. This was marginally better than our initial approach since now at least we were recycling the connection and the channel. What’s more, that appeared to be the standard way to do RPC in RabbitMQ according to the <a href="http://stackoverflow.com/a/31705146/993769" target="_blank">few</a> <a href="https://github.com/rudijs/amqp.node-rpc-factory">spots</a> where I found non-tutorial implementation details, so, as Paul Graham would say, we wouldn’t get in trouble for using it.</p>
  449. <p style="text-align:justify;">And it worked well for us as long as we run a single RabbitMQ instance. When we moved to a RabbitMQ cluster the performance was pretty much the same as when we were creating connections like there was no tomorrow.</p>
  450. <h3 style="text-align:justify;">Using direct reply-to</h3>
  451. <p style="text-align:justify;">We were seriously considering dropping the RabbitMQ cluster altogether (which meant turning our broker into a single point of failure), when I came across the link to the <a href="https://www.rabbitmq.com/direct-reply-to.html">direct reply-to documentation</a>. The first interesting thing there was that it confirmed why we were seeing such bad performance when running a RabbitMQ cluster:</p>
  452. <blockquote>
  453. <p style="text-align:justify;">The client can declare a single-use queue for each request-response pair. But this is inefficient; even a transient unmirrored queue can be expensive to create and then delete (compared with the cost of sending a message). This is especially true in a cluster as all cluster nodes need to agree that the queue has been created, even if it is unmirrored.</p>
  454. </blockquote>
  455. <p style="text-align:justify;">Direct reply-to uses a pseudo-queue instead, avoiding the queue declaration cost. And fortunately it was fairly straightforward to implement:</p>
  456. <pre class="brush: jscript; title: ; notranslate">
  457. const createClient = (settings) =&gt; amqp.connect(settings.url, settings.socketOptions)
  458.  
  459. const sendRPCMessage = (client, message, rpcQueue) =&gt; conn.createChannel()
  460.  .then((channel) =&gt; new Promise((resolve, reject) =&gt; {
  461.    const replyToQueue = 'amq.rabbitmq.reply-to';
  462.    const timeout = setTimeout(() =&gt; channel.close(), 10000);
  463.  
  464.    const correlationId = uuid.v4();
  465.    const msgProperties = {
  466.      correlationId,
  467.      replyTo: replyToQueue
  468.    };
  469.  
  470.    function consumeAndReply (msg) {
  471.      if (!msg) return reject(Error.create('consumer cancelled by rabbitmq'));
  472.  
  473.      if (msg.properties.correlationId === correlationId) {
  474.        resolve(msg.content);
  475.        clearTimeout(timeout);
  476.        channel.close();
  477.      }
  478.    }
  479.  
  480.    channel.consume(replyToQueue, consumeAndReply, {noAck: true})
  481.    .then(() =&gt; channel.sendToQueue(rpcQueue, new Buffer(content), msgProperties))
  482.  });
  483. </pre>
  484. <p style="text-align:justify;">This worked just as we expected, even in the cluster. As the code shows, though, we were still creating a new channel per request and we needed to handle its closing, even when the response never came. Trying to use a single channel resulted in a &#8220;reply consumer already set&#8221; error, because the queue was always the same.</p>
  485. <p style="text-align:justify;">Creating so many channels didn&#8217;t feel right, so I <a href="https://github.com/squaremo/amqp.node/issues/259">filed an issue</a> asking for advice in the amqp.node repo. The creator confirmed that that was indeed an anti-pattern and suggested not only using a single channel but registering a single consumer (i.e. a single callback function to handle all RPC responses). This meant introducing some structure to be able to route responses back to the promise that was expecting it. Using an <code>EventEmitter</code> turned out to be an elegant way to accomplish it:</p>
  486. <pre class="brush: jscript; title: ; notranslate">
  487. const REPLY_QUEUE = 'amq.rabbitmq.reply-to';
  488.  
  489. const createClient = (settings) =&gt; amqp.connect(settings.url, settings.socketOptions)
  490.  .then((conn) =&gt; conn.createChannel())
  491.  .then((channel) =&gt; {
  492.    // create an event emitter where rpc responses will be published by correlationId
  493.    channel.responseEmitter = new EventEmitter();
  494.    channel.responseEmitter.setMaxListeners(0);
  495.    channel.consume(REPLY_QUEUE,
  496.      (msg) =&gt; channel.responseEmitter.emit(msg.properties.correlationId, msg.content),
  497.      {noAck: true});
  498.  
  499.    return channel;
  500.  });
  501.  
  502. const sendRPCMessage = (channel, message, rpcQueue) =&gt; new Promise((resolve) =&gt; {
  503.  const correlationId = uuid.v4();
  504.  // listen for the content emitted on the correlationId event
  505.  channel.responseEmitter.once(correlationId, resolve);
  506.  channel.sendToQueue(rpcQueue, new Buffer(message), { correlationId, replyTo: REPLY_QUEUE })
  507. });</pre>
  508. ]]></content:encoded>
  509. <wfw:commentRss>https://facundoolano.wordpress.com/2016/06/26/real-world-rpc-with-rabbitmq-and-node-js/feed/</wfw:commentRss>
  510. <slash:comments>27</slash:comments>
  511. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  512. <media:title type="html">facundoolano</media:title>
  513. </media:content>
  514.  
  515. <media:content url="https://facundoolano.files.wordpress.com/2016/06/python-six.png" medium="image">
  516. <media:title type="html">python-six</media:title>
  517. </media:content>
  518. </item>
  519. <item>
  520. <title>Clojure: the good, the bad and the ugly</title>
  521. <link>https://facundoolano.wordpress.com/2016/03/20/first-impressions-on-clojure/</link>
  522. <comments>https://facundoolano.wordpress.com/2016/03/20/first-impressions-on-clojure/#comments</comments>
  523. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  524. <pubDate>Sun, 20 Mar 2016 20:25:43 +0000</pubDate>
  525. <category><![CDATA[Uncategorized]]></category>
  526. <category><![CDATA[clojure]]></category>
  527. <category><![CDATA[functional programming]]></category>
  528. <category><![CDATA[Java]]></category>
  529. <category><![CDATA[lisp]]></category>
  530. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=682</guid>
  531.  
  532. <description><![CDATA[Four years ago I wrote about my first (and last) experience with Common Lisp. I had high expectations and was disappointed; I ended up thinking maybe I should give Scheme or Clojure a try. It took a while, but I finally did it last month: learn Clojure. And it looks like a keeper. Clojure has all the goodness [&#8230;]]]></description>
  533. <content:encoded><![CDATA[<p style="text-align:justify;"><span style="font-weight:400;">Four years ago <a href="https://facundoolano.wordpress.com/2012/01/31/first-impressions-on-common-lisp/">I wrote</a> about my first (and last) experience with Common Lisp. I had high expectations and was disappointed; I ended up thinking maybe I should give Scheme or Clojure a try. It took a while, but I finally did it last month: learn Clojure. And it looks like a keeper. </span></p>
  534. <p style="text-align:justify;"><span style="font-weight:400;">Clojure has all the goodness of Lisp and functional programming, and it </span><i><span style="font-weight:400;">feels</span></i><span style="font-weight:400;"> like a modern language: it addresses most of things that annoyed me about Common Lisp.</span></p>
  535. <p style="text-align:justify;"><span style="font-weight:400;">I’ve followed the great </span><i><span style="font-weight:400;"><a href="http://braveclojure.com">Clojure for the brave and true</a></span></i><span style="font-weight:400;"> book by Daniel Higginbotham and then I’ve tackled a <a href="https://github.com/facundoolano/advenjure">small project</a> to train my skills. Here are my notes.</span></p>
  536. <h2 style="text-align:justify;">The good</h2>
  537. <ul style="text-align:justify;">
  538. <li style="font-weight:400;"><span style="font-weight:400;">A consistent syntax, operation names and polymorphic functions. No weird illegible names, no type specific versions of the same function (I’m looking at you Common Lisp).</span></li>
  539. <li style="font-weight:400;">Functional! Immutable! Expressive!
  540. <ul>
  541. <li style="font-weight:400;">I don’t miss objects. Structuring programs in small functions; isolated, never changing data; those things just feel right. And I’m not even waving the old “shared state is bad for concurrency” flag; I don’t care —just now— about concurrency. This stuff makes programs simpler to reason about and test, and more fun to write.</li>
  542. <li style="font-weight:400;"><span style="font-weight:400;">There’s more: Clojure is so expressive and gives you enough options (I’m thinking loop, doseq, destructuring, etc.) that you don’t necessarily need to incur in “head/tail” recursive processing as much as I found in other functional languages, so the leap is not so rough.</span></li>
  543. </ul>
  544. </li>
  545. <li style="font-weight:400;">Did I say I don’t care about concurrency? I don’t. Mostly. Not at the language level, anyway. Clojure has a lot of cool tools for concurrency (future, delay, promise, pmap, core.async). Too much options, maybe, but I don’t mind about that either. I can just RTFM whenever I do have the need to do things concurrently. And, yes, immutability and pure functions make it simpler.</li>
  546. <li>A strong philosophy behind the language, that seems to drive its design. Python has this too and to me it’s its biggest selling point. Languages like C++ and increasingly JavaScript, on the other hand, feel like magic bags where features are added carelessly without consideration of the results. Java <em>does</em> have a strong philosophy: <a href="https://facundoolano.wordpress.com/2011/11/03/python-doesn%e2%80%99t-treat-me-like-i%e2%80%99m-stupid/">programmers are mostly idiots</a>.</li>
  547. <li>Runs on the JVM. Seriously? I personally couldn’t care less about that but JVM languages seem to attract a lot of attention. There are tons of Java devs for sure and some of them seem to have a symbiotic relationship with the JVM: it’s like they aren’t cheating on Java if they keep the deal inside the VM. Why would people learn Groovy instead of Ruby or Python, god only knows, but because of the “Runs in Java” part there’s a better chance of finding a Clojure Job than one using Haskell, Scheme or most other functional languages around. That alone is enough reason for me to stick with Clojure instead of keep trying Lisp dialects, even if some other one may fit my taste better.</li>
  548. <li>Haven’t tried it yet, but the mere existence of ClojureScript is good news to me, specially considering how annoyed I am with the direction the JavaScript syntax and ecosystem is taking lately. <a href="https://youtu.be/gsffg5xxFQI">This talk</a> totally sold it to me.</li>
  549. <li>Said it before and say it again: forget about parenthesis. People seem to worry a lot about them beforehand, but as with Python whitespace indentation, once you’ve used it for five minutes it just goes away. Specially if you use the darn awesome <a href="https://shaunlebron.github.io/parinfer/">Parinfer</a>.</li>
  550. <li style="font-weight:400;"><span style="font-weight:400;">Which brings me to: you don’t need Emacs for Lisp programming. Yes, I hear you, once I master Emacs I’ll be a more powerful programmer. But I’m trying to learn a weird language here, don’t make me also learn a weird, counter-intuitive editor at the same time. That would just increase the chances of me dropping the effort altogether. </span>There are decent ports of Paredit for Sublime and Atom, which is good enough. But with Parinfer you just learn one command and forget about it, it just works.</li>
  551. <li style="font-weight:400;">REPL driven development. Because of pure functions it’s easy to write a piece of code and test it right away in the REPL. Together with unit tests it pretty much removes the need for debugging.</li>
  552. <li style="font-weight:400;"><a href="http://leiningen.org/">Leiningen</a> looks good, it covers the small needs I had starting out and didn’t get in the way. Clojurians say it does a lot more than that, so great. Much better than the 17 tools you need to set up to have a Node.js project running these days.</li>
  553. </ul>
  554. <h2 style="text-align:justify;">The bad</h2>
  555. <ul style="text-align:justify;">
  556. <li style="font-weight:400;"><span style="font-weight:400;">Namespace syntax is complicated, there are too many operations and keywords to do it (require, refer, use, alias, import and ns —which can do all of the others with a slightly different notation). It’s flexible but boilerplatish, even when sticking to ns:</span></li>
  557. </ul>
  558. <pre class="brush: clojure; title: ; notranslate">
  559. (ns advenjure.game
  560.  (:require [advenjure.rooms :as rooms]
  561.            [advenjure.utils :as utils]
  562.            [advenjure.verb-map :refer [find-verb verb-map]]))
  563. </pre>
  564. <ul style="text-align:justify;">
  565. <li style="font-weight:400;"><span style="font-weight:400;">And while there’s no hard rule to keep a one to one relation between files and namespaces, there’s a strong convention to do it, so having to declare the package name in every file seems totally redundant (and Java-ish, let&#8217;s be honest).</span></li>
  566. <li style="font-weight:400;"><span style="font-weight:400;"><a href="https://clojuredocs.org/clojure.core/contains_q">contains?</a> Works in a <a href="http://stackoverflow.com/questions/3249334/test-whether-a-list-contains-a-specific-value-in-clojure">counter-intuitive way</a> for vectors.</span></li>
  567. </ul>
  568. <p style="text-align:justify;"><span style="font-weight:400;">That’s all I got.</span></p>
  569. <h2 style="text-align:justify;">And the ugly</h2>
  570. <p style="text-align:justify;"><span style="font-weight:400;">Ok, there wasn’t much bad stuff, but there is some </span><i><span style="font-weight:400;">maybe not so good</span></i><span style="font-weight:400;"> or </span><i><span style="font-weight:400;">arguably not good</span></i><span style="font-weight:400;"> things I can think of.</span></p>
  571. <ul style="text-align:justify;">
  572. <li style="font-weight:400;"><span style="font-weight:400;">The built in operator set doesn’t follow the Unix and Python philosophy of small core and a lot of libraries that I like so much: the functions are way too many to easily remember, and they aren’t entirely orthogonal (some of them do the same thing in slightly different ways). Then again, the <a href="http://clojure.org/api/cheatsheet">Clojure Cheatsheet</a>, the REPL and <a href="http://clojuredocs.org/clojure.repl/doc">doc</a> are more than enough to cope with that.</span></li>
  573. <li style="font-weight:400;"><span style="font-weight:400;">Polymorphism is great: sequence and collection functions work as expected in all data structures. The downside is that to do so the results are always coerced to seqs, which may be unexpected, specially for hash maps. In practice, though, I found myself just chaining those functions and rarely caring about the resulting type.</span></li>
  574. <li style="font-weight:400;"><span style="font-weight:400;">Macros are powerful and awesome but the quoting syntax can get very tricky. I definitely need more experience to learn to reason about macro code, but the syntax will remain ugly. I guess that’s the cost you pay for being able to fiddle with how the language processes the code. In the end (much like Python metaclasses), macros are a great tool to keep in the box, but to use sparingly. So far every time I thought about implementing one I got away fine by using closures instead.</span></li>
  575. <li style="font-weight:400;"><span style="font-weight:400;">Java does sneak in quite a bit and that’s a turn off. (spoiler alert: I don’t like Java). </span><span style="font-weight:400;">OK, Java interop is simple and powerful, probably the most straightforward language interfacing I’ve seen (boy was SWIG a nightmare). That being said, Java code inside Clojure looks like, well, Java code inside Clojure: it reeks. </span><span style="font-weight:400;">This wouldn’t be so much of a problem if needed only to interact with some third party Java libraries, but in practice I’ve found that there’s basic stuff lacking in the Clojure standard library and it’s either add a dependency or use Java interop. I saw this while solving an exercise from the Brave Clojure book: it asked to list the first results of a google search. The request should be a one liner using the built in <a href="https://clojuredocs.org/clojure.core/slurp">slurp</a> function but, wait, you need to set the User-Agent header to request google, so you end up with:</span></li>
  576. </ul>
  577. <pre class="brush: clojure; title: ; notranslate">
  578. (with-open [inputstream (-&gt; (java.net.URL. url)
  579.                            .openConnection
  580.                            (doto (.setRequestProperty &quot;User-Agent&quot;
  581.                                                       &quot;Mozilla/5.0 ...&quot;))
  582.                            .getContent)]
  583. </pre>
  584. <h2 style="text-align:justify;">The end</h2>
  585. <p style="text-align:justify;"><span style="font-weight:400;">Even though it’s not my ideal language and it may be less ideal to me than Python was, it looks like I’ll start to look for excuses to use Clojure as much as possible and it’ll be a while before I jump to study another new language.</span></p>
  586. ]]></content:encoded>
  587. <wfw:commentRss>https://facundoolano.wordpress.com/2016/03/20/first-impressions-on-clojure/feed/</wfw:commentRss>
  588. <slash:comments>3</slash:comments>
  589. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  590. <media:title type="html">facundoolano</media:title>
  591. </media:content>
  592. </item>
  593. <item>
  594. <title>Panda vs Zombies: my new Android video game</title>
  595. <link>https://facundoolano.wordpress.com/2015/02/27/panda-vs-zombies-my-new-android-video-game/</link>
  596. <comments>https://facundoolano.wordpress.com/2015/02/27/panda-vs-zombies-my-new-android-video-game/#respond</comments>
  597. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  598. <pubDate>Sat, 28 Feb 2015 00:59:37 +0000</pubDate>
  599. <category><![CDATA[Uncategorized]]></category>
  600. <category><![CDATA[action]]></category>
  601. <category><![CDATA[android]]></category>
  602. <category><![CDATA[C++]]></category>
  603. <category><![CDATA[shooter]]></category>
  604. <category><![CDATA[videogames]]></category>
  605. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=659</guid>
  606.  
  607. <description><![CDATA[Over most of last year I&#8217;ve been working along a couple of college friends on an action game for Android and it&#8217;s finally out. It&#8217;s done using cocos2d-x in C++, which is by no means a language I like, so hopefully I&#8217;ll get to write here about the experience I had building it. In the meantime, [&#8230;]]]></description>
  608. <content:encoded><![CDATA[<p><a href="https://facundoolano.files.wordpress.com/2015/02/front.png"><img data-attachment-id="661" data-permalink="https://facundoolano.wordpress.com/2015/02/27/panda-vs-zombies-my-new-android-video-game/front/#main" data-orig-file="https://facundoolano.files.wordpress.com/2015/02/front.png" data-orig-size="1280,720" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="front" data-image-description="" data-image-caption="" data-medium-file="https://facundoolano.files.wordpress.com/2015/02/front.png?w=300" data-large-file="https://facundoolano.files.wordpress.com/2015/02/front.png?w=594" class="  wp-image-661 aligncenter" src="https://facundoolano.files.wordpress.com/2015/02/front.png?w=481&#038;h=276" alt="front" width="481" height="276" /></a></p>
  609. <p>Over most of last year I&#8217;ve been working along a couple of college friends on an action game for Android and it&#8217;s finally out. It&#8217;s done using cocos2d-x in C++, which is by no means a language I like, so hopefully I&#8217;ll get to write here about the experience I had building it.</p>
  610. <p>In the meantime, here&#8217;s the link to <a title="Panda vs Zombies" href="https://play.google.com/store/apps/details?id=com.dxco.pandavszombies" target="_blank">install it from the google play store</a> and the trailer of the game, for those who are interested in checking it out.</p>
  611. <div class="jetpack-video-wrapper"><iframe class="youtube-player" width="594" height="335" src="https://www.youtube.com/embed/PFGj-W8Pe5s?version=3&#038;rel=1&#038;showsearch=0&#038;showinfo=1&#038;iv_load_policy=1&#038;fs=1&#038;hl=en&#038;autohide=2&#038;wmode=transparent" allowfullscreen="true" style="border:0;" sandbox="allow-scripts allow-same-origin allow-popups allow-presentation allow-popups-to-escape-sandbox"></iframe></div>
  612. ]]></content:encoded>
  613. <wfw:commentRss>https://facundoolano.wordpress.com/2015/02/27/panda-vs-zombies-my-new-android-video-game/feed/</wfw:commentRss>
  614. <slash:comments>0</slash:comments>
  615. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  616. <media:title type="html">facundoolano</media:title>
  617. </media:content>
  618.  
  619. <media:content url="https://facundoolano.files.wordpress.com/2015/02/front.png?w=300" medium="image">
  620. <media:title type="html">front</media:title>
  621. </media:content>
  622. </item>
  623. <item>
  624. <title>Better authentication for socket.io (no query strings!)</title>
  625. <link>https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/</link>
  626. <comments>https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/#comments</comments>
  627. <dc:creator><![CDATA[facundoolano]]></dc:creator>
  628. <pubDate>Sat, 11 Oct 2014 17:08:35 +0000</pubDate>
  629. <category><![CDATA[Uncategorized]]></category>
  630. <category><![CDATA[JavaScript]]></category>
  631. <category><![CDATA[Node.js]]></category>
  632. <category><![CDATA[OAuth]]></category>
  633. <category><![CDATA[socket.io]]></category>
  634. <category><![CDATA[WebSocket]]></category>
  635. <guid isPermaLink="false">http://facundoolano.wordpress.com/?p=636</guid>
  636.  
  637. <description><![CDATA[Introduction This post describes an authentication method for socket.io that sends the credentials in a message after connection, rather than including them in the query string as usually done. Note that the implementation is already packed in the socketio-auth module, so you should use that instead of the code below. The reason to use this [&#8230;]]]></description>
  638. <content:encoded><![CDATA[<h3 style="text-align:justify;">Introduction</h3>
  639. <p style="text-align:justify;">This post describes an authentication method for socket.io that sends the credentials in a message after connection, rather than including them in the query string as usually done. Note that the implementation is already packed in the <a href="https://www.npmjs.com/package/socketio-auth" target="_blank">socketio-auth</a> module, so you should use that instead of the code below.</p>
  640. <p style="text-align:justify;">The reason to use this approach is that putting credentials in a query string is generally a bad security practice (see <a href="http://stackoverflow.com/a/323286/993769" target="_blank">this</a>, <a href="http://stackoverflow.com/a/2629241/993769" target="_blank">this</a> and <a href="http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#query-param" target="_blank">this</a>), and though some of the frequent risks may not apply to the socket.io connection request, it should be avoided as there&#8217;s no general convention in treating urls as sensitive information. Ideally such data should travel on a header, but that <a href="https://github.com/Automattic/socket.io-client/issues/648#issuecomment-42154344">doesn&#8217;t seem to be an option</a> for socket.io, as not all of the transports it supports (WebSocket being one) allow sending headers.</p>
  641. <p style="text-align:justify;">Needless to say, all of this should be done over HTTPS, otherwise no security level is to be expected.</p>
  642. <h3 style="text-align:justify;">Implementation</h3>
  643. <p style="text-align:justify;">In order to authenticate socket.io connections, most tutorials suggest to do something like:</p>
  644. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  645. io.set('authorization', function (handshakeData, callback) {
  646.  var token = handshakeData.query.token;
  647.  //will call callback(null, true) if authorized
  648.  checkAuthToken(token, callback);
  649. });
  650. </pre>
  651. <p style="text-align:justify;">Or, with the middleware syntax introduced in socket.io 1.0:</p>
  652. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  653. io.use(function(socket, next) {
  654.  var token = socket.request.query.token;
  655.  checkAuthToken(token, function(err, authorized){
  656.    if (err || !authorized) {
  657.      next(new Error(&quot;not authorized&quot;));
  658.    }
  659.    next();
  660.  });
  661. });
  662. </pre>
  663. <p style="text-align:justify;">Then the client would connect to the server passing its credentials, which can be an authorization token, user and password or whatever value that can be used for authentication:</p>
  664. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  665. socket = io.connect('http://localhost', {
  666.  query: &quot;token=&quot; + myAuthToken
  667. });
  668. </pre>
  669. <p style="text-align:justify;">The problem with this approach is that it credentials information in a query string, that is as part of an url. As mentioned, this is not a good idea since urls can be logged and cached and are not generally treated as sensitive information.</p>
  670. <p style="text-align:justify;">My workaround for this was to allow the clients to establish a connection, but force them to send an authentication message before they can actually start emitting and receiving data. Upon connection, the server marks the socket as not authenticated and adds a listener to an &#8216;authenticate&#8217; event:</p>
  671. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  672. var io = require('socket.io').listen(app);
  673.  
  674. io.on('connection', function(socket){
  675.  socket.auth = false;
  676.  socket.on('authenticate', function(data){
  677.    //check the auth data sent by the client
  678.    checkAuthToken(data.token, function(err, success){
  679.      if (!err &amp;&amp; success){
  680.        console.log(&quot;Authenticated socket &quot;, socket.id);
  681.        socket.auth = true;
  682.      }
  683.    });
  684.  });
  685.  
  686.  setTimeout(function(){
  687.    //If the socket didn't authenticate, disconnect it
  688.    if (!socket.auth) {
  689.      console.log(&quot;Disconnecting socket &quot;, socket.id);
  690.      socket.disconnect('unauthorized');
  691.    }
  692.  }, 1000);
  693. }
  694. </pre>
  695. <p style="text-align:justify;">A timeout is added to disconnect the client if it didn&#8217;t authenticate after a second. The client will emit it&#8217;s auth data to the &#8216;authenticate&#8217; event right after connection:</p>
  696. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  697. var socket = io.connect('http://localhost');
  698. socket.on('connect', function(){
  699.  socket.emit('authenticate', {token: myAuthToken});
  700. });
  701. </pre>
  702. <p style="text-align:justify;">An extra step is required to prevent the client from receiving broadcast messages during that window where it&#8217;s connected but not authenticated. Doing that required fiddling a bit with the socket.io namespaces code; the socket is removed from the object that tracks the connections to the namespace:</p>
  703. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  704. var _ = require('underscore');
  705. var io = require('socket.io').listen(app);
  706.  
  707. _.each(io.nsps, function(nsp){
  708.  nsp.on('connect', function(socket){
  709.    if (!socket.auth) {
  710.      console.log(&quot;removing socket from&quot;, nsp.name)
  711.      delete nsp.connected[socket.id];
  712.    }
  713.  });
  714. });
  715. </pre>
  716. <p style="text-align:justify;">Then, when the client does authenticate, we set it back as connected to those namespaces where it was connected:</p>
  717. <pre class="brush: jscript; gutter: false; title: ; toolbar: false; notranslate">
  718. socket.on('authenticate', function(data){
  719.  //check the auth data sent by the client
  720.  checkAuthToken(data.token, function(err, success){
  721.    if (!err &amp;&amp; success){
  722.      console.log(&quot;Authenticated socket &quot;, socket.id);
  723.      socket.auth = true;
  724.  
  725.      _.each(io.nsps, function(nsp) {
  726.        if(_.findWhere(nsp.sockets, {id: socket.id})) {
  727.          console.log(&quot;restoring socket to&quot;, nsp.name);
  728.          nsp.connected[socket.id] = socket;
  729.        }
  730.      });
  731.  
  732.    }
  733.  });
  734. });
  735. </pre>
  736. ]]></content:encoded>
  737. <wfw:commentRss>https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/feed/</wfw:commentRss>
  738. <slash:comments>45</slash:comments>
  739. <media:content url="https://1.gravatar.com/avatar/142739d398b5a71da38f6c3a7bf4171df2b199eba71712c4d0c1554fe8cc04de?s=96&#38;d=identicon&#38;r=G" medium="image">
  740. <media:title type="html">facundoolano</media:title>
  741. </media:content>
  742. </item>
  743. </channel>
  744. </rss>
  745.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=https%3A//facundoolano.wordpress.com/feed/

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda