Skip to content

Commit 85c0c62

Browse files
authored
Merge pull request #424 from pixlise/feature/client
Feature/client
2 parents c5bc8d1 + 76974ef commit 85c0c62

File tree

11 files changed

+616
-419
lines changed

11 files changed

+616
-419
lines changed

core/client/client.go

Lines changed: 349 additions & 24 deletions
Large diffs are not rendered by default.

core/client/internal/cmdline/main.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,59 @@ func main() {
1111
// Try to load the config file
1212
apiClient, err := client.Authenticate()
1313
fmt.Printf("auth err: %v\n", err)
14+
if err != nil {
15+
return
16+
}
17+
18+
// err = apiClient.UploadImage(&protos.ImageUploadHttpRequest{
19+
// Name: "myimage.png",
20+
// ImageData: []byte{0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x0, 0x0, 0x0, 0x90, 0x77, 0x53, 0xde, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x28, 0x3d, 0xaf, 0xb, 0x0, 0x3, 0x2e, 0x1, 0x72, 0x50, 0x4e, 0xda, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82},
21+
// OriginScanId: "069927431",
22+
// })
23+
24+
// return
25+
26+
// err = apiClient.SaveMapData("my-data", &protos.ClientMap{
27+
// EntryPMCs: []int32{7, 8, 10, 12},
28+
// FloatValues: []float64{79.4, 89.4, 109.4, 129.4},
29+
// })
30+
// fmt.Printf("SaveMapData: %v\n", err)
31+
32+
// mapData, err := apiClient.LoadMapData("my-data")
33+
// fmt.Printf("LoadMapData: %v|%v\n", err, mapData)
34+
35+
// return
1436

15-
// Dev: 500302337 is missing bulk sum?
37+
// // Dev: 500302337 is missing bulk sum?
1638

1739
// spectrum, err := apiClient.GetScanSpectrum("261161477", 15, protos.SpectrumType_SPECTRUM_NORMAL, "A")
1840
// fmt.Printf("%v|%v|%v\n", err, len(spectrum.Counts), spectrum)
1941

2042
// spectrum, err = apiClient.GetScanSpectrum("261161477", 8383824, protos.SpectrumType_SPECTRUM_BULK, "B")
2143
// fmt.Printf("%v|%v|%v\n", err, len(spectrum.Counts), spectrum)
2244

45+
// rangeMap, err := apiClient.GetScanSpectrumRangeAsMap("475070977", 300, 302, "B")
46+
// fmt.Printf("%v|%v\n", err, len(rangeMap.EntryPMCs))
47+
48+
diffMap, err := apiClient.GetDiffractionAsMap("069927431", protos.EnergyCalibrationSource_CAL_BULK_SUM, 100, 120)
49+
fmt.Printf("err: %v\n", err)
50+
if diffMap != nil {
51+
fmt.Printf("PMC, Value\n")
52+
for k, v := range diffMap.EntryPMCs {
53+
fmt.Printf("All Points,%v,%v\n", v, diffMap.IntValues[k])
54+
}
55+
}
56+
57+
// ruffMap, err := apiClient.GetRoughnessAsMap("475070977", protos.EnergyCalibrationSource_CAL_BULK_SUM)
58+
// fmt.Printf("err: %v\n", err)
59+
// if ruffMap != nil {
60+
// fmt.Printf("PMC, Value\n")
61+
// for k, v := range ruffMap.EntryPMCs {
62+
// fmt.Printf("All Points,%v,%v\n", v, ruffMap.FloatValues[k])
63+
// }
64+
// }
65+
return
66+
2367
xyzs, err := apiClient.GetScanBeamLocations("261161477")
2468
fmt.Print(len(xyzs.Locations))
2569

core/client/lib/main.go

Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ func getScanSpectrum(scanId string, pmc int32, spectrumType int, detector string
119119
})
120120
}
121121

122+
//export getScanSpectrumRangeAsMap
123+
func getScanSpectrumRangeAsMap(scanId string, channelStart int32, channelEnd int32, detector string) *C.char {
124+
return processRequest("getScanSpectrumRangeAsMap", func() (proto.Message, error) {
125+
return apiClient.GetScanSpectrumRangeAsMap(scanId, channelStart, channelEnd, detector)
126+
})
127+
}
128+
122129
//export listScans
123130
func listScans(scanId string) *C.char {
124131
return processRequest("listScans", func() (proto.Message, error) { return apiClient.ListScans(scanId) })
@@ -139,9 +146,9 @@ func getScanEntryDataColumns(scanId string) *C.char {
139146
return processRequest("getScanEntryDataColumns", func() (proto.Message, error) { return apiClient.GetScanEntryDataColumns(scanId) })
140147
}
141148

142-
//export getScanEntryDataColumn
143-
func getScanEntryDataColumn(scanId string, columnName string) *C.char {
144-
return processRequest("getScanEntryDataColumn", func() (proto.Message, error) { return apiClient.GetScanEntryDataColumn(scanId, columnName) })
149+
//export getScanEntryDataColumnAsMap
150+
func getScanEntryDataColumnAsMap(scanId string, columnName string) *C.char {
151+
return processRequest("getScanEntryDataColumnAsMap", func() (proto.Message, error) { return apiClient.GetScanEntryDataColumnAsMap(scanId, columnName) })
145152
}
146153

147154
//export listScanQuants
@@ -216,14 +223,28 @@ func getDiffractionPeaks(scanId string, calibrationSource int) *C.char {
216223
})
217224
}
218225

