Add JS client
This commit is contained in:
@@ -10,13 +10,21 @@ binDir = "bin"
|
|||||||
bin = @["randopix", "pixctrl"]
|
bin = @["randopix", "pixctrl"]
|
||||||
|
|
||||||
# Dependencies
|
# 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":
|
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":
|
task debug, "Compile debug version":
|
||||||
exec "nim c -d:debug --debugger:native -o:bin/randopix src/randopix.nim"
|
exec "nim c -d:debug --debugger:native -o:bin/randopix src/randopix.nim"
|
||||||
|
|
||||||
task release, "Compile release version":
|
before install:
|
||||||
exec fmt"nim c -d:release -o:bin/randopix-{version} src/randopix.nim"
|
genJS()
|
||||||
@@ -21,6 +21,9 @@ type
|
|||||||
command*: Command ## Command that the application should execute
|
command*: Command ## Command that the application should execute
|
||||||
parameter*: string ## Optional parameter for the command
|
parameter*: string ## Optional parameter for the command
|
||||||
|
|
||||||
|
proc `$`(cMsg: CommandMessage): string =
|
||||||
|
$(%cMsg)
|
||||||
|
|
||||||
proc newOpResult*(): OpResult =
|
proc newOpResult*(): OpResult =
|
||||||
OpResult(success: true)
|
OpResult(success: true)
|
||||||
|
|
||||||
@@ -30,9 +33,6 @@ proc newOpResult*(msg: string): OpResult =
|
|||||||
proc newCommandMessage*(c: Command, p: string = ""): CommandMessage =
|
proc newCommandMessage*(c: Command, p: string = ""): CommandMessage =
|
||||||
CommandMessage(command: c, parameter: p)
|
CommandMessage(command: c, parameter: p)
|
||||||
|
|
||||||
proc wrap*(msg: CommandMessage): string =
|
|
||||||
$(%msg) & "\r\L"
|
|
||||||
|
|
||||||
proc enumToStrings*(en: typedesc): seq[string] =
|
proc enumToStrings*(en: typedesc): seq[string] =
|
||||||
for x in en:
|
for x in en:
|
||||||
result.add $x
|
result.add $x
|
||||||
@@ -1,15 +1,30 @@
|
|||||||
import strutils, httpClient
|
import strutils
|
||||||
import argparse
|
|
||||||
import common
|
import common
|
||||||
|
|
||||||
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
when defined(js):
|
||||||
|
import ajax, jsconsole, dom, json
|
||||||
var
|
else:
|
||||||
randopixServer*: string ## URL for the randopix server
|
import httpClient
|
||||||
client = newHttpClient()
|
import argparse
|
||||||
|
var randopixServer* {.exportc.}: string ## URL for the randopix server
|
||||||
|
|
||||||
proc sendCommand(msg: CommandMessage) =
|
proc sendCommand(msg: CommandMessage) =
|
||||||
let resp = client.post(randopixServer, msg.wrap)
|
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"):
|
if not resp.status.contains("200"):
|
||||||
echo "Error while sending command: ", resp.status
|
echo "Error while sending command: ", resp.status
|
||||||
|
|
||||||
@@ -26,7 +41,7 @@ proc switchMode*(mode: string) =
|
|||||||
return
|
return
|
||||||
sendCommand(newCommandMessage(cMode, mode))
|
sendCommand(newCommandMessage(cMode, mode))
|
||||||
|
|
||||||
proc refresh*() =
|
proc refresh*() {.exportc.} =
|
||||||
## Force refresh of the current image
|
## Force refresh of the current image
|
||||||
sendCommand(cRefresh)
|
sendCommand(cRefresh)
|
||||||
|
|
||||||
@@ -34,7 +49,17 @@ proc setTimeout*(seconds: string) =
|
|||||||
## Set the image timeout to this value
|
## Set the image timeout to this value
|
||||||
sendCommand(newCommandMessage(cTimeout, seconds))
|
sendCommand(newCommandMessage(cTimeout, seconds))
|
||||||
|
|
||||||
|
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:
|
when isMainModule:
|
||||||
|
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
||||||
var p = newParser("pixctrl"):
|
var p = newParser("pixctrl"):
|
||||||
help("Control utilitiy for randopix")
|
help("Control utilitiy for randopix")
|
||||||
option("-s", "--server", help="Host running the randopix server", default="http://localhost:8080/")
|
option("-s", "--server", help="Host running the randopix server", default="http://localhost:8080/")
|
||||||
|
|||||||
@@ -9,10 +9,27 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="/style">
|
<link rel="stylesheet" type="text/css" href="/style">
|
||||||
|
|
||||||
|
<script src="/pixctrl" type="text/javascript"></script>
|
||||||
<script src="/script" type="text/javascript"></script>
|
<script src="/script" type="text/javascript"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h1>randopix web control</h1>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -1,3 +1,57 @@
|
|||||||
body {
|
body {
|
||||||
background-color: blue;
|
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;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import asyncdispatch, strutils, json
|
import asyncdispatch, strutils, json, logging
|
||||||
import jester
|
import jester
|
||||||
import common
|
import common
|
||||||
|
|
||||||
const
|
const
|
||||||
index = slurp("resources/index.html")
|
index = slurp("resources/index.html")
|
||||||
style = slurp("resources/site.css")
|
style = slurp("resources/site.css")
|
||||||
|
pixctrlJs = slurp("resources/pixctrl.js")
|
||||||
script = slurp("resources/script.js")
|
script = slurp("resources/script.js")
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -22,24 +23,35 @@ proc log(things: varargs[string, `$`]) =
|
|||||||
|
|
||||||
router randopixRouter:
|
router randopixRouter:
|
||||||
get "/":
|
get "/":
|
||||||
log "Access from ", request.ip
|
|
||||||
resp index
|
resp index
|
||||||
|
|
||||||
get "/style":
|
get "/style":
|
||||||
resp(style, contentType="text/css")
|
resp(style, contentType="text/css")
|
||||||
|
|
||||||
|
get "/pixctrl":
|
||||||
|
resp(pixctrlJs, contentType="text/javascript")
|
||||||
|
|
||||||
get "/script":
|
get "/script":
|
||||||
resp(script, contentType="text/javascript")
|
resp(script, contentType="text/javascript")
|
||||||
|
|
||||||
post "/":
|
post "/":
|
||||||
|
try:
|
||||||
|
log "Command from ", request.ip
|
||||||
let json = request.body.parseJson
|
let json = request.body.parseJson
|
||||||
let msg = json.to(CommandMessage)
|
let msg = json.to(CommandMessage)
|
||||||
|
log "Got message: ", $msg
|
||||||
# Pass command from client to main applicaiton
|
# Pass command from client to main applicaiton
|
||||||
chan.send(msg)
|
chan.send(msg)
|
||||||
resp Http200
|
resp Http200
|
||||||
|
except:
|
||||||
|
log "Error: ", getCurrentExceptionMsg()
|
||||||
|
|
||||||
proc runServer*[ServerArgs](arg: ServerArgs) {.thread, nimcall.} =
|
proc runServer*[ServerArgs](arg: ServerArgs) {.thread, nimcall.} =
|
||||||
verbose = arg.verbose
|
verbose = arg.verbose
|
||||||
|
if verbose:
|
||||||
|
logging.setLogFilter(lvlInfo)
|
||||||
|
else:
|
||||||
|
logging.setLogFilter(lvlNotice)
|
||||||
let port = Port(arg.port)
|
let port = Port(arg.port)
|
||||||
let settings = newSettings(port=port)
|
let settings = newSettings(port=port)
|
||||||
var server = initJester(randopixRouter, settings=settings)
|
var server = initJester(randopixRouter, settings=settings)
|
||||||
|
|||||||
Reference in New Issue
Block a user