maingate 이전
This commit is contained in:
612
core/service.go
Normal file
612
core/service.go
Normal file
@ -0,0 +1,612 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/logger"
|
||||
|
||||
"repositories.action2quare.com/ayo/go-ayo/common"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type blockinfo struct {
|
||||
Start primitive.DateTime
|
||||
End primitive.DateTime `bson:"_ts"`
|
||||
Reason string
|
||||
}
|
||||
|
||||
type whitelistmember struct {
|
||||
Service string
|
||||
Email string
|
||||
Platform string
|
||||
Desc string
|
||||
Expired primitive.DateTime `bson:"_ts,omitempty" json:"_ts,omitempty"`
|
||||
}
|
||||
|
||||
type whitelist struct {
|
||||
emailptr unsafe.Pointer
|
||||
working int32
|
||||
}
|
||||
|
||||
type usertokeninfo struct {
|
||||
platform string
|
||||
userid string
|
||||
token string //refreshtoken
|
||||
secret string
|
||||
brinfo string
|
||||
accesstoken string // microsoft only
|
||||
accesstoken_expire_time int64 // microsoft only
|
||||
}
|
||||
|
||||
func (wl *whitelist) init(total []whitelistmember) {
|
||||
next := make(map[string]*whitelistmember)
|
||||
for _, member := range total {
|
||||
next[whitelistKey(member.Email)] = &member
|
||||
}
|
||||
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
atomic.StoreInt32(&wl.working, 1)
|
||||
}
|
||||
|
||||
func (wl *whitelist) add(m *whitelistmember) {
|
||||
ptr := atomic.LoadPointer(&wl.emailptr)
|
||||
src := (*map[string]*whitelistmember)(ptr)
|
||||
|
||||
next := map[string]*whitelistmember{}
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
next[whitelistKey(m.Email)] = m
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (wl *whitelist) remove(email string) {
|
||||
ptr := atomic.LoadPointer(&wl.emailptr)
|
||||
src := (*map[string]*whitelistmember)(ptr)
|
||||
|
||||
next := make(map[string]*whitelistmember)
|
||||
for k, v := range *src {
|
||||
next[k] = v
|
||||
}
|
||||
delete(next, whitelistKey(email))
|
||||
atomic.StorePointer(&wl.emailptr, unsafe.Pointer(&next))
|
||||
}
|
||||
|
||||
func (wl *whitelist) isMember(email string, platform string) bool {
|
||||
if atomic.LoadInt32(&wl.working) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
ptr := atomic.LoadPointer(&wl.emailptr)
|
||||
src := *(*map[string]*whitelistmember)(ptr)
|
||||
|
||||
if member, exists := src[whitelistKey(email)]; exists {
|
||||
return member.Platform == platform
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type serviceDescription struct {
|
||||
// sync.Mutex
|
||||
Id primitive.ObjectID `bson:"_id"`
|
||||
ServiceName string `bson:"service"`
|
||||
Divisions map[string]any `bson:"divisions"`
|
||||
ServiceCode string `bson:"code"`
|
||||
UseWhitelist bool `bson:"use_whitelist"`
|
||||
Closed bool `bson:"closed"`
|
||||
ServerApiTokens []primitive.ObjectID `bson:"api_tokens"`
|
||||
ApiUsers map[string][]string `bson:"api_users"`
|
||||
|
||||
auths *common.AuthCollection
|
||||
wl whitelist
|
||||
mongoClient common.MongoClient
|
||||
sessionTTL time.Duration
|
||||
closed int32
|
||||
serviceCodeBytes []byte
|
||||
getUserBrowserInfo func(r *http.Request) (string, error)
|
||||
getUserTokenWithCheck func(platform string, userid string, brinfo string) (usertokeninfo, error)
|
||||
updateUserinfo func(info usertokeninfo) (bool, string, string)
|
||||
getProviderInfo func(platform string, uid string) (error, string, string)
|
||||
|
||||
apiUsers unsafe.Pointer
|
||||
divisionsSerialized unsafe.Pointer
|
||||
serviceSerialized unsafe.Pointer
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) readProfile(authtype string, id string, binfo string) (email string, err error) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error("readProfile failed :", authtype, id, s)
|
||||
if errt, ok := s.(error); ok {
|
||||
err = errt
|
||||
} else {
|
||||
err = errors.New(fmt.Sprint(s))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
userinfo, err := sh.getUserTokenWithCheck(authtype, id, binfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if userinfo.token == "" {
|
||||
return "", errors.New("refreshtoken token not found")
|
||||
}
|
||||
|
||||
//-- 토큰으로 모두 확인이 끝났으면 갱신한다.
|
||||
ok, _, email := sh.updateUserinfo(userinfo)
|
||||
|
||||
if !ok {
|
||||
return "", errors.New("updateUserinfo failed")
|
||||
}
|
||||
|
||||
return email, nil
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) prepare(mg *Maingate) error {
|
||||
div := sh.Divisions
|
||||
if len(sh.ServiceCode) == 0 {
|
||||
sh.ServiceCode = hex.EncodeToString(sh.Id[6:])
|
||||
}
|
||||
|
||||
divmarshaled, _ := json.Marshal(div)
|
||||
devstr := string(divmarshaled)
|
||||
sh.divisionsSerialized = unsafe.Pointer(&devstr)
|
||||
|
||||
sh.mongoClient = mg.mongoClient
|
||||
sh.auths = mg.auths
|
||||
sh.sessionTTL = time.Duration(mg.SessionTTL * int64(time.Second))
|
||||
sh.wl = whitelist{}
|
||||
sh.serviceCodeBytes, _ = hex.DecodeString(sh.ServiceCode)
|
||||
sh.getUserBrowserInfo = mg.GetUserBrowserInfo
|
||||
sh.getUserTokenWithCheck = mg.getUserTokenWithCheck
|
||||
sh.updateUserinfo = mg.updateUserinfo
|
||||
sh.getProviderInfo = mg.getProviderInfo
|
||||
|
||||
if sh.Closed {
|
||||
sh.closed = 1
|
||||
} else {
|
||||
sh.closed = 0
|
||||
}
|
||||
|
||||
if sh.UseWhitelist {
|
||||
var whites []whitelistmember
|
||||
if err := mg.mongoClient.FindAllAs(CollectionWhitelist, bson.M{
|
||||
"$or": []bson.M{{"service": sh.ServiceName}, {"service": sh.ServiceCode}},
|
||||
}, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sh.wl.init(whites)
|
||||
} else {
|
||||
sh.wl.working = 0
|
||||
}
|
||||
|
||||
if len(sh.ApiUsers) == 0 {
|
||||
sh.ApiUsers = map[string][]string{
|
||||
"service": {},
|
||||
"whitelist": {},
|
||||
"account": {},
|
||||
}
|
||||
}
|
||||
parsedUsers := make(map[string]map[string]bool)
|
||||
for cat, users := range sh.ApiUsers {
|
||||
catusers := make(map[string]bool)
|
||||
for _, user := range users {
|
||||
catusers[user] = true
|
||||
}
|
||||
parsedUsers[cat] = catusers
|
||||
}
|
||||
|
||||
sh.apiUsers = unsafe.Pointer(&parsedUsers)
|
||||
for _, keyid := range sh.ServerApiTokens {
|
||||
mg.apiTokenToService.add(keyid.Hex(), sh.ServiceCode)
|
||||
}
|
||||
|
||||
bt, _ := json.Marshal(sh)
|
||||
atomic.StorePointer(&sh.serviceSerialized, unsafe.Pointer(&bt))
|
||||
|
||||
logger.Println("service is ready :", sh.ServiceName, sh.ServiceCode, sh.UseWhitelist, string(divmarshaled))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error(s)
|
||||
}
|
||||
}()
|
||||
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
queryvals := r.URL.Query()
|
||||
//oldToken := queryvals.Get("otoken")
|
||||
oldType := queryvals.Get("otype")
|
||||
oldId := queryvals.Get("oid")
|
||||
sk := queryvals.Get("sk")
|
||||
//newToken := queryvals.Get("ntoken")
|
||||
newType := queryvals.Get("ntype")
|
||||
newId := queryvals.Get("nid")
|
||||
|
||||
oldAuth := sh.auths.Find(sk)
|
||||
if oldAuth == nil {
|
||||
// 잘못된 세션
|
||||
logger.Println("link failed. session key is not valid :", sk)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Println("=================")
|
||||
// fmt.Println(oldType)
|
||||
// fmt.Println(oldId)
|
||||
// fmt.Println("=================")
|
||||
// fmt.Println(newType)
|
||||
// fmt.Println(newId)
|
||||
// fmt.Println("=================")
|
||||
// fmt.Println(oldAuth.Platform)
|
||||
// fmt.Println(oldAuth.Uid)
|
||||
// fmt.Println("=================")
|
||||
|
||||
//if oldAuth.Token != oldToken || oldAuth.Uid != oldId || oldAuth.Platform != oldType {
|
||||
if oldAuth.Uid != oldId || oldAuth.Platform != oldType {
|
||||
logger.Println("link failed. session key is not correct :", *oldAuth, queryvals)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
bfinfo, err := sh.getUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
logger.Error("getUserBrowserInfo failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = sh.readProfile(oldType, oldId, bfinfo)
|
||||
if err != nil {
|
||||
logger.Error("readProfile(old) failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
email, err := sh.readProfile(newType, newId, bfinfo)
|
||||
if err != nil {
|
||||
logger.Error("readProfile(new) failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// if len(email) == 0 {
|
||||
// logger.Println("link failed. email is missing :", r.URL.Query())
|
||||
// w.WriteHeader(http.StatusBadRequest)
|
||||
// return
|
||||
// }
|
||||
|
||||
if !sh.wl.isMember(email, newType) {
|
||||
logger.Println("link failed. not whitelist member :", r.URL.Query(), email)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err, newType, newId = sh.getProviderInfo(newType, newId)
|
||||
if err != nil {
|
||||
logger.Error("getProviderInfo failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
|
||||
createtime := primitive.NewDateTimeFromTime(time.Now().UTC())
|
||||
link, err := sh.mongoClient.FindOneAndUpdate(CollectionLink, bson.M{
|
||||
"platform": newType,
|
||||
"uid": newId,
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"create": createtime,
|
||||
"email": email,
|
||||
},
|
||||
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"_id": 1}))
|
||||
if err != nil {
|
||||
logger.Error("link failed. FindOneAndUpdate link err:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, newid, err := sh.mongoClient.Update(common.CollectionName(sh.ServiceName), bson.M{
|
||||
"_id": link["_id"].(primitive.ObjectID),
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"accid": oldAuth.Accid,
|
||||
"create": createtime,
|
||||
},
|
||||
}, options.Update().SetUpsert(true))
|
||||
if err != nil {
|
||||
logger.Error("link failed. Update ServiceName err :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// newid가 있어야 한다. 그래야 기존 서비스 계정이 없는 상태이다.
|
||||
if newid == nil {
|
||||
// 이미 계정이 있네?
|
||||
logger.Println("link failed. already have service account :", r.URL.Query())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Println("link success :", r.URL.Query())
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) isValidAPIUser(category string, email string) bool {
|
||||
ptr := atomic.LoadPointer(&sh.apiUsers)
|
||||
catusers := *(*map[string]map[string]bool)(ptr)
|
||||
|
||||
if category == "*" {
|
||||
for _, users := range catusers {
|
||||
if _, ok := users[email]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if users, ok := catusers[category]; ok {
|
||||
if _, ok := users[email]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
logger.Println("isValidAPIUser failed. email is not allowed :", category, email, users)
|
||||
}
|
||||
|
||||
logger.Println("isValidAPIUser failed. category is missing :", category)
|
||||
return false
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error(s)
|
||||
}
|
||||
}()
|
||||
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
queryvals := r.URL.Query()
|
||||
authtype := queryvals.Get("type")
|
||||
uid := queryvals.Get("id")
|
||||
//accesstoken := queryvals.Get("token") //-- 이거 이제 받지마라
|
||||
session := queryvals.Get("sk")
|
||||
|
||||
//email, err := sh.readProfile(authtype, uid, accesstoken)
|
||||
bfinfo, err := sh.getUserBrowserInfo(r)
|
||||
if err != nil {
|
||||
logger.Error("getUserBrowserInfo failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
email, err := sh.readProfile(authtype, uid, bfinfo)
|
||||
if err != nil {
|
||||
logger.Error("readProfile failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !sh.wl.isMember(email, authtype) {
|
||||
logger.Println("auth failed. not whitelist member :", sh.ServiceCode, authtype, uid, email)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Println("auth success :", authtype, uid, email, session)
|
||||
|
||||
err, newType, newId := sh.getProviderInfo(authtype, uid)
|
||||
if err != nil {
|
||||
logger.Error("getProviderInfo failed :", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
|
||||
if authtype != newType || uid != newId {
|
||||
authtype = newType
|
||||
uid = newId
|
||||
logger.Println("auth success ( redirect ) :", authtype, uid, email, session)
|
||||
}
|
||||
|
||||
//if len(session) == 0 && len(email) > 0 {
|
||||
if len(session) == 0 {
|
||||
// platform + id -> account id
|
||||
createtime := primitive.NewDateTimeFromTime(time.Now().UTC())
|
||||
link, err := sh.mongoClient.FindOneAndUpdate(CollectionLink, bson.M{
|
||||
"platform": authtype,
|
||||
"uid": uid,
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"create": createtime,
|
||||
"email": email,
|
||||
},
|
||||
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"_id": 1}))
|
||||
if err != nil {
|
||||
logger.Error("authorize failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
linkid := link["_id"].(primitive.ObjectID)
|
||||
newaccid := primitive.NewObjectID()
|
||||
for i := 0; i < len(sh.serviceCodeBytes); i++ {
|
||||
newaccid[i] ^= sh.serviceCodeBytes[i]
|
||||
}
|
||||
account, err := sh.mongoClient.FindOneAndUpdate(common.CollectionName(sh.ServiceName), bson.M{
|
||||
"_id": linkid,
|
||||
}, bson.M{
|
||||
"$setOnInsert": bson.M{
|
||||
"accid": newaccid,
|
||||
"create": createtime,
|
||||
},
|
||||
}, options.FindOneAndUpdate().SetReturnDocument(options.After).SetUpsert(true).SetProjection(bson.M{"accid": 1, "create": 1}))
|
||||
if err != nil {
|
||||
logger.Error("authorize failed. Update sh.ServiceName err:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
accid := account["accid"].(primitive.ObjectID)
|
||||
oldcreate := account["create"].(primitive.DateTime)
|
||||
newaccount := oldcreate == createtime
|
||||
|
||||
var bi blockinfo
|
||||
if err := sh.mongoClient.FindOneAs(CollectionBlock, bson.M{
|
||||
"code": sh.ServiceCode,
|
||||
"accid": accid,
|
||||
}, &bi); err != nil {
|
||||
logger.Error("authorize failed. find blockinfo in CollectionBlock err:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if !bi.Start.Time().IsZero() {
|
||||
now := time.Now().UTC()
|
||||
if bi.Start.Time().Before(now) && bi.End.Time().After(now) {
|
||||
// block됐네?
|
||||
// status는 정상이고 reason을 넘겨주자
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"blocked": bi,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
newsession := primitive.NewObjectID()
|
||||
expired := primitive.NewDateTimeFromTime(time.Now().UTC().Add(sh.sessionTTL))
|
||||
newauth := common.Authinfo{
|
||||
Accid: accid,
|
||||
ServiceCode: sh.ServiceCode,
|
||||
Platform: authtype,
|
||||
Uid: uid,
|
||||
//Token: accesstoken,
|
||||
Sk: newsession,
|
||||
Expired: expired,
|
||||
//RefreshToken: queryvals.Get("rt"),
|
||||
}
|
||||
|
||||
_, _, err = sh.mongoClient.UpsertOne(CollectionAuth, bson.M{"_id": newauth.Accid}, &newauth)
|
||||
if err != nil {
|
||||
logger.Error("authorize failed :", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
output := map[string]any{
|
||||
"sk": newsession.Hex(),
|
||||
"expirein": sh.sessionTTL.Seconds(),
|
||||
"newAccount": newaccount,
|
||||
"accid": newauth.Accid.Hex(),
|
||||
}
|
||||
bt, _ := json.Marshal(output)
|
||||
w.Write(bt)
|
||||
} else if len(session) > 0 {
|
||||
sessionobj, _ := primitive.ObjectIDFromHex(session)
|
||||
if !sessionobj.IsZero() {
|
||||
updated, _, err := sh.mongoClient.Update(CollectionAuth,
|
||||
bson.M{
|
||||
"sk": sessionobj,
|
||||
},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{
|
||||
"_ts": bson.M{"$type": "date"},
|
||||
},
|
||||
}, options.Update().SetUpsert(false))
|
||||
if err != nil {
|
||||
logger.Error("update auth collection failed")
|
||||
logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !updated {
|
||||
// 세션이 없네?
|
||||
logger.Println("authorize failed. session not exists in database :", session)
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
output := map[string]any{
|
||||
"sk": session,
|
||||
"expirein": sh.sessionTTL.Seconds(),
|
||||
}
|
||||
bt, _ := json.Marshal(output)
|
||||
w.Write(bt)
|
||||
} else {
|
||||
logger.Println("authorize failed. sk is not valid hex :", session)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
logger.Println("authorize failed. id empty :", queryvals)
|
||||
}
|
||||
}
|
||||
|
||||
func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
logger.Error(s)
|
||||
}
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
io.Copy(io.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
}()
|
||||
|
||||
if atomic.LoadInt32(&sh.closed) != 0 {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasSuffix(r.URL.Path, "/auth") {
|
||||
sh.authorize(w, r)
|
||||
} else if strings.HasSuffix(r.URL.Path, "/link") {
|
||||
sh.link(w, r)
|
||||
} else {
|
||||
// TODO : 세션키와 authtoken을 헤더로 받아서 accid 조회
|
||||
queryvals := r.URL.Query()
|
||||
//token := queryvals.Get("token")
|
||||
token := "" // 더이상 쓰지 않는다.
|
||||
sk := queryvals.Get("sk")
|
||||
|
||||
//if len(token) == 0 || len(sk) == 0 {
|
||||
if len(sk) == 0 {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO : 각 서버에 있는 자산? 캐릭터 정보를 보여줘야 하나. 뭘 보여줄지는 프로젝트에 문의
|
||||
// 일단 서버 종류만 내려보내자
|
||||
// 세션키가 있는지 확인
|
||||
if _, ok := sh.auths.IsValid(sk, token); !ok {
|
||||
logger.Println("sessionkey is not valid :", sk, token)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
divstrptr := atomic.LoadPointer(&sh.divisionsSerialized)
|
||||
divstr := *(*string)(divstrptr)
|
||||
w.Write([]byte(divstr))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user