현 상태를 친구에게 공개

This commit is contained in:
2023-09-22 18:32:23 +09:00
parent 343f69d662
commit ad90f63694
4 changed files with 77 additions and 61 deletions

View File

@ -21,7 +21,6 @@ import (
const (
monitoring_center_count = 100
state_online = "online"
state_offline = "offline"
)
@ -42,7 +41,7 @@ type registerListener struct {
type monitoringCenter struct {
regChan chan registerListener
publishState func(string, string, string)
publishState func(primitive.ObjectID, string)
}
type friends struct {
@ -60,9 +59,8 @@ type listener struct {
type listenerMap struct {
listeners map[primitive.ObjectID]*listener
connected bool
online []byte
offline []byte
lastState []byte
}
func init() {
@ -82,28 +80,17 @@ func combineObjectID(l primitive.ObjectID, r primitive.ObjectID) (out primitive.
return
}
func makeSrcMap(src string, connected bool) *listenerMap {
online, _ := json.Marshal(wshandler.DownstreamMessage{
Body: bson.M{
"from": src,
"state": state_online,
},
Tag: friend_state_tag,
})
func makeSrcMap(src string, state []byte) *listenerMap {
offline, _ := json.Marshal(wshandler.DownstreamMessage{
Body: bson.M{
"from": src,
"state": state_offline,
},
Tag: friend_state_tag,
Alias: src,
Body: bson.M{},
Tag: friend_state_tag,
})
return &listenerMap{
listeners: make(map[primitive.ObjectID]*listener),
connected: connected,
online: online,
offline: offline,
lastState: state,
}
}
@ -120,8 +107,12 @@ func makeFriends(ctx context.Context, so *Social, conns *connections) (*friends,
regChan := make(chan registerListener)
moncen = append(moncen, monitoringCenter{
regChan: regChan,
publishState: func(src, alias, state string) {
so.redison.Publish(ctx, subChannel, src+alias+":"+state).Result()
publishState: func(accid primitive.ObjectID, state string) {
if len(state) == 0 {
so.redison.Publish(ctx, subChannel, accid.Hex()).Result()
} else {
so.redison.Publish(ctx, subChannel, accid.Hex()+state).Result()
}
},
})
@ -132,9 +123,9 @@ func makeFriends(ctx context.Context, so *Social, conns *connections) (*friends,
select {
case reg := <-regChan:
// 내가 관심있는 애들 등록
srcmap, online := listeners[reg.src]
if !online {
srcmap = makeSrcMap(reg.alias, false)
srcmap, exists := listeners[reg.src]
if !exists {
srcmap = makeSrcMap(reg.alias, nil)
listeners[reg.src] = srcmap
}
@ -142,51 +133,54 @@ func makeFriends(ctx context.Context, so *Social, conns *connections) (*friends,
// 등록 해제. 모니터링 종료
// listener목록에서 나(reg.l.me)를 제거
delete(srcmap.listeners, reg.l.me)
online = false
exists = false
logger.Println("regChan unregistered :", reg.src.Hex(), reg.l.me.Hex())
} else if oldl, ok := srcmap.listeners[reg.l.me]; ok {
// 내가 이미 리스너로 등록되어 있다.
// 상대방이 나를 차단했을 경우에는 기존 리스너가 nil임
online = oldl != nil
logger.Println("regChan registered :", reg.src.Hex(), reg.l.me.Hex(), "old", online)
exists = oldl != nil
} else {
logger.Println("regChan registered :", reg.src.Hex(), reg.l.me.Hex())
srcmap.listeners[reg.l.me] = reg.l
}
if online && srcmap != nil {
logger.Println("regChan send online :", reg.l.me.Hex(), string(srcmap.online))
reg.l.c.WriteMessage(websocket.TextMessage, srcmap.online)
if exists && srcmap != nil && len(srcmap.lastState) > 0 {
reg.l.c.WriteMessage(websocket.TextMessage, srcmap.lastState)
}
if len(srcmap.listeners) == 0 && !srcmap.connected {
if len(srcmap.listeners) == 0 && len(srcmap.lastState) == 0 {
delete(listeners, reg.src)
}
case msg := <-pubsub.Channel():
target, _ := primitive.ObjectIDFromHex(msg.Payload[:24])
aliasstate := strings.SplitN(msg.Payload[24:], ":", 2)
var sent []byte
state := msg.Payload[24:]
if srcmap, ok := listeners[target]; ok {
if aliasstate[1] == state_online {
sent = srcmap.online
srcmap.connected = true
} else if aliasstate[1] == state_offline {
sent = srcmap.offline
srcmap.connected = false
if srcmap == nil {
delete(listeners, target)
break
}
if len(state) == 0 {
// 접속 종료
srcmap.lastState = nil
if len(srcmap.listeners) == 0 {
delete(listeners, target)
}
}
if len(sent) > 0 {
for _, l := range srcmap.listeners {
logger.Println("state fire :", l.me, string(sent))
l.c.WriteMessage(websocket.TextMessage, sent)
l.c.WriteMessage(websocket.TextMessage, srcmap.offline)
}
} else {
srcmap.lastState = []byte(state)
for _, l := range srcmap.listeners {
l.c.WriteMessage(websocket.TextMessage, srcmap.lastState)
}
}
} else if aliasstate[1] == state_online {
listeners[target] = makeSrcMap(aliasstate[0], true)
} else if len(state) > 0 {
var dnstream wshandler.DownstreamMessage
if err := json.Unmarshal([]byte(state), &dnstream); err == nil {
listeners[target] = makeSrcMap(dnstream.Alias, []byte(state))
}
}
}
}
@ -202,16 +196,10 @@ func makeFriends(ctx context.Context, so *Social, conns *connections) (*friends,
}, nil
}
func (fs *friends) ClientConnected(conn *websocket.Conn, callby *wshandler.Sender) {
// 내 로그인 상태를 알림
meidx := callby.Accid[11] % monitoring_center_count
fs.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_online)
}
func (fs *friends) ClientDisconnected(conn *websocket.Conn, callby *wshandler.Sender) {
// 로그 오프 상태를 알림
meidx := callby.Accid[11] % monitoring_center_count
fs.moncen[meidx].publishState(callby.Accid.Hex(), callby.Alias, state_offline)
fs.moncen[meidx].publishState(callby.Accid, "")
fs.stopMonitoringFriends(callby.Accid)
}
@ -252,6 +240,17 @@ func (fs *friends) addFriend(f *friendDoc) error {
return nil
}
func (fs *friends) BroadcastMyState(ctx wshandler.ApiCallContext) {
stateobj := ctx.Arguments[0].(string)
meidx := ctx.CallBy.Accid[11] % monitoring_center_count
bt, _ := json.Marshal(wshandler.DownstreamMessage{
Alias: ctx.CallBy.Alias,
Body: "${state}",
Tag: friend_state_tag,
})
fs.moncen[meidx].publishState(ctx.CallBy.Accid, strings.Replace(string(bt), `"${state}"`, stateobj, 1))
}
func (fs *friends) DeleteFriend(ctx wshandler.ApiCallContext) {
fid, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))