diff options
author | Alexander Kiryukhin <a.kiryukhin@mail.ru> | 2022-05-28 16:53:20 +0300 |
---|---|---|
committer | Alexander Kiryukhin <a.kiryukhin@mail.ru> | 2022-05-28 16:53:20 +0300 |
commit | f304a07a8cfe67b2a65f95f27eb10a9b854c4ef8 (patch) | |
tree | 9e6a7e9ea6b8d600cccac5a5d50f3232d631d073 /rpc/middleware | |
parent | 281eda83c9f4bcb06318444df3574df0840205fa (diff) |
Improved middlewares
Diffstat (limited to 'rpc/middleware')
-rw-r--r-- | rpc/middleware/logger.go | 41 | ||||
-rw-r--r-- | rpc/middleware/validation.go | 72 |
2 files changed, 113 insertions, 0 deletions
diff --git a/rpc/middleware/logger.go b/rpc/middleware/logger.go new file mode 100644 index 0000000..dbf5a4d --- /dev/null +++ b/rpc/middleware/logger.go @@ -0,0 +1,41 @@ +//Package middleware provides middlewares for rpc server +// +//Copyright (C) 2022 Alexander Kiryukhin <i@neonxp.dev> +// +//This file is part of go.neonxp.dev/jsonrpc2 project. +// +//This program is free software: you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program. If not, see <https://www.gnu.org/licenses/>. + +package middleware + +import ( + "context" + "strings" + "time" + + "go.neonxp.dev/jsonrpc2/rpc" +) + +func Logger(logger rpc.Logger) rpc.Middleware { + return func(handler rpc.RpcHandler) rpc.RpcHandler { + return func(ctx context.Context, req *rpc.RpcRequest) *rpc.RpcResponse { + t1 := time.Now().UnixMicro() + resp := handler(ctx, req) + t2 := time.Now().UnixMicro() + args := strings.ReplaceAll(string(req.Params), "\n", "") + logger.Logf("rpc call=%s, args=%s, take=%dμs", req.Method, args, (t2 - t1)) + return resp + } + } +} diff --git a/rpc/middleware/validation.go b/rpc/middleware/validation.go new file mode 100644 index 0000000..e994383 --- /dev/null +++ b/rpc/middleware/validation.go @@ -0,0 +1,72 @@ +//Package middleware provides middlewares for rpc server +// +//Copyright (C) 2022 Alexander Kiryukhin <i@neonxp.dev> +// +//This file is part of go.neonxp.dev/jsonrpc2 project. +// +//This program is free software: you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation, either version 3 of the License, or +//(at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program. If not, see <https://www.gnu.org/licenses/>. + +package middleware + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/qri-io/jsonschema" + + "go.neonxp.dev/jsonrpc2/rpc" +) + +type MethodSchema struct { + Request jsonschema.Schema + Response jsonschema.Schema +} + +func Validation(serviceSchema map[string]MethodSchema) (rpc.Middleware, error) { + return func(handler rpc.RpcHandler) rpc.RpcHandler { + return func(ctx context.Context, req *rpc.RpcRequest) *rpc.RpcResponse { + if rs, ok := serviceSchema[strings.ToLower(req.Method)]; ok { + if errResp := formatError(ctx, req.Id, rs.Request, req.Params); errResp != nil { + return errResp + } + resp := handler(ctx, req) + if errResp := formatError(ctx, req.Id, rs.Response, resp.Result); errResp != nil { + return errResp + } + return resp + } + return handler(ctx, req) + } + }, nil +} + +func formatError(ctx context.Context, requestId any, schema jsonschema.Schema, data json.RawMessage) *rpc.RpcResponse { + errs, err := schema.ValidateBytes(ctx, data) + if err != nil { + return rpc.ErrorResponse(requestId, err) + } + if errs != nil && len(errs) > 0 { + messages := []string{} + for _, msg := range errs { + messages = append(messages, fmt.Sprintf("%s: %s", msg.PropertyPath, msg.Message)) + } + return rpc.ErrorResponse(requestId, rpc.Error{ + Code: rpc.ErrCodeInvalidParams, + Message: strings.Join(messages, "\n"), + }) + } + return nil +} |