코드 정리 및 websocket도 http와 비슷하게 api handler로 통일
This commit is contained in:
139
wshandler/api_handler.go
Normal file
139
wshandler/api_handler.go
Normal file
@ -0,0 +1,139 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user