차단 목록 관리 추가하고 connection 분리
This commit is contained in:
124
core/blocklist.go
Normal file
124
core/blocklist.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
)
|
||||||
|
|
||||||
|
type blockDoc struct {
|
||||||
|
Id primitive.ObjectID `bson:"_id,omitempty" json:"id"`
|
||||||
|
From primitive.ObjectID `bson:"from,omitempty" json:"-"`
|
||||||
|
To primitive.ObjectID `bson:"to,omitempty" json:"-"`
|
||||||
|
ToAlias string `bson:"talias" json:"to"`
|
||||||
|
Timestamp int64 `bson:"ts" json:"ts"`
|
||||||
|
Deleted bool `bson:"deleted,omitempty" json:"deleted,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type blocklist struct {
|
||||||
|
mongoClient gocommon.MongoClient
|
||||||
|
redison *gocommon.RedisonHandler
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
conns *connections
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBlocklist(ctx context.Context, so *Social, conns *connections) (*blocklist, error) {
|
||||||
|
if err := so.mongoClient.MakeUniqueIndices(block_collection_name, map[string]bson.D{
|
||||||
|
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &blocklist{
|
||||||
|
mongoClient: so.mongoClient,
|
||||||
|
redison: so.redison,
|
||||||
|
wsh: so.wsh,
|
||||||
|
conns: conns,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bl *blocklist) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
_, newid, err := bl.mongoClient.Update(block_collection_name, bson.M{
|
||||||
|
"_id": combineObjectID(block.From, block.To),
|
||||||
|
}, bson.M{
|
||||||
|
"$set": block,
|
||||||
|
}, options.Update().SetUpsert(true))
|
||||||
|
|
||||||
|
if err != nil || newid != block.Id {
|
||||||
|
// 이미 있다고 봐야지
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Id = newid.(primitive.ObjectID)
|
||||||
|
bl.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: block.To.Hex(),
|
||||||
|
Body: []blockDoc{block},
|
||||||
|
Tag: blocks_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bl *blocklist) Unblock(ctx wshandler.ApiCallContext) {
|
||||||
|
id, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
now := time.Now().UTC().Unix()
|
||||||
|
updated, _, err := bl.mongoClient.Update(block_collection_name, bson.M{
|
||||||
|
"_id": id,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"deleted": true,
|
||||||
|
"ts": now,
|
||||||
|
},
|
||||||
|
}, options.Update().SetUpsert(false))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("Unblock failed :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
bl.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
|
Alias: ctx.CallBy.Alias,
|
||||||
|
Body: []blockDoc{{Id: id, Deleted: true, Timestamp: now}},
|
||||||
|
Tag: blocks_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bl *blocklist) QueryBlock(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
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := bl.mongoClient.Exists(block_collection_name, bson.M{
|
||||||
|
"from": block.From,
|
||||||
|
"to": block.To,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("QueryBlock failed :", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
w.WriteHeader(http.StatusGone)
|
||||||
|
}
|
||||||
|
}
|
||||||
14
core/common.go
Normal file
14
core/common.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import "repositories.action2quare.com/ayo/gocommon"
|
||||||
|
|
||||||
|
const (
|
||||||
|
block_collection_name = gocommon.CollectionName("block")
|
||||||
|
friends_collection_name = gocommon.CollectionName("friend")
|
||||||
|
invitation_collection_name = gocommon.CollectionName("invitation")
|
||||||
|
)
|
||||||
|
|
||||||
|
var friend_state_tag = []string{"social.FriendState"}
|
||||||
|
var invitations_tag = []string{"social.Invitations"}
|
||||||
|
var friends_tag = []string{"social.Friends"}
|
||||||
|
var blocks_tag = []string{"social.Blocks"}
|
||||||
106
core/connection.go
Normal file
106
core/connection.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *connections) writeMessage(acc primitive.ObjectID, src any) {
|
||||||
|
cs.connLock.Lock()
|
||||||
|
defer cs.connLock.Unlock()
|
||||||
|
|
||||||
|
conn := cs.conns[acc]
|
||||||
|
if conn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if bt, err := json.Marshal(src); err == nil {
|
||||||
|
conn.c.WriteMessage(websocket.TextMessage, bt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *connections) ClientConnected(conn *websocket.Conn, callby *wshandler.Sender) {
|
||||||
|
cs.new(callby.Accid, conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *connections) ClientDisconnected(conn *websocket.Conn, callby *wshandler.Sender) {
|
||||||
|
cs.delete(callby.Accid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeConnections() *connections {
|
||||||
|
return &connections{
|
||||||
|
conns: make(map[primitive.ObjectID]*connWithFriends),
|
||||||
|
}
|
||||||
|
}
|
||||||
181
core/friend.go
181
core/friend.go
@ -6,8 +6,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
@ -20,14 +20,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
friends_collection_name = gocommon.CollectionName("friends")
|
|
||||||
monitoring_center_count = 100
|
monitoring_center_count = 100
|
||||||
state_online = "online"
|
state_online = "online"
|
||||||
state_offline = "offline"
|
state_offline = "offline"
|
||||||
)
|
)
|
||||||
|
|
||||||
var friend_state_tag = []string{"social.FriendState"}
|
|
||||||
|
|
||||||
type friendDoc struct {
|
type friendDoc struct {
|
||||||
Id primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
|
Id primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
|
||||||
From primitive.ObjectID `bson:"from" json:"-"`
|
From primitive.ObjectID `bson:"from" json:"-"`
|
||||||
@ -48,80 +45,12 @@ type monitoringCenter struct {
|
|||||||
publishState func(string, string, string)
|
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 {
|
type friends struct {
|
||||||
mongoClient gocommon.MongoClient
|
mongoClient gocommon.MongoClient
|
||||||
redison *gocommon.RedisonHandler
|
redison *gocommon.RedisonHandler
|
||||||
wsh *wshandler.WebsocketHandler
|
wsh *wshandler.WebsocketHandler
|
||||||
moncen []monitoringCenter
|
moncen []monitoringCenter
|
||||||
conns connections
|
conns *connections
|
||||||
}
|
}
|
||||||
|
|
||||||
type listener struct {
|
type listener struct {
|
||||||
@ -145,6 +74,14 @@ func init() {
|
|||||||
// - listener(objectid) : socket
|
// - listener(objectid) : socket
|
||||||
// - 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 {
|
func makeSrcMap(src string, connected bool) *listenerMap {
|
||||||
online, _ := json.Marshal(wshandler.DownstreamMessage{
|
online, _ := json.Marshal(wshandler.DownstreamMessage{
|
||||||
Body: bson.M{
|
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{
|
if err := so.mongoClient.MakeUniqueIndices(friends_collection_name, map[string]bson.D{
|
||||||
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@ -261,15 +198,11 @@ func makeFriends(ctx context.Context, so *Social) (*friends, error) {
|
|||||||
redison: so.redison,
|
redison: so.redison,
|
||||||
wsh: so.wsh,
|
wsh: so.wsh,
|
||||||
moncen: moncen,
|
moncen: moncen,
|
||||||
conns: connections{
|
conns: conns,
|
||||||
conns: make(map[primitive.ObjectID]*connWithFriends),
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *friends) ClientConnected(conn *websocket.Conn, callby *wshandler.Sender) {
|
func (fs *friends) ClientConnected(conn *websocket.Conn, callby *wshandler.Sender) {
|
||||||
fs.conns.new(callby.Accid, conn)
|
|
||||||
|
|
||||||
// 내 로그인 상태를 알림
|
// 내 로그인 상태를 알림
|
||||||
meidx := callby.Accid[11] % monitoring_center_count
|
meidx := callby.Accid[11] % monitoring_center_count
|
||||||
fs.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_online)
|
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.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_offline)
|
||||||
|
|
||||||
fs.stopMonitoringFriends(callby.Accid)
|
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")
|
var errAddFriendFailed = errors.New("addFriend failed")
|
||||||
|
|
||||||
func (fs *friends) addFriend(f *friendDoc) error {
|
func (fs *friends) addFriend(f *friendDoc) error {
|
||||||
_, newid, err := fs.mongoClient.Update(friends_collection_name, bson.M{
|
_, newid, err := fs.mongoClient.Update(friends_collection_name, bson.M{
|
||||||
"_id": primitive.NewObjectID(),
|
"_id": combineObjectID(f.From, f.To),
|
||||||
}, bson.M{
|
}, bson.M{
|
||||||
"$setOnInsert": f,
|
"$setOnInsert": f,
|
||||||
}, options.Update().SetUpsert(true))
|
}, options.Update().SetUpsert(true))
|
||||||
@ -332,21 +252,6 @@ func (fs *friends) addFriend(f *friendDoc) error {
|
|||||||
return nil
|
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) {
|
func (fs *friends) DeleteFriend(ctx wshandler.ApiCallContext) {
|
||||||
fid, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
fid, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
|
||||||
@ -378,7 +283,7 @@ func (fs *friends) DeleteFriend(ctx wshandler.ApiCallContext) {
|
|||||||
"ts": fdoc.Timestamp,
|
"ts": fdoc.Timestamp,
|
||||||
},
|
},
|
||||||
}, options.Update().SetUpsert(false))
|
}, options.Update().SetUpsert(false))
|
||||||
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
fs.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
Body: []friendDoc{fdoc},
|
Body: []friendDoc{fdoc},
|
||||||
Tag: friends_tag,
|
Tag: friends_tag,
|
||||||
})
|
})
|
||||||
@ -463,7 +368,7 @@ func (fs *friends) QueryFriends(ctx wshandler.ApiCallContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(myfriends) > 0 {
|
if len(myfriends) > 0 {
|
||||||
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
fs.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
Alias: ctx.CallBy.Alias,
|
Alias: ctx.CallBy.Alias,
|
||||||
Body: myfriends,
|
Body: myfriends,
|
||||||
Tag: friends_tag,
|
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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -14,14 +14,6 @@ import (
|
|||||||
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
invitation_collection_name = gocommon.CollectionName("invitation")
|
|
||||||
)
|
|
||||||
|
|
||||||
var invitation_sent_tag = []string{"social.InvitationsSent"}
|
|
||||||
var invitation_received_tag = []string{"social.InvitationsReceived"}
|
|
||||||
var friends_tag = []string{"social.Friends"}
|
|
||||||
|
|
||||||
type invitation struct {
|
type invitation struct {
|
||||||
mongoClient gocommon.MongoClient
|
mongoClient gocommon.MongoClient
|
||||||
redison *gocommon.RedisonHandler
|
redison *gocommon.RedisonHandler
|
||||||
@ -37,6 +29,7 @@ type invitationDoc struct {
|
|||||||
ToAlias string `bson:"talias,omitempty" json:"to"`
|
ToAlias string `bson:"talias,omitempty" json:"to"`
|
||||||
Timestamp int64 `bson:"ts" json:"ts"`
|
Timestamp int64 `bson:"ts" json:"ts"`
|
||||||
Deleted bool `bson:"deleted,omitempty" json:"deleted,omitempty"`
|
Deleted bool `bson:"deleted,omitempty" json:"deleted,omitempty"`
|
||||||
|
Blocked bool `bson:"blocked,omitempty" json:"-"` // From은 To에 의해 차단된 상태를 표시
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -45,14 +38,14 @@ func init() {
|
|||||||
|
|
||||||
func makeInvitation(ctx context.Context, s *Social, f *friends) (*invitation, error) {
|
func makeInvitation(ctx context.Context, s *Social, f *friends) (*invitation, error) {
|
||||||
if err := s.mongoClient.MakeUniqueIndices(invitation_collection_name, map[string]bson.D{
|
if err := s.mongoClient.MakeUniqueIndices(invitation_collection_name, map[string]bson.D{
|
||||||
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
"fromts": {{Key: "from", Value: 1}, {Key: "ts", Value: -1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 내가 받은거
|
// 내가 받은거
|
||||||
if err := s.mongoClient.MakeIndices(invitation_collection_name, map[string]bson.D{
|
if err := s.mongoClient.MakeIndices(invitation_collection_name, map[string]bson.D{
|
||||||
"received": {{Key: "to", Value: 1}, {Key: "ts", Value: -1}},
|
"tots": {{Key: "to", Value: 1}, {Key: "ts", Value: -1}, {Key: "blocked", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -65,49 +58,34 @@ func makeInvitation(ctx context.Context, s *Social, f *friends) (*invitation, er
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iv *invitation) QueryReceivedInvitations(ctx wshandler.ApiCallContext) {
|
func (iv *invitation) QueryInvitations(ctx wshandler.ApiCallContext) {
|
||||||
// 내가 받은 초대 목록
|
// 내가 받은 초대 목록
|
||||||
queryfrom := int64(ctx.Arguments[0].(float64))
|
queryfrom := int64(ctx.Arguments[0].(float64))
|
||||||
|
|
||||||
var receives []*invitationDoc
|
var receives []*invitationDoc
|
||||||
|
|
||||||
err := iv.mongoClient.FindAllAs(invitation_collection_name, bson.M{
|
if err := iv.mongoClient.FindAllAs(invitation_collection_name, bson.M{
|
||||||
"to": ctx.CallBy.Accid,
|
"to": ctx.CallBy.Accid,
|
||||||
"ts": bson.M{"$gt": queryfrom},
|
"ts": bson.M{"$gt": queryfrom},
|
||||||
}, &receives)
|
"blocked": false,
|
||||||
if err != nil {
|
}, &receives, options.Find().SetHint("tots")); err != nil {
|
||||||
logger.Println("QueryReceivedInvitations failed. FindAllAs err :", err)
|
logger.Println("QueryInvitations failed. FindAllAs err :", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(receives) > 0 {
|
var sents []*invitationDoc
|
||||||
|
if err := iv.mongoClient.FindAllAs(invitation_collection_name, bson.M{
|
||||||
|
"from": ctx.CallBy.Accid,
|
||||||
|
"ts": bson.M{"$gt": queryfrom},
|
||||||
|
}, &sents, options.Find().SetHint("fromts")); err != nil {
|
||||||
|
logger.Println("QueryInvitations failed. FindAllAs err :", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
invitations := append(receives, sents...)
|
||||||
|
if len(invitations) > 0 {
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ctx.CallBy.Accid.Hex(),
|
Target: ctx.CallBy.Accid.Hex(),
|
||||||
Body: receives,
|
Body: invitations,
|
||||||
Tag: invitation_received_tag,
|
Tag: invitations_tag,
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (iv *invitation) QuerySentInvitations(ctx wshandler.ApiCallContext) {
|
|
||||||
// 내가 보낸 초대 목록
|
|
||||||
queryfrom := int64(ctx.Arguments[0].(float64))
|
|
||||||
|
|
||||||
var receives []*invitationDoc
|
|
||||||
|
|
||||||
err := iv.mongoClient.FindAllAs(invitation_collection_name, bson.M{
|
|
||||||
"from": ctx.CallBy.Accid,
|
|
||||||
"ts": bson.M{"$gt": queryfrom},
|
|
||||||
"falias": bson.M{"$exists": true},
|
|
||||||
}, &receives)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("QueryReceivedInvitations failed. FindAllAs err :", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(receives) > 0 {
|
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
|
||||||
Target: ctx.CallBy.Accid.Hex(),
|
|
||||||
Body: receives,
|
|
||||||
Tag: invitation_sent_tag,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,13 +123,13 @@ func (iv *invitation) CancelInvitation(ctx wshandler.ApiCallContext) {
|
|||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ivdoc.To.Hex(),
|
Target: ivdoc.To.Hex(),
|
||||||
Body: []invitationDoc{ivdoc},
|
Body: []invitationDoc{ivdoc},
|
||||||
Tag: invitation_received_tag,
|
Tag: invitations_tag,
|
||||||
})
|
})
|
||||||
|
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ivdoc.From.Hex(),
|
Target: ivdoc.From.Hex(),
|
||||||
Body: []invitationDoc{ivdoc},
|
Body: []invitationDoc{ivdoc},
|
||||||
Tag: invitation_sent_tag,
|
Tag: invitations_tag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,13 +241,13 @@ func (iv *invitation) DenyInvitation(ctx wshandler.ApiCallContext) {
|
|||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ivdoc.To.Hex(),
|
Target: ivdoc.To.Hex(),
|
||||||
Body: []invitationDoc{ivdoc},
|
Body: []invitationDoc{ivdoc},
|
||||||
Tag: invitation_received_tag,
|
Tag: invitations_tag,
|
||||||
})
|
})
|
||||||
|
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ivdoc.From.Hex(),
|
Target: ivdoc.From.Hex(),
|
||||||
Body: []invitationDoc{ivdoc},
|
Body: []invitationDoc{ivdoc},
|
||||||
Tag: invitation_sent_tag,
|
Tag: invitations_tag,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,76 +286,109 @@ func (iv *invitation) InviteAsFriend(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ivdoc.Timestamp = time.Now().UTC().Unix()
|
// ivdoc.To가 invdoc.From을 차단했으면 표시
|
||||||
_, newid, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
exists, err := iv.mongoClient.Exists(block_collection_name, bson.M{"_id": combineObjectID(ivdoc.To, ivdoc.From)})
|
||||||
"from": ivdoc.From,
|
|
||||||
"to": ivdoc.To,
|
|
||||||
}, bson.M{
|
|
||||||
"$set": bson.M{
|
|
||||||
"ts": ivdoc.Timestamp,
|
|
||||||
"falias": ivdoc.FromAlias,
|
|
||||||
"talias": ivdoc.ToAlias,
|
|
||||||
},
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println("IniviteAsFriend failed:", err)
|
logger.Println("IniviteAsFriend failed:", err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if newid != nil {
|
// exists면 차단된 상태
|
||||||
ivdoc.Id = newid.(primitive.ObjectID)
|
ivdoc.Blocked = exists
|
||||||
|
ivdoc.Timestamp = time.Now().UTC().Unix()
|
||||||
|
_, newid, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
"_id": combineObjectID(ivdoc.From, ivdoc.To),
|
||||||
|
}, bson.M{"$setOnInsert": ivdoc}, options.Update().SetUpsert(true))
|
||||||
|
if err != nil || newid == nil {
|
||||||
|
logger.Println("IniviteAsFriend failed:", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ivdoc.Id = newid.(primitive.ObjectID)
|
||||||
|
if !ivdoc.Blocked {
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
Target: ivdoc.To.Hex(),
|
Target: ivdoc.To.Hex(),
|
||||||
Body: []invitationDoc{ivdoc},
|
Body: []invitationDoc{ivdoc},
|
||||||
Tag: invitation_received_tag,
|
Tag: invitations_tag,
|
||||||
})
|
|
||||||
} else {
|
|
||||||
found, _ := iv.mongoClient.FindOne(invitation_collection_name, bson.M{
|
|
||||||
"from": ivdoc.From,
|
|
||||||
"to": ivdoc.To,
|
|
||||||
}, options.FindOne().SetProjection(bson.M{"_id": 1}))
|
|
||||||
|
|
||||||
ivdoc.Id = found["_id"].(primitive.ObjectID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !ivdoc.Id.IsZero() {
|
|
||||||
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
|
||||||
Target: ivdoc.From.Hex(),
|
|
||||||
Body: []invitationDoc{ivdoc},
|
|
||||||
Tag: invitation_sent_tag,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.From.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitations_tag,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iv *invitation) Block(w http.ResponseWriter, r *http.Request) {
|
func (iv *invitation) Block(w http.ResponseWriter, r *http.Request) {
|
||||||
// 초대가 있으면
|
var block blockDoc
|
||||||
// var bi struct {
|
if err := gocommon.MakeDecoder(r).Decode(&block); err != nil {
|
||||||
// From primitive.ObjectID
|
logger.Println("Block failed:", err)
|
||||||
// To primitive.ObjectID
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
// FromAlias string
|
return
|
||||||
// }
|
}
|
||||||
// if err := gocommon.MakeDecoder(r).Decode(&bi); err != nil {
|
|
||||||
// logger.Println("invitation.Block failed :", err)
|
|
||||||
// w.WriteHeader(http.StatusBadRequest)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// now := time.Now().UTC().Unix()
|
// 차단한 상대가 나한테 보낸 초대가 있으면 차단 표시
|
||||||
// // From이 To를 block했으므로 To가 From을 초대하는 것을 방지하려면 둘을 뒤집어서 문서를 만들어 놔야 함
|
// block.From이 block.To를 차단 -> block.To가 block.From을 초대한게 있나?
|
||||||
// // 이미 존재하는 초대일 수도 있다.
|
id := combineObjectID(block.To, block.From)
|
||||||
// _, _, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
now := time.Now().UTC().Unix()
|
||||||
// "from": bi.To,
|
updated, _, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
// "to": bi.From,
|
"_id": id,
|
||||||
// }, bson.M{
|
}, bson.M{
|
||||||
// "$set": invitationDoc{
|
"$set": bson.M{
|
||||||
// ToAlias: bi.FromAlias,
|
"blocked": true,
|
||||||
// Timestamp: now,
|
"ts": now,
|
||||||
// },
|
},
|
||||||
// }, options.Update().SetUpsert(true))
|
}, options.Update().SetUpsert(false))
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// logger.Println("Block failed:", err)
|
logger.Println("Block failed:", err)
|
||||||
// w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
// 초대가 있었다.
|
||||||
|
// 사실은 삭제가 아니지만 초대 삭제 알림. 나중에 쿼리해도 안나옴
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: block.From.Hex(),
|
||||||
|
Body: []invitationDoc{{Id: id, Deleted: true, Timestamp: now}},
|
||||||
|
Tag: invitations_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) Unblock(ctx wshandler.ApiCallContext) {
|
||||||
|
// From이 To를 unblock = to가 from을 block했었다. = from이 to한테 보낸 초대가 있을 수 있다.
|
||||||
|
// invitation key는 to+from이고 block key는 from+to
|
||||||
|
id, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
|
||||||
|
var revertid primitive.ObjectID
|
||||||
|
copy(revertid[:6], id[6:])
|
||||||
|
copy(revertid[6:], id[:6])
|
||||||
|
|
||||||
|
now := time.Now().UTC().Unix()
|
||||||
|
var ivdoc invitationDoc
|
||||||
|
err := iv.mongoClient.FindOneAndUpdateAs(invitation_collection_name, bson.M{
|
||||||
|
"_id": revertid,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"ts": now,
|
||||||
|
},
|
||||||
|
}, &ivdoc, options.FindOneAndUpdate().SetUpsert(false).SetReturnDocument(options.After))
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("Block failed:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ivdoc.Id.IsZero() {
|
||||||
|
// 받은 초대가 있었다.
|
||||||
|
// 나한테 알림
|
||||||
|
iv.f.conns.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
|
Alias: ctx.CallBy.Alias,
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitations_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,18 @@ func (so *Social) prepare(ctx context.Context) error {
|
|||||||
|
|
||||||
so.redison = gocommon.NewRedisonHandler(redisClient.Context(), redisClient)
|
so.redison = gocommon.NewRedisonHandler(redisClient.Context(), redisClient)
|
||||||
|
|
||||||
friends, err := makeFriends(ctx, so)
|
connections := makeConnections()
|
||||||
|
so.wsh.AddHandler(wshandler.MakeWebsocketApiHandler(connections, "social"))
|
||||||
|
so.httpApiBorker.AddHandler(gocommon.MakeHttpApiHandler(connections, "social"))
|
||||||
|
|
||||||
|
blocks, err := makeBlocklist(ctx, so, connections)
|
||||||
|
if err != nil {
|
||||||
|
return logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
so.wsh.AddHandler(wshandler.MakeWebsocketApiHandler(blocks, "social"))
|
||||||
|
so.httpApiBorker.AddHandler(gocommon.MakeHttpApiHandler(blocks, "social"))
|
||||||
|
|
||||||
|
friends, err := makeFriends(ctx, so, connections)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logger.ErrorWithCallStack(err)
|
return logger.ErrorWithCallStack(err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user