gdbclient/internal/graphsonv3/reader.go (112 lines of code) (raw):

/* * (C) 2019-present Alibaba Group Holding Limited. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /** * @author : Liu Jianping * @date : 2019/11/25 */ package graphsonv3 import ( "encoding/json" "errors" "github.com/aliyun/alibabacloud-gdb-go-sdk/gdbclient/graph" "github.com/aliyun/alibabacloud-gdb-go-sdk/gdbclient/internal" "go.uber.org/zap" ) const ( // The server successfully processed a request to completion - threr are no messages remaining in this stream RESPONSE_STATUS_SUCCESS = 200 // The server processed the request but there is no result to return RESPONSE_STATUS_NO_CONTENT = 204 // The server successfully returned some content, but there is more in the stream to arrive - wait for the end of the stream RESPONSE_STATUS_PARITAL_CONTENT = 206 // The server could not authenticate the request or the client requested a resource it did not have access to RESPONSE_STATUS_UNAUTHORIZED = 401 // The server could authenticate the request, but will not fulfill it RESPONSE_STATUS_FORBIDDEN = 403 // A challenge from the server for the client to authenticate its request RESPONSE_STATUS_AUTHENTICATE = 407 // The request message contains objects that were not serializable on the client side RESPONSE_STATUS_REQUEST_ERROR_SERIALIZATION = 497 // The request message was not properly formatted which means it could not be parsed at all or the "op" code was // not recognized such that Gremlin Server could properly route it for processing. Check the message format and // retry the request. RESPONSE_STATUS_REQUEST_ERROR_MALFORMED_REQUEST = 498 // The request message was parseable, but the arguments supplied in the message were in conflict or incomplete. // Check the message format and retry the request. RESPONSE_STATUS_REQUEST_ERROR_INVALID_REQUEST_ARGUMENTS = 499 // A general server error occurred that prevented the request from being processed RESPONSE_STATUS_SERVER_ERROR = 500 // The script submitted for processing evaluated in the {@code ScriptEngine} with errors and could not be // processed. Check the script submitted for syntax errors or other problems and then resubmit. RESPONSE_STATUS_SERVER_ERROR_SCRIPT_EVALUATION = 597 // The server exceeded one of the timeout settings for the request and could therefore only partially responded // or did not respond at all. RESPONSE_STATUS_SERVER_ERROR_TIMEOUT = 598 // The server was not capable of serializing an object that was returned from the script supplied on the request. // Either transform the object into something Gremlin Server can process within the script or install mapper // serialization classes to Gremlin Server. RESPONSE_STATUS_SERVER_ERROR_SERIALIZATION = 599 // The client failed to deliver this request message to server RESPONSE_STATUS_REQUEST_ERROR_DELIVER = 697 ) type Response struct { Data interface{} RequestID string Code int } func NewErrorResponse(requestId string, code int, err error) *Response { return &Response{ RequestID: requestId, Code: code, Data: err} } type responseStatusJson struct { Attributes json.RawMessage `json:"attributes"` Code float64 `json:"code"` Message string `json:"message"` } type responseJson struct { RequestId string `json:"requestId"` Result map[string]json.RawMessage `json:"result"` Status responseStatusJson `json:"status"` } var jsonUnmarshal = json.Unmarshal func ReadResponse(msg []byte) (*Response, error) { if msg == nil { internal.Logger.Warn("response", zap.String("message", "")) return nil, nil } var respJson responseJson if err := jsonUnmarshal(msg, &respJson); err != nil { internal.Logger.Error("response", zap.String("message", string(msg)), zap.Error(err)) return nil, internal.NewDeserializerError("response", msg, err) } status := respJson.Status result := respJson.Result response := &Response{Code: int(status.Code), RequestID: respJson.RequestId} if response.Code == RESPONSE_STATUS_AUTHENTICATE { return response, nil } if response.Code == RESPONSE_STATUS_SUCCESS || response.Code == RESPONSE_STATUS_PARITAL_CONTENT { response.Data = result["data"] // TODO: result["meta"] } else if response.Code == RESPONSE_STATUS_NO_CONTENT { response.Data = nil } else { // this is a "success" but represents no results otherwise it is an error message := status.Message ret, err := resultRouter(status.Attributes) if err != nil { internal.Logger.Error("response attributes", zap.Int("code", response.Code), zap.Error(err), zap.String("raw", string(status.Attributes))) response.Data = err } else { attributes := ret.(map[interface{}]interface{}) stackTrace, ok := attributes[graph.STATUS_ATTRIBUTE_STACK_TRACE].(string) if !ok { internal.Logger.Error("response attributes stack trace", zap.Int("code", response.Code), zap.String("raw", string(status.Attributes))) } var execptions_str []string if exceptions, ok := attributes[graph.STATUS_ATTRIBUTE_EXCEPTIONS].([]interface{}); ok { execptions_str = make([]string, len(exceptions), len(exceptions)) for i := 0; i < len(exceptions); i++ { if execptions_str[i], ok = exceptions[i].(string); !ok { internal.Logger.Error("response attributes stack trace", zap.Int("code", response.Code), zap.Int("idx", i), zap.String("raw", string(status.Attributes))) } } } // set errors to Data response.Data = internal.NewResponseError(response.Code, message, stackTrace, execptions_str) } } return response, nil } // get result from one whole response func GetResult(response *Response) ([]interface{}, error) { if response.Code == RESPONSE_STATUS_SUCCESS { if raw, ok := response.Data.(json.RawMessage); ok { return getResult(raw) } // handle json list if rawList, ok := response.Data.([]json.RawMessage); ok { var resultMerge []interface{} for _, raw := range rawList { if results, err := getResult(raw); err == nil { resultMerge = append(resultMerge, results...) } } return resultMerge, nil } return nil, errors.New("un-handle response Data") } else if response.Code == RESPONSE_STATUS_NO_CONTENT { return nil, nil } return nil, response.Data.(error) }