서버간 api 호출 간소화

This commit is contained in:
2023-09-05 17:14:07 +09:00
parent 6410056c87
commit 4a51f7d433
6 changed files with 189 additions and 287 deletions

View File

@ -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,