차단 목록 관리 추가하고 connection 분리
This commit is contained in:
181
core/friend.go
181
core/friend.go
@ -6,8 +6,8 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
@ -20,14 +20,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
friends_collection_name = gocommon.CollectionName("friends")
|
||||
monitoring_center_count = 100
|
||||
state_online = "online"
|
||||
state_offline = "offline"
|
||||
)
|
||||
|
||||
var friend_state_tag = []string{"social.FriendState"}
|
||||
|
||||
type friendDoc struct {
|
||||
Id primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
|
||||
From primitive.ObjectID `bson:"from" json:"-"`
|
||||
@ -48,80 +45,12 @@ type monitoringCenter struct {
|
||||
publishState func(string, string, string)
|
||||
}
|
||||
|
||||
type connWithFriends struct {
|
||||
c *websocket.Conn
|
||||
friends []*friendDoc
|
||||
initialized bool
|
||||
}
|
||||
|
||||
type connections struct {
|
||||
connLock sync.Mutex
|
||||
conns map[primitive.ObjectID]*connWithFriends
|
||||
}
|
||||
|
||||
func (cs *connections) new(accid primitive.ObjectID, conn *websocket.Conn) {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
cs.conns[accid] = &connWithFriends{
|
||||
c: conn,
|
||||
initialized: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *connections) delete(accid primitive.ObjectID) {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
|
||||
delete(cs.conns, accid)
|
||||
}
|
||||
|
||||
func (cs *connections) conn(accid primitive.ObjectID) *websocket.Conn {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
if cf, ok := cs.conns[accid]; ok {
|
||||
return cf.c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *connections) addFriend(accid primitive.ObjectID, fdoc *friendDoc) bool {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
if cf, ok := cs.conns[accid]; ok {
|
||||
if cf.initialized {
|
||||
cf.friends = append(cf.friends, fdoc)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (cs *connections) initFriends(accid primitive.ObjectID, fdocs []*friendDoc) {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
if cf, ok := cs.conns[accid]; ok {
|
||||
cf.friends = fdocs
|
||||
cf.initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *connections) clearFriends(accid primitive.ObjectID) (out []*friendDoc) {
|
||||
cs.connLock.Lock()
|
||||
defer cs.connLock.Unlock()
|
||||
if cf, ok := cs.conns[accid]; ok {
|
||||
out = cf.friends
|
||||
cf.friends = nil
|
||||
cf.initialized = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type friends struct {
|
||||
mongoClient gocommon.MongoClient
|
||||
redison *gocommon.RedisonHandler
|
||||
wsh *wshandler.WebsocketHandler
|
||||
moncen []monitoringCenter
|
||||
conns connections
|
||||
conns *connections
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
@ -145,6 +74,14 @@ func init() {
|
||||
// - listener(objectid) : socket
|
||||
// - listener(objectid) : socket
|
||||
|
||||
func combineObjectID(l primitive.ObjectID, r primitive.ObjectID) (out primitive.ObjectID) {
|
||||
copy(out[0:2], l[2:4])
|
||||
copy(out[2:6], l[8:12])
|
||||
copy(out[6:8], r[2:4])
|
||||
copy(out[8:12], r[8:12])
|
||||
return
|
||||
}
|
||||
|
||||
func makeSrcMap(src string, connected bool) *listenerMap {
|
||||
online, _ := json.Marshal(wshandler.DownstreamMessage{
|
||||
Body: bson.M{
|
||||
@ -170,7 +107,7 @@ func makeSrcMap(src string, connected bool) *listenerMap {
|
||||
}
|
||||
}
|
||||
|
||||
func makeFriends(ctx context.Context, so *Social) (*friends, error) {
|
||||
func makeFriends(ctx context.Context, so *Social, conns *connections) (*friends, error) {
|
||||
if err := so.mongoClient.MakeUniqueIndices(friends_collection_name, map[string]bson.D{
|
||||
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
||||
}); err != nil {
|
||||
@ -261,15 +198,11 @@ func makeFriends(ctx context.Context, so *Social) (*friends, error) {
|
||||
redison: so.redison,
|
||||
wsh: so.wsh,
|
||||
moncen: moncen,
|
||||
conns: connections{
|
||||
conns: make(map[primitive.ObjectID]*connWithFriends),
|
||||
},
|
||||
conns: conns,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (fs *friends) ClientConnected(conn *websocket.Conn, callby *wshandler.Sender) {
|
||||
fs.conns.new(callby.Accid, conn)
|
||||
|
||||
// 내 로그인 상태를 알림
|
||||
meidx := callby.Accid[11] % monitoring_center_count
|
||||
fs.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_online)
|
||||
@ -281,26 +214,13 @@ func (fs *friends) ClientDisconnected(conn *websocket.Conn, callby *wshandler.Se
|
||||
fs.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_offline)
|
||||
|
||||
fs.stopMonitoringFriends(callby.Accid)
|
||||
|
||||
fs.conns.delete(callby.Accid)
|
||||
}
|
||||
|
||||
func (fs *friends) writeMessage(acc primitive.ObjectID, src any) {
|
||||
c := fs.conns.conn(acc)
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if bt, err := json.Marshal(src); err == nil {
|
||||
c.WriteMessage(websocket.TextMessage, bt)
|
||||
}
|
||||
}
|
||||
|
||||
var errAddFriendFailed = errors.New("addFriend failed")
|
||||
|
||||
func (fs *friends) addFriend(f *friendDoc) error {
|
||||
_, newid, err := fs.mongoClient.Update(friends_collection_name, bson.M{
|
||||
"_id": primitive.NewObjectID(),
|
||||
"_id": combineObjectID(f.From, f.To),
|
||||
}, bson.M{
|
||||
"$setOnInsert": f,
|
||||
}, options.Update().SetUpsert(true))
|
||||
@ -332,21 +252,6 @@ func (fs *friends) addFriend(f *friendDoc) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fs *friends) Block(ctx wshandler.ApiCallContext) {
|
||||
// BlockByMe 에 추가하고 상대의 BlockByYou를 설정한다.
|
||||
|
||||
// var bi struct {
|
||||
// From primitive.ObjectID
|
||||
// To primitive.ObjectID
|
||||
// }
|
||||
// if err := gocommon.MakeDecoder(r).Decode(&bi); err != nil {
|
||||
// logger.Println("friends.Block failed :", err)
|
||||
// w.WriteHeader(http.StatusBadRequest)
|
||||
// return
|
||||
// }
|
||||
// logger.Println("friends.Block :", bi)
|
||||
}
|
||||
|
||||
func (fs *friends) DeleteFriend(ctx wshandler.ApiCallContext) {
|
||||
fid, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||
|
||||
@ -378,7 +283,7 @@ func (fs *friends) DeleteFriend(ctx wshandler.ApiCallContext) {
|
||||
"ts": fdoc.Timestamp,
|
||||
},
|
||||
}, options.Update().SetUpsert(false))
|
||||
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||
fs.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||
Body: []friendDoc{fdoc},
|
||||
Tag: friends_tag,
|
||||
})
|
||||
@ -463,7 +368,7 @@ func (fs *friends) QueryFriends(ctx wshandler.ApiCallContext) {
|
||||
}
|
||||
|
||||
if len(myfriends) > 0 {
|
||||
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||
fs.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||
Alias: ctx.CallBy.Alias,
|
||||
Body: myfriends,
|
||||
Tag: friends_tag,
|
||||
@ -489,3 +394,59 @@ func (fs *friends) Trim(ctx wshandler.ApiCallContext) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *friends) Block(w http.ResponseWriter, r *http.Request) {
|
||||
// 친구를 삭제
|
||||
var block blockDoc
|
||||
if err := gocommon.MakeDecoder(r).Decode(&block); err != nil {
|
||||
logger.Println("Block failed:", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
id := combineObjectID(block.From, block.To)
|
||||
now := time.Now().UTC().Unix()
|
||||
|
||||
// 나한테 삭제
|
||||
updated, _, err := fs.mongoClient.Update(friends_collection_name, bson.M{
|
||||
"_id": id,
|
||||
}, bson.M{
|
||||
"$set": bson.M{
|
||||
"deleted": true,
|
||||
"ts": now,
|
||||
},
|
||||
}, options.Update().SetUpsert(false))
|
||||
|
||||
if err != nil {
|
||||
logger.Println("Block failed:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !updated {
|
||||
// 친구가 아닌 모양. 그냥 넘어가면 끝
|
||||
return
|
||||
}
|
||||
|
||||
fs.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: block.From.Hex(),
|
||||
Body: []friendDoc{{Id: id, Deleted: true, Timestamp: now}},
|
||||
Tag: friends_tag,
|
||||
})
|
||||
|
||||
// 상대방한테서 나를 제거
|
||||
id = combineObjectID(block.To, block.From)
|
||||
fs.mongoClient.Update(friends_collection_name, bson.M{
|
||||
"_id": id,
|
||||
}, bson.M{
|
||||
"$set": bson.M{
|
||||
"deleted": true,
|
||||
"ts": now,
|
||||
},
|
||||
}, options.Update().SetUpsert(false))
|
||||
fs.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: block.To.Hex(),
|
||||
Body: []friendDoc{{Id: id, Deleted: true, Timestamp: now}},
|
||||
Tag: friends_tag,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user