Add control server.
This commit is contained in:
@@ -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
15
src/commands.nim
Normal 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
13
src/pixctrl.nim
Normal 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()
|
||||
@@ -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
40
src/server.nim
Normal 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
1
src/server.nim.cfg
Normal file
@@ -0,0 +1 @@
|
||||
threads:on
|
||||
Reference in New Issue
Block a user