package wshandler import ( "encoding/json" "io" "reflect" "unsafe" "repositories.action2quare.com/ayo/gocommon/logger" ) const ( ClientConnected = "ClientConnected" ClientDisconnected = "ClientDisconnected" ) type apiFuncType func(ApiCallContext) type WebsocketApiHandler struct { methods map[string]apiFuncType connfunc apiFuncType disconnfunc apiFuncType } type ApiCallContext struct { CallBy *Sender Arguments []any } func MakeWebsocketApiHandler[T any](receiver *T, receiverName string) WebsocketApiHandler { methods := make(map[string]apiFuncType) tp := reflect.TypeOf(receiver) if len(receiverName) == 0 { receiverName = tp.Elem().Name() } var connfunc apiFuncType var disconnfunc apiFuncType for i := 0; i < tp.NumMethod(); i++ { method := tp.Method(i) if method.Type.NumIn() != 2 { continue } if method.Type.In(0) != tp { continue } if method.Type.In(1) != reflect.TypeOf((*ApiCallContext)(nil)).Elem() { continue } funcptr := method.Func.Pointer() p1 := unsafe.Pointer(&funcptr) p2 := unsafe.Pointer(&p1) testfunc := (*func(*T, ApiCallContext))(p2) if method.Name == ClientConnected { connfunc = func(ctx ApiCallContext) { (*testfunc)(receiver, ctx) } } else if method.Name == ClientDisconnected { disconnfunc = func(ctx ApiCallContext) { (*testfunc)(receiver, ctx) } } else { methods[receiverName+"."+method.Name] = func(ctx ApiCallContext) { (*testfunc)(receiver, ctx) } } } return WebsocketApiHandler{ methods: methods, connfunc: connfunc, disconnfunc: disconnfunc, } } type WebsocketApiBroker struct { methods map[string]apiFuncType connFuncs []apiFuncType disconnFuncs []apiFuncType } func (hc *WebsocketApiBroker) AddHandler(receiver WebsocketApiHandler) { if hc.methods == nil { hc.methods = make(map[string]apiFuncType) } for k, v := range receiver.methods { logger.Println("http api registered :", k) hc.methods[k] = v } if receiver.connfunc != nil { hc.connFuncs = append(hc.connFuncs, receiver.connfunc) } if receiver.disconnfunc != nil { // disconnfunc은 역순 hc.disconnFuncs = append([]apiFuncType{receiver.disconnfunc}, hc.disconnFuncs...) } } func (hc *WebsocketApiBroker) Call(callby *Sender, funcname string, r io.Reader) { if funcname == ClientConnected { for _, v := range hc.connFuncs { v(ApiCallContext{ CallBy: callby, Arguments: nil, }) } } else if funcname == ClientDisconnected { for _, v := range hc.disconnFuncs { v(ApiCallContext{ CallBy: callby, Arguments: nil, }) } } else if found := hc.methods[funcname]; found != nil { var args []any if r != nil { dec := json.NewDecoder(r) if err := dec.Decode(&args); err != nil { logger.Println("WebsocketApiBroker.Call failed. decode returns err :", err) } } found(ApiCallContext{ CallBy: callby, Arguments: args, }) } else { logger.Println("api is not found :", funcname) } }