2023-02-24 19:16:26 +08:00

99 lines
2.5 KiB
Go

package api2rpc
import (
"context"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
)
type rpcFunc[E, C, D any] func(client E, ctx context.Context, req *C, options ...grpc.CallOption) (*D, error)
func Rpc[A, B, C, D any, E any](apiReq *A, apiResp *B, rpc func(client E, ctx context.Context, req *C, options ...grpc.CallOption) (*D, error)) RpcCall[A, B, C, D, E] {
return &rpcCall[A, B, C, D, E]{
apiReq: apiReq,
apiResp: apiResp,
rpcFn: rpc,
}
}
type rpcCall[A, B, C, D any, E any] struct {
apiReq *A
apiResp *B
client func() (E, error)
rpcFn func(client E, ctx context.Context, req *C, options ...grpc.CallOption) (*D, error)
api Api
before func(apiReq *A, rpcReq *C, bind func() error) error
after func(rpcResp *D, apiResp *B, bind func() error) error
}
func (r *rpcCall[A, B, C, D, E]) Before(fn func(apiReq *A, rpcReq *C, bind func() error) error) RpcCall[A, B, C, D, E] {
r.before = fn
return r
}
func (r *rpcCall[A, B, C, D, E]) After(fn func(rpcResp *D, apiResp *B, bind func() error) error) RpcCall[A, B, C, D, E] {
r.after = fn
return r
}
func (r *rpcCall[A, B, C, D, E]) Must(c *gin.Context, client func() (E, error)) RpcCall[A, B, C, D, E] {
r.api = NewGin1(c)
r.client = client
return r
}
func (r *rpcCall[A, B, C, D, E]) Call() {
r.api.Resp(r.apiResp, r.call())
}
func (r *rpcCall[A, B, C, D, E]) defaultCopyReq(rpcReq *C) error {
if r.apiReq != nil {
CopyAny(r.apiReq, rpcReq)
}
return nil
}
func (r *rpcCall[A, B, C, D, E]) defaultCopyResp(rpcResp *D) error {
if r.apiResp != nil {
CopyAny(rpcResp, r.apiResp)
}
return nil
}
func (r *rpcCall[A, B, C, D, E]) call() error {
if err := r.api.Bind(r.apiReq); err != nil {
return err
}
var err error
var rpcReq C
if r.before == nil {
err = r.defaultCopyReq(&rpcReq)
} else {
err = r.before(r.apiReq, &rpcReq, func() error { return r.defaultCopyReq(&rpcReq) })
}
if err != nil {
return err
}
client, err := r.client()
if err != nil {
return err
}
rpcResp, err := r.rpcFn(client, r.api.Context(), &rpcReq)
if err != nil {
return err
}
var apiResp B
if r.after == nil {
return r.defaultCopyResp(rpcResp)
} else {
return r.after(rpcResp, &apiResp, func() error { return r.defaultCopyResp(rpcResp) })
}
}
type RpcCall[A, B, C, D, E any] interface {
Before(fn func(apiReq *A, rpcReq *C, bind func() error) error) RpcCall[A, B, C, D, E]
After(fn func(rpcResp *D, apiResp *B, bind func() error) error) RpcCall[A, B, C, D, E]
Must(c *gin.Context, client func() (E, error)) RpcCall[A, B, C, D, E]
Call()
}