wshandler peer 추가
This commit is contained in:
187
wshandler/api_handler_peer.go
Normal file
187
wshandler/api_handler_peer.go
Normal file
@ -0,0 +1,187 @@
|
||||
package wshandler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
)
|
||||
|
||||
type peerApiFuncType func(any, []byte) (any, error)
|
||||
type peerConnFuncType func(any, *websocket.Conn)
|
||||
type peerDisconnFuncType func(any, string)
|
||||
|
||||
type WebsocketPeerApiHandler struct {
|
||||
methods map[string]peerApiFuncType
|
||||
connfunc peerConnFuncType
|
||||
disconnfunc peerDisconnFuncType
|
||||
originalReceiverName string
|
||||
}
|
||||
|
||||
func MakeWebsocketPeerApiHandler[T any](receiverName string) WebsocketPeerApiHandler {
|
||||
methods := make(map[string]peerApiFuncType)
|
||||
|
||||
var archetype *T
|
||||
tp := reflect.TypeOf(archetype)
|
||||
if len(receiverName) == 0 {
|
||||
receiverName = tp.Elem().Name()
|
||||
}
|
||||
|
||||
var connfunc peerConnFuncType
|
||||
var disconnfunc peerDisconnFuncType
|
||||
|
||||
for i := 0; i < tp.NumMethod(); i++ {
|
||||
method := tp.Method(i)
|
||||
if method.Type.In(0) != tp {
|
||||
continue
|
||||
}
|
||||
|
||||
if method.Name == ClientConnected {
|
||||
if method.Type.NumIn() != 2 {
|
||||
continue
|
||||
}
|
||||
if method.Type.In(1) != reflect.TypeOf((*websocket.Conn)(nil)) {
|
||||
continue
|
||||
}
|
||||
funcptr := method.Func.Pointer()
|
||||
p1 := unsafe.Pointer(&funcptr)
|
||||
p2 := unsafe.Pointer(&p1)
|
||||
connfuncptr := (*func(*T, *websocket.Conn))(p2)
|
||||
connfunc = func(r any, c *websocket.Conn) {
|
||||
(*connfuncptr)(r.(*T), c)
|
||||
}
|
||||
} else if method.Name == ClientDisconnected {
|
||||
if method.Type.NumIn() != 2 {
|
||||
continue
|
||||
}
|
||||
if method.Type.In(1) != reflect.TypeOf("") {
|
||||
continue
|
||||
}
|
||||
funcptr := method.Func.Pointer()
|
||||
p1 := unsafe.Pointer(&funcptr)
|
||||
p2 := unsafe.Pointer(&p1)
|
||||
disconnfuncptr := (*func(*T, string))(p2)
|
||||
disconnfunc = func(r any, msg string) {
|
||||
(*disconnfuncptr)(r.(*T), msg)
|
||||
}
|
||||
} else {
|
||||
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 any, buff []byte) (any, error) {
|
||||
decoder := json.NewDecoder(bytes.NewBuffer(buff))
|
||||
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{
|
||||
methods: methods,
|
||||
connfunc: connfunc,
|
||||
disconnfunc: disconnfunc,
|
||||
originalReceiverName: tp.Elem().Name(),
|
||||
}
|
||||
}
|
||||
|
||||
type WebsocketPeerApiBroker struct {
|
||||
methods map[string]peerApiFuncType
|
||||
connFuncs []peerConnFuncType
|
||||
disconnFuncs []peerDisconnFuncType
|
||||
CreatePeer func(primitive.ObjectID) any
|
||||
}
|
||||
|
||||
func (hc *WebsocketPeerApiBroker) AddHandler(receiver WebsocketPeerApiHandler) {
|
||||
if hc.methods == nil {
|
||||
hc.methods = make(map[string]peerApiFuncType)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if receiver.connfunc != nil {
|
||||
logger.Printf("ws api registered : %s.ClientConnected\n", receiver.originalReceiverName)
|
||||
hc.connFuncs = append(hc.connFuncs, receiver.connfunc)
|
||||
}
|
||||
|
||||
if receiver.disconnfunc != nil {
|
||||
// disconnfunc은 역순
|
||||
logger.Printf("ws api registered : %s.ClientDisconnected\n", receiver.originalReceiverName)
|
||||
hc.disconnFuncs = append([]peerDisconnFuncType{receiver.disconnfunc}, hc.disconnFuncs...)
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *WebsocketPeerApiBroker) ClientConnected(recv any, c *wsconn) {
|
||||
for _, v := range hc.connFuncs {
|
||||
v(recv, c.Conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *WebsocketPeerApiBroker) ClientDisconnected(recv any, c *wsconn) {
|
||||
for _, v := range hc.disconnFuncs {
|
||||
v(recv, c.closeMessage)
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *WebsocketPeerApiBroker) Call(recv any, funcname string, buff []byte) {
|
||||
if found := hc.methods[funcname]; found != nil {
|
||||
_, err := found(recv, buff)
|
||||
if err != nil {
|
||||
logger.Println("api call is failed. err :", err)
|
||||
}
|
||||
} else {
|
||||
logger.Println("api is not found :", funcname)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user