From 4a51f7d43314db323dd07bfdfab9d02e1cd4956b Mon Sep 17 00:00:00 2001 From: mountain Date: Tue, 5 Sep 2023 17:14:07 +0900 Subject: [PATCH] =?UTF-8?q?=EC=84=9C=EB=B2=84=EA=B0=84=20api=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EA=B0=84=EC=86=8C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/group.go | 47 --------- core/group_chat.go | 92 +++++------------ core/group_party.go | 246 ++++++++++++++++++++++---------------------- core/tavern.go | 73 ++++--------- go.mod | 2 +- go.sum | 16 +++ 6 files changed, 189 insertions(+), 287 deletions(-) diff --git a/core/group.go b/core/group.go index 909fa92..b945077 100644 --- a/core/group.go +++ b/core/group.go @@ -1,56 +1,9 @@ package core import ( - "net/http" - "reflect" - - "repositories.action2quare.com/ayo/gocommon/logger" "repositories.action2quare.com/ayo/gocommon/wshandler" ) -var groupTypes map[string]reflect.Type - -func groupTypeContainer() map[string]reflect.Type { - if groupTypes == nil { - groupTypes = make(map[string]reflect.Type) - } - return groupTypes -} - -type apiFuncType func(http.ResponseWriter, *http.Request) -type apiFuncsContainer struct { - normfuncs map[string]apiFuncType - funcs map[string][]apiFuncType -} - -func (afc *apiFuncsContainer) registApiFunction(name string, f apiFuncType) { - afc.funcs[name] = append(afc.funcs[name], f) -} - -func (afc *apiFuncsContainer) normalize() { - for k, v := range afc.funcs { - if len(v) == 1 { - afc.normfuncs[k] = v[0] - } else { - afc.normfuncs[k] = func(w http.ResponseWriter, r *http.Request) { - for _, f := range v { - f(w, r) - } - } - } - } - afc.funcs = nil -} - -func (afc *apiFuncsContainer) call(fn string, w http.ResponseWriter, r *http.Request) { - f := afc.normfuncs[fn] - if f != nil { - f(w, r) - } else { - logger.Println("api func is missing :", fn) - } -} - type configDocument map[string]any type group interface { Initialize(*Tavern, configDocument) error diff --git a/core/group_chat.go b/core/group_chat.go index 8479e7d..d0f3178 100644 --- a/core/group_chat.go +++ b/core/group_chat.go @@ -3,24 +3,17 @@ package core import ( "encoding/json" "fmt" - "io" "net/http" - "reflect" "strings" "time" "github.com/go-redis/redis/v8" - "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "repositories.action2quare.com/ayo/gocommon" "repositories.action2quare.com/ayo/gocommon/logger" "repositories.action2quare.com/ayo/gocommon/wshandler" ) -func init() { - groupTypeContainer()["chat"] = reflect.TypeOf(&groupChat{}) -} - type channelID = string type channelConfig struct { Capacity int64 `json:"capacity"` @@ -63,10 +56,6 @@ func (gc *groupChat) Initialize(tv *Tavern, cfg configDocument) error { gc.rh = tv.redison - tv.apiFuncs.registApiFunction("FetchChattingChannels", gc.FetchChattingChannels) - tv.apiFuncs.registApiFunction("BroadcastMessageOnChannel", gc.BroadcastMessageOnChannel) - tv.apiFuncs.registApiFunction("QueryPlayerChattingChannel", gc.QueryPlayerChattingChannel) - tv.apiFuncs.registApiFunction("SendMessageOnChannel", gc.SendMessageOnChannel) for name, cfg := range gc.chatConfig.Channels { if cfg.Capacity == 0 { cfg.Capacity = gc.chatConfig.DefaultCapacity @@ -223,7 +212,16 @@ func (gc *groupChat) ClientMessageReceived(sender *wshandler.Sender, mt wshandle } func (gc *groupChat) FetchChattingChannels(w http.ResponseWriter, r *http.Request) { - prefix, _ := gocommon.ReadStringFormValue(r.URL.Query(), "prefix") + var data struct { + Prefix string `bson:"prefix"` + } + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("FetchChattingChannels failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + prefix := data.Prefix if len(prefix) == 0 { logger.Println("FetchChattingChannel failed. prefix is missing") w.WriteHeader(http.StatusBadRequest) @@ -269,8 +267,18 @@ func (gc *groupChat) FetchChattingChannels(w http.ResponseWriter, r *http.Reques } func (gc *groupChat) QueryPlayerChattingChannel(w http.ResponseWriter, r *http.Request) { - accid, _ := gocommon.ReadStringFormValue(r.URL.Query(), "accid") - typename, _ := gocommon.ReadStringFormValue(r.URL.Query(), "typename") + var data struct { + Accid string `bson:"accid"` + Typename string `bson:"typename"` + } + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("QueryPlayerChattingChannel failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + accid := data.Accid + typename := data.Typename var fields []string if len(typename) == 0 { @@ -298,60 +306,12 @@ func (gc *groupChat) QueryPlayerChattingChannel(w http.ResponseWriter, r *http.R } func (gc *groupChat) SendMessageOnChannel(w http.ResponseWriter, r *http.Request) { - channel, _ := gocommon.ReadStringFormValue(r.URL.Query(), "channel") - target, _ := gocommon.ReadStringFormValue(r.URL.Query(), "target") - tag, _ := gocommon.ReadStringFormValue(r.URL.Query(), "tag") - if len(channel) == 0 || len(target) == 0 || len(tag) == 0 { - logger.Println("SendMessageOnChannel failed. channel or target or tag is empty") + var msg wshandler.UpstreamMessage + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &msg); err != nil { + logger.Println("SendMessageOnChannel failed. ReadBsonDocumentFromBody return err :", err) w.WriteHeader(http.StatusBadRequest) return } - var doc map[string]any - bt, err := io.ReadAll(r.Body) - if err != nil { - logger.Println("SendMessageOnChannel failed. io.ReadAll returns err :", err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - if len(bt) > 0 { - if err := bson.Unmarshal(bt, &doc); err != nil { - logger.Println("SendMessageOnChannel failed. decode returns err :", err) - w.WriteHeader(http.StatusBadRequest) - return - } - } - - gc.sendUpstreamMessage(&wshandler.UpstreamMessage{ - Target: fmt.Sprintf("%s@%s", target, channel), - Body: doc, - Tag: []string{tag}, - }) -} - -func (gc *groupChat) BroadcastMessageOnChannel(w http.ResponseWriter, r *http.Request) { - nickname, _ := gocommon.ReadStringFormValue(r.URL.Query(), "nickname") - channel, _ := gocommon.ReadStringFormValue(r.URL.Query(), "channel") - tag, _ := gocommon.ReadStringFormValue(r.URL.Query(), "tag") - text, _ := io.ReadAll(r.Body) - - if len(tag) > 0 { - var doc map[string]any - if err := bson.Unmarshal(text, &doc); err == nil { - gc.sendUpstreamMessage(&wshandler.UpstreamMessage{ - Target: "#" + channel, - Body: doc, - Tag: []string{tag}, - }) - } else { - logger.Println("BroadcastMessageOnChannel failed :", err) - } - } else { - gc.sendUpstreamMessage(&wshandler.UpstreamMessage{ - Target: "#" + channel, - Body: map[string]any{"sender": nickname, "msg": string(text)}, - Tag: []string{"TextMessage"}, - }) - } + gc.sendUpstreamMessage(&msg) } diff --git a/core/group_party.go b/core/group_party.go index 689b61c..6eb2131 100644 --- a/core/group_party.go +++ b/core/group_party.go @@ -2,11 +2,9 @@ package core import ( "context" - "encoding/gob" "encoding/json" "fmt" "net/http" - "reflect" "strings" "time" @@ -22,15 +20,6 @@ import ( type accountID = primitive.ObjectID type groupID = primitive.ObjectID -func init() { - gob.Register(memberDoc{}) - gob.Register(groupDoc{}) - gob.Register(Invitation{}) - gob.Register(InvitationFail{}) - - groupTypeContainer()["party"] = reflect.TypeOf(&groupParty{}) -} - func makeTid(gid groupID, in accountID) string { var out primitive.ObjectID for i := range in { @@ -127,9 +116,9 @@ func (gd *groupDoc) mid(tid string) accountID { return out } -func (gd *groupDoc) addInvite(inviteeDoc bson.M, ttl time.Duration, max int) (*memberDoc, error) { - targetmid := inviteeDoc["_mid"].(accountID) - targetbody := inviteeDoc["body"].(bson.M) +func (gd *groupDoc) addInvite(mid accountID, body bson.M, ttl time.Duration, max int) (*memberDoc, error) { + targetmid := mid + targetbody := body // 초대 가능한 빈 자리가 있나 tids, err := gd.rh.JSONObjKeys(gd.strid(), "$._members") @@ -181,11 +170,11 @@ func (gd *groupDoc) addInvite(inviteeDoc bson.M, ttl time.Duration, max int) (*m return newdoc, err } -func (gd *groupDoc) addMember(mid accountID, doc bson.M) (bson.M, error) { +func (gd *groupDoc) addMember(mid accountID, character bson.M) (bson.M, error) { tid := gd.tid(mid) prefix := "$._members." + tid - if _, err := gd.rh.JSONMerge(gd.strid(), prefix+"._body", doc, gocommon.RedisonSetOptionXX); err != nil { + if _, err := gd.rh.JSONMerge(gd.strid(), prefix+"._body", character, gocommon.RedisonSetOptionXX); err != nil { return nil, err } @@ -273,15 +262,15 @@ func (gp *groupParty) Initialize(tv *Tavern, cfg configDocument) error { tv.wsh.LeaveRoom(gid.Hex(), accid) } - tv.apiFuncs.registApiFunction("JoinParty", gp.JoinParty) - tv.apiFuncs.registApiFunction("InviteToParty", gp.InviteToParty) - tv.apiFuncs.registApiFunction("AcceptPartyInvitation", gp.AcceptPartyInvitation) - tv.apiFuncs.registApiFunction("DenyPartyInvitation", gp.DenyPartyInvitation) - tv.apiFuncs.registApiFunction("QueryPartyMemberState", gp.QueryPartyMemberState) - tv.apiFuncs.registApiFunction("LeaveParty", gp.LeaveParty) - tv.apiFuncs.registApiFunction("UpdatePartyMemberDocument", gp.UpdatePartyMemberDocument) - tv.apiFuncs.registApiFunction("UpdatePartyDocument", gp.UpdatePartyDocument) - tv.apiFuncs.registApiFunction("QueryPartyMembers", gp.QueryPartyMembers) + // tv.apiFuncs.registApiFunction("JoinParty", gp.JoinParty) + // tv.apiFuncs.registApiFunction("InviteToParty", gp.InviteToParty) + // tv.apiFuncs.registApiFunction("AcceptPartyInvitation", gp.AcceptPartyInvitation) + // tv.apiFuncs.registApiFunction("DenyPartyInvitation", gp.DenyPartyInvitation) + // tv.apiFuncs.registApiFunction("QueryPartyMemberState", gp.QueryPartyMemberState) + // tv.apiFuncs.registApiFunction("LeaveParty", gp.LeaveParty) + // tv.apiFuncs.registApiFunction("UpdatePartyMemberDocument", gp.UpdatePartyMemberDocument) + // tv.apiFuncs.registApiFunction("UpdatePartyDocument", gp.UpdatePartyDocument) + // tv.apiFuncs.registApiFunction("QueryPartyMembers", gp.QueryPartyMembers) return nil } @@ -296,20 +285,22 @@ func (gp *groupParty) RegisterApiFunctions() { // - member_id : 참가 멤버의 아이디 // - body : 멤버의 속성 bson document func (gp *groupParty) JoinParty(w http.ResponseWriter, r *http.Request) { - doc := bson.M{} - if err := readBsonDoc(r.Body, &doc); err != nil { - logger.Error("JoinParty failed. readBsonDoc returns err :", err) - w.WriteHeader(http.StatusBadRequest) + var data struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + Character bson.M `bson:"character"` + } + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("JoinParty failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) return } - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("JoinParty failed. gid is missing :", r.URL.Query()) - w.WriteHeader(http.StatusBadRequest) - return - } - mid, midok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") - if !midok { + + doc := data.Character + gid := data.Gid + mid := data.Mid + + if gid.IsZero() || mid.IsZero() { logger.Println("JoinParty failed. mid should be exist") w.WriteHeader(http.StatusBadRequest) return @@ -328,7 +319,7 @@ func (gp *groupParty) JoinParty(w http.ResponseWriter, r *http.Request) { } // 내 정보 업데이트할 때에도 사용됨 - if memdoc, err := gd.addMember(mid, doc); err == nil { + if memdoc, err := gd.addMember(mid, doc["character"].(map[string]any)); err == nil { // 기존 유저에게 새 유저 알림 gp.sendUpstreamMessage(&wshandler.UpstreamMessage{ Target: "#" + gid.Hex(), @@ -363,35 +354,23 @@ func (gp *groupParty) JoinParty(w http.ResponseWriter, r *http.Request) { // - timeout : 초대 유지시간(optional. 없으면 config 기본 값) // - (body) : 검색시 노출되는 document func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("InviteToParty failed. gid is missing :", r) - w.WriteHeader(http.StatusBadRequest) - return - } - mid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") - if !ok { - logger.Println("InviteToParty failed. mid is missing :", r) - w.WriteHeader(http.StatusBadRequest) - return + var doc struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + Targetid primitive.ObjectID `bson:"targetid"` + Inviter bson.M `bson:"inviter"` + Invitee bson.M `bson:"invitee"` } - var reqdoc struct { - Inviter bson.M `bson:"inviter"` - Invitee bson.M `bson:"invitee"` - } - if err := readBsonDoc(r.Body, &reqdoc); err != nil { - logger.Println("InviteToParty failed. readBsonDoc returns err :", err) + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &doc); err != nil { + logger.Println("InviteToParty failed. ReadBsonDocumentFromBody returns err :", err) w.WriteHeader(http.StatusInternalServerError) return } - targetid, ok := reqdoc.Invitee["_mid"].(accountID) - if !ok { - logger.Println("InviteToParty failed. invitee mid is missing :", r) - w.WriteHeader(http.StatusBadRequest) - return - } + targetid := doc.Targetid + gid := doc.Gid + mid := doc.Mid // targetid에 초대한 mid가 들어있다. success, err := gp.rh.SetNX(context.Background(), "inv."+targetid.Hex(), mid.Hex(), time.Duration(gp.InviteExpire)*time.Second).Result() @@ -406,7 +385,7 @@ func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { // inviter한테 알려줘야 한다. gp.sendUpstreamMessage(&wshandler.UpstreamMessage{ Target: mid.Hex(), - Body: reqdoc.Invitee, + Body: doc.Invitee, Tag: []string{"InvitationFail"}, }) return @@ -420,7 +399,7 @@ func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { } if gd == nil { - gd, err = gp.createGroup(gid, mid, reqdoc.Inviter) + gd, err = gp.createGroup(gid, mid, doc.Inviter) if err != nil { logger.Println("InviteToParty failed. gp.createGroup() return err :", err) w.WriteHeader(http.StatusInternalServerError) @@ -436,7 +415,7 @@ func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { }) } - newdoc, err := gd.addInvite(reqdoc.Invitee, time.Duration(gp.InviteExpire+1)*time.Second, gp.MaxMember) + newdoc, err := gd.addInvite(targetid, doc.Invitee, time.Duration(gp.InviteExpire+1)*time.Second, gp.MaxMember) if err != nil { logger.Println("InviteToParty failed. gp.addInvite() return err :", err) w.WriteHeader(http.StatusInternalServerError) @@ -449,7 +428,7 @@ func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { Body: Invitation{ GroupID: gid, TicketID: gd.tid(targetid), - Inviter: reqdoc.Inviter, + Inviter: doc.Inviter, ExpireAtUTC: newdoc.InviteExpire, }, Tag: []string{"Invitation"}, @@ -459,15 +438,22 @@ func (gp *groupParty) InviteToParty(w http.ResponseWriter, r *http.Request) { } func (gp *groupParty) AcceptPartyInvitation(w http.ResponseWriter, r *http.Request) { - gid, _ := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - mid, _ := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") - - var member bson.M - if err := readBsonDoc(r.Body, &member); err != nil { - logger.Error("AcceptPartyInvitation failed. readBsonDoc returns err :", err) + var doc struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + Tid string `bson:"tid"` + Character bson.M `bson:"character"` + } + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &doc); err != nil { + logger.Println("AcceptPartyInvitation failed. ReadBsonDocumentFromBody returns err :", err) w.WriteHeader(http.StatusInternalServerError) return } + + gid := doc.Gid + mid := doc.Mid + member := doc.Character + cnt, err := gp.rh.Del(context.Background(), "inv."+mid.Hex()).Result() if err != nil { logger.Error("AcceptPartyInvitation failed. gp.rh.Del returns err :", err) @@ -543,8 +529,19 @@ func (gp *groupParty) AcceptPartyInvitation(w http.ResponseWriter, r *http.Reque } func (gp *groupParty) DenyPartyInvitation(w http.ResponseWriter, r *http.Request) { - gid, _ := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - mid, _ := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") + var data struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + } + + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("DenyPartyInvitation failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + gid := data.Gid + mid := data.Mid gp.rh.Del(context.Background(), "inv."+mid.Hex()).Result() gd := groupDoc{ @@ -555,14 +552,18 @@ func (gp *groupParty) DenyPartyInvitation(w http.ResponseWriter, r *http.Request } func (gp *groupParty) QueryPartyMemberState(w http.ResponseWriter, r *http.Request) { - mid, ok := gocommon.ReadStringFormValue(r.URL.Query(), "mid") - if !ok { - logger.Println("IsOnline failed. mid is missing :", r.URL.Query()) - w.WriteHeader(http.StatusBadRequest) - return + var data struct { + Mid primitive.ObjectID `bson:"mid"` } - states, err := gp.rh.JSONGetString(mid, "$.party.state") + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("DenyPartyInvitation failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + mid := data.Mid + + states, err := gp.rh.JSONGetString(mid.Hex(), "$.party.state") if err == redis.Nil { return } @@ -579,26 +580,28 @@ func (gp *groupParty) QueryPartyMemberState(w http.ResponseWriter, r *http.Reque // - 그룹 타입에 맞는 키(주로 _id) // - member_id : 나갈 멤버의 아이디 func (gp *groupParty) LeaveParty(w http.ResponseWriter, r *http.Request) { - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("LeaveParty failed. gid is missing :", r.URL.Query()) - w.WriteHeader(http.StatusBadRequest) + var data struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + Tid string `bson:"tid"` + } + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("LeaveParty failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) return } - mid, midok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") - if !midok { - logger.Println("LeaveParty failed. mid is missing") - w.WriteHeader(http.StatusBadRequest) - return - } - tid, tidok := gocommon.ReadStringFormValue(r.URL.Query(), "tid") + + gid := data.Gid + mid := data.Mid + tid := data.Tid + gd := groupDoc{ id: gid, rh: gp.rh, } var err error - if tidok { + if len(tid) > 0 { if tid != gd.tid(mid) { // mid가 incharge여야 한다. 그래야 tid를 쫓아낼 수 있음 incharge, err := gp.rh.JSONGet(gd.strid(), "$._incharge") @@ -674,26 +677,21 @@ func (gp *groupParty) updateMemberDocument(gid groupID, mid accountID, doc bson. } func (gp *groupParty) UpdatePartyMemberDocument(w http.ResponseWriter, r *http.Request) { - mid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "mid") - if !ok { - logger.Println("UpdatePartyMemberDocument failed. member_id is missing") - w.WriteHeader(http.StatusBadRequest) + var data struct { + Gid primitive.ObjectID `bson:"gid"` + Mid primitive.ObjectID `bson:"mid"` + Doc bson.M `bson:"doc"` + } + + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("UpdatePartyMemberDocument failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) return } - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("UpdatePartyMemberDocument failed. _id is missing") - w.WriteHeader(http.StatusBadRequest) - return - } - - var updatedoc bson.M - if err := readBsonDoc(r.Body, &updatedoc); err != nil { - logger.Error("UpdatePartyMemberDocument failed. body decoding error :", err) - w.WriteHeader(http.StatusBadRequest) - return - } + mid := data.Mid + gid := data.Gid + updatedoc := data.Doc if err := gp.updateMemberDocument(gid, mid, updatedoc); err != nil { logger.Println("UpdatePartyMemberDocument failed :", err) @@ -720,19 +718,19 @@ func (gp *groupParty) updatePartyDocument(gid groupID, frag bson.M) error { } func (gp *groupParty) UpdatePartyDocument(w http.ResponseWriter, r *http.Request) { - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("UpdatePartyDocument failed. gid is missing") - w.WriteHeader(http.StatusBadRequest) + var data struct { + Gid primitive.ObjectID `bson:"gid"` + Doc bson.M `bson:"doc"` + } + + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("UpdatePartyDocument failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) return } - var frag bson.M - if err := readBsonDoc(r.Body, &frag); err != nil { - logger.Error("UpdatePartyDocument failed. readBsonDoc err :", err) - w.WriteHeader(http.StatusBadRequest) - return - } + gid := data.Gid + frag := data.Doc if err := gp.updatePartyDocument(gid, frag); err != nil { logger.Error("UpdatePartyDocument failed. group.UpdatePartyDocument returns err :", err) @@ -742,13 +740,17 @@ func (gp *groupParty) UpdatePartyDocument(w http.ResponseWriter, r *http.Request } func (gp *groupParty) QueryPartyMembers(w http.ResponseWriter, r *http.Request) { - gid, ok := gocommon.ReadObjectIDFormValue(r.URL.Query(), "gid") - if !ok { - logger.Println("QueryPartyMembers failed. gid is missing") - w.WriteHeader(http.StatusBadRequest) + var data struct { + Gid primitive.ObjectID `bson:"gid"` + } + + if err := gocommon.ReadBsonDocumentFromBody(r.Body, &data); err != nil { + logger.Println("QueryPartyMembers failed. ReadBsonDocumentFromBody returns err :", err) + w.WriteHeader(http.StatusInternalServerError) return } + gid := data.Gid gd := groupDoc{ id: gid, rh: gp.rh, diff --git a/core/tavern.go b/core/tavern.go index e638ff2..6fcb8d2 100644 --- a/core/tavern.go +++ b/core/tavern.go @@ -4,11 +4,9 @@ import ( "context" "encoding/json" "errors" - "fmt" "io" "net" "net/http" - "reflect" "strings" "time" @@ -39,29 +37,6 @@ func writeBsonDoc[T any](w io.Writer, src T) error { return enc.Encode(src) } -func readBsonDoc(r io.Reader, src any) error { - body, err := io.ReadAll(r) - if err != nil { - return err - } - - if len(body) == 0 { - return nil - } - - decoder, err := bson.NewDecoder(bsonrw.NewBSONDocumentReader(body)) - if err != nil { - return err - } - - err = decoder.Decode(src) - if err != nil { - return err - } - - return nil -} - type TavernConfig struct { session.SessionConfig `json:",inline"` gocommon.StorageAddr `json:"storage"` @@ -75,11 +50,11 @@ type TavernConfig struct { var config TavernConfig type Tavern struct { - wsh *wshandler.WebsocketHandler - mongoClient gocommon.MongoClient - redison *gocommon.RedisonHandler - groups map[string]group - apiFuncs *apiFuncsContainer + wsh *wshandler.WebsocketHandler + mongoClient gocommon.MongoClient + redison *gocommon.RedisonHandler + groups map[string]group + apiReceivers gocommon.HttpApiHandlerContainer } func getMacAddr() (string, error) { @@ -116,10 +91,6 @@ func New(context context.Context, wsh *wshandler.WebsocketHandler, inconfig *Tav config.macAddr = macaddr tv := &Tavern{ wsh: wsh, - apiFuncs: &apiFuncsContainer{ - normfuncs: make(map[string]apiFuncType), - funcs: make(map[string][]apiFuncType), - }, } if err = tv.prepare(context); err != nil { @@ -143,25 +114,24 @@ func (tv *Tavern) prepare(ctx context.Context) error { tv.redison = gocommon.NewRedisonHandler(redisClient.Context(), redisClient) groups := make(map[string]group) - for typename, cfg := range config.Group { - gtype, ok := groupTypeContainer()[typename] - if !ok { - return fmt.Errorf("%s group type is not valid", typename) - } - - if !gtype.Implements(reflect.TypeOf((*group)(nil)).Elem()) { - return fmt.Errorf("%s is not implement proper interface", typename) - } - ptrvalue := reflect.New(gtype.Elem()) - instance := ptrvalue.Interface().(group) - if err := instance.Initialize(tv, cfg); err != nil { + if cfg, ok := config.Group["chat"]; ok { + chat := new(groupChat) + if err := chat.Initialize(tv, cfg); err != nil { return err } - groups[typename] = instance + tv.apiReceivers.RegistReceiver(gocommon.MakeHttpApiReceiver(chat, "chat")) + groups["chat"] = chat } + if cfg, ok := config.Group["party"]; ok { + party := new(groupParty) + if err := party.Initialize(tv, cfg); err != nil { + return err + } + tv.apiReceivers.RegistReceiver(gocommon.MakeHttpApiReceiver(party, "party")) + groups["party"] = party + } tv.groups = groups - tv.apiFuncs.normalize() return nil } @@ -259,11 +229,12 @@ func (tv *Tavern) api(w http.ResponseWriter, r *http.Request) { return } - operation := r.URL.Query().Get("operation") - if len(operation) == 0 { + funcname := r.URL.Query().Get("call") + if len(funcname) == 0 { + logger.Println("query param 'call' is missing") w.WriteHeader(http.StatusBadRequest) return } - tv.apiFuncs.call(operation, w, r) + tv.apiReceivers.Call(funcname, w, r) } diff --git a/go.mod b/go.mod index e194890..411800a 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/go-redis/redis/v8 v8.11.5 go.mongodb.org/mongo-driver v1.11.7 - repositories.action2quare.com/ayo/gocommon v0.0.0-20230904053533-821dc5c639d8 + repositories.action2quare.com/ayo/gocommon v0.0.0-20230905074334-7951814f125d ) require ( diff --git a/go.sum b/go.sum index ff4fdbb..f434170 100644 --- a/go.sum +++ b/go.sum @@ -160,3 +160,19 @@ repositories.action2quare.com/ayo/gocommon v0.0.0-20230904005440-d396a35713ad h1 repositories.action2quare.com/ayo/gocommon v0.0.0-20230904005440-d396a35713ad/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= repositories.action2quare.com/ayo/gocommon v0.0.0-20230904053533-821dc5c639d8 h1:clQB7s726Rt/q2BgGjZMVjek7Z0YDBUrD4HjFKUFSIw= repositories.action2quare.com/ayo/gocommon v0.0.0-20230904053533-821dc5c639d8/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905024342-84f56dfc505c h1:Db+5nxlTu9W7qM0DApVqpG+y2MimlOz02FgTza291Jw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905024342-84f56dfc505c/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905025653-511784774009 h1:GtedcdVrlMY9CFbd6BoayjgFRwR/pbNPngZfAZ7Ublg= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905025653-511784774009/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905030636-def9494dd387 h1:lx9zDFycfr1703qszt9YLz8lae79gpu4tGe+kX41bG4= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905030636-def9494dd387/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905032825-8877bf88c0b7 h1:PkQS5X4t610gxGQD1AYklb2zH2bOUM9HLZowNnPPqlY= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905032825-8877bf88c0b7/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905045203-0762d9311b90 h1:AiG+6UG9vxiDsaTI8c6mPd53qIhon9T3C93jvQ4paAY= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905045203-0762d9311b90/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905054212-7489fa657a86 h1:WtjuPV28reK4RZgWHYH98ggUL6u/yxpaZzGgCvYY7so= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905054212-7489fa657a86/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905060206-3a3839a46187 h1:x+/G4jg2YwOdTmT4rHEw/RVaaxAc38CN8woWP9L/eZY= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905060206-3a3839a46187/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905074334-7951814f125d h1:zvTbz/14pdfjpSpczpSOcRCBZKY8agFILxL/QrIJngQ= +repositories.action2quare.com/ayo/gocommon v0.0.0-20230905074334-7951814f125d/go.mod h1:PdpZ16O1czKKxCxn+0AFNaEX/0kssYwC3G8jR0V7ybw=