채팅 채널 입장 추가
This commit is contained in:
@ -1,8 +1,12 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"repositories.action2quare.com/ayo/gocommon"
|
||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||
)
|
||||
|
||||
@ -10,13 +14,209 @@ func init() {
|
||||
groupTypeContainer()["chat"] = reflect.TypeOf(&groupChat{})
|
||||
}
|
||||
|
||||
type groupChat struct {
|
||||
type channelID = string
|
||||
type chatConfig struct {
|
||||
DefaultCapacity int64 `json:"default_capacity"`
|
||||
Channels map[string]map[string]any `json:"channels"`
|
||||
}
|
||||
|
||||
func (gc *groupChat) Initialize(*subTavern, configDocument) error {
|
||||
type groupChat struct {
|
||||
chatConfig
|
||||
rh *gocommon.RedisonHandler
|
||||
incSizeScript string
|
||||
decSizeScript string
|
||||
enterRoom func(channelID, accountID)
|
||||
leaveRoom func(channelID, accountID)
|
||||
sendUpstreamMessage func(msg *wshandler.UpstreamMessage)
|
||||
}
|
||||
|
||||
var increaseSizeScript = `
|
||||
local cap = redis.call("HGET", KEYS[1], "capacity")
|
||||
local newseq = redis.call("HINCRBY", KEYS[1], "seq", 1)
|
||||
|
||||
local newsize = redis.call("HINCRBY", KEYS[1], "size", 1)
|
||||
if tonumber(cap) < newsize then
|
||||
redis.call("HINCRBY", KEYS[1], "size", -1)
|
||||
return {err = "channel is full"}
|
||||
end
|
||||
|
||||
redis.call("HSET", "_m_"..KEYS[1], KEYS[2], ARGV[1])
|
||||
return {newsize, newseq}
|
||||
`
|
||||
var decreaseSizeScript = `
|
||||
local newseq = redis.call("HINCRBY", KEYS[1], "seq", 1)
|
||||
local newsize = redis.call("HINCRBY", KEYS[1], "size", -1)
|
||||
redis.call("HDEL", "_m_"..KEYS[1], KEYS[2])
|
||||
|
||||
return {newsize, newseq}
|
||||
`
|
||||
|
||||
func (gc *groupChat) Initialize(sub *subTavern, cfg configDocument) error {
|
||||
incScript, err := sub.redisClient.ScriptLoad(sub.redisClient.Context(), increaseSizeScript).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decScript, err := sub.redisClient.ScriptLoad(sub.redisClient.Context(), decreaseSizeScript).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// newsize, err := sub.redisClient.EvalSha(sub.redisClient.Context(), incScript, []string{"myhash", "alias"}, "accid").Result()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// logger.Println(newsize.([]any))
|
||||
// newsize, err = sub.redisClient.EvalSha(sub.redisClient.Context(), decScript, []string{"myhash", "alias"}).Result()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// logger.Println(newsize.([]any))
|
||||
|
||||
rem, _ := json.Marshal(cfg)
|
||||
if err = json.Unmarshal(rem, &gc.chatConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gc.enterRoom = func(chanid channelID, accid accountID) {
|
||||
sub.wsh.EnterRoom(sub.region, string(chanid), accid)
|
||||
}
|
||||
gc.leaveRoom = func(chanid channelID, accid accountID) {
|
||||
sub.wsh.LeaveRoom(sub.region, string(chanid), accid)
|
||||
}
|
||||
gc.sendUpstreamMessage = func(msg *wshandler.UpstreamMessage) {
|
||||
sub.wsh.SendUpstreamMessage(sub.region, msg)
|
||||
}
|
||||
|
||||
gc.rh = gocommon.NewRedisonHandler(sub.redisClient.Context(), sub.redisClient)
|
||||
gc.incSizeScript = incScript
|
||||
gc.decSizeScript = decScript
|
||||
|
||||
sub.apiFuncs.registApiFunction("CreateChattingChannel", gc.CreateChattingChannel)
|
||||
sub.apiFuncs.registApiFunction("FetchChattingChannels", gc.FetchChattingChannels)
|
||||
|
||||
for name, cfg := range gc.chatConfig.Channels {
|
||||
if _, ok := cfg["capacity"]; !ok {
|
||||
cfg["capacity"] = gc.chatConfig.DefaultCapacity
|
||||
}
|
||||
cfg["key"] = name
|
||||
|
||||
_, err := gc.rh.HMSet(gc.rh.Context(), name, cfg).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gc *groupChat) ClientMessageReceved(*wshandler.Sender, wshandler.WebSocketMessageType, any) {
|
||||
func (gc *groupChat) ClientMessageReceived(sender *wshandler.Sender, mt wshandler.WebSocketMessageType, message any) {
|
||||
if mt == wshandler.Disconnected {
|
||||
rooms := message.([]string)
|
||||
for _, chanid := range rooms {
|
||||
sizeseq, err := gc.rh.EvalSha(gc.rh.Context(), gc.decSizeScript, []string{chanid, sender.Alias}).Result()
|
||||
if err == nil {
|
||||
gc.sendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: "#" + chanid,
|
||||
Body: map[string]any{"size": sizeseq.([]any)[0], "seq": sizeseq.([]any)[1]},
|
||||
Tag: []string{"ChattingChannelProperties"},
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if mt == wshandler.BinaryMessage {
|
||||
commandline := message.([]any)
|
||||
cmd := commandline[0].(string)
|
||||
args := commandline[1:]
|
||||
switch cmd {
|
||||
case "EnterChattingChannel":
|
||||
chanid := args[0].(string)
|
||||
sizeseq, err := gc.rh.EvalSha(gc.rh.Context(), gc.incSizeScript, []string{chanid, sender.Alias}, sender.Accid.Hex()).Result()
|
||||
if err == nil {
|
||||
gc.enterRoom(chanid, sender.Accid)
|
||||
gc.sendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: "#" + chanid,
|
||||
Body: map[string]any{"size": sizeseq.([]any)[0], "seq": sizeseq.([]any)[1]},
|
||||
Tag: []string{"ChattingChannelProperties"},
|
||||
})
|
||||
} else {
|
||||
// 입장 실패 알림
|
||||
gc.sendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: "@" + sender.Accid.Hex(),
|
||||
Body: map[string]string{"id": chanid, "err": err.Error()},
|
||||
Tag: []string{"EnterChattingChannelFailed"},
|
||||
})
|
||||
}
|
||||
|
||||
case "LeaveChattingChannel":
|
||||
chanid := args[0].(string)
|
||||
gc.leaveRoom(chanid, sender.Accid)
|
||||
sizeseq, err := gc.rh.EvalSha(gc.rh.Context(), gc.decSizeScript, []string{chanid, sender.Alias}).Result()
|
||||
if err == nil {
|
||||
gc.sendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: "#" + chanid,
|
||||
Body: map[string]any{"size": sizeseq.([]any)[0], "seq": sizeseq.([]any)[1]},
|
||||
Tag: []string{"ChattingChannelProperties"},
|
||||
})
|
||||
}
|
||||
|
||||
case "TextMessage":
|
||||
chanid := args[0].(string)
|
||||
msg := args[1].(string)
|
||||
gc.sendUpstreamMessage(&wshandler.UpstreamMessage{
|
||||
Target: "#" + chanid,
|
||||
Body: map[string]any{"sender": sender.Alias, "msg": msg},
|
||||
Tag: []string{"TextMessage"},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (gc *groupChat) CreateChattingChannel(w http.ResponseWriter, r *http.Request) {
|
||||
chanstr, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
||||
if len(chanstr) == 0 {
|
||||
logger.Println("CreateChattingChannel failed. name is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
capacity, _ := gocommon.ReadIntegerFormValue(r.Form, "capacity")
|
||||
if capacity == 0 {
|
||||
capacity = gc.chatConfig.DefaultCapacity
|
||||
}
|
||||
|
||||
_, err := gc.rh.HSetNX(gc.rh.Context(), chanstr, "capacity", capacity).Result()
|
||||
if err != nil {
|
||||
logger.Println("CreateChattingChannel failed. HSetNX returns err :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (gc *groupChat) FetchChattingChannels(w http.ResponseWriter, r *http.Request) {
|
||||
prefix, _ := gocommon.ReadStringFormValue(r.Form, "prefix")
|
||||
if len(prefix) == 0 {
|
||||
logger.Println("FetchChattingChannel failed. prefix is missing")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
keys, err := gc.rh.Keys(gc.rh.Context(), prefix+"*").Result()
|
||||
if err != nil {
|
||||
logger.Println("FetchChattingChannel failed. Keys return err :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var channels []map[string]string
|
||||
for _, key := range keys {
|
||||
onechan, err := gc.rh.HGetAll(gc.rh.Context(), key).Result()
|
||||
if err != nil {
|
||||
logger.Println("FetchChattingChannel failed. HGetAll return err :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
channels = append(channels, onechan)
|
||||
}
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
enc.Encode(channels)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user