This repository has been archived by the owner on Sep 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 24
/
gmx.go
129 lines (115 loc) · 2.4 KB
/
gmx.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
package gmx
import (
"encoding/json"
"fmt"
"io"
"log"
"net"
"os"
"path/filepath"
"sync"
)
const GMX_VERSION = 0
var (
r = ®istry{
entries: make(map[string]func() interface{}),
}
)
func init() {
s, err := localSocket()
if err != nil {
log.Printf("gmx: unable to open local socket: %v", err)
return
}
// register the registries keys for discovery
Publish("keys", func() interface{} {
return r.keys()
})
go serve(s, r)
}
func localSocket() (net.Listener, error) {
return net.ListenUnix("unix", localSocketAddr())
}
func localSocketAddr() *net.UnixAddr {
return &net.UnixAddr{
filepath.Join(os.TempDir(), fmt.Sprintf(".gmx.%d.%d", os.Getpid(), GMX_VERSION)),
"unix",
}
}
// Publish registers the function f with the supplied key.
func Publish(key string, f func() interface{}) {
r.register(key, f)
}
func serve(l net.Listener, r *registry) {
// if listener is a unix socket, try to delete it on shutdown
if l, ok := l.(*net.UnixListener); ok {
if a, ok := l.Addr().(*net.UnixAddr); ok {
defer os.Remove(a.Name)
}
}
defer l.Close()
for {
c, err := l.Accept()
if err != nil {
return
}
go handle(c, r)
}
}
func handle(nc net.Conn, reg *registry) {
// conn makes it easier to send and receive json
type conn struct {
net.Conn
*json.Encoder
*json.Decoder
}
c := conn{
nc,
json.NewEncoder(nc),
json.NewDecoder(nc),
}
defer c.Close()
for {
var keys []string
if err := c.Decode(&keys); err != nil {
if err != io.EOF {
log.Printf("gmx: client %v sent invalid json request: %v", c.RemoteAddr(), err)
}
return
}
var result = make(map[string]interface{})
for _, key := range keys {
if f, ok := reg.value(key); ok {
// invoke the function for key and store the result
result[key] = f()
}
}
if err := c.Encode(result); err != nil {
log.Printf("gmx: could not send response to client %v: %v", c.RemoteAddr(), err)
return
}
}
}
type registry struct {
sync.Mutex // protects entries from concurrent mutation
entries map[string]func() interface{}
}
func (r *registry) register(key string, f func() interface{}) {
r.Lock()
defer r.Unlock()
r.entries[key] = f
}
func (r *registry) value(key string) (func() interface{}, bool) {
r.Lock()
defer r.Unlock()
f, ok := r.entries[key]
return f, ok
}
func (r *registry) keys() (k []string) {
r.Lock()
defer r.Unlock()
for e := range r.entries {
k = append(k, e)
}
return
}