tavern 분리
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.vscode/
|
||||||
|
__debug_bin.exe
|
||||||
|
*.log
|
||||||
66
config_template.json
Normal file
66
config_template.json
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"region_storage" : {
|
||||||
|
"default" : {
|
||||||
|
"mongo" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||||
|
"redis" : {
|
||||||
|
"url" : "redis://192.168.8.94:6379",
|
||||||
|
"offset" : {
|
||||||
|
"cache" : 0,
|
||||||
|
"session" : 1,
|
||||||
|
"ranking" : 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dev" : {
|
||||||
|
"mongo" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||||
|
"redis" : {
|
||||||
|
"url" : "redis://192.168.8.94:6379",
|
||||||
|
"offset" : {
|
||||||
|
"cache" : 0,
|
||||||
|
"session" : 1,
|
||||||
|
"ranking" : 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"maingate_mongodb_url" : "mongodb://192.168.8.94:27017/?replicaSet=repl01&retrywrites=false",
|
||||||
|
"maingate_service_url" : "http://localhost/maingate",
|
||||||
|
"maingate_api_token" : "63d08aa34f0162622c11284b",
|
||||||
|
|
||||||
|
"tavern_service_url" : "http://localhost/tavern",
|
||||||
|
"tavern_group_types" : {
|
||||||
|
"subjugate" : {
|
||||||
|
"text_search_field" : ["name"],
|
||||||
|
"unique_index" : ["name,_id", "_id,members", "name,hidden"],
|
||||||
|
"search_index" : ["rules"],
|
||||||
|
"member_index" : ["_gid,candidate,luts","_gid,luts","_gid,expiring"],
|
||||||
|
"invite_ttl" : 30,
|
||||||
|
"candidate_ttl" : 3600,
|
||||||
|
"invitee_exlusive" : true,
|
||||||
|
"invitee_is_member" : true,
|
||||||
|
"max_member" : 4
|
||||||
|
},
|
||||||
|
"lobby" : {
|
||||||
|
"max_member" : 3,
|
||||||
|
"invitee_exlusive" : true,
|
||||||
|
"invitee_is_member" : true,
|
||||||
|
"transient" : true,
|
||||||
|
"invite_ttl" : 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"ws_sync_pipeline" : "redis://192.168.8.94:6379/3",
|
||||||
|
|
||||||
|
"services" : {
|
||||||
|
"kingdom" : {
|
||||||
|
"개발중" : {
|
||||||
|
"url" :"http://localhost/warehouse/dev",
|
||||||
|
"development" : true
|
||||||
|
},
|
||||||
|
"개인서버" : {
|
||||||
|
"url" : "http://localhost/warehouse/private",
|
||||||
|
"development" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1067
core/apiimpl.go
Normal file
1067
core/apiimpl.go
Normal file
File diff suppressed because it is too large
Load Diff
49
core/group.go
Normal file
49
core/group.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type groupConfig struct {
|
||||||
|
UniqueIndex []string `json:"unique_index"`
|
||||||
|
SearchIndex []string `json:"search_index"`
|
||||||
|
MemberIndex []string `json:"member_index"`
|
||||||
|
TextSearchFields []string `json:"text_search_field"`
|
||||||
|
InviteExpire int32 `json:"invite_ttl"` // 그룹이 개인에게 보낸 초대장 만료 기한
|
||||||
|
CandidateExpire int32 `json:"candidate_ttl"` // 개인이 그룹에게 보낸 신청서 만료 기한
|
||||||
|
InviteeExlusive bool `json:"invitee_exlusive"`
|
||||||
|
InviteeIsMember bool `json:"invitee_is_member"`
|
||||||
|
MaxMember int `json:"max_member"`
|
||||||
|
Transient bool `json:"transient"`
|
||||||
|
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type group interface {
|
||||||
|
Create(form url.Values, doc bson.M) (primitive.ObjectID, error)
|
||||||
|
Candidate(groupID primitive.ObjectID, memberID primitive.ObjectID, doc bson.M) error
|
||||||
|
Join(groupID primitive.ObjectID, memberID primitive.ObjectID, ticketID primitive.ObjectID, doc bson.M) (newTicketID primitive.ObjectID, err error)
|
||||||
|
FindTicketID(groupID primitive.ObjectID, memberID primitive.ObjectID) primitive.ObjectID
|
||||||
|
Invite(groupID primitive.ObjectID, memberID primitive.ObjectID, inviterDoc bson.M, inviteeDoc bson.M) (string, error)
|
||||||
|
UpdateGroupMember(groupID primitive.ObjectID, memberID primitive.ObjectID, ticketID primitive.ObjectID, doc bson.M) error
|
||||||
|
CancelInvitation(groupID primitive.ObjectID, ticketID primitive.ObjectID) error
|
||||||
|
AcceptInvitation(groupID primitive.ObjectID, mid primitive.ObjectID, ticketID primitive.ObjectID, member bson.M) (primitive.ObjectID, error)
|
||||||
|
DenyInvitation(groupID primitive.ObjectID, mid primitive.ObjectID, ticketID primitive.ObjectID) error
|
||||||
|
QueryInvitations(memberID primitive.ObjectID, after primitive.Timestamp) ([]bson.M, error)
|
||||||
|
Exist(groupID primitive.ObjectID, filter bson.M) (bool, error)
|
||||||
|
FindAll(filter bson.M, projection string, after primitive.Timestamp) ([]bson.M, error)
|
||||||
|
FindOne(groupID primitive.ObjectID, projection string) (bson.M, error)
|
||||||
|
QueryMembers(groupID primitive.ObjectID, requesterID primitive.ObjectID, projection string, after primitive.Timestamp) (map[string]bson.M, error)
|
||||||
|
QueryMember(groupID primitive.ObjectID, memberID primitive.ObjectID, ticketID primitive.ObjectID, projection string) (bson.M, error)
|
||||||
|
Leave(groupID primitive.ObjectID, memberID primitive.ObjectID, ticketID primitive.ObjectID) error
|
||||||
|
DropPausedMember(groupID primitive.ObjectID, memberID primitive.ObjectID) error
|
||||||
|
PauseMember(groupID primitive.ObjectID, memberID primitive.ObjectID, conn *wshandler.Richconn) error
|
||||||
|
UpdateMemberDocument(groupID primitive.ObjectID, memberID primitive.ObjectID, doc bson.M) error
|
||||||
|
Dismiss(groupID primitive.ObjectID) error
|
||||||
|
UpdateGroupDocument(groupID primitive.ObjectID, body []byte) error
|
||||||
|
}
|
||||||
1221
core/group_memory.go
Normal file
1221
core/group_memory.go
Normal file
File diff suppressed because it is too large
Load Diff
1050
core/group_mongo.go
Normal file
1050
core/group_mongo.go
Normal file
File diff suppressed because it is too large
Load Diff
73
core/richconn.go
Normal file
73
core/richconn.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type richConnOuter struct {
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
rc *wshandler.Richconn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) JoinTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, hint string) error {
|
||||||
|
sub.wsh.JoinTag(region, tag, tid, sub.rc, hint)
|
||||||
|
|
||||||
|
wsh := sub.wsh
|
||||||
|
sub.rc.RegistOnCloseFunc(tag.Hex(), func() {
|
||||||
|
wsh.LeaveTag(region, tag, tid)
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) LeaveTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, hint string) error {
|
||||||
|
sub.SetStateInTag(region, tag, tid, "", hint)
|
||||||
|
return sub.wsh.LeaveTag(region, tag, tid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) SetStateInTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, state string, hint string) error {
|
||||||
|
return sub.wsh.SetStateInTag(region, tag, tid, state, hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) TurnGroupOnline(key string, gid primitive.ObjectID, score float64) error {
|
||||||
|
gidhex := gid.Hex()
|
||||||
|
_, err := sub.wsh.RedisSync.ZAdd(context.Background(), key, &redis.Z{Score: score, Member: gidhex}).Result()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("TurnGroupOnline failed. redis.ZAdd return err :", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.rc.RegistOnCloseFunc(key, func() {
|
||||||
|
sub.wsh.RedisSync.ZRem(context.Background(), key, gidhex)
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) TurnGroupOffline(key string, gid primitive.ObjectID) error {
|
||||||
|
f := sub.rc.UnregistOnCloseFunc(key)
|
||||||
|
if f != nil {
|
||||||
|
f()
|
||||||
|
} else {
|
||||||
|
sub.wsh.RedisSync.ZRem(context.Background(), key, gid.Hex())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) SendMessage(doc []byte) error {
|
||||||
|
return sub.rc.WriteBytes(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) SendMessageToTag(region string, tag primitive.ObjectID, msg []byte) error {
|
||||||
|
sub.wsh.BroadcastRaw(region, tag, msg)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub richConnOuter) CloseOnPurpose() error {
|
||||||
|
return sub.rc.Close()
|
||||||
|
}
|
||||||
195
core/rpc/connrpc.go
Normal file
195
core/rpc/connrpc.go
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Everybody = primitive.ObjectID([12]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
gob.Register(bson.M{})
|
||||||
|
gob.Register(primitive.ObjectID{})
|
||||||
|
gob.Register(primitive.Timestamp{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type RpcCaller struct {
|
||||||
|
publish func(bt []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRpcCaller(f func(bt []byte) error) RpcCaller {
|
||||||
|
return RpcCaller{
|
||||||
|
publish: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type rpcCallContext struct {
|
||||||
|
alias primitive.ObjectID
|
||||||
|
publish func(bt []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RpcCaller) One(alias primitive.ObjectID) rpcCallContext {
|
||||||
|
return rpcCallContext{
|
||||||
|
alias: alias,
|
||||||
|
publish: c.publish,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *RpcCaller) Everybody() rpcCallContext {
|
||||||
|
return rpcCallContext{
|
||||||
|
alias: Everybody,
|
||||||
|
publish: c.publish,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsCallerCalleeMethodMatch[Callee any]() error {
|
||||||
|
var caller rpcCallContext
|
||||||
|
var callee Callee
|
||||||
|
|
||||||
|
callerType := reflect.TypeOf(caller)
|
||||||
|
calleeType := reflect.TypeOf(callee)
|
||||||
|
for i := 0; i < callerType.NumMethod(); i++ {
|
||||||
|
callerMethod := callerType.Method(i)
|
||||||
|
calleeMethod, ok := calleeType.MethodByName(callerMethod.Name)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("method '%s' of '%s' is missing", callerMethod.Name, calleeType.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if calleeMethod.Func.Type().NumIn() != callerMethod.Func.Type().NumIn() {
|
||||||
|
return fmt.Errorf("method '%s' argument num is not match", callerMethod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if calleeMethod.Func.Type().NumOut() != callerMethod.Func.Type().NumOut() {
|
||||||
|
return fmt.Errorf("method '%s' out num is not match", callerMethod.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < calleeMethod.Func.Type().NumIn(); i++ {
|
||||||
|
if calleeMethod.Func.Type().In(i) != callerMethod.Func.Type().In(i) {
|
||||||
|
return fmt.Errorf("method '%s' argument is not match. %s-%s", callerMethod.Name, calleeMethod.Func.Type().In(i).Name(), callerMethod.Func.Type().In(i).Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fnsig struct {
|
||||||
|
FunctionName string `bson:"fn"`
|
||||||
|
Args []any `bson:"args"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func Encode[T any](prefix T, fn string, args ...any) ([]byte, error) {
|
||||||
|
m := append([]any{
|
||||||
|
prefix,
|
||||||
|
fn,
|
||||||
|
}, args...)
|
||||||
|
|
||||||
|
buff := new(bytes.Buffer)
|
||||||
|
encoder := gob.NewEncoder(buff)
|
||||||
|
err := encoder.Encode(m)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("rpcCallContext.send err :", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buff.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decode[T any](src []byte) (*T, string, []any, error) {
|
||||||
|
var m []any
|
||||||
|
decoder := gob.NewDecoder(bytes.NewReader(src))
|
||||||
|
if err := decoder.Decode(&m); err != nil {
|
||||||
|
logger.Error("RpcCallee.Call err :", err)
|
||||||
|
return nil, "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prfix := m[0].(T)
|
||||||
|
fn := m[1].(string)
|
||||||
|
|
||||||
|
return &prfix, fn, m[2:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decode(src []byte) (string, []any, error) {
|
||||||
|
var sig fnsig
|
||||||
|
decoder := gob.NewDecoder(bytes.NewReader(src))
|
||||||
|
if err := decoder.Decode(&sig); err != nil {
|
||||||
|
logger.Error("RpcCallee.Call err :", err)
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sig.FunctionName, sig.Args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rpcCallContext) send(fn string, args ...any) error {
|
||||||
|
bt, err := Encode(c.alias, fn, args...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.publish(bt)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RpcCallee[T any] struct {
|
||||||
|
methods map[string]reflect.Method
|
||||||
|
create func(*wshandler.Richconn) *T
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRpcCallee[T any](createReceiverFunc func(*wshandler.Richconn) *T) RpcCallee[T] {
|
||||||
|
out := RpcCallee[T]{
|
||||||
|
methods: make(map[string]reflect.Method),
|
||||||
|
create: createReceiverFunc,
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp *T
|
||||||
|
|
||||||
|
tp := reflect.TypeOf(tmp)
|
||||||
|
for i := 0; i < tp.NumMethod(); i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
out.methods[method.Name] = method
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r RpcCallee[T]) Call(rc *wshandler.Richconn, src []byte) error {
|
||||||
|
defer func() {
|
||||||
|
s := recover()
|
||||||
|
if s != nil {
|
||||||
|
logger.Error(s)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
fn, params, err := decode(src)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("RpcCallee.Call err :", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
method, ok := r.methods[fn]
|
||||||
|
if !ok {
|
||||||
|
err := fmt.Errorf("method '%s' is missing", fn)
|
||||||
|
logger.Error("RpcCallee.Call err :", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
receiver := r.create(rc)
|
||||||
|
args := []reflect.Value{
|
||||||
|
reflect.ValueOf(receiver),
|
||||||
|
}
|
||||||
|
for _, arg := range params {
|
||||||
|
args = append(args, reflect.ValueOf(arg))
|
||||||
|
}
|
||||||
|
|
||||||
|
rets := method.Func.Call(args)
|
||||||
|
if len(rets) > 0 && rets[len(rets)-1].Interface() != nil {
|
||||||
|
return rets[len(rets)-1].Interface().(error)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
33
core/rpc/proxy.go
Normal file
33
core/rpc/proxy.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c rpcCallContext) JoinTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, hint string) error {
|
||||||
|
return c.send("JoinTag", region, tag, tid, hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c rpcCallContext) LeaveTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, hint string) error {
|
||||||
|
return c.send("LeaveTag", region, tag, tid, hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c rpcCallContext) TurnGroupOnline(key string, gid primitive.ObjectID, score float64) error {
|
||||||
|
return c.send("TurnGroupOnline", key, gid, score)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c rpcCallContext) TurnGroupOffline(key string, gid primitive.ObjectID) error {
|
||||||
|
return c.send("TurnGroupOffline", key, gid)
|
||||||
|
}
|
||||||
|
func (c rpcCallContext) SetStateInTag(region string, tag primitive.ObjectID, tid primitive.ObjectID, state string, hint string) error {
|
||||||
|
return c.send("SetStateInTag", region, tag, tid, state, hint)
|
||||||
|
}
|
||||||
|
func (c rpcCallContext) SendMessage(doc []byte) error {
|
||||||
|
return c.send("SendMessage", doc)
|
||||||
|
}
|
||||||
|
func (c rpcCallContext) SendMessageToTag(region string, gid primitive.ObjectID, msg []byte) error {
|
||||||
|
return c.send("SendMessageToTag", region, gid, msg)
|
||||||
|
}
|
||||||
|
func (c rpcCallContext) CloseOnPurpose() error {
|
||||||
|
return c.send("CloseOnPurpose")
|
||||||
|
}
|
||||||
317
core/tavern.go
Normal file
317
core/tavern.go
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
"repositories.action2quare.com/ayo/tavern/core/rpc"
|
||||||
|
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/bsonrw"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultMaxMemory = 32 << 10 // 32 KB
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeBsonArr(w io.Writer, src []bson.M) error {
|
||||||
|
return writeBsonDoc(w, bson.M{
|
||||||
|
"r": src,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func onlineGroupQueryKey(prefix string) string {
|
||||||
|
return prefix + "_olg"
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeBsonDoc[T any](w io.Writer, src T) error {
|
||||||
|
rw, err := bsonrw.NewBSONValueWriter(w)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
enc, err := bson.NewEncoder(rw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return enc.Encode(src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBsonDoc(r io.Reader, src any) error {
|
||||||
|
body, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(body) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder, err := bson.NewDecoder(bsonrw.NewBSONDocumentReader(body))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = decoder.Decode(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type rpcCallDomain[T any] struct {
|
||||||
|
rpcCallChanName string
|
||||||
|
caller rpc.RpcCaller
|
||||||
|
callee rpc.RpcCallee[T]
|
||||||
|
methods map[string]reflect.Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func createRpcCallDomain[CalleeType any](syncConn *redis.Client, creator func(*wshandler.Richconn) *CalleeType) rpcCallDomain[CalleeType] {
|
||||||
|
var tmp *CalleeType
|
||||||
|
methods := make(map[string]reflect.Method)
|
||||||
|
tp := reflect.TypeOf(tmp)
|
||||||
|
for i := 0; i < tp.NumMethod(); i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
methods[method.Name] = method
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcChanName := "conn_rpc_channel_" + tp.Name()
|
||||||
|
publishFunc := func(bt []byte) error {
|
||||||
|
_, err := syncConn.Publish(context.Background(), rpcChanName, bt).Result()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcCallDomain[CalleeType]{
|
||||||
|
rpcCallChanName: rpcChanName,
|
||||||
|
caller: rpc.NewRpcCaller(publishFunc),
|
||||||
|
callee: rpc.NewRpcCallee(creator),
|
||||||
|
methods: methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TavernConfig struct {
|
||||||
|
common.RegionStorageConfig `json:",inline"`
|
||||||
|
|
||||||
|
GroupTypes map[string]*groupConfig `json:"tavern_group_types"`
|
||||||
|
MaingateApiToken string `json:"maingate_api_token"`
|
||||||
|
macAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
var config TavernConfig
|
||||||
|
|
||||||
|
type Tavern struct {
|
||||||
|
subTaverns []*subTavern
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
type subTavern struct {
|
||||||
|
mongoClient common.MongoClient
|
||||||
|
wsh *wshandler.WebsocketHandler
|
||||||
|
region string
|
||||||
|
groups map[string]group
|
||||||
|
methods map[string]reflect.Method
|
||||||
|
wshRpc rpcCallDomain[richConnOuter]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMacAddr() (string, error) {
|
||||||
|
ifas, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ifa := range ifas {
|
||||||
|
a := ifa.HardwareAddr.String()
|
||||||
|
if a != "" {
|
||||||
|
a = strings.ReplaceAll(a, ":", "")
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("no net interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
// New :
|
||||||
|
func New(context context.Context, wsh *wshandler.WebsocketHandler, inconfig *TavernConfig) (*Tavern, error) {
|
||||||
|
if !flag.Parsed() {
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
if inconfig == nil {
|
||||||
|
var loaded TavernConfig
|
||||||
|
if err := common.LoadConfig(&loaded); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inconfig = &loaded
|
||||||
|
}
|
||||||
|
|
||||||
|
config = *inconfig
|
||||||
|
macaddr, err := getMacAddr()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.macAddr = macaddr
|
||||||
|
tv := Tavern{
|
||||||
|
wsh: wsh,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = tv.prepare(context); err != nil {
|
||||||
|
logger.Println("tavern prepare() failed :", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tv *Tavern) Destructor() {
|
||||||
|
tv.wsh.Destructor()
|
||||||
|
for _, st := range tv.subTaverns {
|
||||||
|
st.mongoClient.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type groupPipelineDocument struct {
|
||||||
|
OperationType string `bson:"operationType"`
|
||||||
|
FullDocument map[string]any `bson:"fullDocument"`
|
||||||
|
DocumentKey struct {
|
||||||
|
Id primitive.ObjectID `bson:"_id"`
|
||||||
|
} `bson:"documentKey"`
|
||||||
|
UpdateDescription struct {
|
||||||
|
UpdatedFields bson.M `bson:"updatedFields"`
|
||||||
|
RemovedFileds bson.A `bson:"removedFields"`
|
||||||
|
TruncatedArrays bson.A `bson:"truncatedArrays"`
|
||||||
|
} `bson:"updateDescription"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tv *Tavern) prepare(ctx context.Context) error {
|
||||||
|
for region, url := range config.RegionStorage {
|
||||||
|
var dbconn common.MongoClient
|
||||||
|
var err error
|
||||||
|
var groupinstance group
|
||||||
|
|
||||||
|
if err := rpc.IsCallerCalleeMethodMatch[richConnOuter](); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tmp *subTavern
|
||||||
|
methods := make(map[string]reflect.Method)
|
||||||
|
tp := reflect.TypeOf(tmp)
|
||||||
|
for i := 0; i < tp.NumMethod(); i++ {
|
||||||
|
method := tp.Method(i)
|
||||||
|
methods[method.Name] = method
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := &subTavern{
|
||||||
|
wsh: tv.wsh,
|
||||||
|
mongoClient: dbconn,
|
||||||
|
region: region,
|
||||||
|
methods: methods,
|
||||||
|
}
|
||||||
|
|
||||||
|
sub.wshRpc = createRpcCallDomain(tv.wsh.RedisSync, func(rc *wshandler.Richconn) *richConnOuter {
|
||||||
|
return &richConnOuter{wsh: sub.wsh, rc: rc}
|
||||||
|
})
|
||||||
|
|
||||||
|
groups := make(map[string]group)
|
||||||
|
for typename, cfg := range config.GroupTypes {
|
||||||
|
cfg.Name = typename
|
||||||
|
if cfg.Transient {
|
||||||
|
groupinstance, err = cfg.prepareInMemory(ctx, region, typename, tv.wsh)
|
||||||
|
} else {
|
||||||
|
if !dbconn.Connected() {
|
||||||
|
dbconn, err = common.NewMongoClient(ctx, url.Mongo, region)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
groupinstance, err = cfg.preparePersistent(ctx, region, dbconn, tv.wsh)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
groups[typename] = groupinstance
|
||||||
|
}
|
||||||
|
sub.groups = groups
|
||||||
|
|
||||||
|
tv.subTaverns = append(tv.subTaverns, sub)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tv *Tavern) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
|
||||||
|
// request는 항상 서비스 서버를 거쳐서 들어온다. [client] <--tls--> [service server] <--http--> tavern
|
||||||
|
// 클라이언트는 tavern으로부터 메시지를 수신할 뿐, 송신하지 못한다.
|
||||||
|
// 단, 요청은 https 서비스 서버를 통해 들어오고 클라이언트는 ws으로 수신만 한다는 원칙이 유지되어야 한다.(채팅 메시지는 예외?)
|
||||||
|
for _, sub := range tv.subTaverns {
|
||||||
|
var pattern string
|
||||||
|
if sub.region == "default" {
|
||||||
|
pattern = common.MakeHttpHandlerPattern(prefix, "api")
|
||||||
|
} else {
|
||||||
|
pattern = common.MakeHttpHandlerPattern(prefix, sub.region, "api")
|
||||||
|
}
|
||||||
|
serveMux.HandleFunc(pattern, sub.api)
|
||||||
|
|
||||||
|
deliveryChan := tv.wsh.DeliveryChannel(sub.region)
|
||||||
|
go sub.deliveryMessageHandler(deliveryChan)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sub *subTavern) 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
|
||||||
|
}
|
||||||
|
|
||||||
|
operation := r.URL.Query().Get("operation")
|
||||||
|
if len(operation) == 0 {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
method, ok := sub.methods[operation]
|
||||||
|
if !ok {
|
||||||
|
// 없는 operation
|
||||||
|
logger.Println("fail to call api. operation is not valid :", operation)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.PostForm == nil {
|
||||||
|
r.ParseMultipartForm(defaultMaxMemory)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []reflect.Value{
|
||||||
|
reflect.ValueOf(sub),
|
||||||
|
reflect.ValueOf(w),
|
||||||
|
reflect.ValueOf(r),
|
||||||
|
}
|
||||||
|
|
||||||
|
method.Func.Call(args)
|
||||||
|
}
|
||||||
27
go.mod
Normal file
27
go.mod
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
module repositories.action2quare.com/ayo/tavern
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-redis/redis/v8 v8.11.5
|
||||||
|
github.com/gorilla/websocket v1.5.0
|
||||||
|
go.mongodb.org/mongo-driver v1.11.6
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230524065958-abddf26379d1
|
||||||
|
)
|
||||||
|
|
||||||
|
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.1 // indirect
|
||||||
|
github.com/klauspost/compress v1.13.6 // indirect
|
||||||
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // 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.1 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
)
|
||||||
78
go.sum
Normal file
78
go.sum
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
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 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||||
|
github.com/google/go-cmp v0.5.2/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 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||||
|
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
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 h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||||
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||||
|
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 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||||
|
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||||
|
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||||
|
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||||
|
go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o=
|
||||||
|
go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-20230524065958-abddf26379d1 h1:0OInnPqpzQhRf1zwVTbWqWByWs8MTYbZc8c95099bSM=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230524065958-abddf26379d1/go.mod h1:5RmALPCFGFmqXa+AAPLsQaSlBVBafwX1H2CnIhsCM50=
|
||||||
46
main.go
Normal file
46
main.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// warroom project main.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/wshandler"
|
||||||
|
"repositories.action2quare.com/ayo/tavern/core"
|
||||||
|
|
||||||
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if !flag.Parsed() {
|
||||||
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
var config core.TavernConfig
|
||||||
|
if err := common.LoadConfig(&config); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
authcache, err := common.NewAuthCollectionGlobal(ctx, config.MaingateApiToken)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wsh := wshandler.NewWebsocketHandler(authcache)
|
||||||
|
if tv, err := core.New(ctx, wsh, &config); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
serveMux := http.NewServeMux()
|
||||||
|
wsh.RegisterHandlers(ctx, serveMux, *common.PrefixPtr)
|
||||||
|
tv.RegisterHandlers(ctx, serveMux, *common.PrefixPtr)
|
||||||
|
server := common.NewHTTPServer(serveMux)
|
||||||
|
logger.Println("tavern is started")
|
||||||
|
server.Start()
|
||||||
|
cancel()
|
||||||
|
tv.Destructor()
|
||||||
|
wsh.Destructor()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user