diff options
| author | xengineering <mail2xengineering@protonmail.com> | 2021-06-19 11:08:57 +0200 | 
|---|---|---|
| committer | xengineering <mail2xengineering@protonmail.com> | 2021-06-20 13:57:58 +0200 | 
| commit | 963b86e49fad07a3722646b9d7f4b1c09d199eb1 (patch) | |
| tree | 5ccb6b66bf9ce1c53e3e97fa7057e44b66512295 /src | |
| parent | 198023be0f62ef6bb35cdd5ae78f90ab0a6f187e (diff) | |
| download | birdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.tar birdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.tar.zst birdscan-963b86e49fad07a3722646b9d7f4b1c09d199eb1.zip  | |
Implement continuous Python Daemon
Diffstat (limited to 'src')
| -rw-r--r-- | src/camera.go | 63 | ||||
| -rw-r--r-- | src/main.go | 34 | ||||
| -rw-r--r-- | src/subprocess.go | 102 | ||||
| -rw-r--r-- | src/web.go | 2 | 
4 files changed, 132 insertions, 69 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() +	// 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 goroutines -	server := NewWebServer() -	go server.run()  // http server / user interface +	// start secondary services +	go ipc.Run(IPC_SOCKET) +	go PicameraSubprocess(IPC_SOCKET)  // subprocess to use Python picamera +	go web.run() -	// run camera +	// 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) +	} +} @@ -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))  }  | 