226+
//export getDiffractionAsMap
227+
func getDiffractionAsMap(scanId string, calibrationSource int, channelStart int32, channelEnd int32) *C.char {
228+
return processRequest("getDiffractionAsMap", func() (proto.Message, error) {
229+
return apiClient.GetDiffractionAsMap(scanId, protos.EnergyCalibrationSource(calibrationSource), channelStart, channelEnd)
230+
})
231+
}
232+
233+
//export getRoughnessAsMap
234+
func getRoughnessAsMap(scanId string, calibrationSource int) *C.char {
235+
return processRequest("getRoughnessAsMap", func() (proto.Message, error) {
236+
return apiClient.GetRoughnessAsMap(scanId, protos.EnergyCalibrationSource(calibrationSource))
237+
})
238+
}
239+
219240
//export getQuantColumns
220241
func getQuantColumns(quantId string) *C.char {
221242
return processRequest("getQuantColumns", func() (proto.Message, error) { return apiClient.GetQuantColumns(quantId) })
222243
}
223244

224-
//export getQuantColumn
225-
func getQuantColumn(quantId string, columnName string, detector string) *C.char {
226-
return processRequest("getQuantColumn", func() (proto.Message, error) { return apiClient.GetQuantColumn(quantId, columnName, detector) })
245+
//export getQuantColumnAsMap
246+
func getQuantColumnAsMap(quantId string, columnName string, detector string) *C.char {
247+
return processRequest("getQuantColumnAsMap", func() (proto.Message, error) { return apiClient.GetQuantColumnAsMap(quantId, columnName, detector) })
227248
}
228249

229250
//export createROI
@@ -238,5 +259,66 @@ func createROI(roiBuff string, isMist bool) *C.char {
238259
return processRequest("createROI", func() (proto.Message, error) { return apiClient.CreateROI(roiItem, isMist) })
239260
}
240261

262+
//export saveMapData
263+
func saveMapData(key string, dataBuff string) *C.char {
264+
// Here we can read the data string as a protobuf message and create the right structure
265+
mapItem := &protos.ClientMap{}
266+
err := protojson.Unmarshal([]byte(dataBuff), mapItem)
267+
if err != nil {
268+
return C.CString(fmt.Sprintf("saveMapData: Failed to decode data: %v", err))
269+
}
270+
271+
if apiClient == nil {
272+
return C.CString("Not authenticated")
273+
}
274+
275+
err = apiClient.SaveMapData(key, mapItem)
276+
if err != nil {
277+
return C.CString(fmt.Sprintf("saveMapData error: %v", err))
278+
}
279+
280+
return emptyCString
281+
}
282+
283+
//export loadMapData
284+
func loadMapData(key string) *C.char {
285+
return processRequest("loadMapData", func() (proto.Message, error) { return apiClient.LoadMapData(key) })
286+
}
287+
288+
//export uploadImage
289+
func uploadImage(imageUpload string) *C.char {
290+
// Here we can read the data string as a protobuf message and create the right structure
291+
upload := &protos.ImageUploadHttpRequest{}
292+
err := protojson.Unmarshal([]byte(imageUpload), upload)
293+
if err != nil {
294+
return C.CString(fmt.Sprintf("uploadImage: Failed to decode imageUpload: %v", err))
295+
}
296+
297+
if apiClient == nil {
298+
return C.CString("Not authenticated")
299+
}
300+
301+
err = apiClient.UploadImage(upload)
302+
if err != nil {
303+
return C.CString(fmt.Sprintf("uploadImage error: %v", err))
304+
}
305+
306+
return emptyCString
307+
}
308+
309+
//export deleteImage
310+
func deleteImage(imageName string) *C.char {
311+
if apiClient == nil {
312+
return C.CString("Not authenticated")
313+
}
314+
315+
err := apiClient.DeleteImage(imageName)
316+
if err != nil {
317+
return C.CString(fmt.Sprintf("deleteImage error: %v", err))
318+
}
319+
320+
return emptyCString
321+
}
322+
241323
func main() {
242324
}

core/client/socketconn.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,29 @@ type Auth0Info struct {
3131
}
3232

3333
type SocketConn struct {
34-
JWT string
35-
UserId string
36-
send chan []byte
37-
recv chan []byte
38-
recvList [][]byte // msgs received in past
39-
interrupt chan os.Signal
40-
done chan struct{}
41-
reqCount uint32
34+
Host string
35+
HostProtocol string
36+
JWT string
37+
UserId string
38+
send chan []byte
39+
recv chan []byte
40+
recvList [][]byte // msgs received in past
41+
interrupt chan os.Signal
42+
done chan struct{}
43+
reqCount uint32
4244
}
4345

4446
const maxResponsesBuffered = 100
4547

48+
func (s *SocketConn) GetHost(path string) (*url.URL, error) {
49+
if len(s.HostProtocol) <= 0 || len(s.Host) <= 0 {
50+
// Host is empty, stop here
51+
return nil, fmt.Errorf("Host not set")
52+
}
53+
54+
return &url.URL{Scheme: s.HostProtocol, Host: s.Host, Path: path}, nil
55+
}
56+
4657
// Inspired by: https://tradermade.com/tutorials/golang-websocket-client
4758
func (s *SocketConn) Connect(connectParams ConnectInfo, auth0Params Auth0Info) error {
4859
token, err := s.getWSConnectToken(connectParams, auth0Params)
@@ -239,6 +250,10 @@ func (s *SocketConn) getWSConnectToken(connectParams ConnectInfo, auth0Params Au
239250
return "", err
240251
}
241252

253+
// Remember this host for later
254+
s.Host = hostUrl
255+
s.HostProtocol = protocol
256+
242257
return respBody.ConnToken, nil
243258
}
244259

core/utils/rateLimit.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/pixlise/core/v4/core/timestamper"
8+
)
9+
10+
type RateLimiter struct {
11+
requestTimestamps []int64
12+
timestamper timestamper.ITimeStamper
13+
softLimitInWindow int
14+
hardLimitInWindow int
15+
timeWindowSec int64
16+
softLimitSleepSec int
17+
}
18+
19+
func MakeRateLimiter(timestamper timestamper.ITimeStamper, softLimit int, hardLimit int, timeWindowSec int64, softLimitSleepSec int) *RateLimiter {
20+
return &RateLimiter{
21+
requestTimestamps: []int64{},
22+
timestamper: timestamper,
23+
softLimitInWindow: softLimit,
24+
hardLimitInWindow: hardLimit,
25+
timeWindowSec: timeWindowSec,
26+
softLimitSleepSec: softLimitSleepSec,
27+
}
28+
}
29+
30+
func (r *RateLimiter) CheckRateLimit() {
31+
now := r.timestamper.GetTimeNowSec()
32+
33+
oldest := now - r.timeWindowSec
34+
35+
// Clear too old
36+
validTimestamps := []int64{}
37+
for _, ts := range r.requestTimestamps {
38+
if ts >= oldest {
39+
validTimestamps = append(validTimestamps, ts)
40+
}
41+
}
42+
43+
// Add ours
44+
r.requestTimestamps = append(validTimestamps, now)
45+
46+
// Check if we need to limit
47+
if len(r.requestTimestamps) > r.hardLimitInWindow {
48+
panic("Message hard rate limit exceeded")
49+
}
50+
51+
if len(r.requestTimestamps) > r.softLimitInWindow {
52+
fmt.Printf("Rate limiting %v sec...\n", r.softLimitSleepSec)
53+
time.Sleep(time.Duration(r.softLimitSleepSec) * time.Second)
54+
}
55+
}

