<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="151849" data-post-id="151849">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Ok, I’ve been looking more deeply into Phoenix PubSub and it looks like I can decouple the use of Phoenix PubSub from the client-side channels. This means it’s possible to create a websocket-like channel on top of Phoenix channels. These channels could all connect to the same topic and I could separate them into PubSub topics on the server (at least I think I could do it). I would appreciate help in implementing this websocket-like object on top of Phoenix channels</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="151849" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-151849" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="151849"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #22"></div>
  </section>
</div>
    <div class="postbit" id="151958" data-post-id="151958">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’ve managed to come up with this: <a href="https://gist.github.com/tmbb/a723471ce7d1d666289edea058bfd652" class="inline-onebox" rel="noopener nofollow ugc">Websocket over phoenix channels · GitHub</a></p>
<p>It’s a Javascript class that behaves as a a websocket, but which sends and receives all messages over a Phoenix channel. I’ve plugged this Javascript class (<code>XareDBWebSocket</code>) into a websocket chat example I’ve found somewhere on the internet and made it work with a phoenix channel backend instead of raw websockets. This means that the client is basically handled.</p>
<p>Should I publish this “custom websocket” as a node package? I think it could be useful for other people which want to write Phoenix backends for Javascript tools which expect a websocket connection.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="151958" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-151958" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="151958"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #23"></div>
  </section>
</div>
    <div class="postbit" id="152220" data-post-id="152220">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="axelson" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/axelson/120/26351_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  axelson
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Scenic Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="tmbb" data-post="24" data-topic="9736">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>Should I publish this “custom websocket” as a node package? I think it could be useful for other people which want to write Phoenix backends for Javascript tools which expect a websocket connection.</p>
</blockquote>
</aside>
<p>I think so. I think I remember someone posting in the Elixir Slack about wanting to use raw websockets and they were pointed to Cowboy, which I think would be more difficult than using your package.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="152220" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-152220" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="152220"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #24"></div>
  </section>
</div>
    <div class="postbit" id="152226" data-post-id="152226">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="entone" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/entone/120/18061_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  entone
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The IETF has the Braid protocol <a href="https://datatracker.ietf.org/doc/html/draft-toomim-braid" class="inline-onebox" rel="noopener nofollow ugc">draft-toomim-braid-00</a>, which I believe is used by SharDB, or something similar, would be super interesting to see something like this integrated into Elixir/Cowboy/Phoenix</p>
<p>And here’s the website, <a href="https://braid.news/" rel="noopener nofollow ugc">https://braid.news/</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="152226" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-152226" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="152226"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #25"></div>
  </section>
</div>
    <div class="postbit" id="152227" data-post-id="152227">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="entone" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/entone/120/18061_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  entone
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It was specifically this that caught my attention</p>
<blockquote>
<p>Braid allows Synchronizers to Interoperate<br>
<a href="https://github.com/slickytail" rel="noopener nofollow ugc">Rafie Walker</a> has used the Braid protocol to synchronize an OT system with a CRDT. A <a href="https://en.wikipedia.org/wiki/List_of_races_and_species_in_The_Hitchhiker%27s_Guide_to_the_Galaxy#Babel_fish" rel="noopener nofollow ugc">babelfish</a> sits in the websocket, and converts ShareDB’s network messages into Braid messages, and vice versa.</p>
</blockquote> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="152227" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-152227" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="152227"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #26"></div>
  </section>
</div>
    <div class="postbit" id="179317" data-post-id="179317">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Back from the dead. As part of the plan of writing a ShareDB backend in Elixir (so that we get all the real-time collaboration features for free), I’ve had to solve the problem of protocol mismatch between Phoenix and the ShareDB client. The ShareDB client is supposed to work with raw websockets, while Phoenix can only work in Channels. You <strong>can’t</strong> use raw websockets with Phoenix without getting yourself in a world of pain.</p>
<p>The <em>obvious</em> solution is to implement a websocket on top of Phoenix channels. If this makes as little sense as it made to me at the time, read on. The trick is to write a Javascript object that implements the websocket API but sends and receives messages over a Phoenix Channel.</p>
<p>I’ve ended up with something like this: <a href="https://gist.github.com/tmbb/d0a4930cef8dc41a0125736fb6e0fb6e" class="inline-onebox" rel="noopener nofollow ugc">main.js · GitHub</a></p>
<p>As you can see there, I build a <code>PhoenixWS</code>, which is an object that talks like a websocket but sends and receives messages over a Phoenix channel:</p>
<pre data-code-wrap="javascript"><code class="lang-javascript">const connection = new PhoenixWS(socket, "room:lobby", {});
</code></pre>
<p>It takes as arguments a phoenix <code>socket</code>, a channel topic and an initial payload (which is useful for authentication, for example). This is the only phoenix-specific part of that file. From that point on, the javascript code is written as if it were a normal websocket. The rest of the code in that file was actually copied <em>with no changes</em> from a random Javascript “chat server” implementation, meant to work with a websocket on top of NodeJS. This chat server now works with a Phoenix backend (see here: <a href="https://github.com/tmbb/phwocket_example" class="inline-onebox" rel="noopener nofollow ugc">GitHub - tmbb/phwocket_example: An example using PhoenixWS · GitHub</a>)</p>
<p>The implementation is not complete and this is not production-ready yet, but it shows how easy it is to achieve some basic compatibility with raw websockets while being able to use Phoenix channels underneath.</p>
<p>The Elixir side is actually quite easy too. You add your <code>PhoenixWS.Channel</code> to your socket:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule PhwocketExampleWeb.UserSocket do
  use Phoenix.Socket
  require PhoenixWS.Socket

  ## Channels (actually a very weird channel that talks like a websocket)
  PhoenixWS.Socket.channel("room:*", PhwocketExampleWeb.RoomWSChannel)
  # ...
end
</code></pre>
<p>The code that implements the websocket channel is actually pretty easy to write:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule PhwocketExampleWeb.RoomWSChannel do
  # Import some convenience macros to abstract away the implementation details
  use PhoenixWS.Channel, web: PhwocketExampleWeb

  def join("room:" &lt;&gt; _, _payload, socket) do
    {:ok, socket}
  end

  # Handle messages from the Client
  def phoenix_ws_in(data, socket) do
    # This is just an echo server, so we just broadcast the same message back into the client
    broadcast!(socket, data)
    {:noreply, socket}
  end
end
</code></pre>
<p>Although there are still some holes in the websocket implementation (it doesn’t close properly, for instance), this can serve as a bridge between the ShareDB client and a backend that runs behind Phoenix. I imagine that the <code>PhoenixWS</code> package might be useful by itself in projects where you want to interface directly with a Javascript library that uses websockets.</p>
<p>Expect more developments soon, but not thaaat soon.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179317" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-179317" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179317"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #27"></div>
  </section>
</div>
    <div class="postbit" id="179334" data-post-id="179334">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Exadra37" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Exadra37/120/9183_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Exadra37
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sorry about my ignorance but looking to the ShareDB at a glance in Github it looks likish Phoenuix Live View, but I may be wrong, and probably I am.</p>
<p>So what you are trying to achieve it’s not possible through leveraging Live View?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179334" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-179334" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179334"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #28"></div>
  </section>
</div>
    <div class="postbit" id="179529" data-post-id="179529">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="axelson" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/axelson/120/26351_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  axelson
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Scenic Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="tmbb" data-post="28" data-topic="9736">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>Back from the dead.</p>
</blockquote>
</aside>
<p>Welcome back! <img src="https://forum.elixirforum.com/images/emoji/apple/confetti_ball.png?v=15" title=":confetti_ball:" class="emoji" alt=":confetti_ball:" loading="lazy" width="20" height="20"></p>
<p>ShareDB backend support in Elixir would be quite neat, and since it uses Operational Transforms it should allow some support for offline use-cases (<a class="mention" href="/u/exadra37" rel="nofollow">@Exadra37</a> which LiveView definitely doesn’t support).</p>
<p>Also I wanted to say that the proxying approach  to support raw websockets over Phoenix Channels is very clever. It would be nice to extract that to it’s own URL in some fashion (whether it is a blog post, separate forum post, or github repo, etc). I’m pretty sure that other people have asked about it and usually they’ve been told to drop down to cowboy which is not that ergonomic.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="179529" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-179529" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="179529"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #29"></div>
  </section>
</div>
    <div class="postbit" id="218525" data-post-id="218525">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="TardisBlue" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/TardisBlue/120/23365_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  TardisBlue
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/tmbb" rel="nofollow">@tmbb</a> any updates on this? I am working on a project that uses ShareDB (along with a custom OTType) and it would be great to try and use it while leveraging Pheonix Channels in the backend with 1 channel per document room. If something like this is in the works I would be willing to help out, although I am not too well versed in Elixir/ShareDB.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218525" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/32">Post #31</a>
	                </div>
	            </div>
              <div id="likers-container-218525" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218525"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #31"></div>
  </section>
</div>
    <div class="postbit" id="218538" data-post-id="218538">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>No, I haven’t had the time to work on this.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="218538" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/realtime-collaboration/9736/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-218538" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="218538"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #32"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/9736/load_more?page=4">Load more posts (1 remaining)</a>
</div></template></turbo-stream>