WIP new http server
This commit is contained in:
@@ -9,7 +9,10 @@ srcDir = "src"
|
|||||||
bin = @["randopix", "pixctrl"]
|
bin = @["randopix", "pixctrl"]
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
requires "nim >= 1.0.0", "gintro <= 0.5.5", "argparse >=0.10.1"
|
requires "nim >= 1.0.0", "gintro >= 0.5.5", "argparse >=0.10.1", "jester"
|
||||||
|
|
||||||
|
task genJS, "Generate the Javascript client":
|
||||||
|
exec "nim js --out:src/resources/script.js src/pixscript.nim"
|
||||||
|
|
||||||
task debug, "Compile debug version":
|
task debug, "Compile debug version":
|
||||||
exec "nim c -d:debug --debugger:native --out:randopix src/randopix.nim"
|
exec "nim c -d:debug --debugger:native --out:randopix src/randopix.nim"
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
const
|
|
||||||
defaultPort* = 5555 ## Default port at which the control server will run
|
|
||||||
|
|
||||||
type
|
type
|
||||||
OpResult* = object of RootObj ## Result object for signalling failure state across proc calls
|
OpResult* = object of RootObj ## Result object for signalling failure state across proc calls
|
||||||
success*: bool ## Indicating if the opration was successfull
|
success*: bool ## Indicating if the opration was successfull
|
||||||
@@ -30,7 +27,7 @@ proc newOpResult*(): OpResult =
|
|||||||
proc newOpResult*(msg: string): OpResult =
|
proc newOpResult*(msg: string): OpResult =
|
||||||
OpResult(success: false, errorMsg: msg)
|
OpResult(success: false, errorMsg: msg)
|
||||||
|
|
||||||
proc newCommand*(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 =
|
proc wrap*(msg: CommandMessage): string =
|
||||||
|
|||||||
@@ -1,52 +1,66 @@
|
|||||||
import strutils, net
|
import strutils, httpClient
|
||||||
import argparse
|
import argparse
|
||||||
import common
|
import common
|
||||||
|
|
||||||
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
const modeHelp = "Change the display mode. Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
||||||
|
|
||||||
var socket = newSocket()
|
var
|
||||||
|
randopixServer*: string ## URL for the randopix server
|
||||||
|
client = newHttpClient()
|
||||||
|
|
||||||
proc sendCommand*(server, port: string, msg: CommandMessage) =
|
proc sendCommand(msg: CommandMessage) =
|
||||||
socket.connect(server, Port(port.parseInt))
|
let resp = client.post(randopixServer, msg.wrap)
|
||||||
if not socket.trySend(msg.wrap):
|
if not resp.status.contains("200"):
|
||||||
echo "Cannot send command: ", msg
|
echo "Error while sending command: ", resp.status
|
||||||
socket.close()
|
|
||||||
|
|
||||||
proc switchMode*(server, port: string, mode: string) =
|
proc sendCommand(cmd: Command) =
|
||||||
|
sendCommand(newCommandMessage(cmd))
|
||||||
|
|
||||||
|
proc switchMode*(mode: string) =
|
||||||
|
## Update the display mode
|
||||||
try:
|
try:
|
||||||
discard parseEnum[Mode](mode)
|
discard parseEnum[Mode](mode)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
echo "Invalid mode: ", mode
|
echo "Invalid mode: ", mode
|
||||||
echo "Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
echo "Possible values: [$1]" % Mode.enumToStrings().join(", ")
|
||||||
return
|
return
|
||||||
let c = newCommand(cMode, mode)
|
sendCommand(newCommandMessage(cMode, mode))
|
||||||
sendCommand(server, port, c)
|
|
||||||
|
proc refresh*() =
|
||||||
|
## Force refresh of the current image
|
||||||
|
sendCommand(cRefresh)
|
||||||
|
|
||||||
|
proc setTimeout*(seconds: string) =
|
||||||
|
## Set the image timeout to this value
|
||||||
|
sendCommand(newCommandMessage(cTimeout, seconds))
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
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="127.0.0.1")
|
option("-s", "--server", help="Host running the randopix server", default="http://localhost/")
|
||||||
option("-p", "--port", help="Port to connect to the randopix server", default = $defaultPort)
|
run:
|
||||||
|
randopixServer = opts.server
|
||||||
|
|
||||||
command($cRefresh):
|
command($cRefresh):
|
||||||
|
## Force refresh command
|
||||||
help("Force image refresh now")
|
help("Force image refresh now")
|
||||||
run:
|
run:
|
||||||
let c = newCommand(cRefresh)
|
refresh()
|
||||||
sendCommand(opts.parentOpts.server, opts.parentOpts.port, c)
|
|
||||||
|
|
||||||
command($cTimeout):
|
command($cTimeout):
|
||||||
|
## Timeout Command
|
||||||
help("Set timeout in seconds before a new image is displayed")
|
help("Set timeout in seconds before a new image is displayed")
|
||||||
arg("seconds", default = "300")
|
arg("seconds", default = "300")
|
||||||
run:
|
run:
|
||||||
let c = newCommand(cTimeout, opts.seconds)
|
setTimeout(opts.seconds)
|
||||||
sendCommand(opts.parentOpts.server, opts.parentOpts.port, c)
|
|
||||||
|
|
||||||
command($cMode):
|
command($cMode):
|
||||||
|
## Mode switch command
|
||||||
help(modeHelp)
|
help(modeHelp)
|
||||||
arg("mode")
|
arg("mode")
|
||||||
run:
|
run:
|
||||||
switchMode(opts.parentOpts.server, opts.parentOpts.port, opts.mode)
|
switchMode(opts.mode)
|
||||||
try:
|
try:
|
||||||
p.run(commandLineParams())
|
p.run(commandLineParams())
|
||||||
except:
|
except:
|
||||||
echo p.help
|
echo getCurrentExceptionMsg()
|
||||||
4
src/pixscript.nim
Normal file
4
src/pixscript.nim
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import pixctrl
|
||||||
|
|
||||||
|
proc doRefresh*() =
|
||||||
|
refresh()
|
||||||
@@ -2,10 +2,10 @@ import os, options, strformat
|
|||||||
import gintro/[glib, gobject, gtk, gio]
|
import gintro/[glib, gobject, gtk, gio]
|
||||||
import gintro/gdk except Window
|
import gintro/gdk except Window
|
||||||
import argparse except run
|
import argparse except run
|
||||||
import providers, server, common
|
import providers, serverNew, common
|
||||||
|
|
||||||
const
|
const
|
||||||
css = slurp("app.css")
|
css = slurp("resources/app.css")
|
||||||
version = "0.1"
|
version = "0.1"
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -13,6 +13,7 @@ type
|
|||||||
fullscreen: bool ## Applicaion is show in fullscreen mode
|
fullscreen: bool ## Applicaion is show in fullscreen mode
|
||||||
verbose: bool ## More debug information in notification label
|
verbose: bool ## More debug information in notification label
|
||||||
timeout: int ## Milliseconds between image refreshes
|
timeout: int ## Milliseconds between image refreshes
|
||||||
|
port: int ## Port to host the control server
|
||||||
|
|
||||||
var
|
var
|
||||||
imageProvider: ImageProvider ## Gets images from the chosen source
|
imageProvider: ImageProvider ## Gets images from the chosen source
|
||||||
@@ -41,8 +42,9 @@ proc newArgs(): Option[Args] =
|
|||||||
let p = newParser("randopix"):
|
let p = newParser("randopix"):
|
||||||
help(fmt"Version {version} - Display random images from different sources")
|
help(fmt"Version {version} - Display random images from different sources")
|
||||||
option("-m", "--mode", help="The image source mode.", choices=enumToStrings(Mode))
|
option("-m", "--mode", help="The image source mode.", choices=enumToStrings(Mode))
|
||||||
option("-p", "--path", help="Path to a directory with images for the 'file' mode")
|
option("-d", "--directoy", help="Path to a directory with images for the 'file' mode")
|
||||||
option("-t", "--timeout", help="Seconds before the image is refreshed", default="300")
|
option("-t", "--timeout", help="Seconds before the image is refreshed", default="300")
|
||||||
|
option("-p", "--port", help="Port over which the control server should be accessible", default="80")
|
||||||
flag("-w", "--windowed", help="Do not start in fullscreen mode")
|
flag("-w", "--windowed", help="Do not start in fullscreen mode")
|
||||||
flag("-v", "--verbose", help="Show more information")
|
flag("-v", "--verbose", help="Show more information")
|
||||||
|
|
||||||
@@ -61,8 +63,8 @@ proc newArgs(): Option[Args] =
|
|||||||
startMode = Mode.None
|
startMode = Mode.None
|
||||||
|
|
||||||
# Create the image provider
|
# Create the image provider
|
||||||
if opts.path != "":
|
if opts.directoy != "":
|
||||||
imageProvider = newImageProvider(opts.verbose, startMode, opts.path)
|
imageProvider = newImageProvider(opts.verbose, startMode, opts.directoy)
|
||||||
else:
|
else:
|
||||||
imageProvider = newImageProvider(opts.verbose, startMode)
|
imageProvider = newImageProvider(opts.verbose, startMode)
|
||||||
|
|
||||||
@@ -76,7 +78,8 @@ proc newArgs(): Option[Args] =
|
|||||||
return some(Args(
|
return some(Args(
|
||||||
fullscreen: not opts.windowed,
|
fullscreen: not opts.windowed,
|
||||||
verbose: opts.verbose,
|
verbose: opts.verbose,
|
||||||
timeout: timeout))
|
timeout: timeout,
|
||||||
|
port: opts.port.parseInt))
|
||||||
except:
|
except:
|
||||||
echo p.help
|
echo p.help
|
||||||
|
|
||||||
@@ -164,11 +167,8 @@ proc toggleFullscreen(action: SimpleAction; parameter: Variant; window: Applicat
|
|||||||
|
|
||||||
proc cleanUp(w: ApplicationWindow, app: Application) =
|
proc cleanUp(w: ApplicationWindow, app: Application) =
|
||||||
## Stop the control server and exit the GTK application
|
## Stop the control server and exit the GTK application
|
||||||
log "Stopping control server..."
|
|
||||||
closeServer()
|
|
||||||
serverWorker.joinThread()
|
|
||||||
chan.close()
|
chan.close()
|
||||||
log "Server stopped."
|
log "Server channel closed."
|
||||||
app.quit()
|
app.quit()
|
||||||
|
|
||||||
proc quit(action: SimpleAction; parameter: Variant; app: Application) =
|
proc quit(action: SimpleAction; parameter: Variant; app: Application) =
|
||||||
@@ -236,7 +236,7 @@ proc appActivate(app: Application) =
|
|||||||
chan.open()
|
chan.open()
|
||||||
|
|
||||||
## Start the server for handling incoming commands
|
## Start the server for handling incoming commands
|
||||||
let serverArgs = newServerArgs(args.verbose)
|
let serverArgs = ServerArgs(verbose: args.verbose, port: args.port)
|
||||||
createThread(serverWorker, runServer, serverArgs)
|
createThread(serverWorker, runServer, serverArgs)
|
||||||
discard idleAdd(checkServerChannel, image)
|
discard idleAdd(checkServerChannel, image)
|
||||||
|
|
||||||
|
|||||||
18
src/resources/index.html
Normal file
18
src/resources/index.html
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
|
||||||
|
<title>randopix</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="/style">
|
||||||
|
|
||||||
|
<script src="/script" type="text/javascript"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>randopix web control</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3
src/resources/site.css
Normal file
3
src/resources/site.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
body {
|
||||||
|
background-color: blue;
|
||||||
|
}
|
||||||
46
src/serverNew.nim
Normal file
46
src/serverNew.nim
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import asyncdispatch, strutils, json
|
||||||
|
import jester
|
||||||
|
import common
|
||||||
|
|
||||||
|
const
|
||||||
|
index = slurp("resources/index.html")
|
||||||
|
style = slurp("resources/site.css")
|
||||||
|
script = ""
|
||||||
|
|
||||||
|
type
|
||||||
|
ServerArgs* = object of RootObj
|
||||||
|
verbose*: bool
|
||||||
|
port*: int
|
||||||
|
|
||||||
|
var
|
||||||
|
chan*: Channel[CommandMessage]
|
||||||
|
verbose: bool
|
||||||
|
|
||||||
|
proc log(things: varargs[string, `$`]) =
|
||||||
|
if verbose:
|
||||||
|
echo things.join()
|
||||||
|
|
||||||
|
router randopixRouter:
|
||||||
|
get "/":
|
||||||
|
log "Access from ", request.ip
|
||||||
|
resp index
|
||||||
|
|
||||||
|
get "/style":
|
||||||
|
resp(style, contentType="text/css")
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
proc runServer*[ServerArgs](arg: ServerArgs) {.thread, nimcall.} =
|
||||||
|
verbose = arg.verbose
|
||||||
|
let port = Port(arg.port)
|
||||||
|
let settings = newSettings(port=port)
|
||||||
|
var server = initJester(randopixRouter, settings=settings)
|
||||||
|
server.serve()
|
||||||
1
src/serverNew.nim.cfg
Normal file
1
src/serverNew.nim.cfg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
threads:on
|
||||||
Reference in New Issue
Block a user