ws peer 를 제네릭으로 변경

This commit is contained in:
2023-12-20 10:02:49 +09:00
parent b2ee40249a
commit 00f4cab992
3 changed files with 89 additions and 144 deletions

View File

@ -6,144 +6,108 @@ import (
"io"
"reflect"
"strings"
"unsafe"
"github.com/gorilla/websocket"
"go.mongodb.org/mongo-driver/bson/primitive"
"repositories.action2quare.com/ayo/gocommon/logger"
)
type peerApiFuncType func(any, io.Reader) (any, error)
type peerConnFuncType func(any, *websocket.Conn)
type peerDisconnFuncType func(any, string)
type PeerInterface interface {
ClientDisconnected(string)
}
type peerApiFuncType[T PeerInterface] func(T, io.Reader) (any, error)
type WebsocketPeerApiHandler struct {
methods map[string]peerApiFuncType
connfunc peerConnFuncType
disconnfunc peerDisconnFuncType
type WebsocketPeerApiHandler[T PeerInterface] struct {
methods map[string]peerApiFuncType[T]
originalReceiverName string
}
func MakeWebsocketPeerApiHandler[T any](receiverName string) WebsocketPeerApiHandler {
methods := make(map[string]peerApiFuncType)
func MakeWebsocketPeerApiHandler[T PeerInterface](receiverName string) WebsocketPeerApiHandler[T] {
methods := make(map[string]peerApiFuncType[T])
var archetype *T
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))
}
if method.Name == ClientDisconnected {
continue
}
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()) {
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[1].Interface() == nil {
return out[0].Interface(), nil
if out[0].Interface() == nil {
return nil, nil
}
return out[0].Interface(), out[1].Interface().(error)
return nil, out[0].Interface().(error)
}
} else {
outconv = func(out []reflect.Value) (any, error) {
return out[0].Interface(), nil
}
}
methods[receiverName+"."+method.Name] = func(recv any, 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()
} 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
}
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 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{
return WebsocketPeerApiHandler[T]{
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
type WebsocketPeerApiBroker[T PeerInterface] struct {
methods map[string]peerApiFuncType[T]
CreatePeer func(primitive.ObjectID) T
}
func (hc *WebsocketPeerApiBroker) AddHandler(receiver WebsocketPeerApiHandler) {
func (hc *WebsocketPeerApiBroker[T]) AddHandler(receiver WebsocketPeerApiHandler[T]) {
if hc.methods == nil {
hc.methods = make(map[string]peerApiFuncType)
hc.methods = make(map[string]peerApiFuncType[T])
}
for k, v := range receiver.methods {
@ -151,32 +115,9 @@ func (hc *WebsocketPeerApiBroker) AddHandler(receiver WebsocketPeerApiHandler) {
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 *websocket.Conn) {
for _, v := range hc.connFuncs {
v(recv, c)
}
}
func (hc *WebsocketPeerApiBroker) ClientDisconnected(recv any, reason string) {
for _, v := range hc.disconnFuncs {
v(recv, reason)
}
}
func (hc *WebsocketPeerApiBroker) Call(recv any, funcname string, r io.Reader) (any, error) {
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)
}