로그 변경
peer handler 코드 정리
This commit is contained in:
@ -7,44 +7,163 @@ import (
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/session"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type WebsocketPeerHandler[T PeerInterface] struct {
|
||||
WebsocketPeerApiBroker[T]
|
||||
type WebsocketPeerHandler interface {
|
||||
RegisterHandlers(serveMux *http.ServeMux, prefix string) error
|
||||
}
|
||||
|
||||
type websocketPeerHandler[T PeerInterface] struct {
|
||||
methods map[string]peerApiFuncType[T]
|
||||
createPeer func(primitive.ObjectID) T
|
||||
sessionConsumer session.Consumer
|
||||
}
|
||||
|
||||
func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer) WebsocketPeerHandler[T] {
|
||||
return WebsocketPeerHandler[T]{
|
||||
sessionConsumer: consumer,
|
||||
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]() websocketPeerApiHandler[T] {
|
||||
methods := make(map[string]peerApiFuncType[T])
|
||||
|
||||
var archetype T
|
||||
tp := reflect.TypeOf(archetype)
|
||||
|
||||
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[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 (ws *WebsocketPeerHandler[T]) RegisterHandlers(serveMux *http.ServeMux, prefix string) error {
|
||||
url := gocommon.MakeHttpHandlerPattern(prefix, "ws")
|
||||
func NewWebsocketPeerHandler[T PeerInterface](consumer session.Consumer, creator func(primitive.ObjectID) T) WebsocketPeerHandler {
|
||||
methods := make(map[string]peerApiFuncType[T])
|
||||
receiver := makeWebsocketPeerApiHandler[T]()
|
||||
|
||||
for k, v := range receiver.methods {
|
||||
logger.Printf("ws api registered : %s.%s\n", receiver.originalReceiverName, k)
|
||||
methods[k] = v
|
||||
}
|
||||
|
||||
return &websocketPeerHandler[T]{
|
||||
sessionConsumer: consumer,
|
||||
methods: methods,
|
||||
createPeer: creator,
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *websocketPeerHandler[T]) RegisterHandlers(serveMux *http.ServeMux, prefix string) error {
|
||||
if *noAuthFlag {
|
||||
serveMux.HandleFunc(url, ws.upgrade_nosession)
|
||||
serveMux.HandleFunc(prefix, ws.upgrade_nosession)
|
||||
} else {
|
||||
serveMux.HandleFunc(url, ws.upgrade)
|
||||
serveMux.HandleFunc(prefix, ws.upgrade)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *WebsocketPeerHandler[T]) upgrade_core(conn *websocket.Conn, accid primitive.ObjectID, nonce uint32) {
|
||||
func (ws *websocketPeerHandler[T]) upgrade_core(conn *websocket.Conn, accid primitive.ObjectID, nonce uint32) {
|
||||
go func(c *websocket.Conn, accid primitive.ObjectID) {
|
||||
peer := ws.CreatePeer(accid)
|
||||
peer := ws.createPeer(accid)
|
||||
var closeReason string
|
||||
|
||||
peer.ClientConnected(conn)
|
||||
|
||||
defer func() {
|
||||
peer.ClientDisconnected(closeReason)
|
||||
}()
|
||||
@ -80,7 +199,7 @@ func (ws *WebsocketPeerHandler[T]) upgrade_core(conn *websocket.Conn, accid prim
|
||||
cmd := make([]byte, size[0])
|
||||
r.Read(cmd)
|
||||
|
||||
result, err := ws.Call(peer, string(cmd), r)
|
||||
result, err := ws.call(peer, string(cmd), r)
|
||||
|
||||
if err != nil {
|
||||
response[0] = 21 // 21 : Negative Ack
|
||||
@ -110,14 +229,14 @@ func (ws *WebsocketPeerHandler[T]) upgrade_core(conn *websocket.Conn, accid prim
|
||||
} else {
|
||||
cmd := make([]byte, flag[0])
|
||||
r.Read(cmd)
|
||||
ws.Call(peer, string(cmd), r)
|
||||
ws.call(peer, string(cmd), r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}(conn, accid)
|
||||
}
|
||||
|
||||
func (ws *WebsocketPeerHandler[T]) upgrade_nosession(w http.ResponseWriter, r *http.Request) {
|
||||
func (ws *websocketPeerHandler[T]) upgrade_nosession(w http.ResponseWriter, r *http.Request) {
|
||||
// 클라이언트 접속
|
||||
defer func() {
|
||||
s := recover()
|
||||
@ -167,7 +286,7 @@ func (ws *WebsocketPeerHandler[T]) upgrade_nosession(w http.ResponseWriter, r *h
|
||||
ws.upgrade_core(conn, accid, nonce)
|
||||
}
|
||||
|
||||
func (ws *WebsocketPeerHandler[T]) upgrade(w http.ResponseWriter, r *http.Request) {
|
||||
func (ws *websocketPeerHandler[T]) upgrade(w http.ResponseWriter, r *http.Request) {
|
||||
// 클라이언트 접속
|
||||
defer func() {
|
||||
s := recover()
|
||||
|
||||
Reference in New Issue
Block a user