mirror of
https://github.com/hanzoai/psrpc.git
synced 2026-09-30 23:47:22 +00:00
PSRPC for Hanzo LiveKit, forked from livekit/psrpc (Apache-2.0). Two rewrites: github.com/livekit/psrpc -> github.com/hanzoai/psrpc github.com/redis/go-redis/v9 -> github.com/hanzokv/go/v9 psrpc's message bus (bus.go, internal/bus/bus_redis.go, internal/bus/bustest) speaks to a KV over go-redis. After hanzoai/livekit moved to our client, psrpc was the one remaining edge pulling upstream go-redis into that binary — not our code, but our dependency, the same shape redsync had for hanzoai/git. The other livekit/* modules (protocol, mediatransportutil, mageutil) are NOT forked and should not be: none of them touch a KV client, so they are ordinary external dependencies and their names are addresses.
180 lines
5.5 KiB
Go
180 lines
5.5 KiB
Go
// Copyright 2023 LiveKit, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package interceptors
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/hanzoai/psrpc"
|
|
"github.com/hanzoai/psrpc/internal"
|
|
"github.com/hanzoai/psrpc/pkg/info"
|
|
"github.com/hanzoai/psrpc/pkg/middleware"
|
|
)
|
|
|
|
func TestInterceptors(t *testing.T) {
|
|
s := ""
|
|
|
|
createInterceptor := func(i int) psrpc.ServerRPCInterceptor {
|
|
return func(ctx context.Context, req proto.Message, _ psrpc.RPCInfo, handler psrpc.ServerRPCHandler) (proto.Message, error) {
|
|
s += fmt.Sprint(i)
|
|
res, err := handler(ctx, req)
|
|
s += fmt.Sprint(i)
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
var code psrpc.ErrorCode
|
|
serverErrorLogger := func(ctx context.Context, req proto.Message, _ psrpc.RPCInfo, handler psrpc.ServerRPCHandler) (proto.Message, error) {
|
|
resp, err := handler(ctx, req)
|
|
if err != nil {
|
|
code = psrpc.Unknown
|
|
if e, ok := err.(psrpc.Error); ok {
|
|
code = e.Code()
|
|
}
|
|
}
|
|
return resp, err
|
|
}
|
|
|
|
interceptors := []psrpc.ServerRPCInterceptor{
|
|
serverErrorLogger,
|
|
createInterceptor(1),
|
|
createInterceptor(2),
|
|
createInterceptor(3),
|
|
middleware.WithServerRecovery(),
|
|
}
|
|
chained := ChainServerInterceptors(interceptors)
|
|
svcImpl := func(ctx context.Context, _ proto.Message) (proto.Message, error) {
|
|
s += fmt.Sprint(4)
|
|
panic("panic")
|
|
}
|
|
|
|
handler := func(ctx context.Context, req proto.Message) (proto.Message, error) {
|
|
rpcInfo := psrpc.RPCInfo{Method: "myRPC"}
|
|
res, err := chained(ctx, req, rpcInfo, func(context.Context, proto.Message) (proto.Message, error) {
|
|
return svcImpl(ctx, req)
|
|
})
|
|
return res, err
|
|
}
|
|
|
|
_, err := handler(context.Background(), nil)
|
|
require.Error(t, err)
|
|
require.Equal(t, "1234321", s)
|
|
require.Equal(t, psrpc.Internal, code)
|
|
}
|
|
|
|
type testContextKey string
|
|
|
|
func TestRPCInterceptors(t *testing.T) {
|
|
s := ""
|
|
|
|
newTestInterceptor := func(k string) psrpc.ClientRPCInterceptor {
|
|
return func(rpcInfo psrpc.RPCInfo, next psrpc.ClientRPCHandler) psrpc.ClientRPCHandler {
|
|
return func(ctx context.Context, req proto.Message, opts ...psrpc.RequestOption) (res proto.Message, err error) {
|
|
ctx = context.WithValue(ctx, testContextKey(k), true)
|
|
opts = append(opts, psrpc.WithRequestTimeout(0))
|
|
s += k
|
|
res, err = next(ctx, req, opts...)
|
|
s += k
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
handler := func(ctx context.Context, req proto.Message, opts ...psrpc.RequestOption) (res proto.Message, err error) {
|
|
require.Equal(t, true, ctx.Value(testContextKey("1")).(bool))
|
|
require.Equal(t, true, ctx.Value(testContextKey("2")).(bool))
|
|
require.Equal(t, true, ctx.Value(testContextKey("3")).(bool))
|
|
require.Equal(t, 3, len(opts))
|
|
s += "4"
|
|
return nil, psrpc.ErrNoResponse
|
|
}
|
|
|
|
interceptors := []psrpc.ClientRPCInterceptor{
|
|
newTestInterceptor("1"),
|
|
newTestInterceptor("2"),
|
|
newTestInterceptor("3"),
|
|
}
|
|
_, err := ChainClientInterceptors[psrpc.ClientRPCHandler](interceptors, &info.RequestInfo{}, handler)(context.Background(), &internal.Request{})
|
|
require.Equal(t, "1234321", s)
|
|
require.Equal(t, psrpc.ErrNoResponse, err)
|
|
}
|
|
|
|
type testMultiRPCInterceptor struct {
|
|
psrpc.ClientMultiRPCHandler
|
|
sendFunc func(ctx context.Context, msg proto.Message, opts ...psrpc.RequestOption) error
|
|
recvFunc func(msg proto.Message, err error)
|
|
}
|
|
|
|
func (t *testMultiRPCInterceptor) Send(ctx context.Context, msg proto.Message, opts ...psrpc.RequestOption) (err error) {
|
|
return t.sendFunc(ctx, msg, opts...)
|
|
}
|
|
|
|
func (t *testMultiRPCInterceptor) Recv(msg proto.Message, err error) {
|
|
t.recvFunc(msg, err)
|
|
}
|
|
|
|
func TestMultiRPCInterceptors(t *testing.T) {
|
|
s := ""
|
|
|
|
newTestInterceptor := func(k string) psrpc.ClientMultiRPCInterceptor {
|
|
return func(rpcInfo psrpc.RPCInfo, next psrpc.ClientMultiRPCHandler) psrpc.ClientMultiRPCHandler {
|
|
return &testMultiRPCInterceptor{
|
|
sendFunc: func(ctx context.Context, msg proto.Message, opts ...psrpc.RequestOption) error {
|
|
ctx = context.WithValue(ctx, testContextKey(k), true)
|
|
opts = append(opts, psrpc.WithRequestTimeout(0))
|
|
s += k
|
|
return next.Send(ctx, msg, opts...)
|
|
},
|
|
recvFunc: func(msg proto.Message, err error) {
|
|
next.Recv(msg, err)
|
|
s += k
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
ok := errors.New("ok")
|
|
|
|
handler := &testMultiRPCInterceptor{
|
|
sendFunc: func(ctx context.Context, msg proto.Message, opts ...psrpc.RequestOption) error {
|
|
require.Equal(t, true, ctx.Value(testContextKey("1")).(bool))
|
|
require.Equal(t, true, ctx.Value(testContextKey("2")).(bool))
|
|
require.Equal(t, true, ctx.Value(testContextKey("3")).(bool))
|
|
require.Equal(t, 3, len(opts))
|
|
return ok
|
|
},
|
|
recvFunc: func(msg proto.Message, err error) {
|
|
s += "4"
|
|
},
|
|
}
|
|
|
|
interceptors := []psrpc.ClientMultiRPCInterceptor{
|
|
newTestInterceptor("1"),
|
|
newTestInterceptor("2"),
|
|
newTestInterceptor("3"),
|
|
}
|
|
interceptor := ChainClientInterceptors[psrpc.ClientMultiRPCHandler](interceptors, &info.RequestInfo{}, handler)
|
|
err := interceptor.Send(context.Background(), &internal.Request{})
|
|
interceptor.Recv(nil, nil)
|
|
require.Equal(t, "1234321", s)
|
|
require.Equal(t, ok, err)
|
|
}
|