1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package jsonrpc2 6 7import ( 8 "encoding/json" 9 "fmt" 10 "strconv" 11) 12 13// this file contains the go forms of the wire specification 14// see http://www.jsonrpc.org/specification for details 15 16const ( 17 // CodeUnknownError should be used for all non coded errors. 18 CodeUnknownError = -32001 19 // CodeParseError is used when invalid JSON was received by the server. 20 CodeParseError = -32700 21 //CodeInvalidRequest is used when the JSON sent is not a valid Request object. 22 CodeInvalidRequest = -32600 23 // CodeMethodNotFound should be returned by the handler when the method does 24 // not exist / is not available. 25 CodeMethodNotFound = -32601 26 // CodeInvalidParams should be returned by the handler when method 27 // parameter(s) were invalid. 28 CodeInvalidParams = -32602 29 // CodeInternalError is not currently returned but defined for completeness. 30 CodeInternalError = -32603 31) 32 33// Request is sent to a server to represent a Call or Notify operaton. 34type Request struct { 35 // VersionTag is always encoded as the string "2.0" 36 VersionTag VersionTag `json:"jsonrpc"` 37 // Method is a string containing the method name to invoke. 38 Method string `json:"method"` 39 // Params is either a struct or an array with the parameters of the method. 40 Params *json.RawMessage `json:"params,omitempty"` 41 // The id of this request, used to tie the Response back to the request. 42 // Will be either a string or a number. If not set, the Request is a notify, 43 // and no response is possible. 44 ID *ID `json:"id,omitempty"` 45} 46 47// Response is a reply to a Request. 48// It will always have the ID field set to tie it back to a request, and will 49// have either the Result or Error fields set depending on whether it is a 50// success or failure response. 51type Response struct { 52 // VersionTag is always encoded as the string "2.0" 53 VersionTag VersionTag `json:"jsonrpc"` 54 // Result is the response value, and is required on success. 55 Result *json.RawMessage `json:"result,omitempty"` 56 // Error is a structured error response if the call fails. 57 Error *Error `json:"error,omitempty"` 58 // ID must be set and is the identifier of the Request this is a response to. 59 ID *ID `json:"id,omitempty"` 60} 61 62// Error represents a structured error in a Response. 63type Error struct { 64 // Code is an error code indicating the type of failure. 65 Code int64 `json:"code"` 66 // Message is a short description of the error. 67 Message string `json:"message"` 68 // Data is optional structured data containing additional information about the error. 69 Data *json.RawMessage `json:"data"` 70} 71 72// VersionTag is a special 0 sized struct that encodes as the jsonrpc version 73// tag. 74// It will fail during decode if it is not the correct version tag in the 75// stream. 76type VersionTag struct{} 77 78// ID is a Request identifier. 79// Only one of either the Name or Number members will be set, using the 80// number form if the Name is the empty string. 81type ID struct { 82 Name string 83 Number int64 84} 85 86// IsNotify returns true if this request is a notification. 87func (r *Request) IsNotify() bool { 88 return r.ID == nil 89} 90 91func (err *Error) Error() string { 92 if err == nil { 93 return "" 94 } 95 return err.Message 96} 97 98func (VersionTag) MarshalJSON() ([]byte, error) { 99 return json.Marshal("2.0") 100} 101 102func (VersionTag) UnmarshalJSON(data []byte) error { 103 version := "" 104 if err := json.Unmarshal(data, &version); err != nil { 105 return err 106 } 107 if version != "2.0" { 108 return fmt.Errorf("Invalid RPC version %v", version) 109 } 110 return nil 111} 112 113// String returns a string representation of the ID. 114// The representation is non ambiguous, string forms are quoted, number forms 115// are preceded by a # 116func (id *ID) String() string { 117 if id == nil { 118 return "" 119 } 120 if id.Name != "" { 121 return strconv.Quote(id.Name) 122 } 123 return "#" + strconv.FormatInt(id.Number, 10) 124} 125 126func (id *ID) MarshalJSON() ([]byte, error) { 127 if id.Name != "" { 128 return json.Marshal(id.Name) 129 } 130 return json.Marshal(id.Number) 131} 132 133func (id *ID) UnmarshalJSON(data []byte) error { 134 *id = ID{} 135 if err := json.Unmarshal(data, &id.Number); err == nil { 136 return nil 137 } 138 return json.Unmarshal(data, &id.Name) 139} 140