From d504f8cd5d22fc9bd696000a948daec120993914 Mon Sep 17 00:00:00 2001 From: luxick Date: Tue, 2 Jun 2020 00:23:07 +0200 Subject: [PATCH] WIP new http server --- randopix.nimble | 5 +++- src/common.nim | 5 +--- src/pixctrl.nim | 50 ++++++++++++++++++++++++------------- src/pixscript.nim | 4 +++ src/randopix.nim | 22 ++++++++-------- src/{ => resources}/app.css | 0 src/resources/index.html | 18 +++++++++++++ src/resources/site.css | 3 +++ src/serverNew.nim | 46 ++++++++++++++++++++++++++++++++++ src/serverNew.nim.cfg | 1 + 10 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 src/pixscript.nim rename src/{ => resources}/app.css (100%) create mode 100644 src/resources/index.html create mode 100644 src/resources/site.css create mode 100644 src/serverNew.nim create mode 100644 src/serverNew.nim.cfg diff --git a/randopix.nimble b/randopix.nimble index d6844c8..78eeb7d 100644 --- a/randopix.nimble +++ b/randopix.nimble @@ -9,7 +9,10 @@ srcDir = "src" bin = @["randopix", "pixctrl"] # 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": exec "nim c -d:debug --debugger:native --out:randopix src/randopix.nim" diff --git a/src/common.nim b/src/common.nim index 478700d..93f1c52 100644 --- a/src/common.nim +++ b/src/common.nim @@ -1,8 +1,5 @@ import json -const - defaultPort* = 5555 ## Default port at which the control server will run - type OpResult* = object of RootObj ## Result object for signalling failure state across proc calls success*: bool ## Indicating if the opration was successfull @@ -30,7 +27,7 @@ proc newOpResult*(): OpResult = proc newOpResult*(msg: string): OpResult = OpResult(success: false, errorMsg: msg) -proc newCommand*(c: Command, p: string = ""): CommandMessage = +proc newCommandMessage*(c: Command, p: string = ""): CommandMessage = CommandMessage(command: c, parameter: p) proc wrap*(msg: CommandMessage): string = diff --git a/src/pixctrl.nim b/src/pixctrl.nim index 2f2b2d3..2f88d13 100644 --- a/src/pixctrl.nim +++ b/src/pixctrl.nim @@ -1,52 +1,66 @@ -import strutils, net +import strutils, httpClient import argparse import common 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) = - socket.connect(server, Port(port.parseInt)) - if not socket.trySend(msg.wrap): - echo "Cannot send command: ", msg - socket.close() +proc sendCommand(msg: CommandMessage) = + let resp = client.post(randopixServer, msg.wrap) + if not resp.status.contains("200"): + echo "Error while sending command: ", resp.status -proc switchMode*(server, port: string, mode: string) = +proc sendCommand(cmd: Command) = + sendCommand(newCommandMessage(cmd)) + +proc switchMode*(mode: string) = + ## Update the display mode try: discard parseEnum[Mode](mode) except ValueError: echo "Invalid mode: ", mode echo "Possible values: [$1]" % Mode.enumToStrings().join(", ") return - let c = newCommand(cMode, mode) - sendCommand(server, port, c) + sendCommand(newCommandMessage(cMode, mode)) + +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: var p = newParser("pixctrl"): help("Control utilitiy for randopix") - option("-s", "--server", help="Host running the randopix server", default="127.0.0.1") - option("-p", "--port", help="Port to connect to the randopix server", default = $defaultPort) + option("-s", "--server", help="Host running the randopix server", default="http://localhost/") + run: + randopixServer = opts.server command($cRefresh): + ## Force refresh command help("Force image refresh now") run: - let c = newCommand(cRefresh) - sendCommand(opts.parentOpts.server, opts.parentOpts.port, c) + refresh() command($cTimeout): + ## Timeout Command help("Set timeout in seconds before a new image is displayed") arg("seconds", default = "300") run: - let c = newCommand(cTimeout, opts.seconds) - sendCommand(opts.parentOpts.server, opts.parentOpts.port, c) + setTimeout(opts.seconds) command($cMode): + ## Mode switch command help(modeHelp) arg("mode") run: - switchMode(opts.parentOpts.server, opts.parentOpts.port, opts.mode) + switchMode(opts.mode) try: p.run(commandLineParams()) except: - echo p.help \ No newline at end of file + echo getCurrentExceptionMsg() \ No newline at end of file diff --git a/src/pixscript.nim b/src/pixscript.nim new file mode 100644 index 0000000..4e4d31d --- /dev/null +++ b/src/pixscript.nim @@ -0,0 +1,4 @@ +import pixctrl + +proc doRefresh*() = + refresh() \ No newline at end of file diff --git a/src/randopix.nim b/src/randopix.nim index 060bb4a..e5aae7b 100644 --- a/src/randopix.nim +++ b/src/randopix.nim @@ -2,10 +2,10 @@ import os, options, strformat import gintro/[glib, gobject, gtk, gio] import gintro/gdk except Window import argparse except run -import providers, server, common +import providers, serverNew, common const - css = slurp("app.css") + css = slurp("resources/app.css") version = "0.1" type @@ -13,6 +13,7 @@ type fullscreen: bool ## Applicaion is show in fullscreen mode verbose: bool ## More debug information in notification label timeout: int ## Milliseconds between image refreshes + port: int ## Port to host the control server var imageProvider: ImageProvider ## Gets images from the chosen source @@ -41,8 +42,9 @@ proc newArgs(): Option[Args] = let p = newParser("randopix"): help(fmt"Version {version} - Display random images from different sources") 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("-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("-v", "--verbose", help="Show more information") @@ -61,8 +63,8 @@ proc newArgs(): Option[Args] = startMode = Mode.None # Create the image provider - if opts.path != "": - imageProvider = newImageProvider(opts.verbose, startMode, opts.path) + if opts.directoy != "": + imageProvider = newImageProvider(opts.verbose, startMode, opts.directoy) else: imageProvider = newImageProvider(opts.verbose, startMode) @@ -76,7 +78,8 @@ proc newArgs(): Option[Args] = return some(Args( fullscreen: not opts.windowed, verbose: opts.verbose, - timeout: timeout)) + timeout: timeout, + port: opts.port.parseInt)) except: echo p.help @@ -164,11 +167,8 @@ proc toggleFullscreen(action: SimpleAction; parameter: Variant; window: Applicat proc cleanUp(w: ApplicationWindow, app: Application) = ## Stop the control server and exit the GTK application - log "Stopping control server..." - closeServer() - serverWorker.joinThread() chan.close() - log "Server stopped." + log "Server channel closed." app.quit() proc quit(action: SimpleAction; parameter: Variant; app: Application) = @@ -236,7 +236,7 @@ proc appActivate(app: Application) = chan.open() ## 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) discard idleAdd(checkServerChannel, image) diff --git a/src/app.css b/src/resources/app.css similarity index 100% rename from src/app.css rename to src/resources/app.css diff --git a/src/resources/index.html b/src/resources/index.html new file mode 100644 index 0000000..6e70aff --- /dev/null +++ b/src/resources/index.html @@ -0,0 +1,18 @@ + + + + + + + + randopix + + + + + + + +

randopix web control

+ + \ No newline at end of file diff --git a/src/resources/site.css b/src/resources/site.css new file mode 100644 index 0000000..aabdee4 --- /dev/null +++ b/src/resources/site.css @@ -0,0 +1,3 @@ +body { + background-color: blue; +} \ No newline at end of file diff --git a/src/serverNew.nim b/src/serverNew.nim new file mode 100644 index 0000000..9dd97b2 --- /dev/null +++ b/src/serverNew.nim @@ -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() \ No newline at end of file diff --git a/src/serverNew.nim.cfg b/src/serverNew.nim.cfg new file mode 100644 index 0000000..6c1ded9 --- /dev/null +++ b/src/serverNew.nim.cfg @@ -0,0 +1 @@ +threads:on \ No newline at end of file