-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
216 lines (189 loc) · 5.16 KB
/
client.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
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package wscl
import (
"bytes"
"encoding/gob"
"fmt"
"log"
"github.com/1414C/sluggo/wscom"
"golang.org/x/net/websocket"
)
// AddUpdCacheEntry adds or updates a cache entry using the value of interface i
// and the string key. It is the callers responsbility to manage the key
// structure. For a struct type of Foo[], the function should be called as
// follows:
//
// f := Foo{F1: "value1", F2: "value2",}
// k := "myUniqueKey1234"
// err := AddUpdCacheEntry(k,f)
func AddUpdCacheEntry(key string, i interface{}, address string) error {
// first gob encode the data
encBuf := new(bytes.Buffer)
err := gob.NewEncoder(encBuf).Encode(i)
if err != nil {
log.Println("failed to gob-encode interface{} i - got:", err)
return err
}
b := encBuf.Bytes()
// create an Article to house the encoded data
a := wscom.Article{
Key: key,
Op: "AU",
Valid: true,
Value: b,
Type: "",
}
// gob-encode the Article
encBuf = new(bytes.Buffer)
err = gob.NewEncoder(encBuf).Encode(a)
if err != nil {
log.Println("failed to gob-encode the Article - got:", err)
return err
}
encArticle := encBuf.Bytes()
// connect to remote server
origin := "http://localhost/"
url := "ws://" + address + "/set"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Println("AddUpdCacheEntry() ws connection failed - got:", err)
return err
}
// push the encoded Article
_, err = ws.Write(encArticle)
if err != nil {
log.Println("AddUpdCacheEntry() ws.Write error - got:", err)
return err
}
var msg = make([]byte, 64)
// single read from the ws is okay here
n, err := ws.Read(msg)
if err != nil {
log.Println("GetCacheEntry() ws.Read error - got:", err)
return err
}
// if update is confirmed do a little dance =)
if string(msg[:n]) == "true" {
// cw <- na
} else {
return fmt.Errorf("AddUpdCacheEntry() appeared to fail - got %v(raw),%v(string)", msg[:n], string(msg[:n]))
}
return nil
}
// GetCacheEntry reads the specified entry from the cache. If the entry does
// not exist, an error will be set. For a struct type of Foo{}, the function
// should be called as follows:
//
// f := &Foo{}
// k := "myUniqueKey1234"
// err := GetCacheEntry(k, f)
//
// followng the call, f will contain the cached value of the Foo{} type if
// the read was successful.
func GetCacheEntry(key string, i interface{}, address string) error {
// create an Article shell
a := wscom.Article{
Key: key,
Op: "G",
Valid: false,
Value: nil,
Type: "",
}
// gob-encode the Article shell
encBuf := new(bytes.Buffer)
err := gob.NewEncoder(encBuf).Encode(a)
if err != nil {
log.Println("GetCacheEntry() failed to gib encode the Article Shell")
}
encArticle := encBuf.Bytes()
origin := "http://localhost/"
url := "ws://" + address + "/get"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Println("GetCacheEntry() failed to make websocket connection with cache - got:", err)
return err
}
// push the encoded Article (command Op=='G' is what counts here)
_, err = ws.Write(encArticle)
if err != nil {
log.Println("GetCacheEntry() ws.Write error:", err)
return err
}
// read from the ws
var msg = make([]byte, 1024)
var n int
readBuf := new(bytes.Buffer)
for {
n, err = ws.Read(msg)
if err != nil {
log.Println("AddUpdCacheEntry() ws.Read error - got:", err)
return err
}
readBuf.Write(msg)
if n < 1024 {
break
}
}
// decode the read Article
decBuf := bytes.NewBuffer(msg[:n])
err = gob.NewDecoder(decBuf).Decode(&a)
if err != nil {
// error thing
log.Println("GetCacheEntry() gob.Decode() error - got:", err)
return err
}
if a.Value != nil {
decBuf := bytes.NewBuffer(a.Value)
err := gob.NewDecoder(decBuf).Decode(i)
if err != nil {
return err
}
} else {
return fmt.Errorf("GetCacheEntry() Article ID %s not in cache", key)
}
return nil
}
// RemoveCacheEntry removes the specified entry from the cache if it exists.
// If the specified entry does not exist, no error is returned, as the cache
// is deemd to be in the correct state. An error will be returned only if
// the function was not able to complete the operation from a technical
// standpoint.
func RemoveCacheEntry(key string, address string) error {
// create an Article shell
a := wscom.Article{
Key: key,
Op: "D",
Valid: false,
Value: nil,
Type: "",
}
// gob-encode the Article shell
encBuf := new(bytes.Buffer)
err := gob.NewEncoder(encBuf).Encode(a)
if err != nil {
log.Fatalf("DELETE gob failed to encode the Article Shell")
}
value := encBuf.Bytes()
origin := "http://localhost/"
url := "ws://" + address + "/delete"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
log.Println("GetCacheEntry() failed to make websocket connection with cache - got:", err)
return err
}
// push the encoded Article (command Op=='D' is what counts here)
_, err = ws.Write(value)
if err != nil {
log.Fatal("DELETE ws.Write error:", err)
}
var msg = make([]byte, 1024)
// read the bool result from the ws
n, err := ws.Read(msg)
if err != nil {
log.Fatal("ws.Read error:", err)
}
// if delete is confirmed, update local cache
if string(msg[:n]) != "true" {
log.Println("Article deletion failed")
}
return nil
}