Add control server.

This commit is contained in:
2020-05-19 10:44:18 +02:00
parent 54501c9390
commit 8db6b5afaa
6 changed files with 122 additions and 19 deletions

View File

@@ -6,16 +6,13 @@ author = "luxick"
description = "Play an image slide show from different sources"
license = "GPL-2.0"
srcDir = "src"
bin = @["randopix"]
bin = @["randopix", "pixctrl"]
# Dependencies
requires "nim >= 1.0.0", "gintro >= 0.5.5", "argparse >=0.10.1"
task debug, "Compile debug version":
exec "nim c -d:debug --debugger:native --out:bin/randopix src/randopix.nim"
task r, "Compile and run":
exec "nim c -r --out:bin/randopix src/randopix.nim"
exec "nim c -d:debug --debugger:native src/randopix.nim"
task release, "Compile release version":
exec fmt"nim c -d:release --out:bin/{version}/randopix src/randopix.nim"
exec fmt"nim c -d:release --out:randopix-{version} src/randopix.nim"

15
src/commands.nim Normal file
View File

@@ -0,0 +1,15 @@
const
defaultPort* = 5555 ## Default port at which the control server will run
type
Command* {.pure.} = enum
Close = "close" ## Closes the control server and exists the applicaiton
Refresh = "refresh" ## Force refresh of the image now
CommandMessage* = object
command*: Command ## Command that the application should execute
parameter*: string ## Optional parameter for the command
proc newCommand*(c: Command, p: string = ""): CommandMessage =
CommandMessage(command: c, parameter: p)

13
src/pixctrl.nim Normal file
View File

@@ -0,0 +1,13 @@
import net
import argparse
import commands
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)
var socket = newSocket()
socket.connect("127.0.0.1", Port(defaultPort))
socket.send("Hello, Sockets!\r\L")
socket.close()

View File

@@ -1,8 +1,10 @@
import os, options, strformat
import gintro/[gtk, glib, gobject, gio, gdkpixbuf]
import gintro/[glib, gobject, gdkpixbuf]
import gintro/gdk except Window
import gintro/gtk except newSocket, Socket
import gintro/gio except Socket
import argparse except run
import providers
import providers, server, commands
const
css = slurp("app.css")
@@ -21,6 +23,8 @@ var
window: ApplicationWindow
imageWidget: Image
label: Label
# Server vor recieving commands from external tools
serverWorker: system.Thread[void]
proc enumToStrings(en: typedesc): seq[string] =
for x in en:
@@ -59,7 +63,7 @@ proc newArgs(): Option[Args] =
fullscreen: not opts.windowed,
verbose: opts.verbose,
timeout: timeout))
except UsageError:
except:
echo getCurrentExceptionMsg()
echo p.help
@@ -106,12 +110,27 @@ proc forceUpdate(action: SimpleAction; parameter: Variant;) =
proc timedUpdate(image: Widget): bool =
let ok = updateImage();
if ok:
return true;
else:
if not ok:
label.notify "Error while refreshing image, retrying..."
discard timeoutAdd(uint32(args.timeout), timedUpdate, imageWidget)
return false
discard timeoutAdd(uint32(args.timeout), timedUpdate, imageWidget)
return false
proc checkServerChannel(parameter: string): bool =
## Check the channel from the control server for incomming commands
let tried = chan.tryRecv()
if tried.dataAvailable:
let msg: CommandMessage = tried.msg
echo "Main app got message: ", msg.command
case msg.command
of Command.Refresh:
discard updateImage()
else:
echo "Command ignored", msg.command
result = false
discard idleAdd(checkServerChannel, parameter)
proc toggleFullscreen(action: SimpleAction; parameter: Variant; window: ApplicationWindow) =
## Fullscreen toggle event
@@ -121,12 +140,21 @@ proc toggleFullscreen(action: SimpleAction; parameter: Variant; window: Applicat
window.fullscreen
args.fullscreen = not args.fullscreen
proc cleanUp(w: ApplicationWindow, app: Application) =
## Stop the control server and exit the GTK application
echo "Stopping control server..."
closeServer()
serverWorker.joinThread()
chan.close()
echo "Server stopped."
app.quit()
proc quit(action: SimpleAction; parameter: Variant; app: Application) =
## Application quit event
app.quit()
cleanUp(window, app)
proc connectSignals(app: Application) =
## Connect th GTK signals to the procs
## Connect the GTK signals to the procs
let fullscreenAction = newSimpleAction("fullscreen")
discard fullscreenAction.connect("activate", toggleFullscreen, window)
app.setAccelsForAction("win.fullscreen", "F")
@@ -142,6 +170,8 @@ proc connectSignals(app: Application) =
app.setAccelsForAction("win.update", "U")
window.actionMap.addAction(updateImageAction)
window.connect("destroy", cleanUp, app)
proc appActivate(app: Application) =
# Parse arguments from the command line
let parsed = newArgs()
@@ -152,7 +182,7 @@ proc appActivate(app: Application) =
window = newApplicationWindow(app)
window.title = "randopix"
window.setKeepAbove(true)
window.setKeepAbove(false)
window.setDefaultSize(800, 600)
# Custom styling for e.g. the background color CSS data is in the "style.nim" module
@@ -177,8 +207,15 @@ proc appActivate(app: Application) =
app.connectSignals
window.showAll
discard updateImage()
discard timeoutAdd(uint32(args.timeout), timedUpdate, imageWidget)
discard timeoutAdd(500, timedUpdate, imageWidget)
## open communication channel from the control server
chan.open()
## Start the server for handling incoming commands
createThread(serverWorker, runServer)
var tag = ""
discard idleAdd(checkServerChannel, tag)
when isMainModule:
let app = newApplication("org.luxick.randopix")

40
src/server.nim Normal file
View File

@@ -0,0 +1,40 @@
import net, json, marshal
import commands
var
chan*: Channel[CommandMessage]
proc closeServer*() =
## Sends a "Close" command to the server
var socket = newSocket()
socket.connect("127.0.0.1", Port(defaultPort))
let c = newCommand(Command.Close)
socket.send($(%c))
socket.close()
proc runServer*() =
var socket = newSocket()
socket.bindAddr(Port(defaultPort))
socket.listen()
echo "Control server is listening"
while true:
# Process client requests
var client = newSocket()
socket.accept(client)
echo("Incomming client")
try:
var line = client.recvLine()
let msg = to[CommandMessage](line)
case msg.command
of Command.Close:
echo "Server recieved termination command. Exiting."
break
else:
# Pass command from client to main applicaiton
chan.send(msg)
except OSError:
echo "Server error: ", getCurrentExceptionMsg()
except:
echo "Invalid command from client"

1
src/server.nim.cfg Normal file
View File

@@ -0,0 +1 @@
threads:on