diff --git a/core/api.go b/core/api.go index e5a9c00..b07bb99 100644 --- a/core/api.go +++ b/core/api.go @@ -257,8 +257,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(&newService)) } - serptr := atomic.LoadPointer(&mg.service().serviceSerialized) - w.Write(*(*[]byte)(serptr)) + w.Write(mg.service().divisionsSerialized) } else if r.Method == "POST" { body, _ := io.ReadAll(r.Body) var service serviceDescription @@ -293,8 +292,7 @@ func (caller apiCaller) serviceAPI(w http.ResponseWriter, r *http.Request) error func (caller apiCaller) maintenanceAPI(w http.ResponseWriter, r *http.Request) error { mg := caller.mg if r.Method == "GET" { - serptr := atomic.LoadPointer(&mg.service().divisionsSerialized) - w.Write(*(*[]byte)(serptr)) + w.Write(mg.service().divisionsSerialized) } else if r.Method == "POST" { var divs map[string]*Division dec := json.NewDecoder(r.Body) diff --git a/core/maingate.go b/core/maingate.go index 932189d..2066cd8 100644 --- a/core/maingate.go +++ b/core/maingate.go @@ -501,7 +501,7 @@ func (mg *Maingate) RegisterHandlers(ctx context.Context, serveMux *http.ServeMu logger.Println("Service is registered :", mg.service().ServiceCode) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, mg.service().ServiceCode, "/"), func(w http.ResponseWriter, r *http.Request) { - mg.service().ServeHTTP(w, r) + mg.service().serveHTTP(w, r) }) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "api/"), mg.api) serveMux.HandleFunc(gocommon.MakeHttpHandlerPattern(prefix, "query/"), mg.query) diff --git a/core/service.go b/core/service.go index bbe5f8d..c3218f4 100644 --- a/core/service.go +++ b/core/service.go @@ -131,13 +131,13 @@ type serviceDescription struct { ServiceDescriptionSummary `bson:",inline" json:",inline"` Divisions map[string]*Division `bson:"divisions" json:"divisions"` ServerApiTokens []primitive.ObjectID `bson:"api_tokens" json:"api_tokens"` - Admins []string `bson:"admins" json:"admins"` + MaximumNumLinkAccount int64 + VersionSplits map[string]string `bson:"version_splits" json:"version_splits"` - auths *gocommon.AuthCollection - wl *whitelist - mongoClient gocommon.MongoClient - sessionTTL time.Duration - MaximumNumLinkAccount int64 + auths *gocommon.AuthCollection + wl *whitelist + mongoClient gocommon.MongoClient + sessionTTL time.Duration serviceCodeBytes []byte getUserBrowserInfo func(r *http.Request) (string, error) @@ -145,11 +145,11 @@ type serviceDescription struct { updateUserinfo func(info usertokeninfo) (bool, string, string) getProviderInfo func(platform string, uid string) (string, string, error) - admins unsafe.Pointer - divisionsForUsersSerialized unsafe.Pointer - divisionsSerialized unsafe.Pointer - serviceSerialized unsafe.Pointer - serviceSummarySerialized unsafe.Pointer + divisionsForUsersSerialized []byte + divisionsSerialized []byte + serviceSerialized []byte + serviceSummarySerialized []byte + divisionsSplits map[string][]byte } func (sh *serviceDescription) isValidToken(apiToken primitive.ObjectID) bool { @@ -211,7 +211,9 @@ func (sh *serviceDescription) prepare(mg *Maingate) error { } divsForUsers := make(map[string]*DivisionForUser) + var namesOnly []string for dn, div := range divs { + namesOnly = append(namesOnly, dn) if div.State == DivisionState_Closed { continue } @@ -249,13 +251,25 @@ func (sh *serviceDescription) prepare(mg *Maingate) error { } } - divmarshaled, _ := json.Marshal(divs) - devstr := string(divmarshaled) - sh.divisionsSerialized = unsafe.Pointer(&devstr) + sh.divisionsSerialized, _ = json.Marshal(divs) + sh.divisionsForUsersSerialized, _ = json.Marshal(divsForUsers) - divmarshaled2, _ := json.Marshal(divsForUsers) - devstr2 := string(divmarshaled2) - sh.divisionsForUsersSerialized = unsafe.Pointer(&devstr2) + if len(sh.VersionSplits) == 0 { + sh.VersionSplits = map[string]string{ + "": strings.Join(namesOnly, ","), + } + } + + sh.divisionsSplits = make(map[string][]byte) + for ver, divnamesT := range sh.VersionSplits { + divnames := strings.Split(divnamesT, ",") + split := make(map[string]*DivisionForUser) + for _, divname := range divnames { + split[divname] = divsForUsers[divname] + } + splitMarshaled, _ := json.Marshal(split) + sh.divisionsSplits[ver] = splitMarshaled + } sh.MaximumNumLinkAccount = mg.maingateConfig.MaximumNumLinkAccount sh.mongoClient = mg.mongoClient @@ -267,19 +281,11 @@ func (sh *serviceDescription) prepare(mg *Maingate) error { sh.updateUserinfo = mg.updateUserinfo sh.getProviderInfo = mg.getProviderInfo - if sh.Admins == nil { - sh.Admins = []string{} - } - sh.admins = unsafe.Pointer(&sh.Admins) - sh.wl = &mg.wl - bt, _ := json.Marshal(sh) - atomic.StorePointer(&sh.serviceSerialized, unsafe.Pointer(&bt)) + sh.divisionsSerialized, _ = json.Marshal(sh) + sh.serviceSummarySerialized, _ = json.Marshal(sh.ServiceDescriptionSummary) - btsum, _ := json.Marshal(sh.ServiceDescriptionSummary) - atomic.StorePointer(&sh.serviceSummarySerialized, unsafe.Pointer(&btsum)) - - logger.Println("service is ready :", sh.ServiceCode, sh.Admins, string(divmarshaled)) + logger.Println("service is ready :", sh.ServiceCode, string(sh.divisionsSerialized)) return nil } @@ -743,7 +749,20 @@ func (sh *serviceDescription) authorize(w http.ResponseWriter, r *http.Request) } } -func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (sh *serviceDescription) findVersionSplit(version string) []byte { + if len(version) > 0 { + for k, v := range sh.divisionsSplits { + if strings.HasPrefix(version, k) { + if version == k || version[len(k)] == '.' { + return v + } + } + } + } + return sh.divisionsSplits[""] +} + +func (sh *serviceDescription) serveHTTP(w http.ResponseWriter, r *http.Request) { defer func() { s := recover() if s != nil { @@ -784,9 +803,8 @@ func (sh *serviceDescription) ServeHTTP(w http.ResponseWriter, r *http.Request) return } - divstrptr := atomic.LoadPointer(&sh.divisionsForUsersSerialized) - divstr := *(*string)(divstrptr) - w.Write([]byte(divstr)) + version := queryvals.Get("version") + w.Write(sh.findVersionSplit(version)) } else if strings.HasSuffix(r.URL.Path, "/addr") { queryvals := r.URL.Query() sk := queryvals.Get("sk") diff --git a/core/watch.go b/core/watch.go index 14c4529..04e3b8c 100644 --- a/core/watch.go +++ b/core/watch.go @@ -285,11 +285,9 @@ func (mg *Maingate) watchServiceCollection(parentctx context.Context, serveMux * logger.Error("service cannot be prepared :", data.Service, err) } else { // 내가 임시로 가지고 있던 서비스일 수 있다. - already := mg.service().Id == data.Service.Id - logger.Println("service is on the board! :", data.Service) - atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service)) - if !already { - serveMux.Handle(gocommon.MakeHttpHandlerPattern(prefix, data.Service.ServiceCode, "/"), mg.service()) + if mg.service().Id == data.Service.Id { + logger.Println("service is on the board! :", data.Service) + atomic.StorePointer(&mg.serviceptr, unsafe.Pointer(data.Service)) } }