Use sockets to broadcast morse progress.
This commit is contained in:
parent
78af9da586
commit
5bb6584286
7 changed files with 54 additions and 62 deletions
|
@ -8,27 +8,41 @@ defmodule MorseServer do
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_link do
|
def start_link do
|
||||||
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
|
GenServer.start_link(__MODULE__, {nil, 0}, name: __MODULE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_morse do
|
def start_morse do
|
||||||
GenServer.call(__MODULE__, :start)
|
GenServer.call(__MODULE__, :start)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_progress(progress) do
|
||||||
|
GenServer.cast(__MODULE__, {:progress, progress})
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init(state) do
|
def init(state) do
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_call(:start, _from, pid) do
|
def handle_call(:start, _from, {pid, _progress} = state) do
|
||||||
cond do
|
cond do
|
||||||
pid == nil or not Process.alive?(pid) ->
|
pid == nil or not Process.alive?(pid) ->
|
||||||
pid = spawn(&MorseSignaler.signal/0)
|
pid = spawn(&MorseSignaler.signal/0)
|
||||||
{:reply, :ok, pid}
|
{:reply, :ok, {pid, 0}}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
{:reply, {:error, :already_started}, pid}
|
{:reply, {:error, :already_started}, state}
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -23,13 +23,23 @@ defmodule MorseSignaler do
|
||||||
{:ok, gpio} = GPIO.open(relay_pin(), :output)
|
{:ok, gpio} = GPIO.open(relay_pin(), :output)
|
||||||
GPIO.write(gpio, @off)
|
GPIO.write(gpio, @off)
|
||||||
Process.sleep(@sleep_start)
|
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
|
end
|
||||||
|
|
||||||
# Signal a whole sentence of symbols with GPIO.
|
# Signal a whole sentence of symbols with GPIO.
|
||||||
defp signal_sentence(gpio, []) do
|
defp signal_sentence(gpio, []) do
|
||||||
GPIO.write(gpio, @off)
|
GPIO.write(gpio, @off)
|
||||||
GPIO.close(gpio)
|
GPIO.close(gpio)
|
||||||
|
update_progress(gpio, [])
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -50,7 +60,7 @@ defmodule MorseSignaler do
|
||||||
defp signal_sentence(gpio, [" " | rest]) do
|
defp signal_sentence(gpio, [" " | rest]) do
|
||||||
Process.sleep(@sleep_pause)
|
Process.sleep(@sleep_pause)
|
||||||
|
|
||||||
signal_sentence(gpio, rest)
|
update_progress(gpio, rest)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp signal_sentence(_gpio, [symbol | _rest]) do
|
defp signal_sentence(_gpio, [symbol | _rest]) do
|
||||||
|
|
|
@ -14,4 +14,4 @@ import "phoenix_html"
|
||||||
// Import local files
|
// Import local files
|
||||||
//
|
//
|
||||||
// Local files can be imported directly using relative paths, for example:
|
// Local files can be imported directly using relative paths, for example:
|
||||||
// import socket from "./socket"
|
import socket from "./socket"
|
||||||
|
|
|
@ -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"
|
import {Socket} from "phoenix"
|
||||||
|
|
||||||
let socket = new Socket("/socket", {params: {token: window.userToken}})
|
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":
|
|
||||||
//
|
|
||||||
// <script>window.userToken = "<%= assigns[:user_token] %>";</script>
|
|
||||||
//
|
|
||||||
// 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()
|
socket.connect()
|
||||||
|
|
||||||
// Now that you are connected, you can join channels with a topic:
|
let channel = socket.channel("morse:progress", {})
|
||||||
let channel = socket.channel("topic:subtopic", {})
|
|
||||||
channel.join()
|
channel.join()
|
||||||
.receive("ok", resp => { console.log("Joined successfully", resp) })
|
.receive("ok", resp => { console.log("Joined successfully", resp) })
|
||||||
.receive("error", resp => { console.log("Unable to join", 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
|
export default socket
|
||||||
|
|
7
ui/lib/ui_web/channels/morse_progress_channel.ex
Normal file
7
ui/lib/ui_web/channels/morse_progress_channel.ex
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
defmodule UiWeb.MorseProgressChannel do
|
||||||
|
use UiWeb, :channel
|
||||||
|
|
||||||
|
def join(channel_name, _params, socket) do
|
||||||
|
{:ok, %{hi: :there}, socket}
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,7 +2,7 @@ defmodule UiWeb.UserSocket do
|
||||||
use Phoenix.Socket
|
use Phoenix.Socket
|
||||||
|
|
||||||
## Channels
|
## Channels
|
||||||
# channel "room:*", UiWeb.RoomChannel
|
channel "morse:progress", UiWeb.MorseProgressChannel
|
||||||
|
|
||||||
# Socket params are passed from the client and can
|
# Socket params are passed from the client and can
|
||||||
# be used to verify and authenticate a user. After
|
# be used to verify and authenticate a user. After
|
||||||
|
|
|
@ -4,8 +4,12 @@
|
||||||
|
|
||||||
<div id="buttonwrap">
|
<div id="buttonwrap">
|
||||||
<input onclick="start()" value="Start" type="button" class="button">
|
<input onclick="start()" value="Start" type="button" class="button">
|
||||||
<p>Response status:</p>
|
<div id="response-block" style="visibility:hidden">
|
||||||
|
<h2>Response status:</h2>
|
||||||
<p id="response"></p>
|
<p id="response"></p>
|
||||||
|
<h2>Progress:</h2>
|
||||||
|
<progress id="morse-progress" max="100" value="0">0%</progress>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a href="http://www.geochecker.com/index.php?code=d9dbdc4542a4911a5f81a51bc9312a35&action=check&wp=47433743363432&name=4573726f6d">en: check your coordinate on GeoChecker.com nl: controleer je coördinaat op GeoChecker.</a>
|
<a href="http://www.geochecker.com/index.php?code=d9dbdc4542a4911a5f81a51bc9312a35&action=check&wp=47433743363432&name=4573726f6d">en: check your coordinate on GeoChecker.com nl: controleer je coördinaat op GeoChecker.</a>
|
||||||
|
@ -31,6 +35,7 @@
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
responseP.innerHTML = "Starting...";
|
responseP.innerHTML = "Starting...";
|
||||||
|
document.getElementById("response-block").style.visibility = "visible";
|
||||||
xhttp.open("GET", "/start", true);
|
xhttp.open("GET", "/start", true);
|
||||||
xhttp.send();
|
xhttp.send();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue