Add JS client

This commit is contained in:
2020-06-04 21:13:21 +02:00
parent 13cf05bf99
commit 05c7bb3291
7 changed files with 198 additions and 53 deletions

View File

@@ -10,13 +10,21 @@ binDir = "bin"
bin = @["randopix", "pixctrl"]
# Dependencies
requires "nim >= 1.0.0", "gintro", "argparse", "jester"
requires "nim >= 1.0.0", "gintro", "argparse", "jester", "ajax"
proc genJS =
echo "Generating JS Client"
exec("nim js -o:src/resources/pixctrl.js src/pixctrl.nim")
task genJS, "Generate the Javascript client":
exec "nim js -o:src/resources/script.js src/pixscript.nim"
genJS()
task buildAll, "Generate JS and run build":
genJS()
exec "nimble build"
task debug, "Compile debug version":
exec "nim c -d:debug --debugger:native -o:bin/randopix src/randopix.nim"
task release, "Compile release version":
exec fmt"nim c -d:release -o:bin/randopix-{version} src/randopix.nim"
before install:
genJS()

View File

@@ -21,6 +21,9 @@ type
command*: Command ## Command that the application should execute
parameter*: string ## Optional parameter for the command
proc `$`(cMsg: CommandMessage): string =
$(%cMsg)
proc newOpResult*(): OpResult =
OpResult(success: true)
@@ -30,9 +33,6 @@ proc newOpResult*(msg: string): OpResult =
proc newCommandMessage*(c: Command, p: string = ""): CommandMessage =
CommandMessage(command: c, parameter: p)
proc wrap*(msg: CommandMessage): string =
$(%msg) & "\r\L"
proc enumToStrings*(en: typedesc): seq[string] =
for x in en:
result.add $x

View File

@@ -1,17 +1,32 @@
import strutils, httpClient
import argparse
import strutils
import common
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
var
randopixServer*: string ## URL for the randopix server
client = newHttpClient()
when defined(js):
import ajax, jsconsole, dom, json
else:
import httpClient
import argparse
var randopixServer* {.exportc.}: string ## URL for the randopix server
proc sendCommand(msg: CommandMessage) =
let resp = client.post(randopixServer, msg.wrap)
if not resp.status.contains("200"):
echo "Error while sending command: ", resp.status
when defined(js):
console.log("Sending:", $msg, "to URL:", document.URL)
var req = newXMLHttpRequest()
proc processSend(e:Event) =
if req.readyState == rsDONE:
if req.status != 200:
console.log("There was a problem with the request.")
console.log($req.status, req.statusText)
req.onreadystatechange = processSend
req.open("POST", document.URL)
req.send(cstring($(%*msg)))
else:
let client = newHttpClient()
let resp = client.post(randopixServer, $msg)
if not resp.status.contains("200"):
echo "Error while sending command: ", resp.status
proc sendCommand(cmd: Command) =
sendCommand(newCommandMessage(cmd))
@@ -26,7 +41,7 @@ proc switchMode*(mode: string) =
return
sendCommand(newCommandMessage(cMode, mode))
proc refresh*() =
proc refresh*() {.exportc.} =
## Force refresh of the current image
sendCommand(cRefresh)
@@ -34,33 +49,43 @@ proc setTimeout*(seconds: string) =
## Set the image timeout to this value
sendCommand(newCommandMessage(cTimeout, seconds))
when isMainModule:
var p = newParser("pixctrl"):
help("Control utilitiy for randopix")
option("-s", "--server", help="Host running the randopix server", default="http://localhost:8080/")
run:
randopixServer = opts.server
command($cRefresh):
## Force refresh command
help("Force image refresh now")
when defined(js):
proc getModes(): seq[cstring] {.exportc.} =
for mode in enumToStrings(Mode):
result.add cstring(mode)
proc switchMode*(mode: cstring) {.exportc.} =
switchMode($mode)
proc setTimeout*(seconds: cstring) {.exportc.} =
setTimeout($seconds)
else:
when isMainModule:
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
var p = newParser("pixctrl"):
help("Control utilitiy for randopix")
option("-s", "--server", help="Host running the randopix server", default="http://localhost:8080/")
run:
refresh()
randopixServer = opts.server
command($cTimeout):
## Timeout Command
help("Set timeout in seconds before a new image is displayed")
arg("seconds", default = "300")
run:
setTimeout(opts.seconds)
command($cRefresh):
## Force refresh command
help("Force image refresh now")
run:
refresh()
command($cMode):
## Mode switch command
help(modeHelp)
arg("mode")
run:
switchMode(opts.mode)
try:
p.run(commandLineParams())
except:
echo getCurrentExceptionMsg()
command($cTimeout):
## Timeout Command
help("Set timeout in seconds before a new image is displayed")
arg("seconds", default = "300")
run:
setTimeout(opts.seconds)
command($cMode):
## Mode switch command
help(modeHelp)
arg("mode")
run:
switchMode(opts.mode)
try:
p.run(commandLineParams())
except:
echo getCurrentExceptionMsg()

