saschatimme / elm-phoenix Goto Github PK
View Code? Open in Web Editor NEWAn Elm client for Phoenix Channels
Home Page: https://saschatimme.github.io/elm-phoenix/
License: BSD 3-Clause "New" or "Revised" License
An Elm client for Phoenix Channels
Home Page: https://saschatimme.github.io/elm-phoenix/
License: BSD 3-Clause "New" or "Revised" License
We are developing Phoenix Channel application with elm-phoenix.
In advance, we thank you deeply for creating the great library with a connection recovery feature that is must for production use!
By the way, we met with a weird phenomenon while developing our app.
Our app uses two channels, so a user socket joins these two channels simultaneously by giving Phoenix.connect
with channel list. The channels returns initial data when joining.
UserSocket —- Channel A
\— Channel B
This works with no problem at normal period. But when reconnecting and rejoining after the socket is disconnected on SocketClosedAbnormally
and switching view to an error page, we cannot retrieve data from these two channels.
In detail, when I inspected inside the library with debug mode, I saw that it could receive data from both channels at Phoenix.open
function. Furthermore Receive endpoint message
worked with channel A correctly, but it didn't work with channel B.
Is this known issue, or we miss something?
Maybe it should be moved out to another repo?
Just a heads-up about installing this within an existing Phoenix app, for example inside of the web/elm directory...
After running elm-github-install
the "example" app ends up in web/elm/elm-stuff. Then if you run "mix compile" from the root directory of the Phoenix app you're embedding Elm within, the gettext compiler isn't happy with the "example" app that comes with "elm-phoenix". You get the following error:
== Compilation error on file web/elm/elm-stuff/packages/saschatimme/elm-phoenix/0.2.0/example/web/gettext.ex ==
** (ArgumentError) unknown application: :elm_phoenix
A work-around is simply to remove the web/elm/elm-stuff/packages/saschatimme/elm-phoenix/0.2.0/example directory. I wonder if perhaps there's a way to not include the "example" app in these situations. In the meantime, it may be worth mentioning this on the README.
Thanks you for this great library!
Mike
Pulled out from #27
@bigardone:
The issue I'm having is that once the connection is made and the channel is joined, if I turn off the wifi it is not receiving any error or anything (not even the onAbnormalClose), until it reaches the socket timeout (which is set to 45 seconds). What I have done is creating a new out port which it is called as the window.navigator.onLine event handlers (https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine), so it detects it immediately. Does it make sense?
This Issue is to keep track of the remaining work, to get full Presence support building on the PR #18
From the docs
Additionally, every metadata entry will contain a
:phx_ref
key which can be used to uniquely identify metadata for a given key. In the event that the metadata was previously updated,:phx_ref_prev
key will be present containing the previous:phx_ref
value.
Where is it necessary? (see API discussion below as well on this point)
From the docs
More detailed information, such as user details that need to be fetched from the database, can be achieved by overriding the
fetch/2
function. [...] The function must return a map of data matching the outlined Presence datastructure, including the:metas
key, but can extend the map of information to include any additional information.
The current implementation has only support for the :metas
key and would ignore any other keys.
The current API is (in the Channel
module)
onPresenceChange : (Dict String (List Value) -> msg) -> Channel msg -> Channel msg
onPresenceChange onPresenceChange_ chan =
{ chan | onPresenceChange = Just onPresenceChange_ }
Some of my questions
:phx_ref
or :phx_ref_prev
values? Currently there would be sometimes a phx_ref_prev
key in some Value
. But since the phx_ref
s are not exposed it would be useless.Values
i.e. that it would be more likeonPresenceChange : (Dict String (List MyVal) -> msg) -> Channel msg -> Channel msg
onPresenceChange onPresenceChange_ chan =
{ chan | onPresenceChange = Just myValDecoder onPresenceChange_ }
I'm probably missing some more things...
@dustinfarris reported that at the moment it can happen that a Msg
from Channel.onJoin
arrives after a Msg
from Channel.on
.
Currently there is a simple dispatch on each incoming message of the websocket (https://github.com/saschatimme/elm-phoenix/blob/master/src/Phoenix.elm#L537). So I think if one pushes a message to the client before the join reply (this should be possible since the socket connection is already established) they could be arrive out of order.
Is it possible to handle reply message after pushing a message? On the javascript client its done with the receive callback method.
channel.push("new_msg", {body: $chatInput.val()}).receive(
"ok", (reply) => console.log("got reply", reply)
)
First off, huge thanks for creating this great library, it has a very nice API and just works!
Now to my issue:
Is it possible to force trying to reconnect immediately once the connection to a websocket was lost, e.g. a function like:
tryReconnect : Socket -> List (Channel msg) -> Cmd msg
My use case is the following:
I have an application that uses chanels to exchange messages 'directly' between multiple devices of a user. (e.g. PC to phone)
For some of these messages, it is important that they are delivered as quickly as possible.
This is no problem when both devices have the website open.
However, if the phone is locked, it loses the connection. If I then want to send a message from my PC to the phone, I expect that the phone will receive the message as soon as I unlock it.
However, since there doesn't seem to be a way to immediately connect to the socket, a user now has to wait up to 30 seconds before the message is delivered.
With a function that would try to reconnect immediately, I could solve this easily by calling it every time the user unlocks the phone.
I hope that made sense.
As described by Evan post on elm-dev
list, native/kernel
code are not allowed to be on package.elm-lang.org except those on @elm-lang, but this library do not use any native/kernel
code. It is is pure Elm.
So, what is stopping this to be on package.elm-lang.org?
Thanks for this awesome library!
Can you please provide some direction on how to reconnect to the channel when the browser is refreshed?
For instance, in the elm-phoenix example, refreshing the browser after joining causes no channel exists
message, and the enterLeaveLobby
view indicates User name already taken
if I attempt to join again with the same user name.
First of all, thanks for this package its awesome and super intuitive to use.
I was wondering why there isn't a way in the library to leave a channel. I was wondering what the thought process behind not including it is. And maybe if you don't think it belongs in the library we could add some documentation to show how to leave a channel by pushing the "phx_leave"
message.
My particular use case involves where a user should only be in one channel at a time. If they join a new channel I would like them automatically leave the old channel. I'm doing this by saving the channelId in the model and using that in channel init. Channel.init ("room:" ++ model.roomId)
And in the update function any branch that changes the channel also sends a Push of "phx_leave"
.
Does that make sense?
It would be good to update the example app in this repo according to https://github.com/jur0/elm_phoenix_example. @jur0 is there any reason not to just replace the current example app with the version you put together? (I haven't had a chance to review the differences yet)
I have a scenario where I provide a payload when joining a channel, and the channel replies with a data structure formatted to my specification.
E.g.
Channel.init channelName
|> Channel.withPayload (object [ ( "scope", string "full" ) ])
So there are 3 situations to consider
1 and 2 work fine. 3 does not. Once the channel is added to elm-phoenix channels, changes to withPayload
do not have any effect.
I realize I could wire up a channel message to verify/adjust parameters on route change (or whatever other model changes) for an existing channel, but I really like the simplicity of just updating a single list of Channels in Phoenix.connect
—it's one of my favorite things about the elm-phoenix API.
tl;dr
I'd like changes to Channel.withPayload
to be treated as a new channel, dropping the old channel of the same topic (if it exists) and joining the new channel with the new payload.
So is this something the community would be open to?
Hi @saschatimme
When I use your module to deploy via edeliver and distillery I have problems while compiling because it also goes over the example project. I haven't found a way to omit/exclude the path from the compiler. If you have any suggestion how to avoid this problem let me know, otherwise would it be possible to move the phoenix example to another repo? Thanks
The repository does not have a .jl suffix.
cc: @saschatimme
due to phoenix version change from 1.2 to 1.3, links in example/README.md are outdated
The URL that my app uses to connect to a websocket includes a JWT as a query param. The JWT expires after 15 minutes so if the websocket needs to reconnect it's likely that the JWT will be stale and need replacing.
As far as I can tell there's no way to detect that reconnection is happening. One solution might be to allow subscription to something like Socket.reconnections
so that I could then fetch a new JWT and update the socket. The effect manager could detect that the socket has been replaced and reset the reconnectTimer.
What are your thoughts on this approach? Is there a simpler solution? I'm happy to put a PR together if we can agree an approach.
edit: I see the socket is replaced all the time in the effect manager so that's not much use a cue for resetting the reconnectTimer. Changes in the url or query params could perhaps be used for that purpose though.
First of all: elm-phoenix is awesome! It's so easy to work with and the API just makes send - so kudos on that!
It would be very neat if it would become possible to install elm-phoenix using the normal elm package
utility. This would mean that we did thinks without using an effects manager.
I have little knowledge of how this should be done, but a discussion on the elm-lang discourse it is said that it should require "minimal modifications": https://discourse.elm-lang.org/t/elm-0-19-from-a-production-perspective/815/7
I'm going to see if I can figure out how this should be done, but any help is highly appreciated
Hi, First of all, thanks for this great library.
My project is based on the Elm example here (https://github.com/saschatimme/elm-phoenix/blob/master/example/assets/elm/src/Chat.elm) and it's working well except the phoenix channel seems to be disconnected whenever the browser is refreshed, which then causes the connection to be removed from the Phoenix Presence list.
I understand elm-phoenix reconnects automatically as long as the channel to join is specified in the channel list as in connect socket [channel]
. But where in the example code, does it handle reconnecting the channel (e.g., by setting isActive to True such that the subscription puts lobby
back in the channel list), or is it something I should handle via localstorage, etc?
Thanks in advance.
Thanks a lot for this package!
I can't seem to find a way to check whether the initial connection to the server fails or not. I hooked up to all the listeners available, but no message is sent back to the application. For the sake of completeness, this is how I'm configuring the Socket
and Channel
:
socket = Phoenix.Socket.init "this is a wrong host on purpose"
|> Phoenix.Socket.onClose (always Error)
|> Phoenix.Socket.onNormalClose Error
|> Phoenix.Socket.onAbnormalClose Error
channel = Phoenix.Channel.init "whatever:msg"
|> Phoenix.Channel.onDisconnect Error
|> Phoenix.Channel.onError Error
|> Phoenix.Channel.onJoinError (always Error)
|> Phoenix.Channel.onLeave (always Error)
|> Phoenix.Channel.withDebug
The issue is that Error
is never dispatched, although withDebug
correctly shows Channel "whatever:msg": Disconnected
so the event seems to be there but it's never sent back to the main Router.
Any help appreciated, thanks! :)
Hi!
I've been using your package quite a lot, but today I'm having an issue I haven't had before. I'm trying to push a message through the socket, but it's actually not doing anything. By anything, I mean that no message by received in the channel and no error is returned.
Here's the line where I'm having the issue:
https://github.com/bigardone/phoenix-trello/blob/elm-version/web/elm/src/Boards/Update.elm#L87
And here is a screenshot of Chrome's developer tools:
So when submitting the form, it tries to send the message, but nothing happens. What might be going wrong? Thanks in advance!
Hi Sascha,
Do you plan to upgrade this package to Elm0.19? I am afraid it may not be the case due to the fact that Elm 0.19 doesn't allow 3rd party native packages, but hope I'm wrong. Thanks!
If I use Socket.withParams to send an authentication token, and the server 403s because the token is invalid, elm-phoenix does not have a way to send a Msg. Its current behavior is to keep retrying the connection.
Unfortunately Elm doesn't come with a generic map
function, and the lack of Channel.map doesn't allow to break code nicely into modules.
Hi, there!
Are you planning to add support for LongPoll, just like in https://github.com/phoenixframework/phoenix/blob/master/assets/js/phoenix.js#L730 ?
Cheers!
Hi!
First of all thanks for creating this package, it looks pretty awesome.
I want to refactor one of my projects so I can use it, but it seems the package is not available via the elm package install
command, and checking out your example app, it is importing it using a partial file path. How can I install it?
Cheers!
I would like to be able to, after establishing a connection, mutate my connection to include additional channels. Is this possible already and I just haven't figured it out? Otherwise, I suggest the addition of a new function in the Phoenix
module that allows for this behavior. Thoughts?
What would be a good way to use elm-phoenix in a non-SPA environment where multiple Elm programs are embedded onto the page? If multiple programs would want to use a channel or two is it possible for them to share the socket?
Refs are managed per socket but the self callbacks dictionary is keyed only be the ref. This means that if one opens multiple sockets, the self callbacks dictionary can overwrite the handler for one push or join message with the handler for a push or join message on another socket. Much ugliness follows.
The fix for this appears to be to key the self callbacks dictionary by (Ref, Endpoint)
instead of just Ref
. Pull request coming.
Hi! I am trying to use it with Absinthe Subscriptions. But there is a problem related to channels - I want an ability to retrieve message from different topic but not join such channel.
As you can see on screenshot we actually join only __absinthe__:control
channel, but got subscription incoming data at __absinthe__:doc:62645988
topic. And I can't join it (and shouldn't).
Do you think it's possible to get data from different topic but same channel?
Thanks!
Hi there! I'm writing a blog post about this library, and I've noticed that the link to the effects manager section of the Elm guide is broken.
Cheers!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.