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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
package internal
/* TODO: Keep any actual logic/compute out of this file */
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"reflect"
)
// {"method": "query","function": "get User","params": {"id": 1, "user": "wcole"}}
type (
LurchMsgBytes = []byte
LurchRespBytes = []byte
lurchLogic = map[string][]any
lurchArgs = map[string]any
lurchCallback func(args map[string]any) error
)
type LurchPackage interface {
Encode() []byte
Decode() error
}
type LurchMsg struct {
Method string `json:"method"`
Function string `json:"function"`
Params lurchArgs `json:"params"`
}
func (m *LurchMsg) Encode() ([]byte, error) {
return json.Marshal(&m)
}
func (m *LurchMsg) Decode(data LurchMsgBytes) error {
return json.Unmarshal(data, m)
}
// arb data; don't know the shape of api data response yet, tbd
// {"data": {"id": 1, "user": "wcole"}}
// {"method": "query","function": "get User","params": {"id": 1, "user": "wcole"}}
type LurchResp struct {
Ok bool `json:"ok"`
Data map[string][]any `json:"data"`
Meta map[string]string `json:"meta"`
}
func (r *LurchResp) Encode() ([]byte, error) {
return json.Marshal(&r)
}
func (r *LurchResp) Decode(data LurchRespBytes) error {
return json.Unmarshal(data, r)
}
func Encode(lp interface{}) ([]byte, error) {
switch v := lp.(type) {
case LurchMsg:
return json.Marshal(v)
case *LurchMsg:
return json.Marshal(*v)
case LurchResp:
return json.Marshal(v)
case *LurchResp:
return json.Marshal(*v)
default:
return nil, errors.New("encode: package value is nil")
}
}
func Decode(lp interface{}, data []byte) error {
switch v := lp.(type) {
case LurchMsg:
return json.Unmarshal(data, &v)
case *LurchMsg:
return json.Unmarshal(data, v)
case LurchResp:
return json.Unmarshal(data, &v)
case *LurchResp:
return json.Unmarshal(data, v)
default:
return errors.New("decode: failed to determine type of package")
}
}
// {"method": "query","function": "get User","params": {"id": 1, "user": "wcole"}}
var fns = lurchLogic{
// using the base rep of the type
"spawnWorker": []any{spawnWorkerArgs, spawnWorker},
"status": []any{statusArgs, status},
}
func Compute(ctx context.Context, m *LurchMsg, conn net.Conn) error {
d := ctx.Value("daemon")
if d != nil {
return errors.New("compute: daemon reference not found in context")
}
a := func(args lurchArgs, pArgs lurchArgs) (lurchArgs, bool) {
buf := lurchArgs{}
for n, v := range args {
if primitive, ok := pArgs[n]; ok {
if reflect.TypeOf(v) != reflect.TypeOf(primitive) {
buf[n] = v
}
}
}
if len(buf) != 0 {
return buf, false
}
args["daemon"] = d
return args, true
}
f := func(fn string) error {
if signature, ok := fns[fn]; ok {
// function signature is in lurch functions; sign is value
if callee, ok := signature[1].(lurchCallback); ok {
// args validation
// COULD PANIC, DON'T GOOF UP THE FNS INF
if params, ok := a(m.Params, signature[0].(lurchArgs)); ok {
err := callee(params)
return err
} else {
return errors.New("parse: malformed lurch message - args")
}
}
}
return errors.New("parse: signature not in lurch logic")
}
switch m.Method {
case "query":
fmt.Fprintln(conn, "query received")
// some query system logic here
return f(m.Function)
case "mutation":
// mutation logic
fmt.Fprintln(conn, "mutation received")
return f(m.Function)
case "subscription":
// subscription logic
fmt.Fprintln(conn, "subscription received")
return f(m.Function)
default:
fmt.Fprintf(conn, "unknown command: %s\n", m.Method)
return errors.New("parse: malformed lurch message - method")
}
}
|