summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorxengineering <mail2xengineering@protonmail.com>2021-06-19 11:08:57 +0200
committerxengineering <mail2xengineering@protonmail.com>2021-06-20 13:57:58 +0200
commit963b86e49fad07a3722646b9d7f4b1c09d199eb1 (patch)
tree5ccb6b66bf9ce1c53e3e97fa7057e44b66512295 /src
parent198023be0f62ef6bb35cdd5ae78f90ab0a6f187e (diff)
downloadbirdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.tar
birdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.tar.zst
birdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.zip
Implement continuous Python Daemon
Diffstat (limited to 'src')
-rw-r--r--src/camera.go63
-rw-r--r--src/main.go38
-rw-r--r--src/subprocess.go102
-rw-r--r--src/web.go2
4 files changed, 134 insertions, 71 deletions
diff --git a/src/camera.go b/src/camera.go
index 519cc65..fe1140e 100644
--- a/src/camera.go
+++ b/src/camera.go
@@ -2,14 +2,6 @@
package main
-import (
- "log"
- "os/exec"
- "os"
- "path/filepath"
- "bufio"
-)
-
type Camera struct {
statemachine Machine
}
@@ -44,63 +36,10 @@ func NewCamera() Camera {
func runCameraHooks(last string, next string, m *Machine) {
if last == "idle" && next == "single_picture" {
- go singlePicture(m)
+ ipc.WriteLineTo("picamera", "single_picture\n")
}
}
-func singlePicture(m *Machine) {
-
- // create command
- var cmd *exec.Cmd
- if !config.Flag.Debug {
- cmd = exec.Command("/usr/bin/python3", "/usr/lib/python3.9/site-packages/birdscan/")
- } else { // debug mode
- pwd,err := os.Getwd()
- if err != nil {
- log.Fatal(err)
- }
- repoDir := filepath.Dir(pwd)
- log.Printf("Repository path is assumed to be = '%s'", repoDir)
- pythonPackage := repoDir + "/python/birdscan"
- cmd = exec.Command("/usr/bin/python3", pythonPackage, "--debug")
- }
-
- // connect stdout of python process
- stdout,err := cmd.StdoutPipe()
- if err != nil {
- log.Print(err)
- }
- defer stdout.Close()
-
- // run command
- err = cmd.Start()
- if err != nil {
- log.Print(err)
- }
-
- scanner := bufio.NewScanner(stdout)
- for scanner.Scan() {
- text := scanner.Text()
- log.Printf("Python returned '%s'", text)
- if text == "ok" {
- break
- }
- }
-
- err = cmd.Wait() // wait until command execution and io is complete
- if err != nil {
- log.Print(err)
- }
-
- // process result
- m.SendEvent("single_picture_taken")
-}
-
func (cam *Camera) run() {
cam.statemachine.Run()
}
-
-// read until '\n'
-func readLine(buff *[]byte, ) {
-
-}
diff --git a/src/main.go b/src/main.go
index 3218df9..dcb201e 100644
--- a/src/main.go
+++ b/src/main.go
@@ -4,11 +4,19 @@ package main
import (
"log"
+ "os"
+ "os/signal"
+ "syscall"
)
var (
config RuntimeConfig
camera Camera
+ ipc IpcServer
+)
+
+const (
+ IPC_SOCKET = "/tmp/birdscan.sock" // FIXME
)
func main() {
@@ -19,13 +27,27 @@ func main() {
// parse flags and read config
config = GetRuntimeConfig()
- // create camera
- camera = NewCamera()
-
- // start goroutines
- server := NewWebServer()
- go server.run() // http server / user interface
-
- // run camera
+ // create services
+ camera = NewCamera() // main service
+ ipc = NewIpcServer() // inter process communication
+ web := NewWebServer() // web frontend
+
+ // allow graceful exit
+ var listener = make(chan os.Signal)
+ signal.Notify(listener, syscall.SIGTERM)
+ signal.Notify(listener, syscall.SIGINT)
+ go func() {
+ signal := <-listener
+ log.Printf("Got signal '%+v'", signal)
+ ipc.Cleanup()
+ os.Exit(0)
+ }()
+
+ // start secondary services
+ go ipc.Run(IPC_SOCKET)
+ go PicameraSubprocess(IPC_SOCKET) // subprocess to use Python picamera
+ go web.run()
+
+ // start main service
camera.run()
}
diff --git a/src/subprocess.go b/src/subprocess.go
new file mode 100644
index 0000000..d16d4fe
--- /dev/null
+++ b/src/subprocess.go
@@ -0,0 +1,102 @@
+// vim: shiftwidth=4 tabstop=4 noexpandtab
+
+package main
+
+import (
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "net"
+ "net/textproto"
+ "bufio"
+)
+
+type IpcServer struct {
+ connections map[string]net.Conn
+ listener net.Listener
+}
+
+func NewIpcServer() IpcServer {
+ return IpcServer{
+ connections: make(map[string]net.Conn),
+ }
+}
+
+func (ipc *IpcServer) Run(ipcSocket string) {
+ log.Println("Running IPC server")
+ var err error
+ ipc.listener,err = net.Listen("unix", ipcSocket)
+ if err != nil {
+ log.Fatal(err)
+ }
+ for {
+ connection,err := ipc.listener.Accept()
+ if err != nil {
+ log.Print(err)
+ }
+ bufioreader := bufio.NewReader(connection)
+ tpreader := textproto.NewReader(bufioreader)
+ line,err := tpreader.ReadLine()
+ log.Printf("IPC: '%s'", line)
+ ipc.connections[line] = connection
+ go ipc.HandleConnection(line)
+ }
+}
+
+func (ipc *IpcServer) HandleConnection(connection string) {
+ for {
+ msg := ipc.ReadLineFrom(connection)
+ if msg != "" {
+ log.Printf("Got IPC message '%s' from '%s'", msg, connection)
+ if connection == "picamera" {
+ camera.statemachine.SendEvent(msg)
+ }
+ }
+ }
+}
+
+func (ipc *IpcServer) WriteLineTo(connection string, line string) {
+ conn := ipc.connections[connection]
+ _,err := conn.Write([]byte(line))
+ if err != nil {
+ log.Print(err)
+ }
+}
+
+func (ipc *IpcServer) ReadLineFrom(connection string) string {
+ conn := ipc.connections[connection]
+ bufioreader := bufio.NewReader(conn)
+ tpreader := textproto.NewReader(bufioreader)
+ line,_ := tpreader.ReadLine()
+ return line
+}
+
+func (ipc *IpcServer) Cleanup() {
+ log.Println("Releasing IPC socket ...")
+ for _,connection := range ipc.connections {
+ connection.Close()
+ }
+ ipc.listener.Close()
+}
+
+func PicameraSubprocess(ipcSocket string) {
+ var cmd *exec.Cmd
+ if config.Flag.Debug {
+ pwd,err := os.Getwd()
+ if err != nil {
+ log.Fatal(err)
+ }
+ repoDir := filepath.Dir(pwd)
+ pythonPackage := repoDir + "/python/birdscan"
+ cmd = exec.Command("python3", pythonPackage, "--debug", "-s", ipcSocket)
+ } else {
+ cmd = exec.Command("python3", "/usr/lib/python3.9/site-packages/birdscan/", "-s", ipcSocket)
+ }
+ log.Println("Starting picamera service")
+ err := cmd.Run()
+ log.Println("picamera service terminated!")
+ if err != nil {
+ log.Print(err)
+ }
+}
diff --git a/src/web.go b/src/web.go
index f7c7b49..8375a89 100644
--- a/src/web.go
+++ b/src/web.go
@@ -43,7 +43,7 @@ func (server *WebServer) run() {
router.Post("/api/reboot", rebootHandler)
router.Post("/api/poweroff", poweroffHandler)
- log.Println("Binding to 'http://" + server.config.BindAddress + ":" + server.config.BindPort + "'")
+ log.Println("Web service binding to 'http://" + server.config.BindAddress + ":" + server.config.BindPort + "'")
log.Fatal(http.ListenAndServe(server.config.BindAddress + ":" + server.config.BindPort, router))
}