그룹 머지 기능 추가

This commit is contained in:
2023-10-09 17:59:15 +09:00
parent b44a6b1fd8
commit e8f74bcd19

View File

@ -78,7 +78,7 @@ func (gd *instantDoc) mid(tid string) accountID {
return out
}
func (gd *instantDoc) addMember(mid accountID, character bson.M) (bson.M, error) {
func (gd *instantDoc) addMember(mid accountID, character any) (bson.M, error) {
tid := gd.tid(mid)
if _, err := gd.rh.JSONSet(gd.strid(), "$._members."+tid, character); err != nil {
return nil, err
@ -95,14 +95,14 @@ func (gd *instantDoc) addMember(mid accountID, character bson.M) (bson.M, error)
var errGroupAlreadyDestroyed = errors.New("instant group is already destroyed")
func (gd *instantDoc) removeMemberByTid(tid string) error {
func (gd *instantDoc) removeMember(mid accountID) error {
counts, _ := gd.rh.JSONNumIncrBy(gd.strid(), "$._count", -1)
if len(counts) == 0 {
// 이미 지워진 인스턴트그룹
return errGroupAlreadyDestroyed
}
if _, err := gd.rh.JSONDel(gd.strid(), "$._members."+tid); err != nil {
if _, err := gd.rh.JSONDel(gd.strid(), "$._members."+gd.tid(mid)); err != nil {
return err
}
@ -110,11 +110,7 @@ func (gd *instantDoc) removeMemberByTid(tid string) error {
return nil
}
func (gd *instantDoc) removeMember(mid accountID) error {
return gd.removeMemberByTid(gd.tid(mid))
}
func (gd *instantDoc) getMembers() (map[string]any, error) {
func (gd *instantDoc) getMembers() (map[primitive.ObjectID]any, error) {
res, err := gd.rh.JSONGet(gd.strid(), "$._members")
if err != nil {
return nil, err
@ -126,9 +122,9 @@ func (gd *instantDoc) getMembers() (map[string]any, error) {
return nil, err
}
out := make(map[string]any)
out := make(map[primitive.ObjectID]any)
for k, v := range temp[0] {
out[gd.mid(k).Hex()] = v
out[gd.mid(k)] = v
}
return out, nil
@ -160,6 +156,35 @@ func (gi *groupInstant) RegisterApiFunctions() {
}
func (gi *groupInstant) join(gd *instantDoc, mid primitive.ObjectID, character any) error {
// 내 정보 업데이트할 때에도 사용됨
memdoc, err := gd.addMember(mid, character)
if err != nil {
return err
}
// 기존 유저에게 새 유저 알림
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: "#" + gd.strid(),
Body: map[string]any{
gd.tid(mid): memdoc,
},
Tag: []string{"MemberDocFull"},
})
gi.rh.JSONSet(mid.Hex(), "$.instant", bson.M{"id": gd.strid()})
// 최초 입장이라면 새 멤버에 그룹 전체를 알림
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: mid.Hex(),
Body: gd.loadFull(),
Tag: []string{"GroupDocFull"},
})
gi.enterRoom(gd.Gid, mid)
return nil
}
func (gi *groupInstant) Join(w http.ResponseWriter, r *http.Request) {
var data struct {
Gid primitive.ObjectID
@ -172,54 +197,25 @@ func (gi *groupInstant) Join(w http.ResponseWriter, r *http.Request) {
return
}
character := data.Character
gid := data.Gid
mid := data.Mid
if gid.IsZero() || mid.IsZero() {
logger.Println("JoinParty failed. mid should be exist")
if data.Gid.IsZero() || data.Mid.IsZero() {
logger.Error("groupInstant.Join failed. gid or mid is zero")
w.WriteHeader(http.StatusBadRequest)
return
}
gd, err := gi.find(gid)
if err != nil {
gd, err := gi.find(data.Gid)
if err != nil || gd == nil {
logger.Error("groupInstant.Join failed. gi find return err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if gd == nil {
// 그룹이 없다. 실패
w.WriteHeader(http.StatusBadRequest)
return
}
// 내 정보 업데이트할 때에도 사용됨
if memdoc, err := gd.addMember(mid, character); err == nil {
// 기존 유저에게 새 유저 알림
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: "#" + gid.Hex(),
Body: map[string]any{
gd.tid(mid): memdoc,
},
Tag: []string{"MemberDocFull"},
})
gi.enterRoom(gid, mid)
gi.rh.JSONSet(mid.Hex(), "$.instant", bson.M{"id": gd.strid()})
// 최초 입장이라면 새 멤버에 그룹 전체를 알림
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: mid.Hex(),
Body: gd.loadFull(),
Tag: []string{"GroupDocFull"},
})
} else if err != nil {
logger.Error("JoinParty failed :", err)
if err := gi.join(gd, data.Mid, data.Character); err != nil {
logger.Error("groupInstant.Join failed :", err)
w.WriteHeader(http.StatusInternalServerError)
} else {
gocommon.MakeEncoder(w, r).Encode(gd.Count)
}
gocommon.MakeEncoder(w, r).Encode(gd.Count)
}
func (gi *groupInstant) Create(w http.ResponseWriter, r *http.Request) {
@ -262,6 +258,43 @@ func (gi *groupInstant) Delete(w http.ResponseWriter, r *http.Request) {
}
}
func (gi *groupInstant) leave(gd *instantDoc, mid primitive.ObjectID) error {
if err := gd.removeMember(mid); err != nil {
if err == errGroupAlreadyDestroyed {
// 정상
gd.Count = 0
return nil
}
return err
}
gi.rh.JSONDel(mid.Hex(), "$.instant.id")
// mid한테는 빈 GroupDocFull을 보낸다. 그러면 지워짐
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: mid.Hex(),
Body: bson.M{"_gid": gd.Gid},
Tag: []string{"GroupDocFull", gd.strid()},
})
// gid에는 제거 메시지 보냄
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: "#" + gd.strid(),
Body: bson.M{
gd.tid(mid): bson.M{},
},
Tag: []string{"MemberDocFull"},
})
gi.leaveRoom(gd.Gid, mid)
if gd.Count == 0 {
gd.rh.Del(gd.rh.Context(), gd.strid()).Result()
}
return nil
}
func (gi *groupInstant) Leave(w http.ResponseWriter, r *http.Request) {
var data struct {
Gid primitive.ObjectID
@ -276,43 +309,78 @@ func (gi *groupInstant) Leave(w http.ResponseWriter, r *http.Request) {
Gid: data.Gid,
rh: gi.rh,
}
if err := gd.removeMember(data.Mid); err != nil {
if err == errGroupAlreadyDestroyed {
// 정상
gocommon.MakeEncoder(w, r).Encode(int64(0))
return
}
if err := gi.leave(&gd, data.Mid); err != nil {
logger.Println("groupInstant.Leave failed. gd.removeMember returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
gi.rh.JSONDel(data.Mid.Hex(), "$.instant.id")
gocommon.MakeEncoder(w, r).Encode(gd.Count)
}
// mid한테는 빈 GroupDocFull을 보낸다. 그러면 지워짐
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: data.Mid.Hex(),
Body: bson.M{"_gid": data.Gid},
Tag: []string{"GroupDocFull", gd.strid()},
})
// gid에는 제거 메시지 보냄
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: "#" + gd.strid(),
Body: bson.M{
gd.tid(data.Mid): bson.M{},
},
Tag: []string{"MemberDocFull"},
})
gi.leaveRoom(gd.Gid, data.Mid)
if gd.Count == 0 {
gd.rh.Del(gd.rh.Context(), gd.strid()).Result()
func (gi *groupInstant) Merge(w http.ResponseWriter, r *http.Request) {
var data struct {
From primitive.ObjectID
Into primitive.ObjectID
Max int64
}
if err := gocommon.MakeDecoder(r).Decode(&data); err != nil {
logger.Println("RemoveFromParty failed. Decode returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
// From에 있는 mid를 Into로 옮김
gdinto, err := gi.find(data.Into)
if err != nil || gdinto == nil {
logger.Println("groupInstant.Merge failed. gd.getMembers returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
gocommon.MakeEncoder(w, r).Encode(gd.Count)
gdfrom := instantDoc{
Gid: data.From,
rh: gi.rh,
}
fromMembers, err := gdfrom.getMembers()
if err != nil {
logger.Println("groupInstant.Merge failed. gd.getMembers returns err :", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var movedmids []primitive.ObjectID
for mid, doc := range fromMembers {
gi.join(gdinto, mid, doc)
gi.leaveRoom(gdfrom.Gid, mid)
movedmids = append(movedmids, mid)
if gdinto.Count == data.Max {
break
}
}
if len(movedmids) == int(gdfrom.Count) {
gi.rh.JSONDel(gdfrom.strid(), "$")
} else {
for _, mid := range movedmids {
gdfrom.removeMember(mid)
// gid에는 제거 메시지 보냄
gi.sendUpstreamMessage(&wshandler.UpstreamMessage{
Target: "#" + gdfrom.strid(),
Body: bson.M{
gdfrom.tid(mid): bson.M{},
},
Tag: []string{"MemberDocFull"},
})
}
}
gocommon.MakeEncoder(w, r).Encode(struct {
From int64
Into int64
}{From: gdfrom.Count, Into: gdinto.Count})
}
func (gi *groupInstant) createInstantGroup(firstAcc primitive.ObjectID, firstChar primitive.M, instDoc primitive.M) (*instantDoc, error) {