forked from schwartzmx/gremgo-neptune
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresponse.go
138 lines (123 loc) · 4.53 KB
/
response.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
package gremgo
import (
"encoding/json"
"fmt"
)
const (
statusSuccess = 200
statusNoContent = 204
statusPartialContent = 206
statusUnauthorized = 401
statusAuthenticate = 407
statusMalformedRequest = 498
statusInvalidRequestArguments = 499
statusServerError = 500
statusScriptEvaluationError = 597
statusServerTimeout = 598
statusServerSerializationError = 599
)
// Status struct is used to hold properties returned from requests to the gremlin server
type Status struct {
Message string `json:"message"`
Code int `json:"code"`
Attributes map[string]interface{} `json:"attributes"`
}
// Result struct is used to hold properties returned for results from requests to the gremlin server
type Result struct {
// Query Response Data
Data json.RawMessage `json:"data"`
Meta map[string]interface{} `json:"meta"`
}
// Response structs holds the entire response from requests to the gremlin server
type Response struct {
RequestID string `json:"requestId"`
Status Status `json:"status"`
Result Result `json:"result"`
}
// ToString returns a string representation of the Response struct
func (r Response) ToString() string {
return fmt.Sprintf("Response \nRequestID: %v, \nStatus: {%#v}, \nResult: {%#v}\n", r.RequestID, r.Status, r.Result)
}
func (c *Client) handleResponse(msg []byte) (err error) {
resp, err := marshalResponse(msg)
if resp.Status.Code == statusAuthenticate { //Server request authentication
return c.authenticate(resp.RequestID)
}
c.saveResponse(resp, err)
return
}
// marshalResponse creates a response struct for every incoming response for further manipulation
func marshalResponse(msg []byte) (resp Response, err error) {
err = json.Unmarshal(msg, &resp)
if err != nil {
return
}
err = resp.detectError()
return
}
// saveResponse makes the response available for retrieval by the requester. Mutexes are used for thread safety.
func (c *Client) saveResponse(resp Response, err error) {
c.mu.Lock()
defer c.mu.Unlock()
var container []interface{}
existingData, ok := c.results.Load(resp.RequestID) // Retrieve old data container (for requests with multiple responses)
if ok {
container = existingData.([]interface{})
}
newdata := append(container, resp) // Create new data container with new data
c.results.Store(resp.RequestID, newdata) // Add new data to buffer for future retrieval
respNotifier, load := c.responseNotifier.LoadOrStore(resp.RequestID, make(chan error, 1))
_ = load
if resp.Status.Code != statusPartialContent {
respNotifier.(chan error) <- err
}
}
// retrieveResponse retrieves the response saved by saveResponse.
func (c *Client) retrieveResponse(id string) (data []Response, err error) {
resp, _ := c.responseNotifier.Load(id)
err = <-resp.(chan error)
if err == nil {
if dataI, ok := c.results.Load(id); ok {
d := dataI.([]interface{})
data = make([]Response, len(d))
for i := range d {
data[i] = d[i].(Response)
}
close(resp.(chan error))
c.responseNotifier.Delete(id)
c.deleteResponse(id)
}
}
return
}
// deleteRespones deletes the response from the container. Used for cleanup purposes by requester.
func (c *Client) deleteResponse(id string) {
c.results.Delete(id)
return
}
// responseDetectError detects any possible errors in responses from Gremlin Server and generates an error for each code
func (r *Response) detectError() (err error) {
switch r.Status.Code {
case statusSuccess, statusNoContent, statusPartialContent:
break
case statusUnauthorized:
err = fmt.Errorf("UNAUTHORIZED - Response Message: %s", r.Status.Message)
case statusAuthenticate:
err = fmt.Errorf("AUTHENTICATE - Response Message: %s", r.Status.Message)
case statusMalformedRequest:
err = fmt.Errorf("MALFORMED REQUEST - Response Message: %s", r.Status.Message)
case statusInvalidRequestArguments:
err = fmt.Errorf("INVALID REQUEST ARGUMENTS - Response Message: %s", r.Status.Message)
case statusServerError:
err = fmt.Errorf("SERVER ERROR - Response Message: %s", r.Status.Message)
case statusScriptEvaluationError:
err = fmt.Errorf("SCRIPT EVALUATION ERROR - Response Message: %s", r.Status.Message)
case statusServerTimeout:
err = fmt.Errorf("SERVER TIMEOUT - Response Message: %s", r.Status.Message)
case statusServerSerializationError:
err = fmt.Errorf("SERVER SERIALIZATION ERROR - Response Message: %s", r.Status.Message)
default:
err = fmt.Errorf("UNKNOWN ERROR - Response Message: %s", r.Status.Message)
}
return
}