create daemon listener for listening for user commands
Jeromy committed
Sep 8, 2014 at 18:21 UTC
05e457e197539bb24947fc95fa0e99db61d69102
3 files changed
+206
daemon/daemon.go
new
+107
@@ -0,0 +1,107 @@
1
+package daemon
2
+
3
+import (
4
+ "encoding/json"
5
+ "errors"
6
+ "net"
7
+ "strings"
8
+
9
+ u "github.com/jbenet/go-ipfs/util"
10
+)
11
+
12
+var ErrInvalidCommand = errors.New("invalid command")
13
+
14
+type DaemonListener struct {
15
+ list net.Listener
16
+ CommChan chan *Command
17
+ closed bool
18
+}
19
+
20
+func NewDaemonListener(addr string) (*DaemonListener, error) {
21
+ list, err := net.Listen("tcp", addr)
22
+ if err != nil {
23
+ return nil, err
24
+ }
25
+
26
+ return &DaemonListener{
27
+ list: list,
28
+ CommChan: make(chan *Command),
29
+ }, nil
30
+}
31
+
32
+type Command struct {
33
+ command string
34
+ args []string
35
+ resp chan string
36
+}
37
+
38
+func (dl *DaemonListener) Listen() {
39
+ for {
40
+ c, err := dl.list.Accept()
41
+ if err != nil {
42
+ if !dl.closed {
43
+ u.PErr("DaemonListener Accept: %v\n", err)
44
+ }
45
+ return
46
+ }
47
+ go dl.handleConnection(c)
48
+ }
49
+}
50
+
51
+func (dl *DaemonListener) handleConnection(c net.Conn) {
52
+ dec := json.NewDecoder(c)
53
+ enc := json.NewEncoder(c)
54
+ var com string
55
+ err := dec.Decode(&com)
56
+ if err != nil {
57
+ err := enc.Encode(err.Error())
58
+ if err != nil {
59
+ u.PErr("DaemonListener decode: %v\n", err)
60
+ }
61
+ return
62
+ }
63
+ u.DOut("Got command: %v\n", com)
64
+
65
+ cmd, err := parseCommand(com)
66
+ if err != nil {
67
+ err := enc.Encode(err.Error())
68
+ if err != nil {
69
+ u.PErr("DaemonListener parse: %v\n", err)
70
+ }
71
+ return
72
+ }
73
+
74
+ select {
75
+ case dl.CommChan <- cmd:
76
+ default:
77
+ u.PErr("Recieved command after closing...")
78
+ return
79
+ }
80
+
81
+ resp := <-cmd.resp
82
+ err = enc.Encode(resp)
83
+ if err != nil {
84
+ u.PErr("handleConnection: %v\n", err)
85
+ }
86
+}
87
+
88
+func parseCommand(cmdi string) (*Command, error) {
89
+ params := strings.Split(cmdi, " ")
90
+ if len(params) == 0 {
91
+ return nil, ErrInvalidCommand
92
+ }
93
+
94
+ //TODO: some sort of validation here
95
+
96
+ return &Command{
97
+ command: params[0],
98
+ args: params[1:],
99
+ resp: make(chan string),
100
+ }, nil
101
+}
102
+
103
+func (dl *DaemonListener) Close() error {
104
+ dl.closed = true
105
+ close(dl.CommChan)
106
+ return dl.list.Close()
107
+}
daemon/daemon_client.go
new
+29
@@ -0,0 +1,29 @@
1
+package daemon
2
+
3
+import (
4
+ "encoding/json"
5
+ "net"
6
+)
7
+
8
+func SendCommand(command, server string) (string, error) {
9
+ con, err := net.Dial("tcp", server)
10
+ if err != nil {
11
+ return "", err
12
+ }
13
+
14
+ enc := json.NewEncoder(con)
15
+ err = enc.Encode(command)
16
+ if err != nil {
17
+ return "", err
18
+ }
19
+
20
+ dec := json.NewDecoder(con)
21
+
22
+ var resp string
23
+ err = dec.Decode(&resp)
24
+ if err != nil {
25
+ return "", err
26
+ }
27
+
28
+ return resp, nil
29
+}
daemon/daemon_test.go
new
+70
@@ -0,0 +1,70 @@
1
+package daemon
2
+
3
+import (
4
+ "fmt"
5
+ "testing"
6
+)
7
+
8
+func TestCommandCall(t *testing.T) {
9
+ dl, err := NewDaemonListener("localhost:12345")
10
+ if err != nil {
11
+ t.Fatal(err)
12
+ }
13
+
14
+ go dl.Listen()
15
+ defer dl.Close()
16
+
17
+ go func() {
18
+ _, err := SendCommand("test command for fun", "localhost:12345")
19
+ if err != nil {
20
+ t.Fatal(err)
21
+ }
22
+ }()
23
+
24
+ cmd := <-dl.CommChan
25
+ if cmd.command != "test" {
26
+ t.Fatal("command parsing failed.")
27
+ }
28
+
29
+ if cmd.args[0] != "command" ||
30
+ cmd.args[1] != "for" ||
31
+ cmd.args[2] != "fun" {
32
+ t.Fatal("Args parsed incorrectly.")
33
+ }
34
+}
35
+
36
+func TestFailures(t *testing.T) {
37
+ dl, err := NewDaemonListener("localhost:12345")
38
+ if err != nil {
39
+ t.Fatal(err)
40
+ }
41
+
42
+ go dl.Listen()
43
+ defer dl.Close()
44
+
45
+ go func() {
46
+ _, err := SendCommand("test", "localhost:12345")
47
+ if err != nil {
48
+ t.Fatal(err)
49
+ }
50
+ }()
51
+
52
+ cmd := <-dl.CommChan
53
+ if cmd.command != "test" || len(cmd.args) > 0 {
54
+ t.Fatal("Parsing Failed.")
55
+ }
56
+
57
+ go func() {
58
+ _, err := SendCommand("", "localhost:12345")
59
+ if err != nil {
60
+ t.Fatal(err)
61
+ }
62
+ }()
63
+
64
+ cmd = <-dl.CommChan
65
+ if cmd.command != "" || len(cmd.args) > 0 {
66
+ fmt.Println(cmd)
67
+ t.Fatal("Parsing Failed.")
68
+ }
69
+
70
+}