aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/ipc/message.go52
-rw-r--r--lib/ipc/receive.go57
-rw-r--r--lib/ipc/send.go24
3 files changed, 105 insertions, 28 deletions
diff --git a/lib/ipc/message.go b/lib/ipc/message.go
new file mode 100644
index 00000000..3bd1e85c
--- /dev/null
+++ b/lib/ipc/message.go
@@ -0,0 +1,52 @@
+package ipc
+
+import "encoding/json"
+
+// Request constains all parameters needed for the main instance to respond to
+// a request.
+type Request struct {
+ // Arguments contains the commandline arguments. The detection of what
+ // action to take is left to the receiver.
+ Arguments []string `json:"arguments"`
+}
+
+// Response is used to report the results of a command.
+type Response struct {
+ // Error contains the success-state of the command. Error is an empty
+ // string if everything ran successfully.
+ Error string `json:"error"`
+}
+
+// Encode transforms the message in an easier to transfer format
+func (msg *Request) Encode() ([]byte, error) {
+ return json.Marshal(msg)
+}
+
+// DecodeMessage consumes a raw message and returns the message contained
+// within.
+func DecodeMessage(data []byte) (*Request, error) {
+ msg := new(Request)
+ err := json.Unmarshal(data, msg)
+ return msg, err
+}
+
+// Encode transforms the message in an easier to transfer format
+func (msg *Response) Encode() ([]byte, error) {
+ return json.Marshal(msg)
+}
+
+// DecodeRequest consumes a raw message and returns the message contained
+// within.
+func DecodeRequest(data []byte) (*Request, error) {
+ msg := new(Request)
+ err := json.Unmarshal(data, msg)
+ return msg, err
+}
+
+// DecodeResponse consumes a raw message and returns the message contained
+// within.
+func DecodeResponse(data []byte) (*Response, error) {
+ msg := new(Response)
+ err := json.Unmarshal(data, msg)
+ return msg, err
+}
diff --git a/lib/ipc/receive.go b/lib/ipc/receive.go
index c074b116..11a96e30 100644
--- a/lib/ipc/receive.go
+++ b/lib/ipc/receive.go
@@ -3,7 +3,6 @@ package ipc
import (
"bufio"
"errors"
- "fmt"
"net"
"net/url"
"os"
@@ -26,7 +25,7 @@ type AercServer struct {
func StartServer() (*AercServer, error) {
sockpath := path.Join(xdg.RuntimeDir(), "aerc.sock")
// remove the socket if it is not connected to a session
- if err := ConnectAndExec(""); err != nil {
+ if err := ConnectAndExec(nil); err != nil {
os.Remove(sockpath)
}
log.Debugf("Starting Unix server: %s", sockpath)
@@ -69,14 +68,25 @@ func (as *AercServer) Serve() {
log.Errorf("unix:%d failed to set deadline: %v", clientId, err)
}
for scanner.Scan() {
+ // allow up to 1 minute between commands
err = conn.SetDeadline(time.Now().Add(1 * time.Minute))
if err != nil {
log.Errorf("unix:%d failed to update deadline: %v", clientId, err)
}
- msg := scanner.Text()
- log.Tracef("unix:%d got message %s", clientId, msg)
+ msg, err := DecodeRequest(scanner.Bytes())
+ log.Tracef("unix:%d got message %s", clientId, scanner.Text())
+ if err != nil {
+ log.Errorf("unix:%d failed to parse request: %v", clientId, err)
+ continue
+ }
- _, err = conn.Write([]byte(as.handleMessage(msg)))
+ response := as.handleMessage(msg)
+ result, err := response.Encode()
+ if err != nil {
+ log.Errorf("unix:%d failed to encode result: %v", clientId, err)
+ continue
+ }
+ _, err = conn.Write(append(result, '\n'))
if err != nil {
log.Errorf("unix:%d failed to send response: %v", clientId, err)
break
@@ -86,31 +96,30 @@ func (as *AercServer) Serve() {
}
}
-func (as *AercServer) handleMessage(msg string) string {
- if !strings.ContainsRune(msg, ':') {
- return "error: invalid command\n"
+func (as *AercServer) handleMessage(req *Request) *Response {
+ if len(req.Arguments) == 0 {
+ return &Response{} // send noop success message, i.e. ping
}
- prefix := msg[:strings.IndexRune(msg, ':')]
var err error
- switch prefix {
- case "mailto":
- mailto, err := url.Parse(msg)
+ switch {
+ case strings.HasPrefix(req.Arguments[0], "mailto:"):
+ mailto, err := url.Parse(req.Arguments[0])
if err != nil {
- return fmt.Sprintf("error: %v\n", err)
+ return &Response{Error: err.Error()}
}
- if as.OnMailto != nil {
- err = as.OnMailto(mailto)
- if err != nil {
- return fmt.Sprintf("mailto failed: %v\n", err)
+ err = as.OnMailto(mailto)
+ if err != nil {
+ return &Response{
+ Error: err.Error(),
}
}
- case "mbox":
- if as.OnMbox != nil {
- err = as.OnMbox(msg)
- if err != nil {
- return fmt.Sprintf("mbox failed: %v\n", err)
- }
+ case strings.HasPrefix(req.Arguments[0], "mbox:"):
+ err = as.OnMbox(req.Arguments[0])
+ if err != nil {
+ return &Response{Error: err.Error()}
}
+ default:
+ return &Response{Error: "command not understood"}
}
- return "result: success\n"
+ return &Response{}
}
diff --git a/lib/ipc/send.go b/lib/ipc/send.go
index 5cc97cc0..522e944a 100644
--- a/lib/ipc/send.go
+++ b/lib/ipc/send.go
@@ -10,14 +10,20 @@ import (
"github.com/kyoh86/xdg"
)
-func ConnectAndExec(msg string) error {
+func ConnectAndExec(args []string) error {
sockpath := path.Join(xdg.RuntimeDir(), "aerc.sock")
conn, err := net.Dial("unix", sockpath)
if err != nil {
return err
}
defer conn.Close()
- _, err = conn.Write([]byte(msg + "\n"))
+
+ req, err := (&Request{Arguments: args}).Encode()
+ if err != nil {
+ return fmt.Errorf("failed to encode request: %w", err)
+ }
+
+ _, err = conn.Write(append(req, '\n'))
if err != nil {
return fmt.Errorf("failed to send message: %w", err)
}
@@ -25,7 +31,17 @@ func ConnectAndExec(msg string) error {
if !scanner.Scan() {
return errors.New("No response from server")
}
- result := scanner.Text()
- fmt.Println(result)
+ resp, err := DecodeResponse(scanner.Bytes())
+ if err != nil {
+ return err
+ }
+
+ // TODO: handle this in a more elegant manner
+ if resp.Error == "" {
+ fmt.Println("result: success")
+ } else {
+ fmt.Println("result: ", resp.Error)
+ }
+
return nil
}