powerman / rpc-codec Goto Github PK
View Code? Open in Web Editor NEWJSON-RPC 2.0 codec for Go net/rpc standard library
License: MIT License
JSON-RPC 2.0 codec for Go net/rpc standard library
License: MIT License
I'm running jsonrpc2 with custom ReadWriteCloser becuase the underlying connection is Websocket.
s.ServeCodec(jsonrpc2.NewServerCodec(rwc, nil))
If you look at the go/src/encoding/json/stream.go:144 (refill method), the default slice size is "const minRead = 512"
So, the stream calls my Read() method by asking for exactly 512 bytes. If I have a json message with exactly that size then the Read() returns n=512 and err=nil
Then the stream calls Read() again, by asking again for new 512 bytes. Since there is no data to return, the method returns n=0, and err=io.EOF which is what is expected by the Reader interface.
Unfortunately that produces "empty" string/json, so that propagates back to ReadRequestHeader method ( go/src/github.com/powerman/rpc-codec/jsonrpc2/server.go ),which cause errParse and shutdown of the RPC handler/current websocket connection.
The only workaround in my Read() is to return the second time n=0, err=nil which is "discouraged" according to the documentation.
Hello,
I'm using your rpc-codec library in order to create a wrapper from Zabbix' API.
https://zabbix.com/documentation/4.0/manual/api
In their documentation they use a custom field "Auth" containing a token obtained after the login. How can I make a call with customs field like this?
{ "jsonrpc": "2.0", "method": "host.get", "params": { "output": [ "hostid", "host" ], "selectInterfaces": [ "interfaceid", "ip" ] }, "id": 2, "auth": "0424bd59b807674191e7d77572075f33" }
hi,
according to the jsonrpc spec:
http://www.jsonrpc.org/specification#response_object
in the response the
"jsonrpc":"2.0"
filed is NOT REQUIRED just optional. while your implementation failed if it's missing. IMHO it's a bug and would be useful to fix.
the same can be seen here:
https://en.wikipedia.org/wiki/JSON-RPC
regards.
At a glance it looks too complicated and it isn't clear is it really useful.
Hi all,
i would like to measure the runtimes each call is taking and group it by the jsonrpc method using the following code:
func handleRequest(ctx context.Context, rc io.ReadCloser) bytes.Buffer {
var res bytes.Buffer
codec := jsonrpc2.NewServerCodecContext(ctx, struct {
io.ReadCloser
io.Writer
}{
rc,
&res,
}, nil)
err := rpc.ServeRequest(codec)
if err != nil {
log.WithError(err).Error("rpc.ServeRequest")
}
fmt.Printf("%+v\n", codec)
return res
}
the data i am looking for is already in the "codec" variable after rpc.ServeRequest:
&{encmutex:{state:0 sema:0} dec:0xc00157fce0 enc:0xc004b47540 c:{ReadCloser:{Reader:0xc00137b8c0} Writer:0xc00137b8f0} srv:0xc0000ec140 ctx:0xc00137b7d0 req:{Version:2.0 Method:System.Hello Params:0xc0053867e0 ID:} mutex:{state:0 sema:0} seq:1 pending:map[]
but i am unable to access it due to "req" not being exported.
Is there really no other way but to decode the json a second time just to get the method name?
Many thanks in advance!
As mentioned in JSON-RPC over HTTP specification Content-Type SHOULD be application/json-rpc
but MAY be application/json
or application/jsonrequest
and The Accept MUST be specified and SHOULD read application/json-rpc
but MAY be application/json
or application/jsonrequest
. Is there any chance for supporting this specification in http.go
?
I have this code:
package main
import (
"io"
"net"
"net/http"
"net/rpc"
"github.com/powerman/rpc-codec/jsonrpc2"
)
type HttpConn struct {
in io.Reader
out io.Writer
}
func (c *HttpConn) Read(p []byte) (n int, err error) {
return c.in.Read(p)
}
func (c *HttpConn) Write(d []byte) (n int, err error) {
return c.out.Write(d)
}
func (c *HttpConn) Close() error {
return nil
}
type Test struct{}
type TestHelloArgs struct {
Name string
}
var server *rpc.Server
func (test *Test) Hello(args *TestHelloArgs, result *string) error {
*result = "Hello " + args.Name
return nil
}
func main() {
server = rpc.NewServer()
_ = server.Register(&Test{})
listener, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
_ = http.Serve(listener, http.HandlerFunc(handler))
}
func handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/rpc" {
serverCodec := jsonrpc2.NewServerCodec(&HttpConn{in: r.Body, out: w}, server )
w.Header().Set( "Content-type", "application/json" )
w.WriteHeader(200)
if err1 := server.ServeRequest(serverCodec) ; err1 != nil {
http.Error(w, "Error while serving JSON request", 500)
return
}
} else {
http.Error(w, "Unknown request", 404)
}
}
I send HTTP-request:
POST http://localhost:8080/rpc
Content-Type: application/json
[
{
"jsonrpc": "2.0",
"method": "Test.Hello",
"params": {
"Name": "R1"
},
"id": "a"
},
{
"jsonrpc": "2.0",
"method": "Test.Hello",
"params": [
"R2"
],
"id": "z"
}
]
... and response:
HTTP/1.1 200 OK
Content-Type: application/json
Date: Wed, 26 Jun 2019 10:45:41 GMT
Content-Length: 122
[
{
"jsonrpc": "2.0",
"id": "a",
"result": "Hello R1"
},
{
"jsonrpc": "2.0",
"id": "z",
"error": {
"code": -32602,
"message": "bad request"
}
}
]
How to make it so that I can use both named and positional parameters
The response returned by this package always contains a result and error attribute. According to the specification those attributes are mutually exclusive:
Response Object
...
result
This member is REQUIRED on success.
This member MUST NOT exist if there was an error invoking the method.
The value of this member is determined by the method invoked on the Server.error
This member is REQUIRED on error.
This member MUST NOT exist if there was no error triggered during invocation.
The value for this member MUST be an Object as defined in section 5.1.
Hi,
Is there an example where we use tcp as transport and have the params as json (encoded) string.
The below code gives me
error:invalid character 'C' looking for beginning of value exit status 1
package main
import (
"encoding/json"
"log"
"net"
"net/rpc/jsonrpc"
"github.com/powerman/rpc-codec"
)
var params interface{}
func main() {
conn, err := net.Dial("tcp", "localhost:7777") // works fine
if err != nil {
panic(err)
}
defer conn.Close()
con := jsonrpc.NewClient(conn)
var paramsJSON string
paramsJSON = `` //`{"namedArg1":"value"}`
err = json.Unmarshal([]byte(paramsJSON), ¶ms)
var result interface{}
err1 := con.Call("help", params, &result)
if err1 != nil {
log.Fatal("error:", err1)
}
log.Printf("%v", reply)
}
I'm converting a legacy system from Python into Go, and I have some restrictions on the method names that don't work with Go's RPC layer and rpc-codec. The legacy method names are all lowercase and do not have a namespace structure "namespace.method". rpc-codec works great for me with a small hack to add "default." and capitalize the first letter of the method name. Is there an interest in making this part of rpc-codec. If desired, I could change this to a more generic "method transform" callback.
see:
For ex. if Content-Length: doesn't match content or if content isn't valid JSON.
Looks like now error message says about bad Content-Type text/โฆ if endpoint url is wrong and server respond with 404 - probably it'll be easier to debug if error message will contain HTTP status code instead.
I didn't find any example of server with batch requests.
It would be appreciated if you add some :)
Http client does not sent notification immediately. It sent a notification out when the next request is sent out via this http client. If you send only a notification over an http client, it will never really sent out.
I modified the package example for reproducing this bug.
See line 160 of https://play.golang.org/p/_uYiot-EyN
Does the project have the support of middlewares?
So if not - I can implement it.
Now I can just wrap around ServeHTTP function, but sometimes I wanna choose a group to wrap it.
Line 117 makes connection goroutine stuck.
Lines 107 to 121 in f48fde4
So after a couple of hours we have 2Gb of memory allocated. And it keeps growing.
I don't know how to fix it (don't even know where the real bug is) but we made a workaround:
func (conn *httpClientConn) Read(buf []byte) (int, error) {
if conn.body == nil {
select {
case conn.body = <-conn.ready:
case <-time.After(time.Second * 30):
return 0, io.EOF
}
}
...
}
Not a smart one but at least it stopped growing as fast as hell.
When i send Builtin type as params direct.
It report errors like this.
arith error:{"code":-32603,"message":"unsupported param type: string"}
arith error:{"code":-32603,"message":"unsupported param type: int"}
Especially for error handling.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.