示例#1
0
func listGame(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	// get game data
	gameValues, err := redis.Values(rc.Do("hgetall", fmt.Sprintf("games/%d", appid)))
	lwutil.CheckError(err, "")

	games := make([]interface{}, 0, len(gameValues)/2)
	for i, v := range gameValues {
		if i%2 == 0 {
			continue
		}
		var game interface{}
		err = json.Unmarshal(v.([]byte), &game)
		lwutil.CheckError(err, "")
		games = append(games, game)
	}

	//reply
	lwutil.WriteResponse(w, games)
}
示例#2
0
文件: auth.go 项目: henyouqian/grid
func authRegister(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	// in
	var in struct {
		Username      string
		Password      string
		CountryAlpha2 string
		SignCode      uint32
	}

	err := lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	if in.Username == "" || in.Password == "" {
		lwutil.SendError("err_input", "")
	}

	pwsha := lwutil.Sha224(in.Password + passwordSalt)

	// insert into db
	res, err := authDB.Exec("INSERT INTO user_accounts (username, password, countryAlpha2, signCode) VALUES (?, ?, ?, ?)",
		in.Username, pwsha, in.CountryAlpha2, in.SignCode)
	lwutil.CheckError(err, "err_account_exists")

	id, err := res.LastInsertId()
	lwutil.CheckError(err, "")

	// reply
	reply := struct {
		Userid int64
	}{id}
	lwutil.WriteResponse(w, reply)
}
示例#3
0
文件: auth.go 项目: henyouqian/grid
func authNewApp(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	session, err := findSession(w, r, nil)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	// input
	var input struct {
		Name string
	}
	err = lwutil.DecodeRequestBody(r, &input)
	lwutil.CheckError(err, "err_decode_body")

	if input.Name == "" {
		lwutil.SendError("err_input", "input.Name empty")
	}

	// db
	stmt, err := authDB.Prepare("INSERT INTO apps (name, secret) VALUES (?, ?)")
	lwutil.CheckError(err, "")

	secret := lwutil.GenUUID()
	_, err = stmt.Exec(input.Name, secret)
	lwutil.CheckError(err, "err_name_exists")

	// reply
	reply := struct {
		Name   string
		Secret string
	}{input.Name, secret}
	lwutil.WriteResponse(w, reply)
}
示例#4
0
文件: dig.go 项目: henyouqian/grid
func dig(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	// in
	var in struct {
		MatchId uint32
	}
	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	// out
	out := struct {
		Rank  int64
		Score int64
	}{1, 2}
	lwutil.WriteResponse(w, out)
}
示例#5
0
文件: auth.go 项目: henyouqian/grid
func authListApp(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	session, err := findSession(w, r, nil)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	// db
	rows, err := authDB.Query("SELECT name, secret FROM apps")
	lwutil.CheckError(err, "")

	type App struct {
		Name   string
		Secret string
	}

	apps := make([]App, 0, 16)
	var app App
	for rows.Next() {
		err = rows.Scan(&app.Name, &app.Secret)
		lwutil.CheckError(err, "")
		apps = append(apps, app)
	}

	lwutil.WriteResponse(w, apps)
}
示例#6
0
func benchJson(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	str := []byte(`
		{
			"Name": "aa",
			"Gameid": 885,
			"Begin": "2013/04/06 23:43:24",
			"End": "2013/05/06 23:43:24",
			"Sort": 0
		}
	`)

	in := struct {
		Name   string
		Gameid uint32
		Begin  string
		End    string
		Sort   uint8
	}{}
	err := json.Unmarshal(str, &in)
	lwutil.CheckError(err, "")

	lwutil.WriteResponse(w, in)
}
示例#7
0
func delGame(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	// input
	gameIds := make([]int, 0, 8)
	err = lwutil.DecodeRequestBody(r, &gameIds)
	lwutil.CheckError(err, "err_decode_body")

	// redis
	args := make([]interface{}, 1, 8)
	args[0] = fmt.Sprintf("games/%d", appid)
	for _, gameId := range gameIds {
		args = append(args, gameId)
	}

	delNum, err := redis.Int(rc.Do("hdel", args...))
	lwutil.CheckError(err, "")

	// reply
	lwutil.WriteResponse(w, delNum)
}
示例#8
0
func authSetInfo(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	session, err := findSession(w, r, nil)
	lwutil.CheckError(err, "err_auth")

	// in
	var in struct {
		CountryCode uint32
		SignCode    uint32
	}

	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	if in.CountryCode == 0 || in.SignCode == 0 {
		lwutil.SendError("err_input", "")
	}

	// insert into db
	_, err = authDB.Exec("UPDATE user_accounts SET countryCode=?, signCode=? WHERE id=?",
		in.CountryCode, in.SignCode, session.Userid)
	lwutil.CheckError(err, "")

	//new session
	newSession(w, session.Userid, session.Username, session.Appid, in.CountryCode, in.SignCode, nil)

	// out
	lwutil.WriteResponse(w, in)
}
示例#9
0
func benchDBSingleSelect(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	row := authDB.QueryRow("SELECT id FROM user_accounts WHERE username=?", "admin")
	var userid uint32
	err := row.Scan(&userid)
	lwutil.CheckError(err, "")

	lwutil.WriteResponse(w, userid)
}
示例#10
0
func newGame(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	// input
	input := struct {
		Id   uint32
		Name string
		Sort string
	}{}
	err = lwutil.DecodeRequestBody(r, &input)
	lwutil.CheckError(err, "err_decode_body")

	if input.Id == 0 || input.Name == "" {
		lwutil.SendError("err_input", "Missing Id or Name")
	}
	if input.Sort != SORT_ASC && input.Sort != SORT_DESC {
		lwutil.SendError("err_input", "Invalid Sort, must be ASC or DESC")
	}

	//
	game := Game{
		input.Id,
		input.Name,
		input.Sort,
	}

	gameJson, err := json.Marshal(game)
	lwutil.CheckError(err, "")

	key := fmt.Sprintf("games/%d", appid)
	_, err = rc.Do("hset", key, input.Id, gameJson)
	lwutil.CheckError(err, "")

	// reply
	lwutil.WriteResponse(w, game)
}
示例#11
0
func delMatch(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	//input
	matchIds := make([]int, 0, 8)
	err = lwutil.DecodeRequestBody(r, &matchIds)
	lwutil.CheckError(err, "err_decode_body")

	//redis
	key := fmt.Sprintf("matchesInApp/%d", appid)
	params := make([]interface{}, 0, 8)
	params = append(params, key)
	matchIdsItf := make([]interface{}, len(matchIds))
	for i, v := range matchIds {
		matchIdsItf[i] = v
	}
	params = append(params, matchIdsItf...)
	rc.Send("zrem", params...)

	args := make([]interface{}, len(matchIds)+1)
	args[0] = "matches"
	for i, matchId := range matchIds {
		key = fmt.Sprintf("%d+%d", appid, matchId)
		args[i+1] = key
	}
	rc.Send("hdel", args...)
	rc.Flush()

	_, err = rc.Receive()
	lwutil.CheckError(err, "")
	delNum, err := rc.Receive()
	lwutil.CheckError(err, "")

	//reply
	lwutil.WriteResponse(w, delNum)
}
示例#12
0
func benchJson2(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	str := []byte(`
		{
			"Name": "aa"
		}
	`)

	in := struct {
		Name string
	}{}
	err := json.Unmarshal(str, &in)
	lwutil.CheckError(err, "")

	lwutil.WriteResponse(w, in)
}
示例#13
0
func benchLogin(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	// input
	in := struct {
		Username  string
		Password  string
		Appsecret string
	}{Username: "******", Password: "******"}

	if in.Username == "" || in.Password == "" {
		lwutil.SendError("err_input", "")
	}

	pwsha := lwutil.Sha224(in.Password + passwordSalt)

	// get userid
	row := authDB.QueryRow("SELECT id, countryCode, signCode FROM user_accounts WHERE username=? AND password=?", in.Username, pwsha)
	var userid uint64
	var countryCode, signCode uint32
	err := row.Scan(&userid, &countryCode, &signCode)
	lwutil.CheckError(err, "")

	// get appid
	appid := uint32(0)
	if in.Appsecret != "" {
		row = authDB.QueryRow("SELECT id FROM apps WHERE secret=?", in.Appsecret)
		err = row.Scan(&appid)
		lwutil.CheckError(err, "")
	}

	// new session
	rc := redisPool.Get()
	defer rc.Close()

	usertoken, err := newSession(w, userid, in.Username, appid, 0, 0, rc)
	lwutil.CheckError(err, "")

	// reply
	reply := struct {
		Usertoken string
		Appid     uint32
	}{usertoken, appid}
	lwutil.WriteResponse(w, reply)
}
示例#14
0
func getMyRank(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	// in
	var in struct {
		MatchId uint32
	}
	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	keyLeaderboard := makeLeaderboardKey(in.MatchId)
	rc.Send("zrank", keyLeaderboard, session.Userid)
	rc.Send("zscore", keyLeaderboard, session.Userid)
	rc.Flush()
	rank, err := redis.Int64(rc.Receive())
	score := int64(0)
	if err == redis.ErrNil {
		rank = 0
	} else {
		lwutil.CheckError(err, "")
		if err == nil {
			rank += 1
		}
		score, err = redis.Int64(rc.Receive())
		lwutil.CheckError(err, "")
	}

	// out
	out := struct {
		Rank  int64
		Score int64
	}{rank, score}
	lwutil.WriteResponse(w, out)
}
示例#15
0
func benchRedisGet(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	rc := redisPool.Get()
	defer rc.Close()

	rc.Send("set", "foo", "yes")
	rc.Send("get", "foo")
	rc.Flush()
	rc.Receive()
	foo, err := redis.String(rc.Receive())
	lwutil.CheckError(err, "")

	// foo, err := redis.String(rc.Do("get", "foo"))
	// lwutil.CheckError(err, "")

	lwutil.WriteResponse(w, foo)
}
示例#16
0
文件: auth.go 项目: henyouqian/grid
func authLoginInfo(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	session, err := findSession(w, r, nil)
	lwutil.CheckError(err, "err_auth")

	//
	usertokenCookie, err := r.Cookie("usertoken")
	usertoken := usertokenCookie.Value

	//
	reply := struct {
		Session   *Session
		UserToken string
	}{session, usertoken}

	lwutil.WriteResponse(w, reply)
}
示例#17
0
func benchDBInsert(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "GET")

	//db
	stmt, err := matchDB.Prepare("INSERT INTO insertTest (a, b, c, d) VALUES (?, ?, ?, ?)")
	lwutil.CheckError(err, "")

	ids := make([]int64, insertCount)
	for i := 0; i < insertCount; i++ {
		res, err := stmt.Exec(1, 2, 3, 4)
		lwutil.CheckError(err, "err_account_exists")

		ids[i], err = res.LastInsertId()
		lwutil.CheckError(err, "")
	}

	lwutil.WriteResponse(w, ids)
}
示例#18
0
文件: auth.go 项目: henyouqian/grid
func authLogin(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	// input
	var input struct {
		Username  string
		Password  string
		Appsecret string
	}
	err := lwutil.DecodeRequestBody(r, &input)
	lwutil.CheckError(err, "err_decode_body")

	if input.Username == "" || input.Password == "" {
		lwutil.SendError("err_input", "")
	}

	pwsha := lwutil.Sha224(input.Password + passwordSalt)

	// get userid
	row := authDB.QueryRow("SELECT id, countryAlpha2, signCode FROM user_accounts WHERE username=? AND password=?", input.Username, pwsha)
	var userid uint64
	var countryAlpha2 string
	var signCode uint32
	err = row.Scan(&userid, &countryAlpha2, &signCode)
	lwutil.CheckError(err, "err_not_match")

	// get appid
	appid := uint32(0)
	if input.Appsecret != "" {
		row = authDB.QueryRow("SELECT id FROM apps WHERE secret=?", input.Appsecret)
		err = row.Scan(&appid)
		lwutil.CheckError(err, "err_app_secret")
	}

	// new session
	rc := redisPool.Get()
	defer rc.Close()

	usertoken, err := newSession(w, userid, input.Username, appid, rc)
	lwutil.CheckError(err, "")

	// reply
	lwutil.WriteResponse(w, usertoken)
}
示例#19
0
文件: auth.go 项目: henyouqian/grid
func authLogout(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_already_logout")

	usertokenCookie, err := r.Cookie("usertoken")
	lwutil.CheckError(err, "err_already_logout")
	usertoken := usertokenCookie.Value

	rc.Send("del", fmt.Sprintf("sessions/%s", usertoken))
	rc.Send("del", fmt.Sprintf("usertokens/%d+%d", session.Userid, session.Appid))
	rc.Flush()
	for i := 0; i < 2; i++ {
		_, err = rc.Receive()
		lwutil.CheckError(err, "")
	}

	// reply
	lwutil.WriteResponse(w, "logout")
}
示例#20
0
func listMatch(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	nowUnix := time.Now().Unix()

	//get matchIds
	key := fmt.Sprintf("matchesInApp/%d", appid)
	matchIdValues, err := redis.Values(rc.Do("zrangebyscore", key, nowUnix, "+inf"))
	lwutil.CheckError(err, "")

	args := make([]interface{}, len(matchIdValues)+1)
	args[0] = "matches"
	for i, v := range matchIdValues {
		var id int
		id, err := redis.Int(v, err)
		lwutil.CheckError(err, "")
		matchkey := fmt.Sprintf("%d+%d", appid, id)
		args[i+1] = matchkey
	}

	//get match data
	matchesValues, err := redis.Values(rc.Do("hmget", args...))

	matches := make([]Match, len(matchesValues))

	for i, v := range matchesValues {
		var match Match
		err = json.Unmarshal(v.([]byte), &match)
		lwutil.CheckError(err, "")
		matches[i] = match
	}

	//out
	type OutMatch struct {
		Id       uint32
		Name     string
		GameId   uint32
		Begin    int64
		End      int64
		Sort     string
		TryMax   uint32
		TryPrice uint32
		TryNum   uint32
	}

	outMatches := make([]OutMatch, len(matches))

	// get try number
	for _, match := range matches {
		tryNumKey := makeTryNumKey(match.Id)
		rc.Send("hget", tryNumKey, session.Userid)
	}
	err = rc.Flush()
	lwutil.CheckError(err, "")

	for i, match := range matches {
		tryNum, err := redis.Int(rc.Receive())
		if err != nil && err != redis.ErrNil {
			lwutil.CheckError(err, "")
		}

		outMatches[i] = OutMatch{
			Id:       match.Id,
			Name:     match.Name,
			GameId:   match.GameId,
			Begin:    match.Begin,
			End:      match.End,
			Sort:     match.Sort,
			TryMax:   match.TryMax,
			TryPrice: match.TryPrice,
			TryNum:   uint32(tryNum),
		}
	}

	lwutil.WriteResponse(w, outMatches)
}
示例#21
0
func newMatch(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")
	checkAdmin(session)

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	//input
	var in struct {
		Name     string
		GameId   uint32
		Begin    string
		End      string
		TryMax   uint32
		TryPrice uint32
	}
	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	if in.Name == "" || in.Begin == "" || in.End == "" || in.GameId == 0 {
		lwutil.SendError("err_input", "Missing Name || Begin || End || Gameid")
	}
	if in.TryMax == 0 {
		in.TryMax = 1
	}

	//game info
	game, err := findGame(in.GameId, appid)
	lwutil.CheckError(err, "err_game")

	//times
	const timeform = "2006-01-02 15:04:05"
	begin, err := time.ParseInLocation(timeform, in.Begin, time.Local)
	lwutil.CheckError(err, "")
	end, err := time.ParseInLocation(timeform, in.End, time.Local)
	lwutil.CheckError(err, "")
	beginUnix := begin.Unix()
	endUnix := end.Unix()

	if endUnix-beginUnix <= 60 {
		lwutil.SendError("err_input", "endUnix - beginUnix must > 60 seconds")
	}
	if time.Now().Unix() > endUnix {
		lwutil.SendError("err_input", "end time before now")
	}

	//
	matchId, err := redis.Int(rc.Do("incr", "idGen/match"))
	lwutil.CheckError(err, "")

	match := Match{
		uint32(matchId),
		in.Name,
		in.GameId,
		beginUnix,
		endUnix,
		game.Sort,
		in.TryMax,
		in.TryPrice,
	}

	matchJson, err := json.Marshal(match)
	lwutil.CheckError(err, "")

	key := fmt.Sprintf("%d+%d", appid, matchId)
	rc.Send("hset", "matches", key, matchJson)
	key = fmt.Sprintf("matchesInApp/%d", appid)
	rc.Send("zadd", key, endUnix, matchId)
	rc.Flush()
	for i := 0; i < 2; i++ {
		_, err = rc.Receive()
		lwutil.CheckError(err, "")
	}

	//reply
	lwutil.WriteResponse(w, match)
}
示例#22
0
func addScore(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	//input
	var in struct {
		TrySecret string
		Score     int64
	}
	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	//use secret to get matchId
	matchIdRaw, err := rc.Do("get", fmt.Sprintf("trySecrets/%s", in.TrySecret))
	lwutil.CheckError(err, "")
	if matchIdRaw == nil {
		lwutil.SendError("err_secret", "")
	}
	matchId64, err := redis.Int64(matchIdRaw, err)
	lwutil.CheckError(err, "")
	matchId := uint32(matchId64)

	//get match info and prev score
	keyLeaderboard := makeLeaderboardKey(matchId)
	matchKey := fmt.Sprintf("%d+%d", appid, matchId)
	rc.Send("hget", "matches", matchKey)
	rc.Send("zscore", keyLeaderboard, session.Userid)
	rc.Flush()
	matchJs, err := redis.Bytes(rc.Receive())
	lwutil.CheckError(err, "")

	var match Match
	err = json.Unmarshal(matchJs, &match)
	lwutil.CheckError(err, "")

	prevScore, err := redis.Int64(rc.Receive())
	needOverwrite := false
	if err == redis.ErrNil {
		needOverwrite = true
	} else {
		lwutil.CheckError(err, "")
		if match.Sort == SORT_ASC {
			if in.Score < prevScore {
				needOverwrite = true
			}
		} else if match.Sort == SORT_DESC {
			if in.Score > prevScore {
				needOverwrite = true
			}
		} else {
			lwutil.SendError("", "invalid match.Sort: "+match.Sort)
		}
	}

	//del from failboard and add to leaderboard and delete secret
	if needOverwrite {
		rc.Send("zadd", keyLeaderboard, in.Score, session.Userid)
	}
	rc.Send("zrank", keyLeaderboard, session.Userid)
	rc.Send("del", fmt.Sprintf("trySecrets/%s", in.TrySecret))

	err = rc.Flush()
	lwutil.CheckError(err, "")

	if needOverwrite {
		_, err := rc.Receive()
		lwutil.CheckError(err, "")
	}
	rank, err := redis.Int(rc.Receive())
	lwutil.CheckError(err, "")
	rank++

	//reply
	lwutil.WriteResponse(w, rank)
}
示例#23
0
func startMatch(w http.ResponseWriter, r *http.Request) {
	lwutil.CheckMathod(r, "POST")

	rc := redisPool.Get()
	defer rc.Close()

	session, err := findSession(w, r, rc)
	lwutil.CheckError(err, "err_auth")

	appid := session.Appid
	if appid == 0 {
		lwutil.SendError("err_auth", "Please login with app secret")
	}

	//input
	var in struct {
		MatchId uint32
	}
	err = lwutil.DecodeRequestBody(r, &in)
	lwutil.CheckError(err, "err_decode_body")

	//get match info
	key := fmt.Sprintf("%d+%d", appid, in.MatchId)
	matchJson, err := redis.Bytes(rc.Do("hget", "matches", key))
	lwutil.CheckError(err, "err_not_found")

	var match Match
	err = json.Unmarshal(matchJson, &match)
	lwutil.CheckError(err, "")

	//check time
	now := time.Now().Unix()
	if now < match.Begin || now >= match.End-MATCH_TRY_DURATION_SEC {
		lwutil.SendError("err_time", "now < match.Begin || now >= match.End-MATCH_TRY_DURATION_SEC")
	}

	//incr and check try number
	tryNumKey := makeTryNumKey(in.MatchId)
	tryNum, err := redis.Int(rc.Do("hget", tryNumKey, session.Userid))
	if err != nil && err != redis.ErrNil {
		lwutil.CheckError(err, "")
	}
	if uint32(tryNum) >= match.TryMax {
		lwutil.SendError("err_no_try", "no try left")
	}
	_, err = rc.Do("hincrby", tryNumKey, session.Userid, 1)
	lwutil.CheckError(err, "")
	tryNum++

	//new try secret
	trySecret := lwutil.GenUUID()
	_, err = rc.Do("setex", fmt.Sprintf("trySecrets/%s", trySecret), MATCH_TRY_DURATION_SEC, in.MatchId)
	lwutil.CheckError(err, "")

	//out
	out := struct {
		Secret string
		TryNum uint32
	}{trySecret, uint32(tryNum)}
	lwutil.WriteResponse(w, out)
}