package wshandler import ( "encoding/json" "fmt" "io" "reflect" "strings" "go.mongodb.org/mongo-driver/bson/primitive" "repositories.action2quare.com/ayo/gocommon/logger" ) type PeerInterface interface { ClientDisconnected(string) } 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) (any, error) { if found := hc.methods[funcname]; found != nil { return found(recv, r) } return nil, fmt.Errorf("api is not found : %s", funcname) }