From 7a489cb0011a34a68d3e77d0174076857cc37902 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 19 Jul 2019 14:15:48 -0400 Subject: Add Unix socket for communicating with aerc --- lib/socket.go | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 lib/socket.go (limited to 'lib') diff --git a/lib/socket.go b/lib/socket.go new file mode 100644 index 0000000..c256579 --- /dev/null +++ b/lib/socket.go @@ -0,0 +1,82 @@ +package lib + +import ( + "bufio" + "fmt" + "log" + "net" + "net/url" + "path" + "strings" + "sync/atomic" + "time" + + "github.com/kyoh86/xdg" +) + +type AercServer struct { + logger *log.Logger + listener net.Listener + OnMailto func(addr *url.URL) error +} + +func StartServer(logger *log.Logger) (*AercServer, error) { + sockpath := path.Join(xdg.RuntimeDir(), "aerc.sock") + l, err := net.Listen("unix", sockpath) + if err != nil { + return nil, err + } + as := &AercServer{ + logger: logger, + listener: l, + } + // TODO: stash clients and close them on exit... bleh racey + go func() { + for { + conn, err := l.Accept() + if err != nil { + // TODO: Something more useful, in some cases, on wednesdays, + // after 2 PM, I guess? + as.logger.Println("Closing Unix server: %v", err) + return + } + go as.handleClient(conn) + } + }() + return as, nil +} + +func (as *AercServer) Close() { + as.listener.Close() +} + +var lastId int64 = 0 // access via atomic + +func (as *AercServer) handleClient(conn net.Conn) { + clientId := atomic.AddInt64(&lastId, 1) + as.logger.Printf("Accepted Unix connection %d", clientId) + scanner := bufio.NewScanner(conn) + conn.SetDeadline(time.Now().Add(1 * time.Minute)) + for scanner.Scan() { + conn.SetDeadline(time.Now().Add(1 * time.Minute)) + msg := scanner.Text() + if !strings.ContainsRune(msg, ':') { + conn.Write([]byte("error: invalid command\n")) + } + as.logger.Printf("unix:%d: got message %s", clientId, msg) + prefix := msg[:strings.IndexRune(msg, ':')] + switch prefix { + case "mailto": + mailto, err := url.Parse(msg) + if err != nil { + conn.Write([]byte(fmt.Sprintf("error: %v\n", err))) + break + } + if as.OnMailto != nil { + err = as.OnMailto(mailto) + } + conn.Write([]byte(fmt.Sprintf("result: %v\n", err))) + } + } + as.logger.Printf("Closed Unix connection %d", clientId) +} -- cgit v1.2.3