package statistics import ( "encoding/json" "fmt" "nCovTrack-Backend/global" "nCovTrack-Backend/models" "nCovTrack-Backend/utils" "sort" "strings" "time" ) const ( rds_NCOV_STATISTIC_KEY = "nCovStatistic" rds_CHINA_TOTAL_KEY = "chinaTotal" rds_CHINA_ADD_KEY = "chinaAdd" rds_COUNTRY_LEVEL_KEY = "countryLevel" rds_COUNTRY_LEVEL_CHILD_KEY = "countryLevelChild" rds_PROVIENCE_LEVEL_CHILD_KEY = "provienceLevelChild" rds_PROVIENCE_LEVEL_NOW_CONFIRM_KEY = "provienceLevelNowConfirm" rds_PROVIENCE_LEVEL_TODAY_CONFIRM_KEY = "provienceLevelTodayConfirm" rds_PROVIENCE_LEVEL_TOTAL_CONFIRM_KEY = "provienceLevelTotalConfirm" rds_CITY_LEVEL_CHILD_KEY = "cityLevelChild" rds_CITY_LEVEL_NOW_CONFIRM_KEY = "cityLevelNowConfirm" rds_CITY_LEVEL_TODAY_CONFIRM_KEY = "cityLevelTodayConfirm" rds_CITY_LEVEL_TOTAL_CONFIRM_KEY = "cityLevelTotalConfirm" rds_LAST_UPDATE_TIME = "statisticsLastUpdateTime" rds_LAST_CACHE_TIME = "statisticsLastCacheTime" SORT_TODAY_CONFIRM = "today" SORT_TOTAL_CONFIRM = "total" SORT_NOW_CONFIRM = "now" json_FOREIGN_COUNTRY = "境外" json_FOREIGN_CITY = "外地" json_TO_BE_CONFIRM = "待确认" ) var ( sortBy string ) type AreaSlice []models.AreaInfo func cacheNCovStatistics() { resp := utils.GetWhioutHeader(global.CHINA_NCOV_STATISTIC_URL) var nCovRes map[string]string json.Unmarshal([]byte(resp), &nCovRes) var nCovResData map[string]interface{} err := json.Unmarshal([]byte(nCovRes["data"]), &nCovResData) if err != nil { panic(err) } if !needToRecache(nCovResData) { return } cacheChinaInfo(nCovResData) cacheLevelInfo(nCovResData) cacheLastUpdateTime(nCovResData) } func cacheChinaInfo(data map[string]interface{}) { chinaTotal, _ := json.Marshal(data["chinaTotal"]) chinaAdd, _ := json.Marshal(data["chinaAdd"]) global.Redis.Set(rds_CHINA_TOTAL_KEY, chinaTotal, time.Duration(12*time.Hour)) global.Redis.Set(rds_CHINA_ADD_KEY, chinaAdd, time.Duration(12*time.Hour)) } func cacheLastUpdateTime(data map[string]interface{}) { global.Redis.Set(rds_LAST_UPDATE_TIME, data["lastUpdateTime"], time.Duration(12*time.Hour)) global.Redis.Set(rds_LAST_CACHE_TIME, time.Now().String(), time.Duration(12*time.Hour)) } func needToRecache(data map[string]interface{}) bool { rdsLastUpdateTime := global.Redis.Get(rds_LAST_UPDATE_TIME).Val() newestUpdateTime := fmt.Sprintf("%v", data["lastUpdateTime"]) return rdsLastUpdateTime != newestUpdateTime } func cacheLevelInfo(data map[string]interface{}) { areaTree, _ := json.Marshal(data["areaTree"]) // Get Every Level's Info var countryLevels []models.AreaInfo json.Unmarshal(areaTree, &countryLevels) provienceLevels := children(countryLevels) cityLevels := children(provienceLevels) // Country Level Area Info With Child cacheList(rds_COUNTRY_LEVEL_CHILD_KEY, areaInfoToJson(countryLevels)...) // Country Level Area Info areaInfoChildNil(&countryLevels) cacheList(rds_COUNTRY_LEVEL_KEY, areaInfoToJson(countryLevels)...) // Provience Level Area Info With Child cacheList(rds_PROVIENCE_LEVEL_CHILD_KEY, areaInfoToJson(provienceLevels)...) areaInfoChildNil(&provienceLevels) // City Level Area Info With Child cacheList(rds_CITY_LEVEL_CHILD_KEY, areaInfoToJson(cityLevels)...) areaInfoChildNil(&provienceLevels) // Provience Level Area Info Sorted by Now Confirm provienceLevelsSlice := AreaSlice(provienceLevels) sort.Sort(provienceLevelsSlice) cacheList(rds_PROVIENCE_LEVEL_NOW_CONFIRM_KEY, areaInfoToJson(provienceLevelsSlice)...) // City Level Area Info Sorted By Now Confirm cityLevelsSlice := AreaSlice(cityLevels) sort.Sort(cityLevelsSlice) cacheList(rds_CITY_LEVEL_NOW_CONFIRM_KEY, areaInfoToJson(cityLevelsSlice)...) sortBy = SORT_TODAY_CONFIRM // Provience Level Area Info Sorted by Today Confirm sort.Sort(provienceLevelsSlice) cacheList(rds_PROVIENCE_LEVEL_TODAY_CONFIRM_KEY, areaInfoToJson(provienceLevelsSlice)...) // City Level Area Info Sorted by Today Confirm sort.Sort(cityLevelsSlice) cacheList(rds_CITY_LEVEL_TODAY_CONFIRM_KEY, areaInfoToJson(cityLevelsSlice)...) sortBy = SORT_TOTAL_CONFIRM // Provience Level Area Info Sorted by Total Confirm sort.Sort(provienceLevelsSlice) cacheList(rds_PROVIENCE_LEVEL_TOTAL_CONFIRM_KEY, areaInfoToJson(provienceLevelsSlice)...) // City Level Area Info Sorted by Total Confirm sort.Sort(cityLevelsSlice) cacheList(rds_CITY_LEVEL_TOTAL_CONFIRM_KEY, areaInfoToJson(cityLevelsSlice)...) } func cacheList(key string, values ...interface{}) { global.Redis.Del(key) global.Redis.RPush(key, values...) } func children(parents []models.AreaInfo) []models.AreaInfo { var areaInfos []models.AreaInfo for _, parent := range parents { if parent.Children == nil { continue } for _, item := range parent.Children { name := item.Name if !strings.Contains(name, json_FOREIGN_CITY) && !strings.Contains(name, json_FOREIGN_COUNTRY) && !strings.Contains(name, json_TO_BE_CONFIRM) { areaInfos = append(areaInfos, item) } } } return areaInfos } func areaInfoToJson(areaInfos []models.AreaInfo) []interface{} { return utils.Map(areaInfos, func(item models.AreaInfo) interface{} { jsonByte, _ := json.Marshal(item) return jsonByte }) } func areaInfoChildNil(areaInfos *[]models.AreaInfo) { utils.ForEach(areaInfos, func(item *models.AreaInfo) { item.Children = nil }) } func checkCache() { if global.Redis.Get(rds_LAST_UPDATE_TIME).Val() == "" { cacheNCovStatistics() } } func (s AreaSlice) Len() int { return len(s) } func (s AreaSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s AreaSlice) Less(i, j int) bool { if sortBy == SORT_TODAY_CONFIRM { return s[i].Today.Comfirm > s[j].Today.Comfirm } if sortBy == SORT_TOTAL_CONFIRM { return s[i].Total.Confirm > s[j].Total.Confirm } // Default sorted by now confirm return s[i].Total.NowConfirm > s[j].Total.NowConfirm } func CacheNCov() { cacheNCovStatistics() }