flag를 내재화함
This commit is contained in:
205
core/api.go
205
core/api.go
@ -7,13 +7,11 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -22,6 +20,7 @@ import (
|
|||||||
|
|
||||||
common "repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/maingate/flag"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
@ -76,79 +75,8 @@ func (fd *fileDocumentDesc) save() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (caller apiCaller) isGlobalAdmin() bool {
|
func (caller apiCaller) isAdmin() bool {
|
||||||
if *noauth {
|
if *flag.Noauth {
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
email, ok := caller.userinfo["email"]
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := caller.globalAdmins[email.(string)]; ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caller apiCaller) writeAccessableServices(w http.ResponseWriter) {
|
|
||||||
services, editable := caller.getAccessableServices()
|
|
||||||
for _, r := range editable {
|
|
||||||
w.Header().Add("MG-X-SERVICE-EDITABLE", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte("{"))
|
|
||||||
start := true
|
|
||||||
for _, v := range services {
|
|
||||||
if !start {
|
|
||||||
w.Write([]byte(","))
|
|
||||||
}
|
|
||||||
w.Write([]byte(fmt.Sprintf(`"%s":`, v.ServiceName)))
|
|
||||||
serptr := atomic.LoadPointer(&v.serviceSummarySerialized)
|
|
||||||
w.Write(*(*[]byte)(serptr))
|
|
||||||
start = false
|
|
||||||
}
|
|
||||||
w.Write([]byte("}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caller apiCaller) getAccessableServices() ([]*serviceDescription, []string) {
|
|
||||||
allservices := caller.mg.services.all()
|
|
||||||
|
|
||||||
admin := caller.isGlobalAdmin()
|
|
||||||
var email string
|
|
||||||
if !*noauth {
|
|
||||||
v, ok := caller.userinfo["email"]
|
|
||||||
if !ok {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
email = v.(string)
|
|
||||||
_, admin = caller.globalAdmins[email]
|
|
||||||
}
|
|
||||||
|
|
||||||
var output []*serviceDescription
|
|
||||||
var editable []string
|
|
||||||
for _, desc := range allservices {
|
|
||||||
if admin {
|
|
||||||
output = append(output, desc)
|
|
||||||
editable = append(editable, desc.ServiceName)
|
|
||||||
} else if caller.isAdminOrValidToken(email) {
|
|
||||||
output = append(output, desc)
|
|
||||||
editable = append(editable, desc.ServiceName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(output, func(i, j int) bool {
|
|
||||||
return output[i].ServiceName < output[j].ServiceName
|
|
||||||
})
|
|
||||||
|
|
||||||
return output, editable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (caller apiCaller) isAdmin(service any) bool {
|
|
||||||
if *noauth {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,66 +91,49 @@ func (caller apiCaller) isAdmin(service any) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
svcdesc := caller.mg.services.get(service)
|
return caller.mg.service().isAdmin(email)
|
||||||
if svcdesc == nil {
|
|
||||||
logger.Println("isVaidUser failed. service is missing :", service)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return svcdesc.isAdmin(email)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (caller apiCaller) isAdminOrValidToken(service any) bool {
|
func (caller apiCaller) isAdminOrValidToken() bool {
|
||||||
if caller.isAdmin(service) {
|
if caller.isAdmin() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
sh := caller.mg.services.get(service)
|
return caller.mg.service().isValidToken(caller.apiToken)
|
||||||
if sh == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return sh.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" {
|
||||||
servicename := r.FormValue("service")
|
if !caller.isAdminOrValidToken() {
|
||||||
if !caller.isAdminOrValidToken(servicename) {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var files []fileDocumentDesc
|
allfiles, err := caller.mg.mongoClient.All(CollectionFile, options.Find().SetProjection(bson.M{
|
||||||
err := caller.mg.mongoClient.FindAllAs(CollectionFile, bson.M{
|
|
||||||
"service": servicename,
|
|
||||||
}, &files, options.Find().SetProjection(bson.M{
|
|
||||||
"contents": 0,
|
"contents": 0,
|
||||||
}))
|
}).SetReturnKey(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(files) > 0 {
|
if len(allfiles) > 0 {
|
||||||
enc := json.NewEncoder(w)
|
enc := json.NewEncoder(w)
|
||||||
return enc.Encode(files)
|
return enc.Encode(allfiles)
|
||||||
}
|
}
|
||||||
} else if r.Method == "DELETE" {
|
} else if r.Method == "DELETE" {
|
||||||
servicename := r.FormValue("service")
|
|
||||||
key := r.FormValue("key")
|
key := r.FormValue("key")
|
||||||
if len(servicename) == 0 || len(key) == 0 {
|
if len(key) == 0 {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !caller.isAdminOrValidToken(servicename) {
|
if !caller.isAdminOrValidToken() {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
_, err := caller.mg.mongoClient.Delete(CollectionFile, bson.M{
|
||||||
"service": servicename,
|
"key": key,
|
||||||
"key": key,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -302,7 +213,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
|||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
service := queryvals.Get("service")
|
service := queryvals.Get("service")
|
||||||
if len(service) > 0 {
|
if len(service) > 0 {
|
||||||
if !caller.isAdminOrValidToken(service) {
|
if !caller.isAdminOrValidToken() {
|
||||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return nil
|
return nil
|
||||||
@ -335,7 +246,7 @@ func (caller apiCaller) whitelistAPI(w http.ResponseWriter, r *http.Request) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !caller.isAdminOrValidToken(member.Service) {
|
if !caller.isAdminOrValidToken() {
|
||||||
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
logger.Println("whitelistAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return nil
|
return nil
|
||||||
@ -378,22 +289,21 @@ 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
|
||||||
queryvals := r.URL.Query()
|
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
name := queryvals.Get("name")
|
if mg.service().Id.IsZero() {
|
||||||
if len(name) > 0 {
|
newService := serviceDescription{
|
||||||
if !caller.isAdminOrValidToken(name) {
|
ServiceDescriptionSummary: ServiceDescriptionSummary{
|
||||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
Id: primitive.NewObjectID(),
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
},
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
if err := newService.prepare(caller.mg); err != nil {
|
||||||
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
|
return err
|
||||||
serptr := atomic.LoadPointer(&mg.services.get(name).serviceSerialized)
|
}
|
||||||
w.Write(*(*[]byte)(serptr))
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService))
|
||||||
} else {
|
|
||||||
caller.writeAccessableServices(w)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@ -401,31 +311,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if service.Id.IsZero() {
|
|
||||||
if caller.isGlobalAdmin() {
|
|
||||||
service.Id = primitive.NewObjectID()
|
|
||||||
} else {
|
|
||||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else if !caller.isAdminOrValidToken(service.Id) {
|
|
||||||
logger.Println("serviceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(service.ServerApiTokens) == 0 {
|
|
||||||
service.ServerApiTokens = []primitive.ObjectID{
|
|
||||||
primitive.NewObjectID(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filter := bson.M{"_id": service.Id}
|
filter := bson.M{"_id": service.Id}
|
||||||
if len(service.ServiceCode) == 0 {
|
|
||||||
service.ServiceCode = hex.EncodeToString(service.Id[6:])
|
|
||||||
}
|
|
||||||
|
|
||||||
success, _, err := mg.mongoClient.Update(CollectionService, filter, bson.M{
|
success, _, err := mg.mongoClient.Update(CollectionService, filter, bson.M{
|
||||||
"$set": &service,
|
"$set": &service,
|
||||||
}, options.Update().SetUpsert(true))
|
}, options.Update().SetUpsert(true))
|
||||||
@ -445,28 +331,10 @@ 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
|
||||||
queryvals := r.URL.Query()
|
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
name := queryvals.Get("name")
|
serptr := atomic.LoadPointer(&mg.service().divisionsSerialized)
|
||||||
if len(name) > 0 {
|
w.Write(*(*[]byte)(serptr))
|
||||||
if !caller.isAdminOrValidToken(name) {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
w.Header().Add("MG-X-SERVICE-EDITABLE", name)
|
|
||||||
serptr := atomic.LoadPointer(&mg.services.get(name).divisionsSerialized)
|
|
||||||
w.Write(*(*[]byte)(serptr))
|
|
||||||
} else {
|
|
||||||
caller.writeAccessableServices(w)
|
|
||||||
}
|
|
||||||
} else if r.Method == "POST" {
|
} else if r.Method == "POST" {
|
||||||
servicename := queryvals.Get("name")
|
|
||||||
if !caller.isAdminOrValidToken(servicename) {
|
|
||||||
logger.Println("maintenanceAPI failed. not vaild user :", r.Method, caller.userinfo)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var divs map[string]*Division
|
var divs map[string]*Division
|
||||||
dec := json.NewDecoder(r.Body)
|
dec := json.NewDecoder(r.Body)
|
||||||
if err := dec.Decode(&divs); err != nil {
|
if err := dec.Decode(&divs); err != nil {
|
||||||
@ -475,7 +343,7 @@ func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, _, err := mg.mongoClient.Update(CollectionService, bson.M{
|
_, _, err := mg.mongoClient.Update(CollectionService, bson.M{
|
||||||
"service": servicename,
|
"_Id": mg.service().Id,
|
||||||
}, bson.M{
|
}, bson.M{
|
||||||
"$set": bson.M{"divisions": divs},
|
"$set": bson.M{"divisions": divs},
|
||||||
}, options.Update().SetUpsert(false))
|
}, options.Update().SetUpsert(false))
|
||||||
@ -498,7 +366,7 @@ func (caller apiCaller) accountAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !caller.isAdminOrValidToken(service) {
|
if !caller.isAdminOrValidToken() {
|
||||||
logger.Println("accountAPI failed. not vaild user :", r.Method, caller.userinfo)
|
logger.Println("accountAPI failed. not vaild user :", r.Method, caller.userinfo)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return nil
|
return nil
|
||||||
@ -615,15 +483,14 @@ func (caller apiCaller) configAPI(w http.ResponseWriter, r *http.Request) error
|
|||||||
return errApiTokenMissing
|
return errApiTokenMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := mg.apiTokenToService.get(apitoken); !exists {
|
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||||
|
if !mg.service().isValidToken(apitokenObj) {
|
||||||
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
return fmt.Errorf("mg-x-api-token is not valid : %s", apitoken)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var noauth = flag.Bool("noauth", false, "")
|
|
||||||
|
|
||||||
type apiCaller struct {
|
type apiCaller struct {
|
||||||
userinfo map[string]any
|
userinfo map[string]any
|
||||||
globalAdmins map[string]bool
|
globalAdmins map[string]bool
|
||||||
@ -646,7 +513,7 @@ func (mg *Maingate) api(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
var userinfo map[string]any
|
var userinfo map[string]any
|
||||||
|
|
||||||
if !*noauth {
|
if !*flag.Noauth {
|
||||||
authheader := r.Header.Get("Authorization")
|
authheader := r.Header.Get("Authorization")
|
||||||
if len(authheader) == 0 {
|
if len(authheader) == 0 {
|
||||||
logger.Println("Authorization header is not valid :", authheader)
|
logger.Println("Authorization header is not valid :", authheader)
|
||||||
|
|||||||
182
core/maingate.go
182
core/maingate.go
@ -14,13 +14,13 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
common "repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
|
"repositories.action2quare.com/ayo/maingate/flag"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
@ -61,7 +61,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SessionTTL() time.Duration {
|
func SessionTTL() time.Duration {
|
||||||
if *common.Devflag {
|
if *flag.Devflag {
|
||||||
return sessionTTLDev
|
return sessionTTLDev
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ type mongoAuthCell struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if *common.Devflag {
|
if *flag.Devflag {
|
||||||
hostname, _ := os.Hostname()
|
hostname, _ := os.Hostname()
|
||||||
CollectionLink = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionLink)))
|
CollectionLink = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionLink)))
|
||||||
CollectionAuth = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionAuth)))
|
CollectionAuth = common.CollectionName(fmt.Sprintf("%s-%s", hostname, string(CollectionAuth)))
|
||||||
@ -129,33 +129,6 @@ func makeAuthCollection(mongoClient common.MongoClient, sessionTTL time.Duration
|
|||||||
return authcoll
|
return authcoll
|
||||||
}
|
}
|
||||||
|
|
||||||
type apiTokenMap struct {
|
|
||||||
sync.Mutex
|
|
||||||
tokenToService map[string]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *apiTokenMap) add(token string, serviceCode string) {
|
|
||||||
tm.Lock()
|
|
||||||
defer tm.Unlock()
|
|
||||||
|
|
||||||
tm.tokenToService[token] = serviceCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *apiTokenMap) remove(token string) {
|
|
||||||
tm.Lock()
|
|
||||||
defer tm.Unlock()
|
|
||||||
|
|
||||||
delete(tm.tokenToService, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *apiTokenMap) get(token string) (code string, exists bool) {
|
|
||||||
tm.Lock()
|
|
||||||
defer tm.Unlock()
|
|
||||||
|
|
||||||
code, exists = tm.tokenToService[token]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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"`
|
||||||
@ -194,104 +167,16 @@ func (ga *globalAdmins) parse() {
|
|||||||
ga.modtime = common.ConfigModTime()
|
ga.modtime = common.ConfigModTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
type servicelist struct {
|
|
||||||
services unsafe.Pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) init(total []*serviceDescription) error {
|
|
||||||
next := make(map[string]*serviceDescription)
|
|
||||||
for _, service := range total {
|
|
||||||
next[service.ServiceName] = service
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) add(s *serviceDescription) {
|
|
||||||
ptr := atomic.LoadPointer(&sl.services)
|
|
||||||
src := (*map[string]*serviceDescription)(ptr)
|
|
||||||
|
|
||||||
next := map[string]*serviceDescription{}
|
|
||||||
for k, v := range *src {
|
|
||||||
next[k] = v
|
|
||||||
}
|
|
||||||
next[s.ServiceName] = s
|
|
||||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) getByCode(code string) *serviceDescription {
|
|
||||||
ptr := atomic.LoadPointer(&sl.services)
|
|
||||||
src := *(*map[string]*serviceDescription)(ptr)
|
|
||||||
|
|
||||||
for _, v := range src {
|
|
||||||
if v.ServiceCode == code {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) get(sn any) *serviceDescription {
|
|
||||||
ptr := atomic.LoadPointer(&sl.services)
|
|
||||||
src := *(*map[string]*serviceDescription)(ptr)
|
|
||||||
|
|
||||||
switch sn := sn.(type) {
|
|
||||||
case string:
|
|
||||||
return src[sn]
|
|
||||||
|
|
||||||
case primitive.ObjectID:
|
|
||||||
for _, desc := range src {
|
|
||||||
if desc.Id == sn {
|
|
||||||
return desc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) all() map[string]*serviceDescription {
|
|
||||||
ptr := atomic.LoadPointer(&sl.services)
|
|
||||||
src := (*map[string]*serviceDescription)(ptr)
|
|
||||||
|
|
||||||
next := map[string]*serviceDescription{}
|
|
||||||
for k, v := range *src {
|
|
||||||
next[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sl *servicelist) remove(uid primitive.ObjectID) (out *serviceDescription) {
|
|
||||||
ptr := atomic.LoadPointer(&sl.services)
|
|
||||||
src := (*map[string]*serviceDescription)(ptr)
|
|
||||||
|
|
||||||
next := map[string]*serviceDescription{}
|
|
||||||
var targetkey string
|
|
||||||
out = nil
|
|
||||||
for k, v := range *src {
|
|
||||||
next[k] = v
|
|
||||||
if v.Id == uid {
|
|
||||||
targetkey = k
|
|
||||||
out = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete(next, targetkey)
|
|
||||||
atomic.StorePointer(&sl.services, unsafe.Pointer(&next))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maingate :
|
// Maingate :
|
||||||
type Maingate struct {
|
type Maingate struct {
|
||||||
maingateConfig
|
maingateConfig
|
||||||
|
|
||||||
mongoClient common.MongoClient
|
mongoClient common.MongoClient
|
||||||
|
|
||||||
auths *common.AuthCollection
|
auths *common.AuthCollection
|
||||||
services servicelist
|
//services servicelist
|
||||||
|
serviceptr unsafe.Pointer
|
||||||
admins unsafe.Pointer
|
admins unsafe.Pointer
|
||||||
apiTokenToService apiTokenMap
|
|
||||||
tokenEndpoints map[string]string
|
tokenEndpoints map[string]string
|
||||||
authorizationEndpoints map[string]string
|
authorizationEndpoints map[string]string
|
||||||
userinfoEndpoint map[string]string
|
userinfoEndpoint map[string]string
|
||||||
@ -318,12 +203,8 @@ func New(ctx context.Context) (*Maingate, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mg := Maingate{
|
mg := Maingate{
|
||||||
maingateConfig: config,
|
maingateConfig: config,
|
||||||
services: servicelist{},
|
admins: unsafe.Pointer(&admins),
|
||||||
admins: unsafe.Pointer(&admins),
|
|
||||||
apiTokenToService: apiTokenMap{
|
|
||||||
tokenToService: make(map[string]string),
|
|
||||||
},
|
|
||||||
tokenEndpoints: make(map[string]string),
|
tokenEndpoints: make(map[string]string),
|
||||||
authorizationEndpoints: make(map[string]string),
|
authorizationEndpoints: make(map[string]string),
|
||||||
userinfoEndpoint: make(map[string]string),
|
userinfoEndpoint: make(map[string]string),
|
||||||
@ -352,6 +233,11 @@ func New(ctx context.Context) (*Maingate, error) {
|
|||||||
return &mg, nil
|
return &mg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mg *Maingate) service() *serviceDescription {
|
||||||
|
valptr := atomic.LoadPointer(&mg.serviceptr)
|
||||||
|
return (*serviceDescription)(valptr)
|
||||||
|
}
|
||||||
|
|
||||||
func (mg *Maingate) Destructor() {
|
func (mg *Maingate) Destructor() {
|
||||||
logger.Println("maingate.Destructor")
|
logger.Println("maingate.Destructor")
|
||||||
mg.mongoClient.Close()
|
mg.mongoClient.Close()
|
||||||
@ -554,23 +440,19 @@ func whitelistKey(email string) string {
|
|||||||
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
|
||||||
logger.Println(CollectionService)
|
logger.Println(CollectionService)
|
||||||
if err := mg.mongoClient.FindAllAs(CollectionService, bson.M{}, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
if err := mg.mongoClient.AllAs(CollectionService, &allServices, options.Find().SetReturnKey(false)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range allServices {
|
if len(allServices) > 0 {
|
||||||
if err := service.prepare(mg); err != nil {
|
only := allServices[0]
|
||||||
return err
|
only.prepare(mg)
|
||||||
}
|
|
||||||
}
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(only))
|
||||||
|
|
||||||
logger.Println("RegisterHandlers...")
|
|
||||||
mg.services.init(allServices)
|
|
||||||
for _, service := range allServices {
|
|
||||||
logger.Println("ServiceCode:", service.ServiceCode)
|
|
||||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, service.ServiceCode, "/"), service)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Println("Service is registered :", mg.service().ServiceCode)
|
||||||
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), mg.service())
|
||||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "api/"), mg.api)
|
||||||
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
|
serveMux.HandleFunc(common.MakeHttpHandlerPattern(prefix, "query/"), mg.query)
|
||||||
|
|
||||||
@ -595,16 +477,10 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
code, exists := mg.apiTokenToService.get(apitoken)
|
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||||
if !exists {
|
if mg.service().isValidToken(apitokenObj) {
|
||||||
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
convertedConfig["divisions"] = mg.service().Divisions
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
service := mg.services.getByCode(code)
|
|
||||||
convertedConfig["divisions"] = service.Divisions
|
|
||||||
|
|
||||||
enc := json.NewEncoder(w)
|
enc := json.NewEncoder(w)
|
||||||
enc.Encode(convertedConfig)
|
enc.Encode(convertedConfig)
|
||||||
})
|
})
|
||||||
@ -687,19 +563,13 @@ func (mg *Maingate) query(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
servicecode, exists := mg.apiTokenToService.get(apitoken)
|
apitokenObj, _ := primitive.ObjectIDFromHex(apitoken)
|
||||||
if !exists {
|
if !mg.service().isValidToken(apitokenObj) {
|
||||||
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
logger.Println("MG-X-API-TOKEN is invalid :", apitoken)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.ServiceCode != servicecode {
|
|
||||||
logger.Println("session is not for this service :", info.ServiceCode, servicecode)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bt, _ := json.Marshal(info)
|
bt, _ := json.Marshal(info)
|
||||||
w.Write(bt)
|
w.Write(bt)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,6 @@ type blockinfo struct {
|
|||||||
type whitelistMemberTag = string
|
type whitelistMemberTag = string
|
||||||
|
|
||||||
type whitelistmember struct {
|
type whitelistmember struct {
|
||||||
Service string `bson:"service" json:"service"`
|
|
||||||
Email string `bson:"email" json:"email"`
|
Email string `bson:"email" json:"email"`
|
||||||
Platform string `bson:"platform" json:"platform"`
|
Platform string `bson:"platform" json:"platform"`
|
||||||
Desc string `bson:"desc" json:"desc"`
|
Desc string `bson:"desc" json:"desc"`
|
||||||
@ -130,7 +129,6 @@ type Division struct {
|
|||||||
|
|
||||||
type ServiceDescriptionSummary struct {
|
type ServiceDescriptionSummary struct {
|
||||||
Id primitive.ObjectID `bson:"_id" json:"_id"`
|
Id primitive.ObjectID `bson:"_id" json:"_id"`
|
||||||
ServiceName string `bson:"service" json:"service"`
|
|
||||||
ServiceCode string `bson:"code" json:"code"`
|
ServiceCode string `bson:"code" json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +228,7 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
|
|||||||
div.Maintenance.link = div.Maintenance.Notice
|
div.Maintenance.link = div.Maintenance.Notice
|
||||||
} else {
|
} else {
|
||||||
hasher := md5.New()
|
hasher := md5.New()
|
||||||
hasher.Write([]byte(sh.ServiceName))
|
hasher.Write(sh.Id[:])
|
||||||
subfolder := hex.EncodeToString(hasher.Sum(nil))[:8]
|
subfolder := hex.EncodeToString(hasher.Sum(nil))[:8]
|
||||||
|
|
||||||
div.Maintenance.link = path.Join("static", subfolder, div.Maintenance.Notice)
|
div.Maintenance.link = path.Join("static", subfolder, div.Maintenance.Notice)
|
||||||
@ -260,25 +258,19 @@ func (sh *serviceDescription) prepare(mg *Maingate) error {
|
|||||||
sh.getProviderInfo = mg.getProviderInfo
|
sh.getProviderInfo = mg.getProviderInfo
|
||||||
|
|
||||||
var whites []whitelistmember
|
var whites []whitelistmember
|
||||||
if err := mg.mongoClient.FindAllAs(CollectionWhitelist, bson.M{
|
if err := mg.mongoClient.AllAs(CollectionWhitelist, &whites, options.Find().SetReturnKey(false)); err != nil {
|
||||||
"$or": []bson.M{{"service": sh.ServiceName}, {"service": sh.ServiceCode}},
|
|
||||||
}, &whites, options.Find().SetReturnKey(false)); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sh.wl.init(whites)
|
sh.wl.init(whites)
|
||||||
sh.admins = unsafe.Pointer(&sh.Admins)
|
sh.admins = unsafe.Pointer(&sh.Admins)
|
||||||
for _, keyid := range sh.ServerApiTokens {
|
|
||||||
mg.apiTokenToService.add(keyid.Hex(), sh.ServiceCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
bt, _ := json.Marshal(sh)
|
bt, _ := json.Marshal(sh)
|
||||||
atomic.StorePointer(&sh.serviceSerialized, unsafe.Pointer(&bt))
|
atomic.StorePointer(&sh.serviceSerialized, unsafe.Pointer(&bt))
|
||||||
|
|
||||||
btsum, _ := json.Marshal(sh.ServiceDescriptionSummary)
|
btsum, _ := json.Marshal(sh.ServiceDescriptionSummary)
|
||||||
atomic.StorePointer(&sh.serviceSummarySerialized, unsafe.Pointer(&btsum))
|
atomic.StorePointer(&sh.serviceSummarySerialized, unsafe.Pointer(&btsum))
|
||||||
|
|
||||||
logger.Println("service is ready :", sh.ServiceName, sh.ServiceCode, sh.Admins, string(divmarshaled))
|
logger.Println("service is ready :", sh.ServiceCode, sh.Admins, string(divmarshaled))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -380,7 +372,7 @@ func (sh *serviceDescription) link(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, newid, err := sh.mongoClient.Update(common.CollectionName(sh.ServiceName), bson.M{
|
_, newid, err := sh.mongoClient.Update(CollectionService, bson.M{
|
||||||
"_id": link["_id"].(primitive.ObjectID),
|
"_id": link["_id"].(primitive.ObjectID),
|
||||||
}, bson.M{
|
}, bson.M{
|
||||||
"$setOnInsert": bson.M{
|
"$setOnInsert": bson.M{
|
||||||
@ -489,7 +481,7 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request)
|
|||||||
for i := 0; i < len(sh.serviceCodeBytes); i++ {
|
for i := 0; i < len(sh.serviceCodeBytes); i++ {
|
||||||
newaccid[i] ^= sh.serviceCodeBytes[i]
|
newaccid[i] ^= sh.serviceCodeBytes[i]
|
||||||
}
|
}
|
||||||
account, err := sh.mongoClient.FindOneAndUpdate(common.CollectionName(sh.ServiceName), bson.M{
|
account, err := sh.mongoClient.FindOneAndUpdate(CollectionService, bson.M{
|
||||||
"_id": linkid,
|
"_id": linkid,
|
||||||
}, bson.M{
|
}, bson.M{
|
||||||
"$setOnInsert": bson.M{
|
"$setOnInsert": bson.M{
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
common "repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
@ -109,18 +110,14 @@ func (mg *Maingate) watchWhitelistCollection(parentctx context.Context) {
|
|||||||
switch ot {
|
switch ot {
|
||||||
case "insert":
|
case "insert":
|
||||||
// 새 화이트리스트 멤버
|
// 새 화이트리스트 멤버
|
||||||
if svc := mg.services.get(data.Member.Service); svc != nil {
|
mg.service().wl.add(data.Member)
|
||||||
svc.wl.add(data.Member)
|
|
||||||
}
|
|
||||||
case "update":
|
case "update":
|
||||||
if svc := mg.services.get(data.Member.Service); svc != nil {
|
if data.Member.Expired != 0 {
|
||||||
if data.Member.Expired != 0 {
|
logger.Println("whitelist member is removed :", *data.Member)
|
||||||
logger.Println("whitelist member is removed :", *data.Member)
|
mg.service().wl.remove(data.Member.Email)
|
||||||
svc.wl.remove(data.Member.Email)
|
} else {
|
||||||
} else {
|
logger.Println("whitelist member is updated :", *data.Member)
|
||||||
logger.Println("whitelist member is updated :", *data.Member)
|
mg.service().wl.add(data.Member)
|
||||||
svc.wl.add(data.Member)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -242,7 +239,6 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
|||||||
Key: "$match", Value: bson.D{
|
Key: "$match", Value: bson.D{
|
||||||
{Key: "operationType", Value: bson.D{
|
{Key: "operationType", Value: bson.D{
|
||||||
{Key: "$in", Value: bson.A{
|
{Key: "$in", Value: bson.A{
|
||||||
"delete",
|
|
||||||
"insert",
|
"insert",
|
||||||
"update",
|
"update",
|
||||||
"replace",
|
"replace",
|
||||||
@ -291,8 +287,8 @@ 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 {
|
||||||
logger.Println("service is on the board! :", data.Service)
|
logger.Println("service is on the board! :", data.Service)
|
||||||
mg.services.add(data.Service)
|
atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service))
|
||||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), data.Service)
|
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), mg.service())
|
||||||
}
|
}
|
||||||
|
|
||||||
case "replace":
|
case "replace":
|
||||||
@ -300,49 +296,32 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux *
|
|||||||
|
|
||||||
case "update":
|
case "update":
|
||||||
data.Service.prepare(mg)
|
data.Service.prepare(mg)
|
||||||
if old := mg.services.get(data.Service.ServiceName); old != nil {
|
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)
|
|
||||||
|
|
||||||
for _, token := range old.ServerApiTokens {
|
atomic.SwapPointer(&old.divisionsForUsersSerialized, data.Service.divisionsForUsersSerialized)
|
||||||
mg.apiTokenToService.remove(token.Hex())
|
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))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, token := range data.Service.ServerApiTokens {
|
if req != nil {
|
||||||
mg.apiTokenToService.add(token.Hex(), data.Service.ServiceCode)
|
// MG-X-API-TOKEN
|
||||||
}
|
req.Header.Add("MG-X-API-TOKEN", old.ServerApiTokens[0].Hex())
|
||||||
|
if resp, err := http.DefaultClient.Do(req); err == nil {
|
||||||
atomic.SwapPointer(&old.wl.emailptr, data.Service.wl.emailptr)
|
resp.Body.Close()
|
||||||
|
|
||||||
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 {
|
|
||||||
logger.Println("service is on the board! :", data.Service)
|
|
||||||
mg.services.add(data.Service)
|
|
||||||
serveMux.Handle(common.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), data.Service)
|
|
||||||
}
|
|
||||||
case "delete":
|
|
||||||
if deleted := mg.services.remove(data.DocumentKey.Id); deleted != nil {
|
|
||||||
logger.Println("service is closed :", data.Service)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
18
flag/commandline.go
Normal file
18
flag/commandline.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package flag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var commandLine = flag.NewFlagSet("maingate", flag.ExitOnError)
|
||||||
|
var Devflag = commandLine.Bool("dev", false, "")
|
||||||
|
var Noauth = commandLine.Bool("noauth", false, "")
|
||||||
|
|
||||||
|
func Parsed() bool {
|
||||||
|
return commandLine.Parsed()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse() error {
|
||||||
|
return commandLine.Parse(os.Args[1:])
|
||||||
|
}
|
||||||
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.6
|
go.mongodb.org/mongo-driver v1.11.6
|
||||||
google.golang.org/api v0.123.0
|
google.golang.org/api v0.123.0
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230620005911-15ba3e93d621
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -266,3 +266,5 @@ repositories.action2quare.com/ayo/gocommon v0.0.0-20230616031450-0b2c9351a717 h1
|
|||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616031450-0b2c9351a717/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616031450-0b2c9351a717/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742 h1:qEbzwVDz1w2ewNHu+vipzV+a804wmwRWe+0vnhCbJr4=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742 h1:qEbzwVDz1w2ewNHu+vipzV+a804wmwRWe+0vnhCbJr4=
|
||||||
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230616032216-378bc19f3742/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230620005911-15ba3e93d621 h1:9Hzdn13l9U0RJn9mMXsZQr+jsmsgy3zQFsBHPSOJnxM=
|
||||||
|
repositories.action2quare.com/ayo/gocommon v0.0.0-20230620005911-15ba3e93d621/go.mod h1:ng62uGMGXyQSeuxePG5gJAMtip4Rnspu5Tu7hgvaXns=
|
||||||
|
|||||||
2
main.go
2
main.go
@ -2,13 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
common "repositories.action2quare.com/ayo/gocommon"
|
common "repositories.action2quare.com/ayo/gocommon"
|
||||||
"repositories.action2quare.com/ayo/maingate/core"
|
"repositories.action2quare.com/ayo/maingate/core"
|
||||||
|
flag "repositories.action2quare.com/ayo/maingate/flag"
|
||||||
|
|
||||||
"repositories.action2quare.com/ayo/gocommon/logger"
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user