초기 커밋. 친구 초대 및 관리 완료
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
.vscode/
|
||||||
|
__debug_bin.exe
|
||||||
|
*.log
|
||||||
|
config.json
|
||||||
47
config_template.json
Normal file
47
config_template.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"region_storage": {
|
||||||
|
"default": {
|
||||||
|
"mongo": "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||||
|
"redis": {
|
||||||
|
"cache": "redis://192.168.8.94:6380/0",
|
||||||
|
"session": "redis://192.168.8.94:6380/1",
|
||||||
|
"tx": "redis://192.168.8.94:6380/2",
|
||||||
|
"tavern": "redis://192.168.8.94:6380/3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"maingate_session_storage": "redis://192.168.8.94:6380/1",
|
||||||
|
"maingate_session_ttl" : 3600,
|
||||||
|
"maingate_api_token": "63d08aa34f0162622c11284b",
|
||||||
|
|
||||||
|
"social_redis_url": "redis://192.168.8.94:6380/4",
|
||||||
|
"social_storage_url" : "mongodb://192.168.8.94:27017/social?replicaSet=repl01&retrywrites=false",
|
||||||
|
|
||||||
|
"tavern_service_url": "http://localhost/tavern",
|
||||||
|
"tavern_group_types": {
|
||||||
|
"party": {
|
||||||
|
"max_member": 3,
|
||||||
|
"invite_ttl": 30
|
||||||
|
},
|
||||||
|
"chat" : {
|
||||||
|
"default_capacity" : 1000,
|
||||||
|
"channels" : {
|
||||||
|
"bazzar-1" : {
|
||||||
|
"name" : "FText(bazzar-1)"
|
||||||
|
},
|
||||||
|
"bazzar-2" : {
|
||||||
|
"name" : "FText(bazzar-2)"
|
||||||
|
},
|
||||||
|
"bazzar-3" : {
|
||||||
|
"name" : "FText(bazzar-3)"
|
||||||
|
},
|
||||||
|
"bazzar-4" : {
|
||||||
|
"name" : "FText(bazzar-4)"
|
||||||
|
},
|
||||||
|
"bazzar-5" : {
|
||||||
|
"name" : "FText(bazzar-5)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
491
core/friend.go
Normal file
491
core/friend.go
Normal file
@ -0,0 +1,491 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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:"-"`
|
||||||
|
To primitive.ObjectID `bson:"to" json:"-"`
|
||||||
|
ToAlias string `bson:"talias" json:"to"`
|
||||||
|
Timestamp int64 `bson:"ts" json:"ts"`
|
||||||
|
Deleted bool `bson:"deleted,omitempty" json:"deleted,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type registerListener struct {
|
||||||
|
src primitive.ObjectID
|
||||||
|
alias string
|
||||||
|
l *listener
|
||||||
|
}
|
||||||
|
|
||||||
|
type monitoringCenter struct {
|
||||||
|
regChan chan registerListener
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
type listener struct {
|
||||||
|
c *websocket.Conn
|
||||||
|
me primitive.ObjectID
|
||||||
|
}
|
||||||
|
|
||||||
|
type listenerMap struct {
|
||||||
|
listeners map[primitive.ObjectID]*listener
|
||||||
|
connected bool
|
||||||
|
online []byte
|
||||||
|
offline []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register([]friendDoc{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// per channel
|
||||||
|
// src(alias) - listener(objectid) : socket
|
||||||
|
// - listener(objectid) : socket
|
||||||
|
// - listener(objectid) : socket
|
||||||
|
|
||||||
|
func makeSrcMap(src string, connected bool) *listenerMap {
|
||||||
|
online, _ := json.Marshal(wshandler.DownstreamMessage{
|
||||||
|
Body: bson.M{
|
||||||
|
"from": src,
|
||||||
|
"state": state_online,
|
||||||
|
},
|
||||||
|
Tag: friend_state_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
offline, _ := json.Marshal(wshandler.DownstreamMessage{
|
||||||
|
Body: bson.M{
|
||||||
|
"from": src,
|
||||||
|
"state": state_offline,
|
||||||
|
},
|
||||||
|
Tag: friend_state_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
return &listenerMap{
|
||||||
|
listeners: make(map[primitive.ObjectID]*listener),
|
||||||
|
connected: connected,
|
||||||
|
online: online,
|
||||||
|
offline: offline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeFriends(ctx context.Context, so *Social) (*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 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var moncen []monitoringCenter
|
||||||
|
for i := 0; i < monitoring_center_count; i++ {
|
||||||
|
subChannel := fmt.Sprintf("_soc_fr_monitor_ch_%d_%d", i, so.redison.Options().DB)
|
||||||
|
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()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
go func(subChannel string, regChan chan registerListener) {
|
||||||
|
pubsub := so.redison.Subscribe(ctx, subChannel)
|
||||||
|
listeners := make(map[primitive.ObjectID]*listenerMap)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case reg := <-regChan:
|
||||||
|
// 내가 관심있는 애들 등록
|
||||||
|
srcmap, online := listeners[reg.src]
|
||||||
|
if !online {
|
||||||
|
srcmap = makeSrcMap(reg.alias, false)
|
||||||
|
listeners[reg.src] = srcmap
|
||||||
|
}
|
||||||
|
|
||||||
|
if reg.l.c == nil {
|
||||||
|
// 등록 해제. 모니터링 종료
|
||||||
|
// listener목록에서 나(reg.l.me)를 제거
|
||||||
|
delete(srcmap.listeners, reg.l.me)
|
||||||
|
online = 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)
|
||||||
|
} 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 len(srcmap.listeners) == 0 && !srcmap.connected {
|
||||||
|
delete(listeners, reg.src)
|
||||||
|
}
|
||||||
|
|
||||||
|
case msg := <-pubsub.Channel():
|
||||||
|
target, _ := primitive.ObjectIDFromHex(msg.Payload[:24])
|
||||||
|
aliasstate := strings.SplitN(msg.Payload[24:], ":", 2)
|
||||||
|
var sent []byte
|
||||||
|
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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if aliasstate[1] == state_online {
|
||||||
|
listeners[target] = makeSrcMap(aliasstate[0], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(subChannel, regChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &friends{
|
||||||
|
mongoClient: so.mongoClient,
|
||||||
|
redison: so.redison,
|
||||||
|
wsh: so.wsh,
|
||||||
|
moncen: moncen,
|
||||||
|
conns: connections{
|
||||||
|
conns: make(map[primitive.ObjectID]*connWithFriends),
|
||||||
|
},
|
||||||
|
}, 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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(),
|
||||||
|
}, bson.M{
|
||||||
|
"$setOnInsert": f,
|
||||||
|
}, options.Update().SetUpsert(true))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if newid == nil {
|
||||||
|
return errAddFriendFailed
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Id = newid.(primitive.ObjectID)
|
||||||
|
if fs.conns.addFriend(f.From, f) {
|
||||||
|
// 모니터링 중
|
||||||
|
conn := fs.conns.conn(f.From)
|
||||||
|
if conn != nil {
|
||||||
|
toidx := f.To[11] % monitoring_center_count
|
||||||
|
fs.moncen[toidx].regChan <- registerListener{
|
||||||
|
src: f.To,
|
||||||
|
alias: f.ToAlias,
|
||||||
|
l: &listener{
|
||||||
|
c: conn,
|
||||||
|
me: f.From,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
var fdoc friendDoc
|
||||||
|
if err := fs.mongoClient.FindOneAs(friends_collection_name, bson.M{
|
||||||
|
"_id": fid,
|
||||||
|
}, &fdoc, options.FindOne().SetProjection(bson.M{
|
||||||
|
"from": 1,
|
||||||
|
"to": 1,
|
||||||
|
})); err != nil {
|
||||||
|
logger.Println("DeleteFriend is failed :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if fdoc.Id.IsZero() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UTC().Unix()
|
||||||
|
fdoc.Deleted = true
|
||||||
|
fdoc.Timestamp = now
|
||||||
|
|
||||||
|
// 나한테 삭제
|
||||||
|
fs.mongoClient.Update(friends_collection_name, bson.M{
|
||||||
|
"_id": fid,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"deleted": true,
|
||||||
|
"ts": fdoc.Timestamp,
|
||||||
|
},
|
||||||
|
}, options.Update().SetUpsert(false))
|
||||||
|
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
|
Body: []friendDoc{fdoc},
|
||||||
|
Tag: friends_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 상대방에게 삭제
|
||||||
|
var yourdoc friendDoc
|
||||||
|
if err := fs.mongoClient.FindOneAndUpdateAs(friends_collection_name, bson.M{
|
||||||
|
"from": fdoc.To,
|
||||||
|
"to": fdoc.From,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"deleted": true,
|
||||||
|
"ts": now,
|
||||||
|
},
|
||||||
|
}, &yourdoc, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(false)); err == nil {
|
||||||
|
fs.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: fdoc.To.Hex(),
|
||||||
|
Body: []friendDoc{yourdoc},
|
||||||
|
Tag: friends_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *friends) StartMonitoringFriends(ctx wshandler.ApiCallContext) {
|
||||||
|
// 내 친구 목록에 나를 등록
|
||||||
|
var friends []*friendDoc
|
||||||
|
if err := fs.mongoClient.FindAllAs(friends_collection_name, bson.M{
|
||||||
|
"from": ctx.CallBy.Accid,
|
||||||
|
}, &friends, options.Find().SetProjection(bson.M{"to": 1, "talias": 1})); err != nil {
|
||||||
|
logger.Println("StartMonitoringFriends is failed :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
me := &listener{
|
||||||
|
c: fs.conns.conn(ctx.CallBy.Accid),
|
||||||
|
me: ctx.CallBy.Accid,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range friends {
|
||||||
|
toidx := f.To[11] % monitoring_center_count
|
||||||
|
fs.moncen[toidx].regChan <- registerListener{
|
||||||
|
src: f.To,
|
||||||
|
alias: f.ToAlias,
|
||||||
|
l: me,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.conns.initFriends(ctx.CallBy.Accid, friends)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *friends) stopMonitoringFriends(accid primitive.ObjectID) {
|
||||||
|
friends := fs.conns.clearFriends(accid)
|
||||||
|
|
||||||
|
if len(friends) > 0 {
|
||||||
|
// 나를 상대방 모니터링에서 뺀다
|
||||||
|
nilListener := &listener{c: nil, me: accid}
|
||||||
|
for _, f := range friends {
|
||||||
|
toidx := f.To[11] % monitoring_center_count
|
||||||
|
fs.moncen[toidx].regChan <- registerListener{
|
||||||
|
src: f.To,
|
||||||
|
alias: f.ToAlias,
|
||||||
|
l: nilListener,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *friends) StopMonitoringFriends(ctx wshandler.ApiCallContext) {
|
||||||
|
fs.stopMonitoringFriends(ctx.CallBy.Accid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *friends) QueryFriends(ctx wshandler.ApiCallContext) {
|
||||||
|
queryfrom := int64(ctx.Arguments[0].(float64))
|
||||||
|
|
||||||
|
var myfriends []friendDoc
|
||||||
|
err := fs.mongoClient.FindAllAs(friends_collection_name, bson.M{
|
||||||
|
"from": ctx.CallBy.Accid,
|
||||||
|
"ts": bson.M{"$gt": queryfrom},
|
||||||
|
}, &myfriends)
|
||||||
|
if err != nil {
|
||||||
|
logger.Println("QueryReceivedInvitations failed. FindAllAs err :", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(myfriends) > 0 {
|
||||||
|
fs.writeMessage(ctx.CallBy.Accid, &wshandler.DownstreamMessage{
|
||||||
|
Alias: ctx.CallBy.Alias,
|
||||||
|
Body: myfriends,
|
||||||
|
Tag: friends_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *friends) Trim(ctx wshandler.ApiCallContext) {
|
||||||
|
stringsTobjs := func(in []any) (out []primitive.ObjectID) {
|
||||||
|
for _, i := range in {
|
||||||
|
p, _ := primitive.ObjectIDFromHex(i.(string))
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := stringsTobjs(ctx.Arguments[2].([]any))
|
||||||
|
if len(ids) > 0 {
|
||||||
|
if len(ids) == 1 {
|
||||||
|
fs.mongoClient.Delete(friends_collection_name, bson.M{"_id": ids[0]})
|
||||||
|
} else {
|
||||||
|
fs.mongoClient.DeleteMany(friends_collection_name, bson.D{{Key: "_id", Value: bson.M{"$in": ids}}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
383
core/invitation.go
Normal file
383
core/invitation.go
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/gob"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
mongoClient gocommon.MongoClient
|
||||||
|
redison *gocommon.RedisonHandler
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
f *friends
|
||||||
|
}
|
||||||
|
|
||||||
|
type invitationDoc struct {
|
||||||
|
Id primitive.ObjectID `bson:"_id,omitempty" json:"_id"`
|
||||||
|
From primitive.ObjectID `bson:"from,omitempty" json:"-"`
|
||||||
|
To primitive.ObjectID `bson:"to,omitempty" json:"-"`
|
||||||
|
FromAlias string `bson:"falias,omitempty" json:"from"`
|
||||||
|
ToAlias string `bson:"talias,omitempty" json:"to"`
|
||||||
|
Timestamp int64 `bson:"ts" json:"ts"`
|
||||||
|
Deleted bool `bson:"deleted,omitempty" json:"deleted,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register([]invitationDoc{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeInvitation(ctx context.Context, s *Social, f *friends) (*invitation, error) {
|
||||||
|
if err := s.mongoClient.MakeUniqueIndices(invitation_collection_name, map[string]bson.D{
|
||||||
|
"fromto": {{Key: "from", Value: 1}, {Key: "to", Value: 1}},
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 내가 받은거
|
||||||
|
if err := s.mongoClient.MakeIndices(invitation_collection_name, map[string]bson.D{
|
||||||
|
"received": {{Key: "to", Value: 1}, {Key: "ts", Value: -1}},
|
||||||
|
}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &invitation{
|
||||||
|
mongoClient: s.mongoClient,
|
||||||
|
redison: s.redison,
|
||||||
|
wsh: s.wsh,
|
||||||
|
f: f,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) QueryReceivedInvitations(ctx wshandler.ApiCallContext) {
|
||||||
|
// 내가 받은 초대 목록
|
||||||
|
queryfrom := int64(ctx.Arguments[0].(float64))
|
||||||
|
|
||||||
|
var receives []*invitationDoc
|
||||||
|
|
||||||
|
err := iv.mongoClient.FindAllAs(invitation_collection_name, bson.M{
|
||||||
|
"to": ctx.CallBy.Accid,
|
||||||
|
"ts": bson.M{"$gt": queryfrom},
|
||||||
|
}, &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_received_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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) CancelInvitation(ctx wshandler.ApiCallContext) {
|
||||||
|
// ctx.CallBy.Accid
|
||||||
|
id, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
|
||||||
|
var ivdoc invitationDoc
|
||||||
|
if err := iv.mongoClient.FindOneAs(invitation_collection_name, bson.M{
|
||||||
|
"_id": id,
|
||||||
|
}, &ivdoc); err != nil {
|
||||||
|
logger.Println("CancelInvitation failed:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivdoc.From != ctx.CallBy.Accid {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ivdoc.Deleted = true
|
||||||
|
if _, _, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
"_id": id,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"falias": "",
|
||||||
|
"deleted": true,
|
||||||
|
"ts": time.Now().UTC().Unix(),
|
||||||
|
},
|
||||||
|
}); err != nil {
|
||||||
|
logger.Println("CancelInvitation failed:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.To.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitation_received_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.From.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitation_sent_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) AcceptInvitation(ctx wshandler.ApiCallContext) {
|
||||||
|
invId, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
|
||||||
|
var ivdoc invitationDoc
|
||||||
|
if err := iv.mongoClient.FindOneAs(invitation_collection_name, bson.M{
|
||||||
|
"_id": invId,
|
||||||
|
}, &ivdoc); err != nil {
|
||||||
|
logger.Println("AcceptInvitation failed:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivdoc.Id != invId {
|
||||||
|
// 초대가 없다
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivdoc.To != ctx.CallBy.Accid {
|
||||||
|
// 내가 받은 초대가 아니네?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UTC().Unix()
|
||||||
|
f1 := friendDoc{
|
||||||
|
From: ivdoc.To, // 수락한 나
|
||||||
|
To: ivdoc.From, // 상대방
|
||||||
|
ToAlias: ivdoc.FromAlias,
|
||||||
|
Timestamp: now,
|
||||||
|
}
|
||||||
|
f2 := friendDoc{
|
||||||
|
From: ivdoc.From, // 상대방
|
||||||
|
To: ivdoc.To, // 나
|
||||||
|
ToAlias: ivdoc.ToAlias,
|
||||||
|
Timestamp: now,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 나한테 상대방을 친구로 만들고
|
||||||
|
if err := iv.f.addFriend(&f1); err == nil {
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: f1.From.Hex(),
|
||||||
|
Body: []friendDoc{f1},
|
||||||
|
Tag: friends_tag,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.Println("AcceptInvitation failed. addFriend(f1) err :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 상대방한테 나를 친구로 만듬
|
||||||
|
if err := iv.f.addFriend(&f2); err == nil {
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: f2.From.Hex(),
|
||||||
|
Body: []friendDoc{f2},
|
||||||
|
Tag: friends_tag,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
logger.Println("AcceptInvitation failed. addFriend(f2) err :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
"_id": invId,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"deleted": true,
|
||||||
|
"ts": now,
|
||||||
|
},
|
||||||
|
}, options.Update().SetUpsert(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) DenyInvitation(ctx wshandler.ApiCallContext) {
|
||||||
|
invId, _ := primitive.ObjectIDFromHex(ctx.Arguments[0].(string))
|
||||||
|
|
||||||
|
var ivdoc invitationDoc
|
||||||
|
if err := iv.mongoClient.FindOneAs(invitation_collection_name, bson.M{
|
||||||
|
"_id": invId,
|
||||||
|
}, &ivdoc); err != nil {
|
||||||
|
logger.Println("AcceptInvitation failed:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivdoc.Id != invId {
|
||||||
|
// 초대가 없다
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ivdoc.To != ctx.CallBy.Accid {
|
||||||
|
// 내가 받은 초대가 아니네?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now().UTC().Unix()
|
||||||
|
ivdoc.Timestamp = now
|
||||||
|
ivdoc.Deleted = true
|
||||||
|
if _, _, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
"_id": invId,
|
||||||
|
}, bson.M{
|
||||||
|
"$set": bson.M{
|
||||||
|
"deleted": true,
|
||||||
|
"ts": now,
|
||||||
|
},
|
||||||
|
}, options.Update().SetUpsert(false)); err != nil {
|
||||||
|
logger.Println("DenyInvitation failed. addFriend(f2) err :", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.To.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitation_received_tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.From.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitation_sent_tag,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) Trim(ctx wshandler.ApiCallContext) {
|
||||||
|
stringsTobjs := func(in []any) (out []primitive.ObjectID) {
|
||||||
|
for _, i := range in {
|
||||||
|
p, _ := primitive.ObjectIDFromHex(i.(string))
|
||||||
|
out = append(out, p)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ids := stringsTobjs(ctx.Arguments[0].([]any))
|
||||||
|
ids = append(ids, stringsTobjs(ctx.Arguments[1].([]any))...)
|
||||||
|
if len(ids) > 0 {
|
||||||
|
if len(ids) == 1 {
|
||||||
|
iv.mongoClient.Delete(invitation_collection_name, bson.M{"_id": ids[0], "deleted": true})
|
||||||
|
} else {
|
||||||
|
iv.mongoClient.DeleteMany(invitation_collection_name, bson.D{
|
||||||
|
{Key: "_id", Value: bson.M{"$in": ids}},
|
||||||
|
{Key: "deleted", Value: true},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) InviteAsFriend(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 1. mongodb에 추가
|
||||||
|
// 1-1. block이 되어있다면(==이미 도큐먼트가 있다면) 마치 성공인 것처럼 아무것도 안하고 끝
|
||||||
|
// 2. mongodb에 추가가 성공하면 publish
|
||||||
|
var ivdoc invitationDoc
|
||||||
|
|
||||||
|
if err := gocommon.MakeDecoder(r).Decode(&ivdoc); err != nil {
|
||||||
|
logger.Println("IniviteAsFriend failed:", err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ivdoc.Timestamp = time.Now().UTC().Unix()
|
||||||
|
_, newid, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
"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 {
|
||||||
|
logger.Println("IniviteAsFriend failed:", err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if newid != nil {
|
||||||
|
ivdoc.Id = newid.(primitive.ObjectID)
|
||||||
|
iv.wsh.SendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||||
|
Target: ivdoc.To.Hex(),
|
||||||
|
Body: []invitationDoc{ivdoc},
|
||||||
|
Tag: invitation_received_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,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (iv *invitation) Block(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 초대가 있으면
|
||||||
|
// var bi struct {
|
||||||
|
// From primitive.ObjectID
|
||||||
|
// To primitive.ObjectID
|
||||||
|
// FromAlias string
|
||||||
|
// }
|
||||||
|
// 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을 초대하는 것을 방지하려면 둘을 뒤집어서 문서를 만들어 놔야 함
|
||||||
|
// // 이미 존재하는 초대일 수도 있다.
|
||||||
|
// _, _, err := iv.mongoClient.Update(invitation_collection_name, bson.M{
|
||||||
|
// "from": bi.To,
|
||||||
|
// "to": bi.From,
|
||||||
|
// }, bson.M{
|
||||||
|
// "$set": invitationDoc{
|
||||||
|
// ToAlias: bi.FromAlias,
|
||||||
|
// Timestamp: now,
|
||||||
|
// },
|
||||||
|
// }, options.Update().SetUpsert(true))
|
||||||
|
// if err != nil {
|
||||||
|
// logger.Println("Block failed:", err)
|
||||||
|
// w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
}
|
||||||
134
core/social.go
Normal file
134
core/social.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/session"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
)
|
||||||
|
|
||||||
|
var devflag = flagx.Bool("dev", false, "")
|
||||||
|
|
||||||
|
type SocialConfig struct {
|
||||||
|
session.SessionConfig `json:",inline"`
|
||||||
|
|
||||||
|
MaingateApiToken string `json:"maingate_api_token"`
|
||||||
|
RedisURL string `json:"social_redis_url"`
|
||||||
|
MongoURL string `json:"social_storage_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var config SocialConfig
|
||||||
|
|
||||||
|
type Social struct {
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
mongoClient gocommon.MongoClient
|
||||||
|
redison *gocommon.RedisonHandler
|
||||||
|
httpApiBorker gocommon.HttpApiBroker
|
||||||
|
}
|
||||||
|
|
||||||
|
// New :
|
||||||
|
func New(ctx context.Context, wsh *wshandler.WebsocketHandler, inconfig *SocialConfig) (*Social, error) {
|
||||||
|
if inconfig == nil {
|
||||||
|
var loaded SocialConfig
|
||||||
|
if err := gocommon.LoadConfig(&loaded); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inconfig = &loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
config = *inconfig
|
||||||
|
opt, err := redis.ParseURL(config.RedisURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mc, err := gocommon.NewMongoClient(ctx, config.MongoURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
so := &Social{
|
||||||
|
wsh: wsh,
|
||||||
|
redison: gocommon.NewRedisonHandler(ctx, redis.NewClient(opt)),
|
||||||
|
mongoClient: mc,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := so.prepare(ctx); err != nil {
|
||||||
|
logger.Println("social prepare() failed :", err)
|
||||||
|
return nil, logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return so, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *Social) Cleanup() {
|
||||||
|
so.mongoClient.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *Social) prepare(ctx context.Context) error {
|
||||||
|
redisClient, err := gocommon.NewRedisClient(config.RedisURL)
|
||||||
|
if err != nil {
|
||||||
|
return logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
so.redison = gocommon.NewRedisonHandler(redisClient.Context(), redisClient)
|
||||||
|
|
||||||
|
friends, err := makeFriends(ctx, so)
|
||||||
|
if err != nil {
|
||||||
|
return logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
so.wsh.AddHandler(wshandler.MakeWebsocketApiHandler(friends, "social"))
|
||||||
|
so.httpApiBorker.AddHandler(gocommon.MakeHttpApiHandler(friends, "social"))
|
||||||
|
|
||||||
|
invitation, err := makeInvitation(ctx, so, friends)
|
||||||
|
if err != nil {
|
||||||
|
return logger.ErrorWithCallStack(err)
|
||||||
|
}
|
||||||
|
so.wsh.AddHandler(wshandler.MakeWebsocketApiHandler(invitation, "social"))
|
||||||
|
so.httpApiBorker.AddHandler(gocommon.MakeHttpApiHandler(invitation, "social"))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *Social) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
|
||||||
|
so.wsh.AddHandler(wshandler.MakeWebsocketApiHandler(so, "social"))
|
||||||
|
pattern := gocommon.MakeHttpHandlerPattern(prefix, "api")
|
||||||
|
serveMux.HandleFunc(pattern, so.api)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (so *Social) api(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
s := recover()
|
||||||
|
if s != nil {
|
||||||
|
logger.Error(s)
|
||||||
|
}
|
||||||
|
io.Copy(io.Discard, r.Body)
|
||||||
|
r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 서버에서 오는 요청만 처리
|
||||||
|
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||||
|
if apitoken != config.MaingateApiToken {
|
||||||
|
// 서버가 보내는 쿼리만 허용
|
||||||
|
logger.Println("MG-X-API-TOKEN is missing")
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
funcname := r.URL.Query().Get("call")
|
||||||
|
if len(funcname) == 0 {
|
||||||
|
logger.Println("query param 'call' is missing")
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
so.httpApiBorker.Call(funcname, w, r)
|
||||||
|
}
|
||||||
65
core/social_test.go
Normal file
65
core/social_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// warroom project main.go
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPubSub(t *testing.T) {
|
||||||
|
opt0, _ := redis.ParseURL("redis://192.168.8.94:6380/0")
|
||||||
|
opt1, _ := redis.ParseURL("redis://192.168.8.94:6380/1")
|
||||||
|
|
||||||
|
rc0 := redis.NewClient(opt0)
|
||||||
|
rc1 := redis.NewClient(opt1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
rc1.Publish(context.Background(), "__testchan", "real???")
|
||||||
|
fmt.Println("published")
|
||||||
|
}()
|
||||||
|
|
||||||
|
pubsub := rc0.Subscribe(context.Background(), "__testchan")
|
||||||
|
msg, err := pubsub.ReceiveMessage(context.Background())
|
||||||
|
fmt.Println(msg.Payload, err)
|
||||||
|
}
|
||||||
|
func makeHash(chanName string, index uint32) string {
|
||||||
|
for len(chanName) < 12 {
|
||||||
|
chanName += chanName
|
||||||
|
}
|
||||||
|
left := chanName[:6]
|
||||||
|
right := chanName[len(chanName)-6:]
|
||||||
|
base := []byte(left + right)
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
base[i] += base[12-i-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := make([]byte, 4)
|
||||||
|
binary.LittleEndian.PutUint32(bs, index)
|
||||||
|
for i, c := range bs {
|
||||||
|
base[i] ^= c
|
||||||
|
}
|
||||||
|
var gid primitive.ObjectID
|
||||||
|
copy(gid[:], base)
|
||||||
|
|
||||||
|
return gid.Hex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNameHash(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
makeHash("Urud", uint32(i))
|
||||||
|
fmt.Printf("Urud:%d - %s\n", i, makeHash("Urud", uint32(i)))
|
||||||
|
makeHash("Sheldon", uint32(i))
|
||||||
|
fmt.Printf("Sheldon:%d - %s\n", i, makeHash("Sheldon", uint32(i)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReJSON(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
||||||
29
go.mod
Normal file
29
go.mod
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module repositories.action2quare.com/ayo/social
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
go.mongodb.org/mongo-driver v1.11.7
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230911034515-1af5d7281946
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.4 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.6 // indirect
|
||||||
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
|
github.com/pires/go-proxyproto v0.7.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
|
||||||
|
golang.org/x/crypto v0.10.0 // indirect
|
||||||
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
|
golang.org/x/text v0.10.0 // indirect
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
|
)
|
||||||
108
go.sum
Normal file
108
go.sum
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||||
|
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
|
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||||
|
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
|
github.com/pires/go-proxyproto v0.7.0 h1:IukmRewDQFWC7kfnb66CSomk2q/seBuilHBYFwyq0Hs=
|
||||||
|
github.com/pires/go-proxyproto v0.7.0/go.mod h1:Vz/1JPY/OACxWGQNIRY2BeyDmpoaWmEP40O9LbuiFR4=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
|
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||||
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
|
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||||
|
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
go.mongodb.org/mongo-driver v1.11.7 h1:LIwYxASDLGUg/8wOhgOOZhX8tQa/9tgZPgzZoVqJvcs=
|
||||||
|
go.mongodb.org/mongo-driver v1.11.7/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||||
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230911034515-1af5d7281946 h1:YSvgTNuHeKis37+FfOvzVLYCaXQ0oF+CWBTy4bRqq3g=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230911034515-1af5d7281946/go.mod h1:XvklTTSvQX5uviivGBcZo8eIL+mV94W2e4uBBXcT5JY=
|
||||||
51
main.go
Normal file
51
main.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
"repositories.action2quare.com/ayo/social/core"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
var prefix = flagx.String("prefix", "", "")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flagx.Parse()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
var config core.SocialConfig
|
||||||
|
if err := gocommon.LoadConfig(&config); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
consumer, err := session.NewConsumerWithConfig(ctx, config.SessionConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wsh, err := wshandler.NewWebsocketHandler(consumer, config.RedisURL)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if so, err := core.New(ctx, wsh, &config); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
serveMux := http.NewServeMux()
|
||||||
|
wsh.RegisterHandlers(serveMux, *prefix)
|
||||||
|
so.RegisterHandlers(ctx, serveMux, *prefix)
|
||||||
|
server := gocommon.NewHTTPServer(serveMux)
|
||||||
|
logger.Println("social is started")
|
||||||
|
wsh.Start(ctx)
|
||||||
|
server.Start()
|
||||||
|
cancel()
|
||||||
|
so.Cleanup()
|
||||||
|
wsh.Cleanup()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user