From 5bb6584286f715ed5cb200b33d32bef66d686dd6 Mon Sep 17 00:00:00 2001 From: Pim Kunis Date: Wed, 31 Jul 2019 00:20:09 +0200 Subject: [PATCH] Use sockets to broadcast morse progress. --- morse/lib/morse_server.ex | 22 +++++-- morse/lib/morse_signaler.ex | 14 ++++- ui/assets/js/app.js | 2 +- ui/assets/js/socket.js | 60 +++---------------- .../ui_web/channels/morse_progress_channel.ex | 7 +++ ui/lib/ui_web/channels/user_socket.ex | 2 +- ui/lib/ui_web/templates/page/morse.html.eex | 9 ++- 7 files changed, 54 insertions(+), 62 deletions(-) create mode 100644 ui/lib/ui_web/channels/morse_progress_channel.ex diff --git a/morse/lib/morse_server.ex b/morse/lib/morse_server.ex index ab17dfb..af38117 100644 --- a/morse/lib/morse_server.ex +++ b/morse/lib/morse_server.ex @@ -8,27 +8,41 @@ defmodule MorseServer do end def start_link do - GenServer.start_link(__MODULE__, nil, name: __MODULE__) + GenServer.start_link(__MODULE__, {nil, 0}, name: __MODULE__) end def start_morse do GenServer.call(__MODULE__, :start) end + def update_progress(progress) do + GenServer.cast(__MODULE__, {:progress, progress}) + end + @impl true def init(state) do {:ok, state} end @impl true - def handle_call(:start, _from, pid) do + def handle_call(:start, _from, {pid, _progress} = state) do cond do pid == nil or not Process.alive?(pid) -> pid = spawn(&MorseSignaler.signal/0) - {:reply, :ok, pid} + {:reply, :ok, {pid, 0}} true -> - {:reply, {:error, :already_started}, pid} + {:reply, {:error, :already_started}, state} end end + + @impl true + def handle_cast({:progress, new_progress}, {pid, progress}) do + broadcast_progress(new_progress) + {:noreply, {pid, new_progress}} + end + + defp broadcast_progress(progress) do + UiWeb.Endpoint.broadcast("morse:progress", "update", %{value: progress}) + end end diff --git a/morse/lib/morse_signaler.ex b/morse/lib/morse_signaler.ex index fda9260..cfaca4d 100644 --- a/morse/lib/morse_signaler.ex +++ b/morse/lib/morse_signaler.ex @@ -23,13 +23,23 @@ defmodule MorseSignaler do {:ok, gpio} = GPIO.open(relay_pin(), :output) GPIO.write(gpio, @off) Process.sleep(@sleep_start) - signal_sentence(gpio, String.graphemes(secret_code())) + update_progress(gpio, String.graphemes(secret_code())) + end + + # Update progress for clients, and signals the rest of the sentence. + defp update_progress(gpio, symbols) do + 100 - length(symbols) / String.length(secret_code()) * 100 + |> MorseServer.update_progress() + if symbols != [] do + signal_sentence(gpio, symbols) + end end # Signal a whole sentence of symbols with GPIO. defp signal_sentence(gpio, []) do GPIO.write(gpio, @off) GPIO.close(gpio) + update_progress(gpio, []) :ok end @@ -50,7 +60,7 @@ defmodule MorseSignaler do defp signal_sentence(gpio, [" " | rest]) do Process.sleep(@sleep_pause) - signal_sentence(gpio, rest) + update_progress(gpio, rest) end defp signal_sentence(_gpio, [symbol | _rest]) do diff --git a/ui/assets/js/app.js b/ui/assets/js/app.js index 8a5d386..3c21c71 100644 --- a/ui/assets/js/app.js +++ b/ui/assets/js/app.js @@ -14,4 +14,4 @@ import "phoenix_html" // Import local files // // Local files can be imported directly using relative paths, for example: -// import socket from "./socket" +import socket from "./socket" diff --git a/ui/assets/js/socket.js b/ui/assets/js/socket.js index 09929ab..be009a5 100644 --- a/ui/assets/js/socket.js +++ b/ui/assets/js/socket.js @@ -1,63 +1,19 @@ -// NOTE: The contents of this file will only be executed if -// you uncomment its entry in "assets/js/app.js". - -// To use Phoenix channels, the first step is to import Socket, -// and connect at the socket path in "lib/web/endpoint.ex". -// -// Pass the token on params as below. Or remove it -// from the params if you are not using authentication. import {Socket} from "phoenix" let socket = new Socket("/socket", {params: {token: window.userToken}}) -// When you connect, you'll often need to authenticate the client. -// For example, imagine you have an authentication plug, `MyAuth`, -// which authenticates the session and assigns a `:current_user`. -// If the current user exists you can assign the user's token in -// the connection for use in the layout. -// -// In your "lib/web/router.ex": -// -// pipeline :browser do -// ... -// plug MyAuth -// plug :put_user_token -// end -// -// defp put_user_token(conn, _) do -// if current_user = conn.assigns[:current_user] do -// token = Phoenix.Token.sign(conn, "user socket", current_user.id) -// assign(conn, :user_token, token) -// else -// conn -// end -// end -// -// Now you need to pass this token to JavaScript. You can do so -// inside a script tag in "lib/web/templates/layout/app.html.eex": -// -// -// -// You will need to verify the user token in the "connect/3" function -// in "lib/web/channels/user_socket.ex": -// -// def connect(%{"token" => token}, socket, _connect_info) do -// # max_age: 1209600 is equivalent to two weeks in seconds -// case Phoenix.Token.verify(socket, "user socket", token, max_age: 1209600) do -// {:ok, user_id} -> -// {:ok, assign(socket, :user, user_id)} -// {:error, reason} -> -// :error -// end -// end -// -// Finally, connect to the socket: socket.connect() -// Now that you are connected, you can join channels with a topic: -let channel = socket.channel("topic:subtopic", {}) +let channel = socket.channel("morse:progress", {}) channel.join() .receive("ok", resp => { console.log("Joined successfully", resp) }) .receive("error", resp => { console.log("Unable to join", resp) }) +let progressBar = document.getElementById("morse-progress") + +channel.on("update", (content) => { + console.log(content["value"]) + progressBar.value = content["value"] +}); + export default socket diff --git a/ui/lib/ui_web/channels/morse_progress_channel.ex b/ui/lib/ui_web/channels/morse_progress_channel.ex new file mode 100644 index 0000000..80a6dcb --- /dev/null +++ b/ui/lib/ui_web/channels/morse_progress_channel.ex @@ -0,0 +1,7 @@ +defmodule UiWeb.MorseProgressChannel do + use UiWeb, :channel + + def join(channel_name, _params, socket) do + {:ok, %{hi: :there}, socket} + end +end diff --git a/ui/lib/ui_web/channels/user_socket.ex b/ui/lib/ui_web/channels/user_socket.ex index 71eb341..4a588ea 100644 --- a/ui/lib/ui_web/channels/user_socket.ex +++ b/ui/lib/ui_web/channels/user_socket.ex @@ -2,7 +2,7 @@ defmodule UiWeb.UserSocket do use Phoenix.Socket ## Channels - # channel "room:*", UiWeb.RoomChannel + channel "morse:progress", UiWeb.MorseProgressChannel # Socket params are passed from the client and can # be used to verify and authenticate a user. After diff --git a/ui/lib/ui_web/templates/page/morse.html.eex b/ui/lib/ui_web/templates/page/morse.html.eex index 42c2d47..d6b5169 100644 --- a/ui/lib/ui_web/templates/page/morse.html.eex +++ b/ui/lib/ui_web/templates/page/morse.html.eex @@ -4,8 +4,12 @@
-

Response status:

-

+
en: check your coordinate on GeoChecker.com nl: controleer je coördinaat op GeoChecker. @@ -31,6 +35,7 @@ function start() { responseP.innerHTML = "Starting..."; + document.getElementById("response-block").style.visibility = "visible"; xhttp.open("GET", "/start", true); xhttp.send(); }