block collection 에 account를 복수로 저장
This commit is contained in:
52
core/api.go
52
core/api.go
@ -161,18 +161,21 @@ func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
mg := caller.mg
|
mg := caller.mg
|
||||||
logger.Println("blockAPI :", r.Method)
|
logger.Println("blockAPI :", r.Method)
|
||||||
if r.Method == "GET" {
|
switch r.Method {
|
||||||
|
case "GET":
|
||||||
target, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
|
target, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
|
||||||
logger.Println("Get :", target, ok)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
// 페이지네이션 해야할 듯
|
// 페이지네이션 해야할 듯
|
||||||
json.NewEncoder(w).Encode(mg.bl.all())
|
//json.NewEncoder(w).Encode(mg.bl.all())
|
||||||
} else if !target.IsZero() {
|
} else if !target.IsZero() {
|
||||||
if blocked, ok := mg.bl.get(target); ok && blocked != nil {
|
var blocked []blockinfo
|
||||||
|
if err := caller.mg.mongoClient.FindAllAs(CollectionBlock, bson.M{
|
||||||
|
"accid": target,
|
||||||
|
}, &blocked); err == nil {
|
||||||
json.NewEncoder(w).Encode(blocked)
|
json.NewEncoder(w).Encode(blocked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if r.Method == "PUT" {
|
case "PUT":
|
||||||
var targets struct {
|
var targets struct {
|
||||||
Start primitive.DateTime
|
Start primitive.DateTime
|
||||||
End primitive.DateTime
|
End primitive.DateTime
|
||||||
@ -189,22 +192,15 @@ func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
|||||||
Meta: meta,
|
Meta: meta,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := mg.mongoClient.Update(CollectionBlock, bson.M{
|
_, err := mg.mongoClient.Collection(CollectionBlock).InsertOne(r.Context(), bi)
|
||||||
"_id": accid,
|
|
||||||
}, bson.M{
|
|
||||||
"$set": &bi,
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Println("account is not blocked. err :", err)
|
logger.Println("account is not blocked. err :", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Println("account is blocked :", meta)
|
logger.Println("account is blocked :", meta)
|
||||||
|
|
||||||
bi.Accid = accid
|
|
||||||
caller.mg.bl.add(&bi)
|
|
||||||
mg.sessionProvider.RevokeAll(accid)
|
mg.sessionProvider.RevokeAll(accid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if r.Method == "DELETE" {
|
case "DELETE":
|
||||||
id := r.URL.Query().Get("id")
|
id := r.URL.Query().Get("id")
|
||||||
|
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
@ -215,29 +211,21 @@ func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = mg.mongoClient.Update(CollectionBlock, bson.M{
|
mg.mongoClient.Delete(CollectionBlock, bson.M{"_id": idobj})
|
||||||
"_id": idobj,
|
|
||||||
}, bson.M{
|
|
||||||
"$currentDate": bson.M{
|
|
||||||
"_ts": bson.M{"$type": "date"},
|
|
||||||
},
|
|
||||||
}, options.Update().SetUpsert(false))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
caller.mg.bl.remove(idobj)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
mg := caller.mg
|
mg := caller.mg
|
||||||
if r.Method == "GET" {
|
switch r.Method {
|
||||||
enc := json.NewEncoder(w)
|
case "GET":
|
||||||
enc.Encode(mg.wl.all())
|
var all []whitelistmember
|
||||||
} else if r.Method == "PUT" {
|
if err := mg.mongoClient.AllAs(CollectionWhitelist, &all); err == nil {
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.Encode(all)
|
||||||
|
}
|
||||||
|
case "PUT":
|
||||||
body, _ := io.ReadAll(r.Body)
|
body, _ := io.ReadAll(r.Body)
|
||||||
var member whitelistmember
|
var member whitelistmember
|
||||||
if err := json.Unmarshal(body, &member); err != nil {
|
if err := json.Unmarshal(body, &member); err != nil {
|
||||||
@ -254,7 +242,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if r.Method == "DELETE" {
|
case "DELETE":
|
||||||
id := r.URL.Query().Get("id")
|
id := r.URL.Query().Get("id")
|
||||||
|
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
|
|||||||
@ -148,8 +148,6 @@ type Maingate struct {
|
|||||||
//services servicelist
|
//services servicelist
|
||||||
serviceptr unsafe.Pointer
|
serviceptr unsafe.Pointer
|
||||||
admins unsafe.Pointer
|
admins unsafe.Pointer
|
||||||
wl memberContainerPtr[string, *whitelistmember]
|
|
||||||
bl memberContainerPtr[primitive.ObjectID, *blockinfo]
|
|
||||||
|
|
||||||
tokenEndpoints map[string]string
|
tokenEndpoints map[string]string
|
||||||
authorizationEndpoints map[string]string
|
authorizationEndpoints map[string]string
|
||||||
@ -345,7 +343,15 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
|
|||||||
mg.mongoClient.DropIndex(CollectionBlock, "codeaccid")
|
mg.mongoClient.DropIndex(CollectionBlock, "codeaccid")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
|
if _, err := mg.mongoClient.Collection(CollectionBlock).Indexes().DropOne(context, "_ts_1"); err == nil {
|
||||||
|
// 인덱스가 방금 지워졌다.
|
||||||
|
// 전체 document 제거
|
||||||
|
logger.Println(mg.mongoClient.Collection(CollectionBlock).Drop(context))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionBlock, map[string]bson.D{
|
||||||
|
"accidend": {{Key: "accid", Value: 1}, {Key: "end", Value: 1}},
|
||||||
|
}); err != nil {
|
||||||
return logger.ErrorWithCallStack(err)
|
return logger.ErrorWithCallStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,23 +418,6 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var whites []*whitelistmember
|
|
||||||
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
|
|
||||||
return logger.ErrorWithCallStack(err)
|
|
||||||
}
|
|
||||||
mg.wl.init(whites)
|
|
||||||
|
|
||||||
var blocks []*blockinfo
|
|
||||||
if err := mg.mongoClient.AllAs(CollectionBlock, &blocks); err != nil {
|
|
||||||
return logger.ErrorWithCallStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Println("allblocks :", blocks)
|
|
||||||
mg.bl.init(blocks)
|
|
||||||
|
|
||||||
go mg.wl.watchCollection(context, CollectionWhitelist, mg.mongoClient)
|
|
||||||
go mg.bl.watchCollection(context, CollectionBlock, mg.mongoClient)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,159 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type memberContraints[K comparable] interface {
|
|
||||||
Key() K
|
|
||||||
Expired() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type memberContainerPtr[K comparable, T memberContraints[K]] struct {
|
|
||||||
ptr unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) init(ms []T) {
|
|
||||||
next := map[K]T{}
|
|
||||||
for _, m := range ms {
|
|
||||||
next[m.Key()] = m
|
|
||||||
}
|
|
||||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) add(m T) {
|
|
||||||
ptr := atomic.LoadPointer(&p.ptr)
|
|
||||||
src := (*map[K]T)(ptr)
|
|
||||||
|
|
||||||
next := map[K]T{}
|
|
||||||
for k, v := range *src {
|
|
||||||
next[k] = v
|
|
||||||
}
|
|
||||||
next[m.Key()] = m
|
|
||||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) get(key K) (T, bool) {
|
|
||||||
ptr := atomic.LoadPointer(&p.ptr)
|
|
||||||
src := (*map[K]T)(ptr)
|
|
||||||
|
|
||||||
out, found := (*src)[key]
|
|
||||||
return out, found
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) remove(key K) {
|
|
||||||
ptr := atomic.LoadPointer(&p.ptr)
|
|
||||||
src := (*map[K]T)(ptr)
|
|
||||||
|
|
||||||
next := map[K]T{}
|
|
||||||
for k, v := range *src {
|
|
||||||
next[k] = v
|
|
||||||
}
|
|
||||||
delete(next, key)
|
|
||||||
atomic.StorePointer(&p.ptr, unsafe.Pointer(&next))
|
|
||||||
}
|
|
||||||
|
|
||||||
type memberPipelineDocument[K comparable, T memberContraints[K]] struct {
|
|
||||||
OperationType string `bson:"operationType"`
|
|
||||||
DocumentKey struct {
|
|
||||||
Id primitive.ObjectID `bson:"_id"`
|
|
||||||
} `bson:"documentKey"`
|
|
||||||
Member T `bson:"fullDocument"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) all() []T {
|
|
||||||
ptr := atomic.LoadPointer(&p.ptr)
|
|
||||||
src := (*map[K]T)(ptr)
|
|
||||||
|
|
||||||
out := make([]T, 0, len(*src))
|
|
||||||
for _, m := range *src {
|
|
||||||
if m.Expired() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, m)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *memberContainerPtr[K, T]) watchCollection(parentctx context.Context, coll gocommon.CollectionName, mc gocommon.MongoClient) {
|
|
||||||
defer func() {
|
|
||||||
s := recover()
|
|
||||||
if s != nil {
|
|
||||||
logger.Error(s)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
matchStage := bson.D{
|
|
||||||
{
|
|
||||||
Key: "$match", Value: bson.D{
|
|
||||||
{Key: "operationType", Value: bson.D{
|
|
||||||
{Key: "$in", Value: bson.A{
|
|
||||||
"update",
|
|
||||||
"insert",
|
|
||||||
}},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
projectStage := bson.D{
|
|
||||||
{
|
|
||||||
Key: "$project", Value: bson.D{
|
|
||||||
{Key: "documentKey", Value: 1},
|
|
||||||
{Key: "fullDocument", Value: 1},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var stream *mongo.ChangeStream
|
|
||||||
var err error
|
|
||||||
var ctx context.Context
|
|
||||||
|
|
||||||
for {
|
|
||||||
if stream == nil {
|
|
||||||
stream, err = mc.Watch(coll, mongo.Pipeline{matchStage, projectStage})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("watchCollection watch failed :", err)
|
|
||||||
time.Sleep(time.Minute)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ctx = context.TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
changed := stream.TryNext(ctx)
|
|
||||||
if ctx.Err() != nil {
|
|
||||||
logger.Error("watchCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if changed {
|
|
||||||
var data memberPipelineDocument[K, T]
|
|
||||||
if err := stream.Decode(&data); err == nil {
|
|
||||||
p.add(data.Member)
|
|
||||||
} else {
|
|
||||||
logger.Error("watchCollection stream.Decode failed :", err)
|
|
||||||
}
|
|
||||||
} else if stream.Err() != nil || stream.ID() == 0 {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
logger.Println("watchCollection is done")
|
|
||||||
stream.Close(ctx)
|
|
||||||
return
|
|
||||||
|
|
||||||
case <-time.After(time.Second):
|
|
||||||
logger.Error("watchCollection stream error :", stream.Err())
|
|
||||||
stream.Close(ctx)
|
|
||||||
stream = nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -22,9 +22,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type blockinfo struct {
|
type blockinfo struct {
|
||||||
|
Id primitive.ObjectID `bson:"_id" json:"_id"`
|
||||||
Start primitive.DateTime `bson:"start" json:"start"`
|
Start primitive.DateTime `bson:"start" json:"start"`
|
||||||
End primitive.DateTime `bson:"_ts" json:"_ts"`
|
End primitive.DateTime `bson:"end" json:"end"`
|
||||||
Accid primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
|
Accid primitive.ObjectID `bson:"accid,omitempty" json:"accid,omitempty"`
|
||||||
Meta primitive.M `bson:"meta,omitempty" json:"meta,omitempty"`
|
Meta primitive.M `bson:"meta,omitempty" json:"meta,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,8 +100,6 @@ type serviceDescription struct {
|
|||||||
VersionSplits map[string]string `bson:"version_splits" json:"version_splits"`
|
VersionSplits map[string]string `bson:"version_splits" json:"version_splits"`
|
||||||
|
|
||||||
sessionProvider session.Provider
|
sessionProvider session.Provider
|
||||||
wl *memberContainerPtr[string, *whitelistmember]
|
|
||||||
bl *memberContainerPtr[primitive.ObjectID, *blockinfo]
|
|
||||||
mongoClient gocommon.MongoClient
|
mongoClient gocommon.MongoClient
|
||||||
sessionTTL time.Duration
|
sessionTTL time.Duration
|
||||||
|
|
||||||
@ -264,9 +263,6 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.wl = &mg.wl
|
|
||||||
sh.bl = &mg.bl
|
|
||||||
sh.serviceSerialized, _ = json.Marshal(sh)
|
sh.serviceSerialized, _ = json.Marshal(sh)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -672,15 +668,6 @@ func (sh *serviceDescription) authorize_dev(w http.ResponseWriter, r *http.Reque
|
|||||||
if r.Method == "DELETE" {
|
if r.Method == "DELETE" {
|
||||||
sk := r.Header.Get("AS-X-SESSION")
|
sk := r.Header.Get("AS-X-SESSION")
|
||||||
if authinfo, err := sh.sessionProvider.Query(sk); err == nil {
|
if authinfo, err := sh.sessionProvider.Query(sk); err == nil {
|
||||||
bt := r.Header.Get("AS-X-BLOCK")
|
|
||||||
if len(bt) > 0 {
|
|
||||||
dur, _ := strconv.ParseInt(bt, 10, 0)
|
|
||||||
sh.bl.add(&blockinfo{
|
|
||||||
Start: primitive.NewDateTimeFromTime(time.Now().UTC()),
|
|
||||||
End: primitive.NewDateTimeFromTime(time.Now().UTC().Add(time.Second * time.Duration(dur))),
|
|
||||||
Accid: authinfo.Account,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sh.sessionProvider.RevokeAll(authinfo.Account)
|
sh.sessionProvider.RevokeAll(authinfo.Account)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -799,7 +786,8 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
|
|||||||
oldcreate := account["create"].(primitive.DateTime)
|
oldcreate := account["create"].(primitive.DateTime)
|
||||||
newaccount := oldcreate == createtime
|
newaccount := oldcreate == createtime
|
||||||
|
|
||||||
if bi, ok := sh.bl.get(accid); ok {
|
var bi blockinfo
|
||||||
|
if err := sh.mongoClient.FindOneAs(CollectionBlock, bson.M{"accid": accid, "end": bson.M{"$gt": time.Now().UTC()}}, &bi); err == nil {
|
||||||
// 블럭된 계정. 블락 정보를 알려준다.
|
// 블럭된 계정. 블락 정보를 알려준다.
|
||||||
w.Header().Add("MG-ACCOUNTBLOCK-START", strconv.FormatInt(bi.Start.Time().Unix(), 10))
|
w.Header().Add("MG-ACCOUNTBLOCK-START", strconv.FormatInt(bi.Start.Time().Unix(), 10))
|
||||||
w.Header().Add("MG-ACCOUNTBLOCK-END", strconv.FormatInt(bi.End.Time().Unix(), 10))
|
w.Header().Add("MG-ACCOUNTBLOCK-END", strconv.FormatInt(bi.End.Time().Unix(), 10))
|
||||||
@ -1081,7 +1069,8 @@ func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wm := &whitelistmember{Alias: authInfo.Alias, Platform: authInfo.Platform}
|
wm := &whitelistmember{Alias: authInfo.Alias, Platform: authInfo.Platform}
|
||||||
if _, ok := sh.wl.get(wm.Key()); ok {
|
doc, err := sh.mongoClient.FindOne(CollectionWhitelist, bson.M{"alias": wm.Key()})
|
||||||
|
if err == nil && doc != nil {
|
||||||
// qa 권한이면 입장 가능
|
// qa 권한이면 입장 가능
|
||||||
addrresp = div.urlsSerialized
|
addrresp = div.urlsSerialized
|
||||||
} else if div.Maintenance != nil {
|
} else if div.Maintenance != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user