agent/solo/solo.go

153 lines
4.1 KiB
Go
Raw Normal View History

2020-02-24 23:40:55 -05:00
package solo
import (
"bytes"
"fmt"
2020-02-24 23:40:55 -05:00
"log"
"net"
"github.com/clbanning/mxj"
2020-02-24 23:40:55 -05:00
"github.com/fatih/color"
"github.com/indihub-space/agent/lib"
"github.com/indihub-space/agent/proto/indihub"
)
var (
getProperties = []byte("<getProperties version='1.7'/>")
enableBLOB = "<enableBLOB device='%s'>Also</enableBLOB>"
2020-03-19 00:08:08 -04:00
setBLOBVector = []byte("<setBLOBVector")
defNumberVector = []byte("<defNumberVector")
2020-02-24 23:40:55 -05:00
)
type INDIHubSoloTunnel interface {
Send(response *indihub.Response) error
CloseAndRecv() (*indihub.SoloSummary, error)
}
type Agent struct {
indiServerAddr string
indiConn net.Conn
tunnel INDIHubSoloTunnel
shouldExit bool
2020-02-24 23:40:55 -05:00
}
2020-03-19 00:08:08 -04:00
func New(indiServerAddr string, tunnel INDIHubSoloTunnel) *Agent {
return &Agent{
indiServerAddr: indiServerAddr,
tunnel: tunnel,
2020-02-24 23:40:55 -05:00
}
}
2020-02-28 15:06:29 -05:00
func (p *Agent) Start(sessionID uint64, sessionToken string) error {
// open connection to real INDI-server
2020-02-24 23:40:55 -05:00
var err error
p.indiConn, err = net.Dial("tcp", p.indiServerAddr)
2020-02-24 23:40:55 -05:00
if err != nil {
log.Printf("could not connect to INDI-server in solo-mode: %s\n", err)
return err
2020-02-24 23:40:55 -05:00
}
defer p.indiConn.Close()
2020-02-24 23:40:55 -05:00
// set connection to receive data
if _, err := p.indiConn.Write(getProperties); err != nil {
log.Printf("could not write to INDI-server in solo-mode: %s\n", err)
return err
}
2020-02-24 23:40:55 -05:00
// listen INDI-server for data
buf := make([]byte, lib.INDIServerMaxSendMsgSize, lib.INDIServerMaxSendMsgSize)
xmlFlattener := lib.NewXmlFlattener()
2020-03-19 00:08:08 -04:00
subscribedCCDs := map[string]bool{}
2020-02-24 23:40:55 -05:00
for {
if p.shouldExit {
2020-02-24 23:40:55 -05:00
break
}
n, err := p.indiConn.Read(buf)
2020-02-24 23:40:55 -05:00
if err != nil {
log.Println("could not read from INDI-server in solo-mode:", err)
2020-02-24 23:40:55 -05:00
break
}
// subscribe to BLOBs and catch images
xmlCommands := xmlFlattener.FeedChunk(buf[:n])
2020-02-24 23:40:55 -05:00
for _, xmlCmd := range xmlCommands {
// catch images
if bytes.HasPrefix(xmlCmd, setBLOBVector) {
err := p.sendImages(xmlCmd, 1, sessionID, sessionToken)
2020-02-24 23:40:55 -05:00
if err != nil {
log.Println("could not send image to INDIHUB in solo-mode:", err)
2020-02-24 23:40:55 -05:00
}
continue
}
2020-02-24 23:40:55 -05:00
2020-03-19 00:08:08 -04:00
// subscribe to BLOBs from CCDs by catching defNumberVector property with name="CCD_EXPOSURE"
if !bytes.HasPrefix(xmlCmd, defNumberVector) {
continue
}
2020-02-24 23:40:55 -05:00
mapVal, err := mxj.NewMapXml(xmlCmd, true)
if err != nil {
log.Println("could not parse XML chunk in solo-mode:", err)
continue
}
2020-03-19 00:08:08 -04:00
defNumberVectorMap, _ := mapVal.ValueForKey("defNumberVector")
if defNumberVectorMap == nil {
continue
}
2020-03-19 00:08:08 -04:00
defNumberVectorVal := defNumberVectorMap.(map[string]interface{})
if nameStr, ok := defNumberVectorVal["attr_name"].(string); ok && nameStr == "CCD_EXPOSURE" {
if deviceStr, ok := defNumberVectorVal["attr_device"].(string); ok && !subscribedCCDs[deviceStr] {
_, err := p.indiConn.Write([]byte(fmt.Sprintf(enableBLOB, deviceStr)))
if err != nil {
log.Printf("could not write to INDI-server in solo-mode: %s\n", err)
2020-02-24 23:40:55 -05:00
}
2020-03-19 00:08:08 -04:00
subscribedCCDs[deviceStr] = true
break
2020-02-24 23:40:55 -05:00
}
}
}
2020-02-24 23:40:55 -05:00
}
2020-02-24 23:40:55 -05:00
// close connections to tunnel
if summary, err := p.tunnel.CloseAndRecv(); err == nil {
2020-02-24 23:40:55 -05:00
gc := color.New(color.FgGreen)
gc.Println()
gc.Println(" ************************************************************")
gc.Println(" * INDIHUB solo session finished!! *")
gc.Println(" ************************************************************")
gc.Println(" ")
gc.Printf(" "+
"Processed %d images. Thank you for your contribution!\n",
summary.ImagesNum,
)
gc.Println(" ************************************************************")
} else {
log.Printf("Error getting solo-session summary: %v", err)
}
return nil
2020-02-24 23:40:55 -05:00
}
func (p *Agent) Close() {
p.indiConn.Close()
p.shouldExit = true
2020-02-24 23:40:55 -05:00
}
func (p *Agent) sendImages(imagesData []byte, cNum uint32, sessID uint64, sessToken string) error {
2020-02-24 23:40:55 -05:00
resp := &indihub.Response{
Data: imagesData,
Conn: cNum,
SessionID: sessID,
SessionToken: sessToken,
}
return p.tunnel.Send(resp)
2020-02-24 23:40:55 -05:00
}