Compare commits
5 Commits
kd-live
...
ddc34aef55
| Author | SHA1 | Date | |
|---|---|---|---|
| ddc34aef55 | |||
| aef7282556 | |||
| 2369d52a11 | |||
| 23d5281481 | |||
| c2330ad52b |
@ -1,37 +0,0 @@
|
|||||||
// Import the functions you need from the SDKs you need
|
|
||||||
import { initializeApp } from './firebase-app.js';
|
|
||||||
import { getAnalytics, logEvent } from './firebase-analytics.js';
|
|
||||||
|
|
||||||
// TODO: Add SDKs for Firebase products that you want to use
|
|
||||||
// https://firebase.google.com/docs/web/setup#available-libraries
|
|
||||||
|
|
||||||
// Your web app's Firebase configuration
|
|
||||||
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
|
|
||||||
const firebaseConfig = {
|
|
||||||
apiKey: "{{.FBA_apiKey}}",
|
|
||||||
authDomain: "{{.FBA_authDomain}}",
|
|
||||||
databaseURL: "{{.FBA_databaseURL}}",
|
|
||||||
projectId: "{{.FBA_projectId}}",
|
|
||||||
storageBucket: "{{.FBA_storageBucket}}",
|
|
||||||
messagingSenderId: "{{.FBA_messagingSenderId}}",
|
|
||||||
appId: "{{.FBA_appId}}",
|
|
||||||
measurementId: "{{.FBA_measurementId}}"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize Firebase
|
|
||||||
const app = initializeApp(firebaseConfig);
|
|
||||||
const analytics = getAnalytics(app);
|
|
||||||
|
|
||||||
// LogEvent('DESKTOP_TEST8');
|
|
||||||
|
|
||||||
export function LogEvent(args){
|
|
||||||
|
|
||||||
if ( arguments.length == 1) {
|
|
||||||
logEvent(analytics, arguments[0]);
|
|
||||||
} else {
|
|
||||||
logEvent(analytics, arguments[0], arguments[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
1
backup/firebase-jssdk/fb-ga.min.js
vendored
1
backup/firebase-jssdk/fb-ga.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,6 @@
|
|||||||
{
|
{
|
||||||
"maingate_mongodb_url": "mongodb://...",
|
"maingate_mongodb_url": "mongodb://...",
|
||||||
"autologin_ttl": 604800,
|
"autologin_ttl": 604800,
|
||||||
"acc_del_ttl": 7776000,
|
|
||||||
"maximum_num_link_account": 10,
|
|
||||||
"redirect_base_url": "",
|
"redirect_base_url": "",
|
||||||
"google_client_id" : "",
|
"google_client_id" : "",
|
||||||
"google_client_secret" : "",
|
"google_client_secret" : "",
|
||||||
@ -26,15 +24,6 @@
|
|||||||
|
|
||||||
"firebase_admin_sdk_credentialfile": "",
|
"firebase_admin_sdk_credentialfile": "",
|
||||||
|
|
||||||
"firebase_google_analytics_jssdk_apikey": "",
|
|
||||||
"firebase_google_analytics_jssdk_authdomain": "",
|
|
||||||
"firebase_google_analytics_jssdk_databaseurl": "",
|
|
||||||
"firebase_google_analytics_jssdk_projectid": "",
|
|
||||||
"firebase_google_analytics_jssdk_storagebucket": "",
|
|
||||||
"firebase_google_analytics_jssdk_messagingsenderid": "",
|
|
||||||
"firebase_google_analytics_jssdk_apiid": "",
|
|
||||||
"firebase_google_analytics_jssdk_measurementid": "",
|
|
||||||
|
|
||||||
"maingate_global_admins" : [
|
"maingate_global_admins" : [
|
||||||
"mountain@action2quare.com"
|
"mountain@action2quare.com"
|
||||||
]
|
]
|
||||||
|
|||||||
359
core/api.go
359
core/api.go
@ -2,7 +2,9 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -16,7 +18,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
@ -24,7 +26,8 @@ import (
|
|||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileDocumentDesc struct {
|
type fileDocumentDesc struct {
|
||||||
|
Service string `bson:"service" json:"service"`
|
||||||
Key string `bson:"key" json:"key"`
|
Key string `bson:"key" json:"key"`
|
||||||
Src string `bson:"src" json:"src"`
|
Src string `bson:"src" json:"src"`
|
||||||
Link string `bson:"link" json:"link"`
|
Link string `bson:"link" json:"link"`
|
||||||
@ -34,7 +37,7 @@ type FileDocumentDesc struct {
|
|||||||
Contents []byte `bson:"contents,omitempty" json:"contents,omitempty"`
|
Contents []byte `bson:"contents,omitempty" json:"contents,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FileDocumentDesc) Save() error {
|
func (fd *fileDocumentDesc) save() error {
|
||||||
// 새 파일 올라옴
|
// 새 파일 올라옴
|
||||||
if len(fd.Contents) == 0 {
|
if len(fd.Contents) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -63,16 +66,48 @@ func (fd *FileDocumentDesc) Save() error {
|
|||||||
if fd.Extract {
|
if fd.Extract {
|
||||||
switch path.Ext(destFile) {
|
switch path.Ext(destFile) {
|
||||||
case ".zip":
|
case ".zip":
|
||||||
err = gocommon.Unzip(destFile)
|
err = common.Unzip(destFile)
|
||||||
case ".tar":
|
case ".tar":
|
||||||
err = gocommon.Untar(destFile)
|
err = common.Untar(destFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (caller apiCaller) isAdmin() bool {
|
||||||
|
if *noauth {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
v, ok := caller.userinfo["email"]
|
||||||
|
if !ok {
|
||||||
|
logger.Println("isVaidUser failed. email is missing :", caller.userinfo)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
email := v.(string)
|
||||||
|
if _, ok := caller.globalAdmins[email]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return caller.mg.service().isAdmin(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (caller apiCaller) isAdminOrValidToken() bool {
|
||||||
|
if caller.isAdmin() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return caller.mg.service().isValidToken(caller.apiToken)
|
||||||
|
}
|
||||||
|
|
||||||
func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
|
// if !caller.isAdminOrValidToken() {
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
allfiles, err := caller.mg.mongoClient.All(CollectionFile, options.Find().SetProjection(bson.M{
|
allfiles, err := caller.mg.mongoClient.All(CollectionFile, options.Find().SetProjection(bson.M{
|
||||||
"contents": 0,
|
"contents": 0,
|
||||||
}).SetReturnKey(false))
|
}).SetReturnKey(false))
|
||||||
@ -91,6 +126,11 @@ func (caller apiCaller) filesAPI(w http.ResponseWriter, r *http.Request) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if !caller.isAdminOrValidToken() {
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
||||||
"key": key,
|
"key": key,
|
||||||
})
|
})
|
||||||
@ -107,6 +147,11 @@ var seq = uint32(0)
|
|||||||
|
|
||||||
func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
if r.Method == "PUT" {
|
if r.Method == "PUT" {
|
||||||
|
servicename := r.FormValue("service")
|
||||||
|
hasher := md5.New()
|
||||||
|
hasher.Write([]byte(servicename))
|
||||||
|
subfolder := hex.EncodeToString(hasher.Sum(nil))[:8]
|
||||||
|
|
||||||
infile, header, err := r.FormFile("file")
|
infile, header, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
@ -122,19 +167,20 @@ func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
var b [5]byte
|
var b [5]byte
|
||||||
binary.BigEndian.PutUint32(b[0:4], uint32(time.Now().Unix()))
|
binary.BigEndian.PutUint32(b[0:4], uint32(time.Now().Unix()))
|
||||||
b[4] = byte(atomic.AddUint32(&seq, 1) % 255)
|
b[4] = byte(atomic.AddUint32(&seq, 1) % 255)
|
||||||
|
rf := hex.EncodeToString(b[1:])
|
||||||
|
newidstr := subfolder + rf
|
||||||
|
newidbt, _ := hex.DecodeString(newidstr)
|
||||||
newidobj := primitive.NewObjectID()
|
newidobj := primitive.NewObjectID()
|
||||||
copy(newidobj[:], b[1:])
|
copy(newidobj[:], newidbt[:8])
|
||||||
|
|
||||||
rf := newidobj.Hex()
|
|
||||||
var link string
|
var link string
|
||||||
if extract {
|
if extract {
|
||||||
link = path.Join("static", rf)
|
link = path.Join("static", subfolder, rf)
|
||||||
} else {
|
} else {
|
||||||
link = path.Join("static", rf, header.Filename)
|
link = path.Join("static", subfolder, rf, header.Filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
newdoc := FileDocumentDesc{
|
newdoc := fileDocumentDesc{
|
||||||
Contents: contents,
|
Contents: contents,
|
||||||
Src: header.Filename,
|
Src: header.Filename,
|
||||||
Timestamp: time.Now().UTC().Unix(),
|
Timestamp: time.Now().UTC().Unix(),
|
||||||
@ -142,10 +188,12 @@ func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
Link: link,
|
Link: link,
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
Key: rf,
|
Key: rf,
|
||||||
|
Service: servicename,
|
||||||
}
|
}
|
||||||
_, _, err = caller.mg.mongoClient.UpsertOne(CollectionFile, bson.M{
|
_, _, err = caller.mg.mongoClient.UpsertOne(CollectionFile, bson.M{
|
||||||
"_id": newidobj,
|
"_id": newidobj,
|
||||||
"key": rf,
|
"service": servicename,
|
||||||
|
"key": rf,
|
||||||
}, newdoc)
|
}, newdoc)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -158,81 +206,46 @@ func (caller apiCaller) uploadAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (caller apiCaller) blockAPI(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
mg := caller.mg
|
|
||||||
if r.Method == "GET" {
|
|
||||||
json.NewEncoder(w).Encode(mg.bl.all())
|
|
||||||
} else if r.Method == "PUT" {
|
|
||||||
body, _ := io.ReadAll(r.Body)
|
|
||||||
|
|
||||||
var bipl blockinfoWithStringId
|
|
||||||
if err := json.Unmarshal(body, &bipl); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
accid, err := primitive.ObjectIDFromHex(bipl.StrId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bi := blockinfo{
|
|
||||||
Start: primitive.NewDateTimeFromTime(time.Unix(bipl.StartUnix, 0)),
|
|
||||||
End: primitive.NewDateTimeFromTime(time.Unix(bipl.EndUnix, 0)),
|
|
||||||
Reason: bipl.Reason,
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Println("bi :", accid, bi)
|
|
||||||
|
|
||||||
_, _, err = mg.mongoClient.Update(CollectionBlock, bson.M{
|
|
||||||
"_id": accid,
|
|
||||||
}, bson.M{
|
|
||||||
"$set": &bi,
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if r.Method == "DELETE" {
|
|
||||||
id := r.URL.Query().Get("id")
|
|
||||||
|
|
||||||
if len(id) == 0 {
|
|
||||||
return errors.New("id param is missing")
|
|
||||||
}
|
|
||||||
idobj, err := primitive.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err = mg.mongoClient.Update(CollectionBlock, bson.M{
|
|
||||||
"_id": idobj,
|
|
||||||
}, bson.M{
|
|
||||||
"$currentDate": bson.M{
|
|
||||||
"_ts": bson.M{"$type": "date"},
|
|
||||||
},
|
|
||||||
}, options.Update().SetUpsert(false))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mg.mongoClient.Delete(CollectionAuth, bson.M{"_id": idobj})
|
|
||||||
}
|
|
||||||
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
|
||||||
|
queryvals := r.URL.Query()
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
enc := json.NewEncoder(w)
|
// if !caller.isAdminOrValidToken() {
|
||||||
enc.Encode(mg.wl.all())
|
// logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
all, err := mg.mongoClient.All(CollectionWhitelist)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(all) > 0 {
|
||||||
|
var notexp []primitive.M
|
||||||
|
for _, v := range all {
|
||||||
|
if _, exp := v["_ts"]; !exp {
|
||||||
|
notexp = append(notexp, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allraw, _ := json.Marshal(notexp)
|
||||||
|
w.Write(allraw)
|
||||||
|
}
|
||||||
} else if r.Method == "PUT" {
|
} else if r.Method == "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 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
member.ExpiredAt = 0
|
|
||||||
member.Id = primitive.NilObjectID
|
// if !caller.isAdminOrValidToken() {
|
||||||
|
// logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||||
|
// w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
member.Expired = 0
|
||||||
|
|
||||||
_, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{
|
_, _, err := mg.mongoClient.Update(CollectionWhitelist, bson.M{
|
||||||
"_id": primitive.NewObjectID(),
|
"_id": primitive.NewObjectID(),
|
||||||
}, bson.M{
|
}, bson.M{
|
||||||
@ -243,8 +256,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if r.Method == "DELETE" {
|
} else if r.Method == "DELETE" {
|
||||||
id := r.URL.Query().Get("id")
|
id := queryvals.Get("id")
|
||||||
|
|
||||||
if len(id) == 0 {
|
if len(id) == 0 {
|
||||||
return errors.New("id param is missing")
|
return errors.New("id param is missing")
|
||||||
}
|
}
|
||||||
@ -270,22 +282,20 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
|||||||
func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
mg := caller.mg
|
mg := caller.mg
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
logger.Println("serviceAPI :", r.URL.Path)
|
|
||||||
if mg.service().Id.IsZero() {
|
if mg.service().Id.IsZero() {
|
||||||
logger.Println(" id is zero")
|
|
||||||
newService := serviceDescription{
|
newService := serviceDescription{
|
||||||
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||||
Id: primitive.NewObjectID(),
|
Id: primitive.NewObjectID(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := newService.prepare(caller.mg); err != nil {
|
if err := newService.prepare(caller.mg); err != nil {
|
||||||
logger.Println(" prepare failed :", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write(mg.service().serviceSerialized)
|
serptr := atomic.LoadPointer(&mg.service().serviceSerialized)
|
||||||
|
w.Write(*(*[]byte)(serptr))
|
||||||
} else if r.Method == "POST" {
|
} else if r.Method == "POST" {
|
||||||
body, _ := io.ReadAll(r.Body)
|
body, _ := io.ReadAll(r.Body)
|
||||||
var service serviceDescription
|
var service serviceDescription
|
||||||
@ -320,7 +330,8 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
mg := caller.mg
|
mg := caller.mg
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
w.Write(mg.service().divisionsSerialized)
|
serptr := atomic.LoadPointer(&mg.service().divisionsSerialized)
|
||||||
|
w.Write(*(*[]byte)(serptr))
|
||||||
} else if r.Method == "POST" {
|
} else if r.Method == "POST" {
|
||||||
var divs map[string]*Division
|
var divs map[string]*Division
|
||||||
dec := json.NewDecoder(r.Body)
|
dec := json.NewDecoder(r.Body)
|
||||||
@ -344,94 +355,20 @@ func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (caller apiCaller) couponAPI(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
switch r.Method {
|
|
||||||
case "PUT":
|
|
||||||
// 쿠폰 생성
|
|
||||||
logger.Println("begin generateCoupons")
|
|
||||||
generateCoupons(caller.mg.mongoClient, w, r)
|
|
||||||
|
|
||||||
case "POST":
|
|
||||||
// TODO : 쿠폰 사용
|
|
||||||
// 쿠폰 사용 표시 해주고 내용을 응답
|
|
||||||
logger.Println("begin useCoupon")
|
|
||||||
useCoupon(caller.mg.mongoClient, w, r)
|
|
||||||
|
|
||||||
case "GET":
|
|
||||||
// 쿠폰 조회
|
|
||||||
if r.Form.Has("code") {
|
|
||||||
// 쿠폰 코드 조회
|
|
||||||
logger.Println("begin queryCoupon")
|
|
||||||
queryCoupon(caller.mg.mongoClient, w, r)
|
|
||||||
} else if r.Form.Has("name") {
|
|
||||||
// 쿠폰 코드 다운
|
|
||||||
logger.Println("begin downloadCoupons")
|
|
||||||
downloadCoupons(caller.mg.mongoClient, w, r)
|
|
||||||
} else {
|
|
||||||
// 쿠폰 이름 목록
|
|
||||||
logger.Println("begin listAllCouponNames")
|
|
||||||
listAllCouponNames(caller.mg.mongoClient, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "DELETE":
|
|
||||||
// 쿠폰 삭제
|
|
||||||
logger.Println("begin deleteCoupon")
|
|
||||||
deleteCoupon(caller.mg.mongoClient, w, r)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var errApiTokenMissing = errors.New("mg-x-api-token is missing")
|
var errApiTokenMissing = errors.New("mg-x-api-token is missing")
|
||||||
|
|
||||||
func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error {
|
func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error {
|
||||||
mg := caller.mg
|
mg := caller.mg
|
||||||
|
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||||
if !*devflag {
|
if len(apitoken) == 0 {
|
||||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
return errApiTokenMissing
|
||||||
if len(apitoken) == 0 {
|
|
||||||
return errApiTokenMissing
|
|
||||||
}
|
|
||||||
|
|
||||||
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
|
||||||
if !mg.service().isValidToken(apitokenObj) {
|
|
||||||
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||||
}
|
if !mg.service().isValidToken(apitokenObj) {
|
||||||
|
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
||||||
func (caller apiCaller) lockcreatecharAPI(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
mg, err := caller.mg.mongoClient.FindAll(CollectionService, bson.M{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
haschr, _ := gocommon.ReadStringFormValue(r.Form, "haschr")
|
|
||||||
|
|
||||||
locked := make(map[string]any)
|
|
||||||
if haschr == "true" {
|
|
||||||
locked["lock"] = false
|
|
||||||
} else {
|
|
||||||
curregion, _ := gocommon.ReadStringFormValue(r.Form, "region")
|
|
||||||
|
|
||||||
for _, regioninfo := range mg {
|
|
||||||
region := regioninfo["divisions"].(primitive.M)
|
|
||||||
for idx, rl := range region {
|
|
||||||
if idx == curregion {
|
|
||||||
if rl.(primitive.M)["lockcreatechar"].(bool) {
|
|
||||||
locked["lock"] = true
|
|
||||||
} else {
|
|
||||||
locked["lock"] = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create, _ := json.Marshal(locked)
|
|
||||||
w.Write(create)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,71 +392,63 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
|||||||
r.Body.Close()
|
r.Body.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
r.ParseMultipartForm(32 << 20)
|
|
||||||
|
|
||||||
var userinfo map[string]any
|
var userinfo map[string]any
|
||||||
|
|
||||||
var apiTokenObj primitive.ObjectID
|
if !*noauth {
|
||||||
if !*devflag {
|
authheader := r.Header.Get("Authorization")
|
||||||
apiToken := r.Header.Get("MG-X-API-TOKEN")
|
if len(authheader) == 0 {
|
||||||
if len(apiToken) > 0 {
|
logger.Println("Authorization header is not valid :", authheader)
|
||||||
if apiToken != mg.maingateConfig.ApiToken {
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
return
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := primitive.ObjectIDFromHex(apiToken)
|
req, _ := http.NewRequest("GET", "https://graph.microsoft.com/oidc/userinfo", nil)
|
||||||
if err != nil {
|
req.Header.Add("Authorization", authheader)
|
||||||
logger.Error(err)
|
client := &http.Client{}
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
apiTokenObj = obj
|
resp, err := client.Do(req)
|
||||||
} else {
|
if err != nil {
|
||||||
authheader := r.Header.Get("Authorization")
|
logger.Println("graph microsoft api call failed :", err)
|
||||||
if len(authheader) == 0 {
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
logger.Println("Authorization header is not valid :", authheader)
|
return
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
}
|
||||||
return
|
defer resp.Body.Close()
|
||||||
}
|
|
||||||
|
|
||||||
req, _ := http.NewRequest("GET", "https://graph.microsoft.com/oidc/userinfo", nil)
|
raw, _ := io.ReadAll(resp.Body)
|
||||||
req.Header.Add("Authorization", authheader)
|
if err = json.Unmarshal(raw, &userinfo); err != nil {
|
||||||
client := &http.Client{}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
if _, expired := userinfo["error"]; expired {
|
||||||
if err != nil {
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
logger.Println("graph microsoft api call failed :", err)
|
return
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
raw, _ := io.ReadAll(resp.Body)
|
|
||||||
if err = json.Unmarshal(raw, &userinfo); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, expired := userinfo["error"]; expired {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr := atomic.LoadPointer(&mg.admins)
|
ptr := atomic.LoadPointer(&mg.admins)
|
||||||
adminsptr := (*globalAdmins)(ptr)
|
adminsptr := (*globalAdmins)(ptr)
|
||||||
|
|
||||||
if adminsptr.modtime != gocommon.ConfigModTime() {
|
if adminsptr.modtime != common.ConfigModTime() {
|
||||||
var config globalAdmins
|
var config globalAdmins
|
||||||
if err := gocommon.LoadConfig(&config); err == nil {
|
if err := common.LoadConfig(&config); err == nil {
|
||||||
config.parse()
|
config.parse()
|
||||||
adminsptr = &config
|
adminsptr = &config
|
||||||
atomic.StorePointer(&mg.admins, unsafe.Pointer(adminsptr))
|
atomic.StorePointer(&mg.admins, unsafe.Pointer(adminsptr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiToken := r.Header.Get("MG-X-API-TOKEN")
|
||||||
|
var apiTokenObj primitive.ObjectID
|
||||||
|
if len(apiToken) > 0 {
|
||||||
|
obj, err := primitive.ObjectIDFromHex(apiToken)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
apiTokenObj = obj
|
||||||
|
}
|
||||||
|
|
||||||
logger.Println("api call :", r.URL.Path, r.Method, r.URL.Query(), userinfo)
|
logger.Println("api call :", r.URL.Path, r.Method, r.URL.Query(), userinfo)
|
||||||
caller := apiCaller{
|
caller := apiCaller{
|
||||||
userinfo: userinfo,
|
userinfo: userinfo,
|
||||||
@ -541,12 +470,6 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
|||||||
err = caller.maintenanceAPI(w, r)
|
err = caller.maintenanceAPI(w, r)
|
||||||
} else if strings.HasSuffix(r.URL.Path, "/files") {
|
} else if strings.HasSuffix(r.URL.Path, "/files") {
|
||||||
err = caller.filesAPI(w, r)
|
err = caller.filesAPI(w, r)
|
||||||
} else if strings.HasSuffix(r.URL.Path, "/block") {
|
|
||||||
err = caller.blockAPI(w, r)
|
|
||||||
} else if strings.HasSuffix(r.URL.Path, "/coupon") {
|
|
||||||
err = caller.couponAPI(w, r)
|
|
||||||
} else if strings.HasSuffix(r.URL.Path, "/lockcreatechar") {
|
|
||||||
err = caller.lockcreatecharAPI(w, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -1,407 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"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"
|
|
||||||
coupon "repositories.action2quare.com/ayo/gocommon/coupon"
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CollectionCoupon = gocommon.CollectionName("coupon")
|
|
||||||
CollectionCouponUse = gocommon.CollectionName("coupon_use")
|
|
||||||
)
|
|
||||||
|
|
||||||
type couponDoc struct {
|
|
||||||
Name string `json:"name" bson:"name"`
|
|
||||||
Effect string `json:"effect" bson:"effect"`
|
|
||||||
Desc string `json:"desc" bson:"desc"`
|
|
||||||
Total int64 `json:"total" bson:"total"`
|
|
||||||
Remains []string `json:"remains,omitempty" bson:"remains,omitempty"`
|
|
||||||
Used []string `json:"used,omitempty" bson:"used,omitempty"`
|
|
||||||
Expire int64 `json:"expire" bson:"expire"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCouponKey(roundnum uint32, uid []byte) string {
|
|
||||||
left := binary.BigEndian.Uint16(uid[0:2])
|
|
||||||
right := binary.BigEndian.Uint16(uid[2:4])
|
|
||||||
multi := uint32(left) * uint32(right)
|
|
||||||
xor := roundnum ^ multi
|
|
||||||
|
|
||||||
final := make([]byte, 8)
|
|
||||||
binary.LittleEndian.PutUint32(final, xor)
|
|
||||||
copy(final[4:], uid)
|
|
||||||
return fmt.Sprintf("%s-%s-%s-%s", hex.EncodeToString(final[0:2]), hex.EncodeToString(final[2:4]), hex.EncodeToString(final[4:6]), hex.EncodeToString(final[6:8]))
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCouponCodes(name string, count int) (string, map[string]string) {
|
|
||||||
checkunique := make(map[string]bool)
|
|
||||||
keys := make(map[string]string)
|
|
||||||
uid := make([]byte, 4)
|
|
||||||
|
|
||||||
roundHash, roundnum := coupon.MakeCouponRoundHash(name)
|
|
||||||
seed := time.Now().UnixNano()
|
|
||||||
|
|
||||||
for len(keys) < count {
|
|
||||||
rand.Seed(seed)
|
|
||||||
rand.Read(uid)
|
|
||||||
|
|
||||||
code := makeCouponKey(roundnum, uid)
|
|
||||||
|
|
||||||
if _, ok := checkunique[code]; !ok {
|
|
||||||
checkunique[code] = true
|
|
||||||
keys[hex.EncodeToString(uid)] = code
|
|
||||||
}
|
|
||||||
seed = int64(binary.BigEndian.Uint32(uid))
|
|
||||||
}
|
|
||||||
return roundHash, keys
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateCoupons(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
name, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
|
||||||
effect, _ := gocommon.ReadStringFormValue(r.Form, "effect")
|
|
||||||
count, _ := gocommon.ReadIntegerFormValue(r.Form, "count")
|
|
||||||
desc, _ := gocommon.ReadStringFormValue(r.Form, "desc")
|
|
||||||
expire, _ := gocommon.ReadIntegerFormValue(r.Form, "expire")
|
|
||||||
|
|
||||||
if count == 0 {
|
|
||||||
logger.Println("[generateCoupons] count == 0")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
roundHash, _ := coupon.MakeCouponRoundHash(name)
|
|
||||||
roundObj, _ := primitive.ObjectIDFromHex(roundHash + roundHash + roundHash)
|
|
||||||
|
|
||||||
if count < 0 {
|
|
||||||
// 무한 쿠폰이므로 그냥 문서 생성해 주고 끝
|
|
||||||
if _, _, err := mongoClient.Update(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, bson.M{
|
|
||||||
"$set": &couponDoc{
|
|
||||||
Name: name,
|
|
||||||
Effect: effect,
|
|
||||||
Desc: desc,
|
|
||||||
Total: -1,
|
|
||||||
Expire: expire,
|
|
||||||
},
|
|
||||||
}, options.Update().SetUpsert(true)); err != nil {
|
|
||||||
logger.Println("[generateCoupons] Update failed :", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// effect가 비어있으면 기존의 roundName에 갯수를 추가해 준다
|
|
||||||
// effect가 비어있지 않으면 roundName이 겹쳐서는 안된다.
|
|
||||||
coupondoc, err := mongoClient.FindOne(CollectionCoupon, bson.M{"_id": roundObj})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("[generateCoupons] FindOne failed :", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastKeys := make(map[string]bool)
|
|
||||||
if coupondoc != nil {
|
|
||||||
if r, ok := coupondoc["remains"]; ok {
|
|
||||||
remains := r.(primitive.A)
|
|
||||||
for _, uid := range remains {
|
|
||||||
lastKeys[uid.(string)] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
issuedKeys := make(map[string]string)
|
|
||||||
for len(issuedKeys) < int(count) {
|
|
||||||
_, vs := makeCouponCodes(name, int(count)-len(issuedKeys))
|
|
||||||
for k, v := range vs {
|
|
||||||
if _, ok := lastKeys[k]; !ok {
|
|
||||||
// 기존 키와 중복되지 않는 것만
|
|
||||||
issuedKeys[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var coupons []string
|
|
||||||
var uids []string
|
|
||||||
for uid, code := range issuedKeys {
|
|
||||||
uids = append(uids, uid)
|
|
||||||
coupons = append(coupons, code)
|
|
||||||
}
|
|
||||||
|
|
||||||
if coupondoc != nil {
|
|
||||||
_, _, err = mongoClient.Update(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, bson.M{
|
|
||||||
"$push": bson.M{"remains": bson.M{"$each": uids}},
|
|
||||||
"$inc": bson.M{"total": count},
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
} else {
|
|
||||||
_, _, err = mongoClient.Update(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, bson.M{
|
|
||||||
"$push": bson.M{"remains": bson.M{"$each": uids}},
|
|
||||||
"$set": couponDoc{
|
|
||||||
Name: name,
|
|
||||||
Effect: effect,
|
|
||||||
Desc: desc,
|
|
||||||
Total: count,
|
|
||||||
Expire: expire,
|
|
||||||
},
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("[generateCoupons] Update failed :", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
|
||||||
enc.Encode(coupons)
|
|
||||||
}
|
|
||||||
|
|
||||||
func downloadCoupons(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
name, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
|
||||||
if len(name) == 0 {
|
|
||||||
logger.Println("[downloadCoupons] name is empty")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
round, _ := coupon.MakeCouponRoundHash(name)
|
|
||||||
|
|
||||||
roundObj, err := primitive.ObjectIDFromHex(round + round + round)
|
|
||||||
if err != nil {
|
|
||||||
// 유효하지 않은 형식의 code
|
|
||||||
logger.Println("[downloadCoupons] ObjectIDFromHex failed :", err)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var coupon couponDoc
|
|
||||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, &coupon, options.FindOne().SetProjection(bson.M{"_id": 0, "remains": 1})); err != nil {
|
|
||||||
logger.Println("[downloadCoupons] FindOne failed :", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
roundnum := binary.BigEndian.Uint32(roundObj[:])
|
|
||||||
var coupons []string
|
|
||||||
for _, uid := range coupon.Remains {
|
|
||||||
decUid, err := hex.DecodeString(uid)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("downloadCoupons Fail", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
coupons = append(coupons, makeCouponKey(roundnum, decUid))
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
|
||||||
enc.Encode(coupons)
|
|
||||||
}
|
|
||||||
|
|
||||||
func queryCoupon(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
code, _ := gocommon.ReadStringFormValue(r.Form, "code")
|
|
||||||
if len(code) == 0 {
|
|
||||||
logger.Println("[queryCoupon] code is empty")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
round, _ := coupon.DisolveCouponCode(code)
|
|
||||||
if len(round) == 0 {
|
|
||||||
// 유효하지 않은 형식의 code
|
|
||||||
// 쿠폰 이름일 수 있으므로 round hash를 계산한다.
|
|
||||||
round, _ = coupon.MakeCouponRoundHash(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
roundObj, err := primitive.ObjectIDFromHex(round + round + round)
|
|
||||||
if err != nil {
|
|
||||||
// 유효하지 않은 형식의 code
|
|
||||||
logger.Println("[queryCoupon] ObjectIDFromHex failed :", err)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var coupon couponDoc
|
|
||||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, &coupon, options.FindOne().SetProjection(bson.M{"effect": 1, "name": 1, "reason": 1, "total": 1, "desc": 1, "expire": 1}).SetReturnKey(false)); err != nil {
|
|
||||||
logger.Println("[queryCoupon] FindOneAs failed :", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
|
||||||
enc.Encode(coupon)
|
|
||||||
}
|
|
||||||
|
|
||||||
func listAllCouponNames(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
all, err := mongoClient.FindAll(CollectionCoupon, bson.M{}, options.Find().SetProjection(bson.M{"name": 1}))
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var names []string
|
|
||||||
for _, doc := range all {
|
|
||||||
names = append(names, doc["name"].(string))
|
|
||||||
}
|
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
|
||||||
enc.Encode(names)
|
|
||||||
}
|
|
||||||
|
|
||||||
func useCoupon(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
acc, ok := gocommon.ReadObjectIDFormValue(r.Form, "accid")
|
|
||||||
if !ok || acc.IsZero() {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
code, _ := gocommon.ReadStringFormValue(r.Form, "code")
|
|
||||||
code = strings.TrimSpace(code)
|
|
||||||
if len(code) == 0 {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
round, key := coupon.DisolveCouponCode(code)
|
|
||||||
if len(round) == 0 {
|
|
||||||
// couponId가 쿠폰 이름일 수도 있다. 무한 쿠폰
|
|
||||||
round, _ = coupon.MakeCouponRoundHash(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 쿠폰 사용 유무 검사
|
|
||||||
alreadyused, err := mongoClient.Exists(CollectionCouponUse, bson.M{
|
|
||||||
"_id": acc,
|
|
||||||
"rounds": round,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if alreadyused {
|
|
||||||
// 이미 이 라운드의 쿠폰을 사용한 적이 있다.
|
|
||||||
w.WriteHeader(http.StatusConflict)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var coupon couponDoc
|
|
||||||
roundObj, _ := primitive.ObjectIDFromHex(round + round + round)
|
|
||||||
if len(key) == 0 {
|
|
||||||
// 무한 쿠폰일 수 있으므로 존재하는지 확인
|
|
||||||
if err := mongoClient.FindOneAs(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, &coupon, options.FindOne().SetProjection(bson.M{"_id": 0, "effect": 1, "name": 1, "total": 1, "expire": 1})); err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if coupon.Total > 0 {
|
|
||||||
// 무한 쿠폰 아니네?
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 쿠폰을 하나 꺼냄
|
|
||||||
matched, _, err := mongoClient.Update(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
"remains": key,
|
|
||||||
}, bson.M{
|
|
||||||
"$pull": bson.M{"remains": key},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !matched {
|
|
||||||
// 쿠폰이 없다.
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// round의 효과 읽기
|
|
||||||
if err := mongoClient.FindOneAndUpdateAs(CollectionCoupon, bson.M{
|
|
||||||
"_id": roundObj,
|
|
||||||
}, bson.M{
|
|
||||||
"$push": bson.M{"used": key},
|
|
||||||
}, &coupon, options.FindOneAndUpdate().SetProjection(bson.M{"effect": 1, "expire": 1})); err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if coupon.Expire < time.Now().Unix() {
|
|
||||||
// 쿠폰 만료시간 경과
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(coupon.Effect) == 0 {
|
|
||||||
// 쿠폰이 없네?
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 쿠폰은 사용한 것으로 표시
|
|
||||||
// 이제 이 아래에서 실패하면 이 쿠폰은 못쓴다.
|
|
||||||
updated, _, err := mongoClient.Update(CollectionCouponUse, bson.M{
|
|
||||||
"_id": acc,
|
|
||||||
}, bson.M{
|
|
||||||
"$push": bson.M{"rounds": round},
|
|
||||||
"$set": bson.M{round + ".id": code},
|
|
||||||
"$currentDate": bson.M{round + ".ts": true},
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !updated {
|
|
||||||
logger.Println(err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(coupon.Effect))
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteCoupon(mongoClient gocommon.MongoClient, w http.ResponseWriter, r *http.Request) {
|
|
||||||
code, _ := gocommon.ReadStringFormValue(r.Form, "name")
|
|
||||||
if len(code) == 0 {
|
|
||||||
logger.Println("coupon delete code error")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := mongoClient.Delete(CollectionCoupon, bson.M{
|
|
||||||
"name": code,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("coupon delete error")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMakeLocalUniqueId(t *testing.T) {
|
|
||||||
ts := int64(1690815600)
|
|
||||||
start := primitive.NewDateTimeFromTime(time.Unix(ts, 0))
|
|
||||||
ts = int64(1693493999)
|
|
||||||
end := primitive.NewDateTimeFromTime(time.Unix(ts, 0))
|
|
||||||
|
|
||||||
fmt.Println(start.Time().Format(time.RFC3339))
|
|
||||||
fmt.Println(end.Time().Format(time.RFC3339))
|
|
||||||
|
|
||||||
mongoClient, err := gocommon.NewMongoClient(context.Background(), "mongodb://121.134.91.160:27018/mountain-maingate?replicaSet=rs0&retrywrites=true", "maingate")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bi := blockinfo{
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
Reason: "test",
|
|
||||||
}
|
|
||||||
mongoClient.Update(CollectionBlock, bson.M{
|
|
||||||
"_id": primitive.NewObjectID(),
|
|
||||||
}, bson.M{
|
|
||||||
"$set": &bi,
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
}
|
|
||||||
354
core/maingate.go
354
core/maingate.go
@ -10,17 +10,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"runtime/debug"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"text/template"
|
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
|
||||||
@ -39,21 +36,20 @@ var devflag = flagx.Bool("dev", false, "")
|
|||||||
var noauth = flagx.Bool("noauth", false, "")
|
var noauth = flagx.Bool("noauth", false, "")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
CollectionLink = gocommon.CollectionName("link")
|
CollectionLink = common.CollectionName("link")
|
||||||
CollectionAuth = gocommon.CollectionName("auth")
|
CollectionAuth = common.CollectionName("auth")
|
||||||
CollectionWhitelist = gocommon.CollectionName("whitelist")
|
CollectionWhitelist = common.CollectionName("whitelist")
|
||||||
CollectionService = gocommon.CollectionName("service")
|
CollectionService = common.CollectionName("service")
|
||||||
CollectionAccount = gocommon.CollectionName("account")
|
CollectionAccount = common.CollectionName("account")
|
||||||
CollectionFile = gocommon.CollectionName("file")
|
CollectionFile = common.CollectionName("file")
|
||||||
CollectionBlock = gocommon.CollectionName("block")
|
CollectionBlock = common.CollectionName("block")
|
||||||
CollectionPlatformLoginToken = gocommon.CollectionName("platform_login_token") //-- 각 플랫폼에 로그인 및 권한 받아오는 과정에 사용하는 Key
|
CollectionPlatformLoginToken = common.CollectionName("platform_login_token") //-- 각 플랫폼에 로그인 및 권한 받아오는 과정에 사용하는 Key
|
||||||
CollectionUserToken = gocommon.CollectionName("usertoken")
|
CollectionUserToken = common.CollectionName("usertoken")
|
||||||
CollectionGamepotUserInfo = gocommon.CollectionName("gamepot_userinfo") //-- 클라로부터 수집된 gamepot 정보 - server to server로 유효성이 검증되진 않았지만 수집은 한다.
|
CollectionGamepotUserInfo = common.CollectionName("gamepot_userinfo") //-- 클라로부터 수집된 gamepot 정보 - server to server로 유효성이 검증되진 않았지만 수집은 한다.
|
||||||
CollectionFirebaseUserInfo = gocommon.CollectionName("firebase_userinfo") //-- Firebase UserInfo
|
CollectionFirebaseUserInfo = common.CollectionName("firebase_userinfo") //-- Firebase UserInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AuthPlatformSteamSDK = "steam"
|
|
||||||
AuthPlatformFirebaseAuth = "firebase"
|
AuthPlatformFirebaseAuth = "firebase"
|
||||||
AuthPlatformGoogle = "google"
|
AuthPlatformGoogle = "google"
|
||||||
AuthPlatformMicrosoft = "microsoft"
|
AuthPlatformMicrosoft = "microsoft"
|
||||||
@ -75,10 +71,10 @@ func SessionTTL() time.Duration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type mongoAuthCell struct {
|
type mongoAuthCell struct {
|
||||||
src *gocommon.Authinfo
|
src *common.Authinfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ac *mongoAuthCell) ToAuthinfo() *gocommon.Authinfo {
|
func (ac *mongoAuthCell) ToAuthinfo() *common.Authinfo {
|
||||||
if ac.src == nil {
|
if ac.src == nil {
|
||||||
logger.Error("mongoAuthCell ToAuthinfo failed. ac.src is nil")
|
logger.Error("mongoAuthCell ToAuthinfo failed. ac.src is nil")
|
||||||
}
|
}
|
||||||
@ -90,15 +86,15 @@ func (ac *mongoAuthCell) ToBytes() []byte {
|
|||||||
return bt
|
return bt
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAuthCollection(mongoClient gocommon.MongoClient, sessionTTL time.Duration) *gocommon.AuthCollection {
|
func makeAuthCollection(mongoClient common.MongoClient, sessionTTL time.Duration) *common.AuthCollection {
|
||||||
authcoll := gocommon.MakeAuthCollection(sessionTTL)
|
authcoll := common.MakeAuthCollection(sessionTTL)
|
||||||
authcoll.SessionRemoved = func(sk string) {
|
authcoll.SessionRemoved = func(sk string) {
|
||||||
skid, _ := primitive.ObjectIDFromHex(sk)
|
skid, _ := primitive.ObjectIDFromHex(sk)
|
||||||
mongoClient.Delete(CollectionAuth, bson.M{
|
mongoClient.Delete(CollectionAuth, bson.M{
|
||||||
"sk": skid,
|
"sk": skid,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
authcoll.QuerySession = func(sk string, token string) gocommon.AuthinfoCell {
|
authcoll.QuerySession = func(sk string, token string) common.AuthinfoCell {
|
||||||
skid, _ := primitive.ObjectIDFromHex(sk)
|
skid, _ := primitive.ObjectIDFromHex(sk)
|
||||||
var outcell mongoAuthCell
|
var outcell mongoAuthCell
|
||||||
err := mongoClient.FindOneAs(CollectionAuth, bson.M{
|
err := mongoClient.FindOneAs(CollectionAuth, bson.M{
|
||||||
@ -123,10 +119,7 @@ func makeAuthCollection(mongoClient gocommon.MongoClient, sessionTTL time.Durati
|
|||||||
type maingateConfig struct {
|
type maingateConfig struct {
|
||||||
Mongo string `json:"maingate_mongodb_url"`
|
Mongo string `json:"maingate_mongodb_url"`
|
||||||
SessionTTL int64 `json:"maingate_session_ttl"`
|
SessionTTL int64 `json:"maingate_session_ttl"`
|
||||||
ApiToken string `json:"maingate_api_token"`
|
|
||||||
Autologin_ttl int64 `json:"autologin_ttl"`
|
Autologin_ttl int64 `json:"autologin_ttl"`
|
||||||
AccDelTTL int64 `json:"acc_del_ttl"`
|
|
||||||
MaximumNumLinkAccount int64 `json:"maximum_num_link_account"`
|
|
||||||
RedirectBaseUrl string `json:"redirect_base_url"`
|
RedirectBaseUrl string `json:"redirect_base_url"`
|
||||||
GoogleClientId string `json:"google_client_id"`
|
GoogleClientId string `json:"google_client_id"`
|
||||||
GoogleClientSecret string `json:"google_client_secret"`
|
GoogleClientSecret string `json:"google_client_secret"`
|
||||||
@ -144,20 +137,6 @@ type maingateConfig struct {
|
|||||||
GamepotProjectId string `json:"gamepot_project_id"`
|
GamepotProjectId string `json:"gamepot_project_id"`
|
||||||
GamepotLoginCheckAPIURL string `json:"gamepot_logincheckapi_url"`
|
GamepotLoginCheckAPIURL string `json:"gamepot_logincheckapi_url"`
|
||||||
FirebaseAdminSDKCredentialFile string `json:"firebase_admin_sdk_credentialfile"`
|
FirebaseAdminSDKCredentialFile string `json:"firebase_admin_sdk_credentialfile"`
|
||||||
SteamAppId string `json:"steam_app_id"`
|
|
||||||
SteamPublisherAuthKey string `json:"steam_publisher_authkey"`
|
|
||||||
Firebase_Google_Analytics_JS_SDK_Config
|
|
||||||
}
|
|
||||||
|
|
||||||
type Firebase_Google_Analytics_JS_SDK_Config struct {
|
|
||||||
FGA_apiKey string `json:"firebase_google_analytics_jssdk_apikey"`
|
|
||||||
FGA_authDomain string `json:"firebase_google_analytics_jssdk_authdomain"`
|
|
||||||
FGA_databaseURL string `json:"firebase_google_analytics_jssdk_databaseurl"`
|
|
||||||
FGA_projectId string `json:"firebase_google_analytics_jssdk_projectid"`
|
|
||||||
FGA_storageBucket string `json:"firebase_google_analytics_jssdk_storagebucket"`
|
|
||||||
FGA_messagingSenderId string `json:"firebase_google_analytics_jssdk_messagingsenderid"`
|
|
||||||
FGA_appId string `json:"firebase_google_analytics_jssdk_apiid"`
|
|
||||||
FGA_measurementId string `json:"ffirebase_google_analytics_jssdk_measurementid"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type globalAdmins struct {
|
type globalAdmins struct {
|
||||||
@ -172,21 +151,20 @@ func (ga *globalAdmins) parse() {
|
|||||||
parsed[admin] = true
|
parsed[admin] = true
|
||||||
}
|
}
|
||||||
ga.emails = parsed
|
ga.emails = parsed
|
||||||
ga.modtime = gocommon.ConfigModTime()
|
ga.modtime = common.ConfigModTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maingate :
|
// Maingate :
|
||||||
type Maingate struct {
|
type Maingate struct {
|
||||||
maingateConfig
|
maingateConfig
|
||||||
|
|
||||||
mongoClient gocommon.MongoClient
|
mongoClient common.MongoClient
|
||||||
|
|
||||||
auths *gocommon.AuthCollection
|
auths *common.AuthCollection
|
||||||
//services servicelist
|
//services servicelist
|
||||||
serviceptr unsafe.Pointer
|
serviceptr unsafe.Pointer
|
||||||
admins unsafe.Pointer
|
admins unsafe.Pointer
|
||||||
wl memberContainerPtr[string, *whitelistmember]
|
wl whitelist
|
||||||
bl memberContainerPtr[primitive.ObjectID, *blockinfo]
|
|
||||||
|
|
||||||
tokenEndpoints map[string]string
|
tokenEndpoints map[string]string
|
||||||
authorizationEndpoints map[string]string
|
authorizationEndpoints map[string]string
|
||||||
@ -196,15 +174,31 @@ type Maingate struct {
|
|||||||
firebaseAppContext context.Context
|
firebaseAppContext context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var collectionNameMod = int32(0)
|
||||||
|
|
||||||
// New :
|
// New :
|
||||||
func New(ctx context.Context) (*Maingate, error) {
|
func New(ctx context.Context) (*Maingate, error) {
|
||||||
|
if *devflag && atomic.AddInt32(&collectionNameMod, 1) == 1 {
|
||||||
|
hostname, _ := os.Hostname()
|
||||||
|
CollectionLink = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionLink)))
|
||||||
|
CollectionAuth = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionAuth)))
|
||||||
|
CollectionWhitelist = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionWhitelist)))
|
||||||
|
CollectionService = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionService)))
|
||||||
|
CollectionAccount = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionAccount)))
|
||||||
|
CollectionBlock = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionBlock)))
|
||||||
|
CollectionPlatformLoginToken = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionPlatformLoginToken)))
|
||||||
|
CollectionUserToken = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionUserToken)))
|
||||||
|
CollectionGamepotUserInfo = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionGamepotUserInfo)))
|
||||||
|
CollectionFirebaseUserInfo = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionFirebaseUserInfo)))
|
||||||
|
}
|
||||||
|
|
||||||
var config maingateConfig
|
var config maingateConfig
|
||||||
if err := gocommon.LoadConfig(&config); err != nil {
|
if err := common.LoadConfig(&config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var admins globalAdmins
|
var admins globalAdmins
|
||||||
if err := gocommon.LoadConfig(&admins); err == nil {
|
if err := common.LoadConfig(&admins); err == nil {
|
||||||
admins.parse()
|
admins.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,6 +217,7 @@ func New(ctx context.Context) (*Maingate, error) {
|
|||||||
|
|
||||||
err := mg.prepare(ctx)
|
err := mg.prepare(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("mg.prepare() failed :", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,107 +297,100 @@ func (mg *Maingate) discoverOpenIdConfiguration(name string, url string) error {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeErrorWithStack(err error) error {
|
|
||||||
return fmt.Errorf("%s\n%s", err.Error(), string(debug.Stack()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mg *Maingate) prepare(context context.Context) (err error) {
|
func (mg *Maingate) prepare(context context.Context) (err error) {
|
||||||
if err := mg.discoverOpenIdConfiguration(AuthPlatformMicrosoft, "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"); err != nil {
|
if err := mg.discoverOpenIdConfiguration(AuthPlatformMicrosoft, "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
if err := mg.discoverOpenIdConfiguration("google", "https://accounts.google.com/.well-known/openid-configuration"); err != nil {
|
if err := mg.discoverOpenIdConfiguration("google", "https://accounts.google.com/.well-known/openid-configuration"); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// redis에서 env를 가져온 후에
|
// redis에서 env를 가져온 후에
|
||||||
mg.mongoClient, err = gocommon.NewMongoClient(context, mg.Mongo, "maingate")
|
mg.mongoClient, err = common.NewMongoClient(context, mg.Mongo, "maingate")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeErrorWithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionCouponUse, map[string]bson.D{
|
|
||||||
"idrounds": {{Key: "_id", Value: 1}, {Key: "rounds", Value: 1}},
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionAuth, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionAuth, map[string]bson.D{
|
||||||
"skonly": {{Key: "sk", Value: 1}},
|
"skonly": {{Key: "sk", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
||||||
"platformuid": {{Key: "platform", Value: 1}, {Key: "uid", Value: 1}},
|
"platformuid": {{Key: "platform", Value: 1}, {Key: "uid", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionLink, map[string]bson.D{
|
||||||
"emailplatform": {{Key: "email", Value: 1}, {Key: "platform", Value: 1}},
|
"emailplatform": {{Key: "email", Value: 1}, {Key: "platform", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeIndices(CollectionAccount, map[string]bson.D{
|
if err = mg.mongoClient.MakeIndices(CollectionWhitelist, map[string]bson.D{
|
||||||
"accid": {{Key: "accid", Value: 1}},
|
"service": {{Key: "service", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mg.mongoClient.MakeIndices(CollectionFile, map[string]bson.D{
|
||||||
|
"service": {{Key: "service", Value: 1}},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionFile, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionFile, map[string]bson.D{
|
||||||
"keyonly": {{Key: "key", Value: 1}},
|
"sk": {{Key: "service", Value: 1}, {Key: "key", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionAccount, int32(mg.AccDelTTL)); err != nil {
|
|
||||||
return makeErrorWithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionLink, int32(mg.AccDelTTL)); err != nil {
|
|
||||||
return makeErrorWithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete대신 _ts로 expire시킴. pipeline에 삭제 알려주기 위함
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil {
|
if err = mg.mongoClient.MakeExpireIndex(CollectionWhitelist, 10); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionAuth, int32(mg.SessionTTL+300)); err != nil {
|
if err = mg.mongoClient.MakeExpireIndex(CollectionAuth, int32(mg.SessionTTL+300)); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionBlock, map[string]bson.D{
|
||||||
|
"codeaccid": {{Key: "code", Value: 1}, {Key: "accid", Value: 1}},
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
|
if err = mg.mongoClient.MakeExpireIndex(CollectionBlock, int32(3)); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionPlatformLoginToken, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionPlatformLoginToken, map[string]bson.D{
|
||||||
"platformauthtoken": {{Key: "platform", Value: 1}, {Key: "key", Value: 1}},
|
"platformauthtoken": {{Key: "platform", Value: 1}, {Key: "key", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeExpireIndex(CollectionPlatformLoginToken, int32(mg.SessionTTL+300)); err != nil {
|
if err = mg.mongoClient.MakeExpireIndex(CollectionPlatformLoginToken, int32(mg.SessionTTL+300)); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionUserToken, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionUserToken, map[string]bson.D{
|
||||||
"platformusertoken": {{Key: "platform", Value: 1}, {Key: "userid", Value: 1}},
|
"platformusertoken": {{Key: "platform", Value: 1}, {Key: "userid", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionGamepotUserInfo, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionGamepotUserInfo, map[string]bson.D{
|
||||||
"gamepotuserid": {{Key: "gamepotuserid", Value: 1}},
|
"gamepotuserid": {{Key: "gamepotuserid", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = mg.mongoClient.MakeUniqueIndices(CollectionFirebaseUserInfo, map[string]bson.D{
|
if err = mg.mongoClient.MakeUniqueIndices(CollectionFirebaseUserInfo, map[string]bson.D{
|
||||||
"firebaseuserid": {{Key: "firebaseuserid", Value: 1}},
|
"firebaseuserid": {{Key: "firebaseuserid", Value: 1}},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
mg.auths = makeAuthCollection(mg.mongoClient, time.Duration(mg.SessionTTL*int64(time.Second)))
|
mg.auths = makeAuthCollection(mg.mongoClient, time.Duration(mg.SessionTTL*int64(time.Second)))
|
||||||
@ -414,7 +402,7 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
|
|||||||
if err = mg.mongoClient.FindAllAs(CollectionFile, nil, &preall, options.Find().SetProjection(bson.M{
|
if err = mg.mongoClient.FindAllAs(CollectionFile, nil, &preall, options.Find().SetProjection(bson.M{
|
||||||
"link": 1,
|
"link": 1,
|
||||||
})); err != nil {
|
})); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pre := range preall {
|
for _, pre := range preall {
|
||||||
@ -424,41 +412,62 @@ func (mg *Maingate) prepare(context context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
logger.Println("saving files :", pre.Link)
|
logger.Println("saving files :", pre.Link)
|
||||||
|
|
||||||
var fulldoc FileDocumentDesc
|
var fulldoc fileDocumentDesc
|
||||||
err = mg.mongoClient.FindOneAs(CollectionFile, bson.M{
|
err = mg.mongoClient.FindOneAs(CollectionFile, bson.M{
|
||||||
"_id": pre.Id,
|
"_id": pre.Id,
|
||||||
}, &fulldoc)
|
}, &fulldoc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
err = fulldoc.Save()
|
err = fulldoc.save()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var whites []*whitelistmember
|
var whites []whitelistmember
|
||||||
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
|
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||||
return makeErrorWithStack(err)
|
return err
|
||||||
}
|
}
|
||||||
mg.wl.init(whites)
|
mg.wl.init(whites)
|
||||||
|
|
||||||
var blocks []*blockinfo
|
|
||||||
if err := mg.mongoClient.AllAs(CollectionBlock, &blocks); err != nil {
|
|
||||||
return makeErrorWithStack(err)
|
|
||||||
}
|
|
||||||
mg.bl.init(blocks)
|
|
||||||
|
|
||||||
go watchAuthCollection(context, mg.auths, mg.mongoClient)
|
go watchAuthCollection(context, mg.auths, mg.mongoClient)
|
||||||
go mg.wl.watchCollection(context, CollectionWhitelist, mg.mongoClient)
|
go mg.watchWhitelistCollection(context)
|
||||||
go mg.bl.watchCollection(context, CollectionBlock, mg.mongoClient)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func whitelistKey(email string) string {
|
||||||
|
if strings.HasPrefix(email, "*@") {
|
||||||
|
// 도메인 전체 허용
|
||||||
|
return email[2:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return email
|
||||||
|
}
|
||||||
|
|
||||||
func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
|
func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMux, prefix string) error {
|
||||||
var allServices []*serviceDescription
|
var allServices []*serviceDescription
|
||||||
if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
|
||||||
|
if *noauth {
|
||||||
|
host, _ := os.Hostname()
|
||||||
|
empty := serviceDescription{
|
||||||
|
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||||
|
ServiceCode: "000000000000",
|
||||||
|
},
|
||||||
|
Divisions: map[string]*Division{
|
||||||
|
host: {
|
||||||
|
DivisionForUser: DivisionForUser{
|
||||||
|
Priority: 0,
|
||||||
|
State: DivisionState_FullOpen,
|
||||||
|
},
|
||||||
|
Url: fmt.Sprintf("http://%s/warehouse", host),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
empty.prepare(mg)
|
||||||
|
allServices = append(allServices, &empty)
|
||||||
|
} else if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,54 +482,14 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
Id: primitive.NewObjectID(),
|
Id: primitive.NewObjectID(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if *devflag {
|
|
||||||
host, _ := os.Hostname()
|
|
||||||
addrs, err := net.InterfaceAddrs()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ipaddr := "127.0.0.1"
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
||||||
if ipnet.IP.To4() != nil && ipnet.IP.IsPrivate() {
|
|
||||||
ipaddr = ipnet.IP.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
empty.Divisions = map[string]*Division{
|
|
||||||
host: {
|
|
||||||
DivisionForUser: DivisionForUser{
|
|
||||||
Priority: 0,
|
|
||||||
State: DivisionState_FullOpen,
|
|
||||||
LockCreateChar: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Url: fmt.Sprintf("http://%s/warehouse", ipaddr),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
empty.prepare(mg)
|
empty.prepare(mg)
|
||||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&empty))
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&empty))
|
||||||
|
|
||||||
filter := bson.M{"_id": empty.Id}
|
|
||||||
_, _, err := mg.mongoClient.Update(CollectionService, filter, bson.M{
|
|
||||||
"$set": &empty,
|
|
||||||
}, options.Update().SetUpsert(true))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Println("Service is registered :", mg.service().ServiceCode)
|
logger.Println("Service is registered :", mg.service().ServiceCode)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), func(w http.ResponseWriter, r *http.Request) {
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), mg.service())
|
||||||
mg.service().serveHTTP(w, r)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
|
||||||
})
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
|
|
||||||
|
|
||||||
configraw, _ := json.Marshal(mg.maingateConfig)
|
configraw, _ := json.Marshal(mg.maingateConfig)
|
||||||
var convertedConfig map[string]any
|
var convertedConfig map[string]any
|
||||||
@ -528,7 +497,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) {
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "config"), func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
s := recover()
|
s := recover()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
@ -536,7 +505,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if !*devflag {
|
if !*noauth {
|
||||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||||
if len(apitoken) == 0 {
|
if len(apitoken) == 0 {
|
||||||
logger.Println("MG-X-API-TOKEN is missing")
|
logger.Println("MG-X-API-TOKEN is missing")
|
||||||
@ -548,8 +517,6 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
if mg.service().isValidToken(apitokenObj) {
|
if mg.service().isValidToken(apitokenObj) {
|
||||||
convertedConfig["divisions"] = mg.service().Divisions
|
convertedConfig["divisions"] = mg.service().Divisions
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
convertedConfig["divisions"] = mg.service().Divisions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
enc := json.NewEncoder(w)
|
||||||
@ -561,44 +528,30 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfsx := http.FileServer(http.Dir("console"))
|
fsx := http.FileServer(http.Dir("./console"))
|
||||||
pattern := gocommon.MakeHttpHandlerPattern(prefix, "console", "/")
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, "console/"), http.StripPrefix("/console/", fsx))
|
||||||
serveMux.Handle(pattern, http.StripPrefix(pattern, cfsx))
|
|
||||||
logger.Println("maingate console registered :", pattern)
|
|
||||||
|
|
||||||
staticfs := http.FileServer(http.Dir("static"))
|
ssx := http.FileServer(http.Dir("./static"))
|
||||||
pattern = gocommon.MakeHttpHandlerPattern(prefix, "static", "/")
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, "static/"), http.StripPrefix("/static/", ssx))
|
||||||
serveMux.Handle(pattern, http.StripPrefix(pattern, staticfs))
|
|
||||||
logger.Println("maingate static registered :", pattern)
|
|
||||||
|
|
||||||
fbafs := http.FileServer(http.Dir("fba"))
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGoogle), mg.platform_google_get_login_url)
|
||||||
pattern = gocommon.MakeHttpHandlerPattern(prefix, "fba", "/")
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformGoogle), mg.platform_google_authorize)
|
||||||
serveMux.Handle(pattern, http.StripPrefix(pattern, fbafs))
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result)
|
||||||
logger.Println("google_analytics static registered :", pattern)
|
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "fba", "fb-ga.min.js"), mg.google_analytics_js)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformMicrosoft), mg.platform_microsoft_get_login_url)
|
||||||
logger.Println("google_analytics.js static registered :", pattern)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformMicrosoft), mg.platform_microsoft_authorize)
|
||||||
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformMicrosoft), mg.platform_microsoft_authorize_result)
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformGoogle), mg.platform_google_get_login_url)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformTwitter), mg.platform_twitter_get_login_url)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformGoogle), mg.platform_google_authorize)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformTwitter), mg.platform_twitter_authorize)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformGoogle), mg.platform_google_authorize_result)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformTwitter), mg.platform_twitter_authorize_result)
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformMicrosoft), mg.platform_microsoft_get_login_url)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformApple), mg.platform_apple_get_login_url)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformMicrosoft), mg.platform_microsoft_authorize)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformApple), mg.platform_apple_authorize)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformMicrosoft), mg.platform_microsoft_authorize_result)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformApple), mg.platform_apple_authorize_result)
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformTwitter), mg.platform_twitter_get_login_url)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_get_login_url)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformTwitter), mg.platform_twitter_authorize)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_authorize_sdk)
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformTwitter), mg.platform_twitter_authorize_result)
|
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformApple), mg.platform_apple_get_login_url)
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize", AuthPlatformApple), mg.platform_apple_authorize)
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_result", AuthPlatformApple), mg.platform_apple_authorize_result)
|
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "request_login_url", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_get_login_url)
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformFirebaseAuth), mg.platform_firebaseauth_authorize_sdk)
|
|
||||||
|
|
||||||
serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "authorize_sdk", AuthPlatformSteamSDK), mg.platform_steamsdk_authorize)
|
|
||||||
|
|
||||||
go mg.watchServiceCollection(ctx, serveMux, prefix)
|
go mg.watchServiceCollection(ctx, serveMux, prefix)
|
||||||
go mg.watchFileCollection(ctx, serveMux, prefix)
|
go mg.watchFileCollection(ctx, serveMux, prefix)
|
||||||
@ -637,7 +590,7 @@ func (mg *Maingate) query(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !*devflag {
|
if !*noauth {
|
||||||
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
apitoken := r.Header.Get("MG-X-API-TOKEN")
|
||||||
if len(apitoken) == 0 {
|
if len(apitoken) == 0 {
|
||||||
logger.Println("MG-X-API-TOKEN is missing")
|
logger.Println("MG-X-API-TOKEN is missing")
|
||||||
@ -769,8 +722,6 @@ func (mg *Maingate) updateUserinfo(info usertokeninfo) (bool, string, string) {
|
|||||||
success, userid, email = mg.platform_microsoft_getuserinfo(info)
|
success, userid, email = mg.platform_microsoft_getuserinfo(info)
|
||||||
case AuthPlatformGoogle:
|
case AuthPlatformGoogle:
|
||||||
success, userid, email = mg.platform_google_getuserinfo(info)
|
success, userid, email = mg.platform_google_getuserinfo(info)
|
||||||
case AuthPlatformSteamSDK:
|
|
||||||
success, userid, email = mg.platform_steamsdk_getuserinfo(info)
|
|
||||||
case AuthPlatformFirebaseAuth:
|
case AuthPlatformFirebaseAuth:
|
||||||
success, userid, email = mg.platform_firebase_getuserinfo(info)
|
success, userid, email = mg.platform_firebase_getuserinfo(info)
|
||||||
}
|
}
|
||||||
@ -811,18 +762,13 @@ func (mg *Maingate) getProviderInfo(platform string, uid string) (string, string
|
|||||||
if provider == "" || providerid == "" {
|
if provider == "" || providerid == "" {
|
||||||
return "", "", errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid)
|
return "", "", errors.New("getProviderInfo - firebase info not found: " + provider + " / " + providerid)
|
||||||
}
|
}
|
||||||
case "":
|
|
||||||
//guest auth
|
|
||||||
providerid = uid
|
|
||||||
if providerid == "" {
|
|
||||||
return "", "", errors.New("getProviderInfo - guest provider id not found: " + provider + " / " + providerid)
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
provider = platform
|
provider = platform
|
||||||
providerid = uid
|
providerid = uid
|
||||||
if provider == "" || providerid == "" {
|
}
|
||||||
return "", "", errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid)
|
|
||||||
}
|
if provider == "" || providerid == "" {
|
||||||
|
return "", "", errors.New("getProviderInfo - provider info not found: " + provider + " / " + providerid)
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider, providerid, nil
|
return provider, providerid, nil
|
||||||
@ -985,31 +931,3 @@ func JWTparseCode(keyurl string, code string) (string, string, string) {
|
|||||||
//--- nonce 체크 필요하다.
|
//--- nonce 체크 필요하다.
|
||||||
return claims["sub"].(string), email, nonce
|
return claims["sub"].(string), email, nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mg *Maingate) google_analytics_html(w http.ResponseWriter, r *http.Request) {
|
|
||||||
parsedTemplate, _ := template.ParseFiles("template/track-event.html")
|
|
||||||
err := parsedTemplate.Execute(w, nil)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error executing template :", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mg *Maingate) google_analytics_js(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fgaconfig := Firebase_Google_Analytics_JS_SDK_Config{
|
|
||||||
FGA_apiKey: mg.FGA_apiKey,
|
|
||||||
FGA_authDomain: mg.FGA_authDomain,
|
|
||||||
FGA_databaseURL: mg.FGA_databaseURL,
|
|
||||||
FGA_projectId: mg.FGA_projectId,
|
|
||||||
FGA_storageBucket: mg.FGA_storageBucket,
|
|
||||||
FGA_messagingSenderId: mg.FGA_messagingSenderId,
|
|
||||||
FGA_appId: mg.FGA_appId,
|
|
||||||
FGA_measurementId: mg.FGA_measurementId,
|
|
||||||
}
|
|
||||||
parsedTemplate, _ := template.ParseFiles("template/fb-ga.min.js")
|
|
||||||
err := parsedTemplate.Execute(w, fgaconfig)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Error executing template :", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,177 +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]) contains(key K, out *T) bool {
|
|
||||||
ptr := atomic.LoadPointer(&p.ptr)
|
|
||||||
src := (*map[K]T)(ptr)
|
|
||||||
|
|
||||||
found, exists := (*src)[key]
|
|
||||||
if exists {
|
|
||||||
if found.Expired() {
|
|
||||||
p.remove(key)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if out != nil {
|
|
||||||
*out = found
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SteamSDKAuthInfo struct {
|
|
||||||
UserSteamId string `json:"steamid"`
|
|
||||||
UserAuthToken string `json:"authtoken"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mg *Maingate) platform_steamsdk_authorize(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
brinfo, err := mg.GetUserBrowserInfo(r)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
logger.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var authinfo SteamSDKAuthInfo
|
|
||||||
|
|
||||||
err = json.NewDecoder(r.Body).Decode(&authinfo)
|
|
||||||
if err != nil {
|
|
||||||
logger.Println("authinfo decoding fail:", err)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !*noauth {
|
|
||||||
err = authenticateSteamUser(mg.SteamPublisherAuthKey, mg.SteamAppId, authinfo.UserSteamId, authinfo.UserAuthToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
acceestoken_expire_time := time.Date(2999, 1, int(time.January), 0, 0, 0, 0, time.UTC).Unix()
|
|
||||||
|
|
||||||
var info usertokeninfo
|
|
||||||
info.platform = AuthPlatformSteamSDK
|
|
||||||
info.userid = authinfo.UserSteamId
|
|
||||||
info.token = authinfo.UserAuthToken
|
|
||||||
info.brinfo = brinfo
|
|
||||||
//info.accesstoken = respReferesh.AccessToken
|
|
||||||
info.accesstoken_expire_time = acceestoken_expire_time
|
|
||||||
mg.setUserToken(info)
|
|
||||||
|
|
||||||
params := url.Values{}
|
|
||||||
params.Add("id", authinfo.UserSteamId)
|
|
||||||
params.Add("authtype", AuthPlatformSteamSDK)
|
|
||||||
w.Write([]byte("?" + params.Encode()))
|
|
||||||
//http.Redirect(w, r, "actionsquare://login?"+Result, http.StatusSeeOther)
|
|
||||||
} else {
|
|
||||||
logger.Println(err)
|
|
||||||
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func authenticateSteamUser(pubkey, appid, playerid, ticket string) error {
|
|
||||||
// Returns: The user's 64-bit SteamID if the user's ticket is valid
|
|
||||||
url := fmt.Sprintf("https://partner.steam-api.com/ISteamUserAuth/AuthenticateUserTicket/v1/?key=%s&appid=%s&ticket=%s", pubkey, appid, ticket)
|
|
||||||
resp, e := http.Get(url)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
io.Copy(io.Discard, resp.Body)
|
|
||||||
resp.Body.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
body, e := ioutil.ReadAll(resp.Body)
|
|
||||||
if e != nil {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// fmt.Println(url)
|
|
||||||
// fmt.Println(string(body))
|
|
||||||
|
|
||||||
var doc map[string]interface{}
|
|
||||||
if err := json.Unmarshal(body, &doc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if v, ok := doc["response"]; ok {
|
|
||||||
response := v.(map[string]interface{})
|
|
||||||
if v, ok = response["params"]; ok {
|
|
||||||
paramsnode := v.(map[string]interface{})
|
|
||||||
if v, ok = paramsnode["result"]; ok {
|
|
||||||
if v.(string) == "OK" {
|
|
||||||
if v, ok = paramsnode["steamid"]; ok {
|
|
||||||
// playerid에는 빌드 구성 suffix가 붙어있는 상태이므로 == 비교가 아니라 HasPrefix로 비교
|
|
||||||
if strings.HasPrefix(playerid, v.(string)) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if v.(string) == "Invalid ticket" {
|
|
||||||
return errors.New("steam: invalid ticket")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if errdocraw, ok := response["error"]; ok {
|
|
||||||
errdoc := errdocraw.(map[string]interface{})
|
|
||||||
desc := errdoc["errordesc"].(string)
|
|
||||||
return errors.New(desc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errors.New("steam: response is not expected")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mg *Maingate) platform_steamsdk_getuserinfo(info usertokeninfo) (bool, string, string) {
|
|
||||||
|
|
||||||
// Steam은 이메일 정보를 받을수 없기 때문에 dummy임시 주소 할당하여 리턴한다.
|
|
||||||
dummyEmail := fmt.Sprintf("__dummy_%s@steamtemp__", info.userid)
|
|
||||||
return true, info.userid, dummyEmail
|
|
||||||
|
|
||||||
}
|
|
||||||
845
core/service.go
845
core/service.go
File diff suppressed because it is too large
Load Diff
144
core/watch.go
144
core/watch.go
@ -1,8 +1,10 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -10,7 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
@ -24,7 +26,7 @@ type authPipelineDocument struct {
|
|||||||
DocumentKey struct {
|
DocumentKey struct {
|
||||||
Id primitive.ObjectID `bson:"_id"`
|
Id primitive.ObjectID `bson:"_id"`
|
||||||
} `bson:"documentKey"`
|
} `bson:"documentKey"`
|
||||||
Authinfo *gocommon.Authinfo `bson:"fullDocument"`
|
Authinfo *common.Authinfo `bson:"fullDocument"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type servicePipelineDocument struct {
|
type servicePipelineDocument struct {
|
||||||
@ -40,7 +42,103 @@ type filePipelineDocument struct {
|
|||||||
DocumentKey struct {
|
DocumentKey struct {
|
||||||
Id primitive.ObjectID `bson:"_id"`
|
Id primitive.ObjectID `bson:"_id"`
|
||||||
} `bson:"documentKey"`
|
} `bson:"documentKey"`
|
||||||
File *FileDocumentDesc `bson:"fullDocument"`
|
File *fileDocumentDesc `bson:"fullDocument"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type whilelistPipelineDocument struct {
|
||||||
|
OperationType string `bson:"operationType"`
|
||||||
|
DocumentKey struct {
|
||||||
|
Id primitive.ObjectID `bson:"_id"`
|
||||||
|
} `bson:"documentKey"`
|
||||||
|
Member *whitelistmember `bson:"fullDocument"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
||||||
|
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: "operationType", Value: 1},
|
||||||
|
{Key: "fullDocument", Value: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var stream *mongo.ChangeStream
|
||||||
|
var err error
|
||||||
|
var ctx context.Context
|
||||||
|
|
||||||
|
for {
|
||||||
|
if stream == nil {
|
||||||
|
stream, err = mg.mongoClient.Watch(CollectionWhitelist, mongo.Pipeline{matchStage, projectStage})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("watchWhitelistCollection watch failed :", err)
|
||||||
|
time.Sleep(time.Minute)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ctx = context.TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
changed := stream.TryNext(ctx)
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
logger.Error("watchWhitelistCollection stream.TryNext failed. process should be restarted! :", ctx.Err().Error())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
var data whilelistPipelineDocument
|
||||||
|
if err := stream.Decode(&data); err == nil {
|
||||||
|
ot := data.OperationType
|
||||||
|
switch ot {
|
||||||
|
case "insert":
|
||||||
|
// 새 화이트리스트 멤버
|
||||||
|
mg.service().wl.add(data.Member)
|
||||||
|
case "update":
|
||||||
|
if data.Member.Expired != 0 {
|
||||||
|
logger.Println("whitelist member is removed :", *data.Member)
|
||||||
|
mg.service().wl.remove(data.Member.Email)
|
||||||
|
} else {
|
||||||
|
logger.Println("whitelist member is updated :", *data.Member)
|
||||||
|
mg.service().wl.add(data.Member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.Error("watchWhitelistCollection stream.Decode failed :", err)
|
||||||
|
}
|
||||||
|
} else if stream.Err() != nil || stream.ID() == 0 {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
logger.Println("watchWhitelistCollection is done")
|
||||||
|
stream.Close(ctx)
|
||||||
|
return
|
||||||
|
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
logger.Error("watchWhitelistCollection stream error :", stream.Err())
|
||||||
|
stream.Close(ctx)
|
||||||
|
stream = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
time.Sleep(time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mg *Maingate) watchFileCollection(parentctx context.Context, serveMux *http.ServeMux, prefix string) {
|
func (mg *Maingate) watchFileCollection(parentctx context.Context, serveMux *http.ServeMux, prefix string) {
|
||||||
@ -115,7 +213,7 @@ func (mg *Maingate) watchFileCollection(parentctx context.Context, serveMux *htt
|
|||||||
if err := stream.Decode(&data); err == nil {
|
if err := stream.Decode(&data); err == nil {
|
||||||
switch data.OperationType {
|
switch data.OperationType {
|
||||||
case "insert":
|
case "insert":
|
||||||
data.File.Save()
|
data.File.save()
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
subfolder := hex.EncodeToString(data.DocumentKey.Id[:4])
|
subfolder := hex.EncodeToString(data.DocumentKey.Id[:4])
|
||||||
@ -189,9 +287,11 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
|||||||
logger.Error("service cannot be prepared :", data.Service, err)
|
logger.Error("service cannot be prepared :", data.Service, err)
|
||||||
} else {
|
} else {
|
||||||
// 내가 임시로 가지고 있던 서비스일 수 있다.
|
// 내가 임시로 가지고 있던 서비스일 수 있다.
|
||||||
if mg.service().Id == data.Service.Id {
|
already := mg.service().Id == data.Service.Id
|
||||||
logger.Println("service is on the board! :", data.Service)
|
logger.Println("service is on the board! :", data.Service)
|
||||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
||||||
|
if !already {
|
||||||
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), mg.service())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +300,33 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
|||||||
|
|
||||||
case "update":
|
case "update":
|
||||||
data.Service.prepare(mg)
|
data.Service.prepare(mg)
|
||||||
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
old := mg.service()
|
||||||
|
|
||||||
|
atomic.SwapPointer(&old.divisionsForUsersSerialized, data.Service.divisionsForUsersSerialized)
|
||||||
|
atomic.SwapPointer(&old.divisionsSerialized, data.Service.divisionsSerialized)
|
||||||
|
atomic.SwapPointer(&old.admins, data.Service.admins)
|
||||||
|
atomic.SwapPointer(&old.serviceSerialized, data.Service.serviceSerialized)
|
||||||
|
atomic.SwapPointer(&old.serviceSummarySerialized, data.Service.serviceSummarySerialized)
|
||||||
|
atomic.SwapPointer(&old.wl.emailptr, data.Service.wl.emailptr)
|
||||||
|
|
||||||
|
old.Divisions = data.Service.Divisions
|
||||||
|
for _, div := range old.Divisions {
|
||||||
|
var req *http.Request
|
||||||
|
if div.State == DivisionState_FullOpen {
|
||||||
|
req, _ = http.NewRequest("POST", div.Url+"/maingate", nil)
|
||||||
|
} else if div.Maintenance != nil {
|
||||||
|
bt, _ := json.Marshal(div.Maintenance)
|
||||||
|
req, _ = http.NewRequest("POST", div.Url+"/maingate", bytes.NewBuffer(bt))
|
||||||
|
}
|
||||||
|
|
||||||
|
if req != nil {
|
||||||
|
// MG-X-API-TOKEN
|
||||||
|
req.Header.Add("MG-X-API-TOKEN", old.ServerApiTokens[0].Hex())
|
||||||
|
if resp, err := http.DefaultClient.Do(req); err == nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.Error("watchServiceCollection stream.Decode failed :", err)
|
logger.Error("watchServiceCollection stream.Decode failed :", err)
|
||||||
@ -223,7 +349,7 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchAuthCollection(parentctx context.Context, ac *gocommon.AuthCollection, mongoClient gocommon.MongoClient) {
|
func watchAuthCollection(parentctx context.Context, ac *common.AuthCollection, mongoClient common.MongoClient) {
|
||||||
defer func() {
|
defer func() {
|
||||||
s := recover()
|
s := recover()
|
||||||
if s != nil {
|
if s != nil {
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<body>
|
|
||||||
<script type="text/javascript" src="./fb-ga.min.js">
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
<!-- <body> -->
|
|
||||||
<!-- <body onload="window.FBA.TrackLogEvent('DESKTOP-TEST');"> -->
|
|
||||||
<!-- <script type="cjs" src="./fb-ga.rollup.js"> -->
|
|
||||||
2
go.mod
2
go.mod
@ -7,7 +7,7 @@ require (
|
|||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
go.mongodb.org/mongo-driver v1.11.7
|
go.mongodb.org/mongo-driver v1.11.7
|
||||||
google.golang.org/api v0.128.0
|
google.golang.org/api v0.128.0
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240205060841-c31f838ba8a9
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621052811-06ef97f11d22
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
6
go.sum
6
go.sum
@ -268,7 +268,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb h1:Rdf6uhBIWunRLZ2LIT1hSovYXxZoOzx9mdSK5bjWpos=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621052811-06ef97f11d22 h1:DImSGNxZrc+Q4WlS1OKMsLAScEfDYLX4XMJdjAaVnXc=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230912075917-f9a146321cdb/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230621052811-06ef97f11d22/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240205060841-c31f838ba8a9 h1:5cQ60XjlI7k0qld0rIpd6gy7+a9csv3ijz1EVKTzsy8=
|
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20240205060841-c31f838ba8a9/go.mod h1:rn6NA28Mej+qgLNx/Bu2wsdGyIycmacqlNP6gUXX2a0=
|
|
||||||
|
|||||||
4
main.go
4
main.go
@ -6,7 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/flagx"
|
"repositories.action2quare.com/ayo/gocommon/flagx"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
"repositories.action2quare.com/ayo/maingate/core"
|
"repositories.action2quare.com/ayo/maingate/core"
|
||||||
@ -36,7 +36,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := gocommon.NewHTTPServer(serveMux)
|
server := common.NewHTTPServer(serveMux)
|
||||||
logger.Println("maingate is started")
|
logger.Println("maingate is started")
|
||||||
if err := server.Start(); err != nil {
|
if err := server.Start(); err != nil {
|
||||||
logger.Error("maingate is stopped with error :", err)
|
logger.Error("maingate is stopped with error :", err)
|
||||||
|
|||||||
@ -4,11 +4,27 @@ $CurBranch = git branch --show-current
|
|||||||
|
|
||||||
Remove-Item maingate.zip -Force -Recurse -ErrorAction SilentlyContinue
|
Remove-Item maingate.zip -Force -Recurse -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
cd maingate-console
|
||||||
|
|
||||||
|
|
||||||
|
git switch $CurBranch
|
||||||
|
git pull
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
Remove-Item console -Force -Recurse -ErrorAction SilentlyContinue
|
||||||
|
Copy-Item build console -Recurse
|
||||||
|
|
||||||
|
Compress-Archive -Path console -DestinationPath ..\maingate\maingate.zip -Force
|
||||||
|
Remove-Item console -Force -Recurse
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
cd maingate
|
||||||
|
|
||||||
$Env:GOOS="linux"
|
$Env:GOOS="linux"
|
||||||
$Env:GOARCH="amd64"
|
$Env:GOARCH="amd64"
|
||||||
go build -ldflags="-s -w" .
|
go build -ldflags="-s -w" .
|
||||||
|
|
||||||
Compress-Archive -Path maingate -Update -DestinationPath maingate.zip
|
Compress-Archive -Path maingate -Update -DestinationPath maingate.zip
|
||||||
Compress-Archive -Path *-firebase-*.json -Update -DestinationPath maingate.zip
|
Compress-Archive -Path *-firebase-*.json -Update -DestinationPath maingate.zip
|
||||||
Compress-Archive -Path fba -Update -DestinationPath maingate.zip
|
|
||||||
Compress-Archive -Path template -Update -DestinationPath maingate.zip
|
|
||||||
|
|||||||
1
template/fb-ga.min.js
vendored
1
template/fb-ga.min.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user