peer handler 코드 정리
This commit is contained in:
@ -1,136 +0,0 @@
|
|||||||
package wshandler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PeerInterface interface {
|
|
||||||
ClientDisconnected(string)
|
|
||||||
ClientConnected(*websocket.Conn)
|
|
||||||
}
|
|
||||||
type peerApiFuncType[T PeerInterface] func(T, io.Reader) (any, error)
|
|
||||||
|
|
||||||
type WebsocketPeerApiHandler[T PeerInterface] struct {
|
|
||||||
methods map[string]peerApiFuncType[T]
|
|
||||||
originalReceiverName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeWebsocketPeerApiHandler[T PeerInterface](receiverName string) WebsocketPeerApiHandler[T] {
|
|
||||||
methods := make(map[string]peerApiFuncType[T])
|
|
||||||
|
|
||||||
var archetype T
|
|
||||||
tp := reflect.TypeOf(archetype)
|
|
||||||
if len(receiverName) == 0 {
|
|
||||||
receiverName = tp.Elem().Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < tp.NumMethod(); i++ {
|
|
||||||
method := tp.Method(i)
|
|
||||||
if method.Type.In(0) != tp {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if method.Name == ClientDisconnected {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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[T]{
|
|
||||||
methods: methods,
|
|
||||||
originalReceiverName: tp.Elem().Name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebsocketPeerApiBroker[T PeerInterface] struct {
|
|
||||||
methods map[string]peerApiFuncType[T]
|
|
||||||
CreatePeer func(primitive.ObjectID) T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *WebsocketPeerApiBroker[T]) AddHandler(receiver WebsocketPeerApiHandler[T]) {
|
|
||||||
if hc.methods == nil {
|
|
||||||
hc.methods = make(map[string]peerApiFuncType[T])
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hc *WebsocketPeerApiBroker[T]) Call(recv T, funcname string, r io.Reader) (v any, e error) {
|
|
||||||
defer func() {
|
|
||||||
r := recover()
|
|
||||||
if r != nil {
|
|
||||||
logger.Error(r)
|
|
||||||
e = fmt.Errorf("%v", r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if found := hc.methods[funcname]; found != nil {
|
|
||||||
return found(recv, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("api is not found : %s", funcname)
|
|
||||||
}
|
|
||||||
@ -96,9 +96,7 @@ func (dsc *dummySessionConsumer) Touch(string) (session.Authorization, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPeerApiBroker(t *testing.T) {
|
func TestPeerApiBroker(t *testing.T) {
|
||||||
handler := MakeWebsocketPeerApiHandler[*testpeer]("test")
|
ws := NewWebsocketPeerHandler[*testpeer](&dummySessionConsumer{}, "test")
|
||||||
ws := NewWebsocketPeerHandler[*testpeer](&dummySessionConsumer{})
|
|
||||||
ws.AddHandler(handler)
|
|
||||||
|
|
||||||
tp := &testpeer{
|
tp := &testpeer{
|
||||||
id: "onlyone",
|
id: "onlyone",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -19,13 +20,130 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WebsocketPeerHandler[T PeerInterface] struct {
|
type WebsocketPeerHandler[T PeerInterface] struct {
|
||||||
WebsocketPeerApiBroker[T]
|
methods map[string]peerApiFuncType[T]
|
||||||
|
CreatePeer func(primitive.ObjectID) T
|
||||||
sessionConsumer session.Consumer
|
sessionConsumer session.Consumer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer) WebsocketPeerHandler[T] {
|
type PeerInterface interface {
|
||||||
|
ClientDisconnected(string)
|
||||||
|
ClientConnected(*websocket.Conn)
|
||||||
|
}
|
||||||
|
type peerApiFuncType[T PeerInterface] func(T, io.Reader) (any, error)
|
||||||
|
|
||||||
|
type websocketPeerApiHandler[T PeerInterface] struct {
|
||||||
|
methods map[string]peerApiFuncType[T]
|
||||||
|
originalReceiverName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hc *WebsocketPeerHandler[T]) Call(recv T, funcname string, r io.Reader) (v any, e error) {
|
||||||
|
defer func() {
|
||||||
|
r := recover()
|
||||||
|
if r != nil {
|
||||||
|
logger.Error(r)
|
||||||
|
e = fmt.Errorf("%v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if found := hc.methods[funcname]; found != nil {
|
||||||
|
return found(recv, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("api is not found : %s", funcname)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeWebsocketPeerApiHandler[T PeerInterface](receiverName string) websocketPeerApiHandler[T] {
|
||||||
|
methods := make(map[string]peerApiFuncType[T])
|
||||||
|
|
||||||
|
var archetype T
|
||||||
|
tp := reflect.TypeOf(archetype)
|
||||||
|
if len(receiverName) == 0 {
|
||||||
|
receiverName = tp.Elem().Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < tp.NumMethod(); i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
if method.Type.In(0) != tp {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if method.Name == ClientDisconnected {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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[T]{
|
||||||
|
methods: methods,
|
||||||
|
originalReceiverName: tp.Elem().Name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer, receiverName string) WebsocketPeerHandler[T] {
|
||||||
|
methods := make(map[string]peerApiFuncType[T])
|
||||||
|
receiver := makeWebsocketPeerApiHandler[T](receiverName)
|
||||||
|
|
||||||
|
for k, v := range receiver.methods {
|
||||||
|
ab := strings.Split(k, ".")
|
||||||
|
logger.Printf("ws api registered : %s.%s -> %s\n", receiver.originalReceiverName, ab[1], k)
|
||||||
|
methods[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
return WebsocketPeerHandler[T]{
|
return WebsocketPeerHandler[T]{
|
||||||
sessionConsumer: consumer,
|
sessionConsumer: consumer,
|
||||||
|
methods: methods,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user