There are new examples on the demo page:
Heh, the issue with unpoly is it does not only DOM-element swapping but also URL changing without reloading the DOM. ^.^;
It makes the concept of a per-page commander kind of breaking without some way to re-establish their connections, as it is if you want to mix unpoly and drab you need to use no per-page commanders and instead use purely only shared commanders, which is doable, just have to design with that in mind.
Whooo!
Iâm curious, does it load it up from DETS then persist it? Or does it access it from DETS on every request (much much slower)? And instead of DETS why not instead just bake it into a module?
Whooo! This will make compositing templates so much nicer!
Very useful! Can have far more shared code now without needing to make more round-trips to the client to get extra information!
Awesome!
I see. Anyway, I am not planning to make a module for any JS library in the nearest future, I will rather concentrate on the Drab core.
It is a genserver loading the cache on start.
I choose DETS on the early experimental stage it was easiest for me to build it and debug. And yes, I am planning to put it into module, like Phoenix.View does. But so far it works, so it can wait
Still, shared commanders have limitations comparing to the ordinary commanders. For example, callbacks and access to the session are not working there. And this is a question: shall shared commanders behave like full commanders, with callbacks, etc? There will be a performance overhead.
Honestly Iâd probably just remove the page-specific commanders and instead build the system around the âsharedâ commander model and optimize around that case.
It could be worse the original idea was to put event handlers into controllers.
Well, I like the idea of pairs controller/commander. It fits and extends Phoenix, it is secure (only page from the specific controller may run handler in the corresponding commander) and easy to understand. So I will keep it.
But⊠why not to do both? If the corresponding commander would not be a requirement, and shared commanders would have all the powers of ordinary commanders (callbacks etc), you could choose the way you want to use it.
You could, but think about it from a page decorated with unpoly, a couple of different phoenix-side pages/controllers could be being displayed all at the same time. Thus which page Commander do you use? If you use all then how do they know only to control the parts of the DOM that they know about and not mess up other parts? If you use only one then potentially large amounts of the page will be non-functional. Etc⊠etcâŠ
That is why I eschew page commanders and only use shared, because the second I add a single partial fragment decoration from unpoly then the page just out-right breaks⊠^.^;
Except what is to keep javascript from building that all up itself and pretending to be that page using information acquired earlier? That is why Phoenix websockets donât handle headers and other such things, because if you have a socket open with whatever access, then you absolutely can NOT know what is opening it or what information they have, thus the concept of page-only accesses makes no sense, only role/permission based accesses based on the arguments passed to the websocket itself, not the page.
Yes I think itâs a failing in the W3 websocket design, but it would have been hard to let it be as functional otherwise.
Does that mean there is currently a security breach as it works today ?
In that model, there will be no one main Page Commander. Only shared.
Interesting.
We may allow shared commander to modify only the parts under <tag drab-commander='...'>
This is what I meant by writing âwhy not do bothâ. You may use only shared commander, I can choose classic way.
Nothing - if you keep the websocket connection opened. PID of the Drab genserver is in the token (to route the request to the correct one), so you canât just reuse the old token.
But, I can imagine the situation, when you acquire enough tokens, and the beam was restarted for some reasons so it is start using small PIDs, for which you already have tokens. You may try, and with some luck find actually running one.
I am going to prevent reusing tokens by adding additional random key generated on application start and kept in memory only. (Prevent reusing Drab tokens · Issue #81 · grych/drab · GitHub)
Actually Drab keeps the controller information in the token, and check if you are running commander generated by the corresponding controller.
Obviously it does not work with shared commanders
Nothing what I am aware of.
That is what I would expect.
Except some malicious bot can just open a few pages, scrape the tokens, and connect with all it wants to do. ^.^
/me constantly tries to think of how to break sitesâŠ
/me still wishes that phoenix websockets passed the headers on, would love to filter connections based on IP for example, thatâs still a bit of a wtf in phoenix to themâŠ
Except of course they could just scrape a page every time they want to hit the websocket again.
Websocketâs security is far different from pages.
Itâs not really page based or even page-safe, itâs only permissions/token safe (assuming the permissions and tokens are safe to begin with, I.E. a page-specific token is not really).
Sure. But they need to keep the scraper connected, if they want to reuse the token. It is going to be invalid after disconnection. Not very handy method of attack
Itâs quite fine if they are probing all the things they can access. ^.^
Got your point. Yes, you may open the browser, keep it connected and just try to run random handler names, using the common name like âbutton_clickedâ or âOvermind.generate_formâ, etc, to find out the function which is a Drab Handler (it is in the connected commander, or it is public
in the shared one).
Now I am thinking about whitelisting handlers also in the âstandardâ commanders. Now you need to keep in mind that public functions there are actually handlers, all of them (with arity of 2 or 3). It is mentioned in the docs, but who reads the docs those days
Hi Grych
I had some trouble using Drab on a very simple case : I just need to toogle a button and change its format depending on Drapâs. Since I render this button n times on the page, I couldnât use Drap assign. My point is in the Drab.Element module functions answer tupples like {:ok, 3} which makes it hard to use in a pipe.
I ended up with this (which I am not very proud of).
Any suggestion on how better I could do ?
Is there a way to render a partial for this button from Drab ?
case Contents.toogle_pack_item(item_id, pack_id) do
{:created, pack_item} ->
socket
|> Drab.Browser.console("PackItem created for item #{item_id} and pack #{pack_id}")
|> set_attr("a.item[id='#{item_id}']", class: "item waves-effect waves-light btn validate")
socket
|> set_prop("a.item[id='#{item_id}']", innerHTML: "Remove")
socket
|> insert_html("a.item[id='#{item_id}']", :beforeend, "<i class='toogle_btn material-icons left'>remove_circle_outline</i>")
{:deleted, pack_item} ->
socket
|> Drab.Browser.console("PackItem removed for item #{item_id} and pack #{pack_id}")
|> set_attr("a.item[id='#{item_id}']", class: "item waves-effect waves-light btn light")
socket
|> set_prop("a.item[id='#{item_id}']", innerHTML: "Add")
socket
|> insert_html("a.item[id='#{item_id}']", :beforeend, "<i class='toogle_btn material-icons left'>add_circle_outline</i>")
{:error, _} ->
socket
|> Drab.Browser.console("Couldn't create PackItem between item #{item_id} and pack #{pack_id}")
end
Hi @thib,
it looks OK.
Drabs API is a little bit chaotic now, as some of bang functions returns sockets (so they could be stacked), and some not it must be changed before going stable. Also, there is a plan to group instructions like this (series of set_prop, set_attr, etc) into one, so behind the scenes it would not send this instructions one by one (and wait for the answer!), but in one bunch.
About the partials, you may use it with Drab! Take a look here. I need to add an example of this feature on the demo page.
Hi folks,
quick update about whatâs cooking in the Drab kettle.
The next big release will be about Commanders and there will be changes in the API. Sorry for this, but I believe it makes sense. Please comment.
-
use Drab.Controller
is going to be optional, if the corresponding commander exists -
all event handlers, even those in the ânormalâ commander, must be declared as handlers; and instead of using existing
public [:handler1, :handler2]
macro, I am thinking about something likedefhandler clicked(socket, payload)
. This is because I want to make sure when you are writing a public function in the commander, you are aware that it could be run from the client side! -
shared commanders must behave like the standard commanders, so all callbacks must work
-
for the above (for onload, onconnect and ondisconnect), Drab must somehow know which commanders are used on the page. I could read it on the client side, but I do not consider it safe. For now I think Iâm gonna force to declare shared commanders with
use Drab.Controller, commanders: [Shared1, Shared2]
in the controller, which generated the page. -
when using shared commander inside the
<tag drab-commander=MyCommander>
, all the reads and updates are going to be done only inside this tag.
Hello, I am using drab to update queues on server.
In my app, i call poke
frequently, and it worked perfectly :).
but i just wonder if there is any way to disable logs.
defp monitor_exq(socket) do
processes = Sally.Utils.Exq.current_processes()
jobs = Sally.Utils.Exq.current_jobs()
poke socket, processes: processes, jobs: jobs
:timer.sleep(3000)
monitor_exq(socket)
end
[debug] INCOMING "event" on "__drab:same_path:/admin" to Drab.Channel
Transport: Phoenix.Transports.WebSocket
Parameters: %{"event_handler_function" => "Drab.Live.Commander.save_assigns", "payload" => %{"__assigns" => %{"gi2tombvguydmnrs" => %{"jobs" => "QTEyOEdDTQ.8ZgkqtnP4eel91aB7QlQB_hDn4XxIgH0X_TeSclbEyFGcEfc4Vfs-UTJd3M.nVU40XJ4mpIPpb9d.Ct_sPkU-pVNrIUo6iB0TqbRul3IvtosrV1KIng.N6bBncQ-51JhWUlUtRe_Rg", "processes" => "QTEyOEdDTQ.8N6RjPO91gN4DcUg-6nDapu4vOoQAy6UXcQVuI0-Y151g9amiPMV_auNOOQ.kvtCWx8kwfyVEl4T.iehsOHUn.Gmvf8LpDDfpRyrfi-ZpZ3Q"}}, "__index" => "gi2tombvguydmnrs"}, "reply_to" => "e78b550d-bd72-465e-9df3-4a7d8579cad2"}
Not currently, but it is a way to pass the logging options to Phoenix.Channel
. Could you please create a github issue with this, so it wonât be forgotten?