Пример #1
0
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
}
Пример #2
0
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() })
}
Пример #3
0
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
}
Пример #4
0
func (*RedisStore) Int64Map(reply interface{}, err error) (map[string]int64, error) {
	return redis.Int64Map(reply, err)
}
Пример #5
0
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)
	}
}
Пример #6
0
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)
	}
}