140 lines
2.9 KiB
Go
140 lines
2.9 KiB
Go
|
|
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)
|
||
|
|
}
|
||
|
|
}
|