-
Notifications
You must be signed in to change notification settings - Fork 7
/
socket.go
131 lines (110 loc) · 2.28 KB
/
socket.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package spm
import (
"encoding/json"
"net"
"sync"
)
// unix socket for communicating between cli apps and running daemon.
var sockName = "/tmp/spm01.sock"
type Socket struct {
// Message emits incoming messages from dialer or listener.
Message chan Message
// conn is a dialer when Socket is a dialer
conn net.Conn
// ln is a listener when Socket is a listener.
ln net.Listener
// Connection emits connected dialers when Socket is a listener.
Connection chan *Socket
mu sync.Mutex // protects following
// Connections holds connected dialers when Socket is a listener.
Connections []*Socket
}
type Message struct {
// Command can be "empty", start, stop and etc.
Command string
Arguments []string
Jobs []Job
JobList []string
JobLogs []string
}
func (s *Socket) Send(m Message) error {
enc := json.NewEncoder(s.conn)
return enc.Encode(m)
}
func NewSocket() *Socket {
return &Socket{
Message: make(chan Message, 0),
Connection: make(chan *Socket, 0),
}
}
func (s *Socket) Close() error {
if s.conn != nil {
return s.conn.Close()
}
if s.ln != nil {
if err := s.ln.Close(); err != nil {
return err
}
s.mu.Lock()
for _, sock := range s.Connections {
sock.Close()
}
s.mu.Unlock()
}
return nil
}
func (s *Socket) readLoop(parent *Socket) {
if parent != nil {
parent.mu.Lock()
parent.Connections = append(parent.Connections, s)
parent.mu.Unlock()
}
dec := json.NewDecoder(s.conn)
for {
var mes Message
if err := dec.Decode(&mes); err != nil {
if parent != nil {
parent.mu.Lock()
for i, conn := range parent.Connections {
if conn == s {
close(conn.Message)
parent.Connections = append(parent.Connections[:i], parent.Connections[i+1:]...)
break
}
}
parent.mu.Unlock()
} else {
close(s.Message)
close(s.Connection)
}
return
}
s.Message <- mes
}
}
func (s *Socket) Listen() error {
ln, err := net.Listen("unix", sockName)
if err != nil {
return err
}
s.ln = ln
for {
c, err := ln.Accept()
if err != nil {
return nil
}
sock := NewSocket()
sock.conn = c
go sock.readLoop(s)
s.Connection <- sock
}
}
func (s *Socket) Dial() error {
conn, err := net.Dial("unix", sockName)
if err != nil {
return err
}
s.conn = conn
go s.readLoop(nil)
return nil
}