diff --git a/wshandler/api_handler_peer.go b/wshandler/api_handler_peer.go deleted file mode 100644 index ec0d73a..0000000 --- a/wshandler/api_handler_peer.go +++ /dev/null @@ -1,136 +0,0 @@ -package wshandler - -import ( - "encoding/json" - "fmt" - "io" - "reflect" - "strings" - - "github.com/gorilla/websocket" - "go.mongodb.org/mongo-driver/bson/primitive" - "repositories.action2quare.com/ayo/gocommon/logger" -) - -type PeerInterface interface { - ClientDisconnected(string) - ClientConnected(*websocket.Conn) -} -type peerApiFuncType[T PeerInterface] func(T, io.Reader) (any, error) - -type WebsocketPeerApiHandler[T PeerInterface] struct { - methods map[string]peerApiFuncType[T] - originalReceiverName string -} - -func MakeWebsocketPeerApiHandler[T PeerInterface](receiverName string) WebsocketPeerApiHandler[T] { - methods := make(map[string]peerApiFuncType[T]) - - var archetype T - tp := reflect.TypeOf(archetype) - if len(receiverName) == 0 { - receiverName = tp.Elem().Name() - } - - for i := 0; i < tp.NumMethod(); i++ { - method := tp.Method(i) - if method.Type.In(0) != tp { - continue - } - - if method.Name == ClientDisconnected { - continue - } - - var intypes []reflect.Type - for i := 1; i < method.Type.NumIn(); i++ { - intypes = append(intypes, method.Type.In(i)) - } - - var outconv func([]reflect.Value) (any, error) - if method.Type.NumOut() == 0 { - outconv = func([]reflect.Value) (any, error) { return nil, nil } - } else if method.Type.NumOut() == 1 { - if method.Type.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) { - outconv = func(out []reflect.Value) (any, error) { - if out[0].Interface() == nil { - return nil, nil - } - return nil, out[0].Interface().(error) - } - } else { - outconv = func(out []reflect.Value) (any, error) { - return out[0].Interface(), nil - } - } - } else if method.Type.NumOut() == 2 && method.Type.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { - outconv = func(out []reflect.Value) (any, error) { - if out[1].Interface() == nil { - return out[0].Interface(), nil - } - return out[0].Interface(), out[1].Interface().(error) - } - } - - methods[receiverName+"."+method.Name] = func(recv T, r io.Reader) (any, error) { - decoder := json.NewDecoder(r) - inargs := make([]any, len(intypes)) - - for i, intype := range intypes { - zerovalueptr := reflect.New(intype) - inargs[i] = zerovalueptr.Interface() - } - - err := decoder.Decode(&inargs) - if err != nil { - return nil, err - } - - reflectargs := make([]reflect.Value, 0, len(inargs)+1) - reflectargs = append(reflectargs, reflect.ValueOf(recv)) - for _, p := range inargs { - reflectargs = append(reflectargs, reflect.ValueOf(p).Elem()) - } - - return outconv(method.Func.Call(reflectargs)) - } - } - - return WebsocketPeerApiHandler[T]{ - methods: methods, - originalReceiverName: tp.Elem().Name(), - } -} - -type WebsocketPeerApiBroker[T PeerInterface] struct { - methods map[string]peerApiFuncType[T] - CreatePeer func(primitive.ObjectID) T -} - -func (hc *WebsocketPeerApiBroker[T]) AddHandler(receiver WebsocketPeerApiHandler[T]) { - if hc.methods == nil { - hc.methods = make(map[string]peerApiFuncType[T]) - } - - for k, v := range receiver.methods { - ab := strings.Split(k, ".") - logger.Printf("ws api registered : %s.%s -> %s\n", receiver.originalReceiverName, ab[1], k) - hc.methods[k] = v - } -} - -func (hc *WebsocketPeerApiBroker[T]) Call(recv T, funcname string, r io.Reader) (v any, e error) { - defer func() { - r := recover() - if r != nil { - logger.Error(r) - e = fmt.Errorf("%v", r) - } - }() - - if found := hc.methods[funcname]; found != nil { - return found(recv, r) - } - - return nil, fmt.Errorf("api is not found : %s", funcname) -} diff --git a/wshandler/api_handler_test.go b/wshandler/api_handler_test.go index 72ad7ad..797e067 100644 --- a/wshandler/api_handler_test.go +++ b/wshandler/api_handler_test.go @@ -96,9 +96,7 @@ func (dsc *dummySessionConsumer) Touch(string) (session.Authorization, error) { } func TestPeerApiBroker(t *testing.T) { - handler := MakeWebsocketPeerApiHandler[*testpeer]("test") - ws := NewWebsocketPeerHandler[*testpeer](&dummySessionConsumer{}) - ws.AddHandler(handler) + ws := NewWebsocketPeerHandler[*testpeer](&dummySessionConsumer{}, "test") tp := &testpeer{ id: "onlyone", diff --git a/wshandler/wshandler_peer.go b/wshandler/wshandler_peer.go index 49a6f09..e759e4e 100644 --- a/wshandler/wshandler_peer.go +++ b/wshandler/wshandler_peer.go @@ -7,6 +7,7 @@ import ( "io" "math/rand" "net/http" + "reflect" "strings" "time" @@ -19,13 +20,130 @@ import ( ) type WebsocketPeerHandler[T PeerInterface] struct { - WebsocketPeerApiBroker[T] + methods map[string]peerApiFuncType[T] + CreatePeer func(primitive.ObjectID) T sessionConsumer session.Consumer } -func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer) WebsocketPeerHandler[T] { +type PeerInterface interface { + ClientDisconnected(string) + ClientConnected(*websocket.Conn) +} +type peerApiFuncType[T PeerInterface] func(T, io.Reader) (any, error) + +type websocketPeerApiHandler[T PeerInterface] struct { + methods map[string]peerApiFuncType[T] + originalReceiverName string +} + +func (hc *WebsocketPeerHandler[T]) Call(recv T, funcname string, r io.Reader) (v any, e error) { + defer func() { + r := recover() + if r != nil { + logger.Error(r) + e = fmt.Errorf("%v", r) + } + }() + + if found := hc.methods[funcname]; found != nil { + return found(recv, r) + } + + return nil, fmt.Errorf("api is not found : %s", funcname) +} + +func makeWebsocketPeerApiHandler[T PeerInterface](receiverName string) websocketPeerApiHandler[T] { + methods := make(map[string]peerApiFuncType[T]) + + var archetype T + tp := reflect.TypeOf(archetype) + if len(receiverName) == 0 { + receiverName = tp.Elem().Name() + } + + for i := 0; i < tp.NumMethod(); i++ { + method := tp.Method(i) + if method.Type.In(0) != tp { + continue + } + + if method.Name == ClientDisconnected { + continue + } + + var intypes []reflect.Type + for i := 1; i < method.Type.NumIn(); i++ { + intypes = append(intypes, method.Type.In(i)) + } + + var outconv func([]reflect.Value) (any, error) + if method.Type.NumOut() == 0 { + outconv = func([]reflect.Value) (any, error) { return nil, nil } + } else if method.Type.NumOut() == 1 { + if method.Type.Out(0).Implements(reflect.TypeOf((*error)(nil)).Elem()) { + outconv = func(out []reflect.Value) (any, error) { + if out[0].Interface() == nil { + return nil, nil + } + return nil, out[0].Interface().(error) + } + } else { + outconv = func(out []reflect.Value) (any, error) { + return out[0].Interface(), nil + } + } + } else if method.Type.NumOut() == 2 && method.Type.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) { + outconv = func(out []reflect.Value) (any, error) { + if out[1].Interface() == nil { + return out[0].Interface(), nil + } + return out[0].Interface(), out[1].Interface().(error) + } + } + + methods[receiverName+"."+method.Name] = func(recv T, r io.Reader) (any, error) { + decoder := json.NewDecoder(r) + inargs := make([]any, len(intypes)) + + for i, intype := range intypes { + zerovalueptr := reflect.New(intype) + inargs[i] = zerovalueptr.Interface() + } + + err := decoder.Decode(&inargs) + if err != nil { + return nil, err + } + + reflectargs := make([]reflect.Value, 0, len(inargs)+1) + reflectargs = append(reflectargs, reflect.ValueOf(recv)) + for _, p := range inargs { + reflectargs = append(reflectargs, reflect.ValueOf(p).Elem()) + } + + return outconv(method.Func.Call(reflectargs)) + } + } + + return websocketPeerApiHandler[T]{ + methods: methods, + originalReceiverName: tp.Elem().Name(), + } +} + +func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer, receiverName string) WebsocketPeerHandler[T] { + methods := make(map[string]peerApiFuncType[T]) + receiver := makeWebsocketPeerApiHandler[T](receiverName) + + for k, v := range receiver.methods { + ab := strings.Split(k, ".") + logger.Printf("ws api registered : %s.%s -> %s\n", receiver.originalReceiverName, ab[1], k) + methods[k] = v + } + return WebsocketPeerHandler[T]{ sessionConsumer: consumer, + methods: methods, } }