-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/kgw jsonrpc #700
Feature/kgw jsonrpc #700
Conversation
After some dev on this issue, I realized that we might not want to support change the impl between jsonrpc and REST in gatewayclient, as it will require two set of configurations(kgw API can support both, but it requires different configuration of kwil-db REST/jsonrpc backend) |
jsonrpc "github.com/kwilteam/kwil-db/core/rpc/json" | ||
) | ||
|
||
const ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe should move to core/rpc/json
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe not, admin and function methods are in core/rpc/json
because it's also used in JSON rpc service server.
1b54713
to
a009f24
Compare
} | ||
err := errors.Join(jsonRPCErr, rpcErr) | ||
|
||
switch jsonRPCErr.Code { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we can delete this block(in every client)? IMO the jsonRPCErr.Code
is very specific, and more useful for app? @jchappelow
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the highest level clients want more abstraction i.e. shouldn't have to know about the jsonrpc package and codes at all. Also errors.Is(err, <some error kind in core/client package>)
is better for a user of core/client.Client
I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codes could move up to a package that's not jsonrpc specific? Or core/client could give a error code getter to extract one from this opaque error
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. this is in the jsonrpc package. Hmm. I guess core/client should be checking codes an translating to Go error types...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean in core/client and core/gatewayclient ? yeah maybe, I just see those errors are not used much really, most of the time we just pop it up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't gotten a solid solution yet, I'll leave it for now
04a05ea
to
81cc307
Compare
e92db20
to
56f6519
Compare
// call sends a JSON-RPC request to the gateway. | ||
// NOTE: this is basically a copy of core/rpc/client/user/jsonrpc/client.call | ||
func (cl *Client) call(ctx context.Context, method string, cmd, res any) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the other client we can export and call this CallMethod
, so that gateway client can embed it perhaps? We just want to add the two auth related methods right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I thought about it and totally forgot about it. I think we should do it. I copied bcz that's when we have two different branch , and my branch is based on another branch..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright I'll make the change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus I think if we go that route, we don't have to worry about id := g.reqID.Add(-1) // Decrement by 1, so it won't be duplicated with txClient
var jsonRPCErr *jsonrpc.Error | ||
if errors.As(err, &jsonRPCErr) { | ||
if jsonRPCErr.Code != jsonrpc.ErrorKGWNotAuthorized { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Yup! core/gatewayclient
can indeed interpret based on the jsonrpc code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is why I have the question #700 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this package, this makes sense. For the consumer of core/client or core/gatewayclient, they don't need know json rpc codes. If they want to introspect to see if it's a json-rpc error that's fine, but it's preferable for external developers to be able to do a simple errors.Is with one of our predefined types. At least that's how I feel for now.
if !errors.Is(err, rpcClient.ErrUnauthorized) { | ||
return nil, err | ||
|
||
var jsonRPCErr *jsonrpc.Error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should prefer this way of handling error or below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah just saw you commit
dcb7514
to
29bb90b
Compare
// JSONRPCClient is a JSON-RPC client that handles sending and receiving | ||
// JSON-RPC requests and responses. It is a low-level client that does not | ||
// care about the specifics of the JSON-RPC methods or responses. | ||
type JSONRPCClient struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well the naming is kind awkward, I tempted to name it like BaseRPCClient
. The reason is in the future say we support WS, we might have another base client
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh. But if we support websocket, that's still json-rpc, just using websocket. Anyway, I think JSONRPCClient
is appropriate, at least while it is defined in core/rpc/client
.
) | ||
|
||
// GatewayClient is a client that is made to interact with a kwil gateway. | ||
// It inherits the functionality of the main Kwil client, but also provides | ||
// authentication cookies to the gateway. | ||
// It automatically handles the authentication process with the gateway. | ||
type GatewayClient struct { | ||
client.Client | ||
client.Client // core client |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GatwayClient still needs this type embeded, I cannot move it to core/rpc/gateway/
, as core/rpc
are just client for handling exact input/output of APIs, but core/client
deals with user input/outputs.
@@ -45,13 +49,18 @@ func (c *Options) Apply(opts *Options) { | |||
c.ChainID = opts.ChainID | |||
} | |||
|
|||
if opts.Conn != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a thought on the style.
TBH, I don't like this way of passing options, i.e. Client(xx, optionObj)
, I prefer Client(xx, WithOptA, WithOptB...)
, and I kind of want to be able to apply those options to all our clients.
Currently we can reuse options though embed(like core/gatewayclient/opts.GatewayOptions
) , I'm not sure how to do it in Client(xx, WithOptA...)
style, maybe using interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have strong feelings about this, but the functional options pattern is generally more cumbersome and time consuming to use and modify compared to a config struct. Yet most of our code does functional options, so might as well here.
In general, I think the main benefit of functional options is on the highest level exported APIs because a config struct changing is technically a breaking change to the constructor while new option functions are not. With how unstable our Go APIs are all around, this benefit is almost non-existent.
Ironically, the most benefit for functional options is in core/client.NewClient
, but the transport-aware clients deeper in core/rpc/client/... benefit less from doing it that way.
Anyway, I don't mind any options refactoring you'd like to do, but the more internal things get, the less important it is to use functional options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, just have this thought so it's consistent everywhere.
I can work with current approach, at least all exposed clients are using config struct, it's consistent.
core/rpc/http/function/client.go
Outdated
@@ -52,7 +52,7 @@ type service struct { | |||
} | |||
|
|||
// NewAPIClient creates a new API client. Requires a userAgent string describing your application. | |||
// optionally a custom http.Client to allow for advanced features such as caching. | |||
// optionally a custom http.JSONRPCClient to allow for advanced features such as caching. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ehh sometime my IDE suggests too much refactor... Will change it back
// message (pb) types sent in POST, or just GET with endpoint implying method. | ||
// - the "method" in the outer request type is instead of the endpoint, all POST | ||
|
||
// Client is a JSON-RPC client for the Kwil user service. It use the JSONRPCClient |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we keep this file named "methods.go" (and squash all commits in this PR), git detects the rename/move of client.go and the diff for both that file and methods.go is minimized.
i.e.
-------------------------- core/rpc/client/jsonrpc.go --------------------------
similarity index 81%
rename from core/rpc/client/user/jsonrpc/client.go
rename to core/rpc/client/jsonrpc.go
index cecb7df8..2059a708 100644
and core/rpc/client/user/jsonrpc/methods.go will have about a dozen lines changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool, I was totally not thinking about this. will change .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That change seems to have worked out well. We can track the changes now, and the PR was more reviewable. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reminding me this aspect as well
This add jsonrpc gateway client and use it as default implementation for gatewayclient. It has three methods, all in `kgw.` namespace, `kgw.authn_param`, `kgw.authn` and `kgw.logout` It has some duplicate(copied) base jsonrpc handling from core/rpc/client/user/jsonrpc
This extract JSONRPCClient type to handles request/response for JSON RPC. Thus elimates duplicated code in core/rpc/client/gateway/jsonrpc
c25fc68
to
70ec5d2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this "base client" / JSONRPCClient
approach does the trick nicely.
I think you're still working on some changes though?
I've done what I wanted. Will squash and merge. |
This resolves #694
This add a new kgw jsonrpc client, which will do all interactions with GKW using json rpc.