func (d *dataAccess) GetNextNotificationTime() (time.Time, error) { conn := d.Get() defer conn.Close() m, err := redis.Int64Map(conn.Do("ZRANGE", pendingNotificationsKey, 0, 0, "WITHSCORES")) if err != nil { return time.Time{}, slog.Wrap(err) } // default time is one hour from now if no pending notifications exist t := time.Now().UTC().Add(time.Hour).Truncate(time.Second) for _, i := range m { t = time.Unix(i, 0).UTC() } return t, nil }
func (r *RedisCache) startGC() { if r.occupyMode { return } kvs, err := redigo.Int64Map(r.do("HGETALL", r.key(GC_HASH_KEY))) if err != nil { return } nowUnix := time.Now().Unix() outKeys := make([]interface{}, 0) for k, v := range kvs { if v == 0 { continue } if v < nowUnix { outKeys = append(outKeys, k) } } if len(outKeys) > 0 { _, err = r.do("DEL", outKeys...) if err != nil { fmt.Println(err) } args := make([]interface{}, len(outKeys)+1) args[0] = r.key(GC_HASH_KEY) copy(args[1:], outKeys) _, err = r.do("HDEL", args...) if err != nil { fmt.Println(err) } } time.AfterFunc(time.Duration(r.interval)*time.Second, func() { r.startGC() }) }
func (d *dataAccess) GetDueNotifications() (map[models.AlertKey]map[string]time.Time, error) { conn := d.Get() defer conn.Close() m, err := redis.Int64Map(conn.Do("ZRANGEBYSCORE", pendingNotificationsKey, 0, time.Now().UTC().Unix(), "WITHSCORES")) if err != nil { return nil, slog.Wrap(err) } results := map[models.AlertKey]map[string]time.Time{} for key, t := range m { last := strings.LastIndex(key, ":") if last == -1 { continue } ak, not := models.AlertKey(key[:last]), key[last+1:] if results[ak] == nil { results[ak] = map[string]time.Time{} } results[ak][not] = time.Unix(t, 0).UTC() } return results, err }
func (*RedisStore) Int64Map(reply interface{}, err error) (map[string]int64, error) { return redis.Int64Map(reply, err) }
func postOrderHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { type inputData struct { CartId string `json:"cart_id"` } uid := checkToken(r) if uid != -1 { decoder := json.NewDecoder(r.Body) var input inputData err := decoder.Decode(&input) if err != nil { if err.Error() == "EOF" { responseEemptyRequest(&w) } else { responseMalformedJson(&w) } return } rc := *(getRC()) //defer rc.Close() rc.Send("HGET", "order", rTokenCache[uid]) rc.Send("HGETALL", "cart:"+input.CartId) rc.Flush() //oid, _ := redis.String(rc.Do("HGET", "order", rTokenCache[uid])) oid, _ := redis.String(rc.Receive()) if oid != "" { rc.Close() response(&w, 403, []byte(`{"code":"ORDER_OUT_OF_LIMIT","message":"每个用户只能下一单"}`)) } else { uh := input.CartId[0 : len(input.CartId)-9] cuid, isHave := tokenCache[uh] if isHave == false { rc.Close() response(&w, 404, []byte(`{"code":"CART_NOT_FOUND","message":"篮子不存在"}`)) } else if uid != cuid { rc.Close() response(&w, 401, []byte(`{"code":"NOT_AUTHORIZED_TO_ACCESS_CART","message":"无权限访问指定的篮子"}`)) } else { total := 0 itemsBuffer := new(bytes.Buffer) itemsBuffer.WriteString("{\"id\":\"") itemsBuffer.WriteString(rTokenCache[uid]) itemsBuffer.WriteString("\",\"user_id\":") itemsBuffer.WriteString(strconv.Itoa(uid)) itemsBuffer.WriteString(",\"items\":[") //res, _ := redis.Int64Map(rc.Do("HGETALL", "cart:" + input.CartId)) res, _ := redis.Int64Map(rc.Receive()) food_id := make([]interface{}, 0, 3) food_count := make([]int, 0, 3) var food_len int simple := true for k, v := range res { fid, _ := strconv.Atoi(k) food_id = append(food_id, fid) value := int(v) food_count = append(food_count, value) if foodCount[fid] < value { rc.Close() response(&w, 403, []byte(`{"code":"FOOD_OUT_OF_STOCK","message":"食物库存不足"}`)) return } // if itemsBuffer.Len() == 1 { // itemsBuffer.WriteString(fmt.Sprintf("{\"food_id\":%d,\"count\":%d}", fid, value)) // } else { // itemsBuffer.WriteString(fmt.Sprintf(",{\"food_id\":%d,\"count\":%d}", fid, value)) // } if total != 0 { itemsBuffer.WriteString(",") } itemsBuffer.WriteString("{\"food_id\":") itemsBuffer.WriteString(strconv.Itoa(fid)) itemsBuffer.WriteString(",\"count\":") itemsBuffer.WriteString(strconv.Itoa(value)) itemsBuffer.WriteString("}") total += foodPrice[fid] * value if foodCount[fid] < 100 { simple = false } } food_len = len(food_id) if simple { for i := 0; i < food_len; i++ { fid := food_id[i].(int) rc.Send("DECRBY", fid, food_count[i]) } // success itemsBuffer.WriteString("],\"total\":") itemsBuffer.WriteString(strconv.Itoa(total)) itemsBuffer.WriteString("}") orderToken := rTokenCache[uid] rc.Send("HSET", "order", orderToken, itemsBuffer.String()) rc.Flush() rc.Close() response(&w, 200, []byte("{\"id\":\""+orderToken+"\"}")) } else { for { rc.Do("WATCH", food_id...) counts := make([]int, 0, 3) fc, _ := redis.Values(rc.Do("MGET", food_id...)) redis.ScanSlice(fc, &counts) toRedis := make([]interface{}, 0, 6) for i := 0; i < food_len; i++ { counts[i] -= food_count[i] if counts[i] < 0 { rc.Do("UNWATCH", food_id...) rc.Close() response(&w, 403, []byte(`{"code":"FOOD_OUT_OF_STOCK","message":"食物库存不足"}`)) return } else { toRedis = append(toRedis, food_id[i], counts[i]) } } rc.Send("MULTI") rc.Send("MSET", toRedis...) queued, _ := rc.Do("EXEC") if queued != nil { break } } // success itemsBuffer.WriteString("],\"total\":") itemsBuffer.WriteString(strconv.Itoa(total)) itemsBuffer.WriteString("}") orderToken := rTokenCache[uid] rc.Do("HSET", "order", orderToken, itemsBuffer.String()) rc.Close() response(&w, 200, []byte("{\"id\":\""+orderToken+"\"}")) } } } } else { responseInvalidToken(&w) } }
func patchCartHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { type inputData struct { FoodId int `json:"food_id"` Count int `json:"count"` } uid := checkToken(r) if uid != -1 { decoder := json.NewDecoder(r.Body) var input inputData err := decoder.Decode(&input) if err != nil { if err.Error() == "EOF" { responseEemptyRequest(&w) } else { responseMalformedJson(&w) } } else if input.FoodId <= 0 || input.FoodId > foodNum { response(&w, 404, []byte(`{"code":"FOOD_NOT_FOUND","message":"食物不存在"}`)) } else { cid := ps.ByName("cid") if len(cid) < 9 { response(&w, 404, []byte(`{"code":"CART_NOT_FOUND","message":"篮子不存在"}`)) return } uh := cid[0 : len(cid)-9] cuid, isHave := tokenCache[uh] if isHave == false { response(&w, 404, []byte(`{"code":"CART_NOT_FOUND","message":"篮子不存在"}`)) } else if uid != cuid { response(&w, 401, []byte(`{"code":"NOT_AUTHORIZED_TO_ACCESS_CART","message":"无权限访问指定的篮子"}`)) } else { rc := *(getRC()) //defer rc.Close() res, _ := redis.Int64Map(rc.Do("HGETALL", "cart:"+cid)) sum := 0 sfid := strconv.Itoa(input.FoodId) res[sfid] += int64(input.Count) if res[sfid] < 0 { res[sfid] = 0 } for _, value := range res { sum += int(value) } if sum > 3 { rc.Close() response(&w, 403, []byte(`{"code":"FOOD_OUT_OF_LIMIT","message":"篮子中食物数量超过了三个"}`)) } else { if res[sfid] > 0 { rc.Do("HSET", "cart:"+cid, input.FoodId, res[sfid]) } else { rc.Do("HDEL", "cart:"+cid, input.FoodId) } rc.Close() response(&w, 204, []byte(``)) } } } } else { responseInvalidToken(&w) } }