View File

@@ -9,10 +9,27 @@
<link rel="stylesheet" type="text/css" href="/style">
<script src="/pixctrl" type="text/javascript"></script>
<script src="/script" type="text/javascript"></script>
</head>
<body>
<h1>randopix web control</h1>
<p>
<button type="button" class="btn" onclick="refresh()">Refresh Image Now!</button>
</p>
<div>Switch the image mode</div>
<p>
<select id="modeselect"></select>
<button type="button" class="btn" onclick="js_setMode()">Set Mode</button>
</p>
<div>Adjust timespan between images</div>
<p>
<input id="timeout" type="number">
<button type="button" class="btn" onclick="js_setTimeout()">Set Timeout</button>
</p>
</body>
</html>

View File

@@ -0,0 +1,29 @@
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
window.onload = () => {
const modes = getModes();
const modeselect = document.getElementById("modeselect");
modes.forEach(mode => {
let opt = document.createElement('option');
opt.value = mode;
opt.innerHTML = capitalize(mode)
modeselect.appendChild(opt);
});
}
function js_setTimeout() {
const elem = document.getElementById("timeout");
const timeout = parseInt(elem.value);
if (timeout < 1) {
console.error("timeout must be positive");
return;
}
setTimeout(timeout.toString());
}
function js_setMode() {
const modeselect = document.getElementById("modeselect");
switchMode(modeselect.value)
}

View File

@@ -1,3 +1,57 @@
body {
background-color: blue;
}
color: yellow;
}
/* Chrome, Safari, Opera */
@-webkit-keyframes rainbow {
0%{color: orange;}
10%{color: purple;}
20%{color: red;}
30%{color: CadetBlue;}
40%{color: yellow;}
50%{color: coral;}
60%{color: green;}
70%{color: cyan;}
80%{color: DeepPink;}
90%{color: DodgerBlue;}
100%{color: orange;}
}
/* Internet Explorer */
@-ms-keyframes rainbow {
0%{color: orange;}
10%{color: purple;}
20%{color: red;}
30%{color: CadetBlue;}
40%{color: yellow;}
50%{color: coral;}
60%{color: green;}
70%{color: cyan;}
80%{color: DeepPink;}
90%{color: DodgerBlue;}
100%{color: orange;}
}
/* Standard Syntax */
@keyframes rainbow {
0%{color: orange;}
10%{color: purple;}
20%{color: red;}
30%{color: CadetBlue;}
40%{color: yellow;}
50%{color: coral;}
60%{color: green;}
70%{color: cyan;}
80%{color: DeepPink;}
90%{color: DodgerBlue;}
100%{color: orange;}
}
h1 {
/* Chrome, Safari, Opera */
-webkit-animation: rainbow 5s infinite;
/* Internet Explorer */
-ms-animation: rainbow 5s infinite;
/* Standar Syntax */
animation: rainbow 5s infinite;
}

View File

@@ -1,10 +1,11 @@
import asyncdispatch, strutils, json
import asyncdispatch, strutils, json, logging
import jester
import common
const
index = slurp("resources/index.html")
style = slurp("resources/site.css")
pixctrlJs = slurp("resources/pixctrl.js")
script = slurp("resources/script.js")
type
@@ -22,24 +23,35 @@ proc log(things: varargs[string, `$`]) =
router randopixRouter:
get "/":
log "Access from ", request.ip
resp index
get "/style":
resp(style, contentType="text/css")
get "/pixctrl":
resp(pixctrlJs, contentType="text/javascript")
get "/script":
resp(script, contentType="text/javascript")
post "/":
let json = request.body.parseJson
let msg = json.to(CommandMessage)
# Pass command from client to main applicaiton
chan.send(msg)
resp Http200
try:
log "Command from ", request.ip
let json = request.body.parseJson
let msg = json.to(CommandMessage)
log "Got message: ", $msg
# Pass command from client to main applicaiton
chan.send(msg)
resp Http200
except:
log "Error: ", getCurrentExceptionMsg()
proc runServer*[ServerArgs](arg: ServerArgs) {.thread, nimcall.} =
verbose = arg.verbose
if verbose:
logging.setLogFilter(lvlInfo)
else:
logging.setLogFilter(lvlNotice)
let port = Port(arg.port)
let settings = newSettings(port=port)
var server = initJester(randopixRouter, settings=settings)