core/utils/rateLimit_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/pixlise/core/v4/core/timestamper"
8+
)
9+
10+
func Example_rateLimiter() {
11+
defer func() {
12+
if r := recover(); r != nil {
13+
fmt.Println("Hard limit")
14+
}
15+
}()
16+
17+
ts := timestamper.MockTimeNowStamper{
18+
QueuedTimeStamps: []int64{1234567000, 1234567000, 1234567001, 1234567003, 1234567009, 12345670010, 12345670012, 12345670013, 1234567017, 1234567025, 1234567030, 1234567030, 1234567031, 1234567032},
19+
}
20+
r := MakeRateLimiter(&ts, 3, 5, 10, 5)
21+
22+
runLoop(r, len(ts.QueuedTimeStamps))
23+
24+
// Output:
25+
// No limit
26+
// No limit
27+
// No limit
28+
// Rate limiting 5 sec...
29+
// Soft limit
30+
// Rate limiting 5 sec...
31+
// Soft limit
32+
// No limit
33+
// No limit
34+
// No limit
35+
// Rate limiting 5 sec...
36+
// Soft limit
37+
// Rate limiting 5 sec...
38+
// Soft limit
39+
// Rate limiting 5 sec...
40+
// Soft limit
41+
// Hard limit
42+
}
43+
44+
func runLoop(r *RateLimiter, iterations int) {
45+
for c := 0; c < iterations; c++ {
46+
startMs := time.Now().UnixMilli()
47+
r.CheckRateLimit()
48+
endMs := time.Now().UnixMilli()
49+
50+
if endMs-startMs > 4000 {
51+
fmt.Println("Soft limit")
52+
} else {
53+
fmt.Println("No limit")
54+
}
55+
}
56+
}

python/README.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

python/genprotos.sh

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)