Initial commit.

This commit is contained in:
genxium
2022-09-20 23:50:01 +08:00
commit e90a335c56
432 changed files with 101884 additions and 0 deletions

155
battle_srv/common/conf.go Normal file
View File

@@ -0,0 +1,155 @@
package common
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"go.uber.org/zap"
)
// 隐式导入
var Conf *config
const (
APP_NAME = "server"
SERVER_ENV_PROD = "PROD"
SERVER_ENV_TEST = "TEST"
)
type generalConf struct {
AppRoot string `json:"-"`
ConfDir string `json:"-"`
TestEnvSQLitePath string `json:"-"`
PreConfSQLitePath string `json:"-"`
ServerEnv string `json:"-"`
}
type mysqlConf struct {
DSN string `json:"-"`
Host string `json:"host"`
Port int `json:"port"`
Dbname string `json:"dbname"`
Username string `json:"username"`
Password string `json:"password"`
}
type sioConf struct {
HostAndPort string `json:"hostAndPort"`
}
type botServerConf struct {
SecondsBeforeSummoning int `json:"secondsBeforeSummoning"`
Protocol string `json:"protocol"`
Host string `json:"host"`
Port int `json:"port"`
SymmetricKey string `json:"symmetricKey"`
}
type redisConf struct {
Dbname int `json:"dbname"`
Host string `json:"host"`
Password string `json:"password"`
Port int `json:"port"`
}
type config struct {
General *generalConf
MySQL *mysqlConf
Sio *sioConf
Redis *redisConf
BotServer *botServerConf
}
func MustParseConfig() {
Conf = &config{
General: new(generalConf),
MySQL: new(mysqlConf),
Sio: new(sioConf),
Redis: new(redisConf),
BotServer: new(botServerConf),
}
execPath, err := os.Executable()
ErrFatal(err)
pwd, err := os.Getwd()
Logger.Debug("os.GetWd", zap.String("pwd", pwd))
ErrFatal(err)
appRoot := pwd
confDir := filepath.Join(appRoot, "configs")
Logger.Debug("conf", zap.String("dir", confDir))
if isNotExist(confDir) {
appRoot = filepath.Dir(execPath)
confDir = filepath.Join(appRoot, "configs")
Logger.Debug("conf", zap.String("dir", confDir))
if isNotExist(confDir) {
i := strings.LastIndex(pwd, "battle_srv")
if i == -1 {
Logger.Fatal("无法找到配置目录cp -rn configs.template configs并配置相关参数再启动")
}
appRoot = pwd[:(i + 10)]
confDir = filepath.Join(appRoot, "configs")
Logger.Debug("conf", zap.String("dir", confDir))
if isNotExist(confDir) {
Logger.Fatal("无法找到配置目录cp -rn configs.template configs并配置相关参数再启动")
}
}
}
Conf.General.AppRoot = appRoot
testEnvSQLitePath := filepath.Join(confDir, "test_env.sqlite")
if !isNotExist(testEnvSQLitePath) {
Conf.General.TestEnvSQLitePath = testEnvSQLitePath
}
preConfSQLitePath := filepath.Join(confDir, "pre_conf_data.sqlite")
if !isNotExist(preConfSQLitePath) {
Conf.General.PreConfSQLitePath = preConfSQLitePath
}
Conf.General.ConfDir = confDir
Conf.General.ServerEnv = os.Getenv("ServerEnv")
loadJSON("mysql.json", Conf.MySQL)
setMySQLDSNURL(Conf.MySQL)
loadJSON("sio.json", Conf.Sio)
loadJSON("redis.json", Conf.Redis)
loadJSON("bot_server.json", Conf.BotServer)
}
func setMySQLDSNURL(c *mysqlConf) {
var dsn = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
c.Username, c.Password, c.Host, c.Port, c.Dbname)
c.DSN = dsn
}
func loadJSON(fp string, v interface{}) {
if !filepath.IsAbs(fp) {
fp = filepath.Join(Conf.General.ConfDir, fp)
}
_, err := os.Stat(fp)
ErrFatal(err)
fd, err := os.Open(fp)
ErrFatal(err)
defer fd.Close()
Logger.Info("Opened json file successfully.", zap.String("fp", fp))
err = json.NewDecoder(fd).Decode(v)
ErrFatal(err)
Logger.Info("Loaded json file successfully.", zap.String("fp", fp))
}
// Please only use this auxiliary function before server is fully started up, but not afterwards (启动过程可以使用,运行时不准使用).
func ErrFatal(err error) {
if err != nil {
Logger.Fatal("ErrFatal", zap.NamedError("err", err))
}
}
func isNotExist(p string) bool {
if _, err := os.Stat(p); err != nil {
return true
}
return false
}

View File

@@ -0,0 +1,67 @@
{
"RET_CODE": {
"__comment__":"基础",
"OK": 9000,
"UNKNOWN_ERROR": 9001,
"INVALID_REQUEST_PARAM": 9002,
"IS_TEST_ACC": 9003,
"MYSQL_ERROR": 9004,
"NONEXISTENT_ACT": 9005,
"LACK_OF_DIAMOND": 9006,
"LACK_OF_GOLD": 9007,
"LACK_OF_ENERGY": 9008,
"NONEXISTENT_ACT_HANDLER": 9009,
"LOCALLY_NO_AVAILABLE_ROOM": 9010,
"LOCALLY_NO_SPECIFIED_ROOM": 9011,
"PLAYER_NOT_ADDABLE_TO_ROOM": 9012,
"PLAYER_NOT_READDABLE_TO_ROOM": 9013,
"PLAYER_NOT_FOUND": 9014,
"PLAYER_CHEATING": 9015,
"WECHAT_SERVER_ERROR": 9016,
"IS_BOT_ACC": 9017,
"__comment__":"SMS",
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 5001,
"SMS_CAPTCHA_NOT_MATCH": 5002,
"INVALID_TOKEN": 2001,
"DUPLICATED": 2002,
"INCORRECT_HANDLE": 2004,
"INCORRECT_PASSWORD": 2006,
"INCORRECT_CAPTCHA": 2007,
"INVALID_EMAIL_LITERAL": 2008,
"NO_ASSOCIATED_EMAIL": 2009,
"SEND_EMAIL_TIMEOUT": 2010,
"INCORRECT_PHONE_COUNTRY_CODE": 2011,
"NEW_HANDLE_CONFLICT": 2013,
"FAILED_TO_UPDATE": 2014,
"FAILED_TO_DELETE": 2015,
"FAILED_TO_CREATE": 2016,
"INCORRECT_PHONE_NUMBER": 2018,
"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 3001,
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 4000,
"TRADE_CREATION_TOO_FREQUENTLY": 4002,
"MAP_NOT_UNLOCKED": 4003,
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 5003,
"NOT_IMPLEMENTED_YET": 65535
},
"AUTH_CHANNEL": {
"SMS": 0,
"WECHAT": 1,
"WECHAT_GAME": 2
},
"PLAYER": {
"DIAMOND": 1,
"GOLD": 2,
"ENERGY": 3,
"SMS_EXPIRED_SECONDS":120,
"SMS_VALID_RESEND_PERIOD_SECONDS":30,
"INT_AUTH_TOKEN_TTL_SECONDS":604800
},
"WS": {
"INTERVAL_TO_PING": 2000,
"WILL_KICK_IF_INACTIVE_FOR": 6000
}
}

View File

@@ -0,0 +1,38 @@
package common
import (
"path/filepath"
"github.com/imdario/mergo"
"go.uber.org/zap"
)
// 隐式导入
var Constants *constants
func MustParseConstants() {
fp := filepath.Join(Conf.General.AppRoot, "common/constants.json")
if isNotExist(fp) {
Logger.Fatal("common/constants.json文件不存在")
}
Constants = new(constants)
loadJSON(fp, Constants)
Logger.Debug("Conf.General.ServerEnv", zap.String("env", Conf.General.ServerEnv))
if Conf.General.ServerEnv == SERVER_ENV_TEST {
fp = filepath.Join(Conf.General.AppRoot, "common/constants_test.json")
if !isNotExist(fp) {
testConstants := new(constants)
loadJSON(fp, testConstants)
//Logger.Debug(spew.Sdump(Constants))
//Logger.Debug(spew.Sdump(testConstants))
err := mergo.Merge(testConstants, Constants)
ErrFatal(err)
Constants = testConstants
//Logger.Debug("mergo.Merge", zap.Error(err))
//Logger.Debug(spew.Sdump(testConstants))
}
}
constantsPost()
// Logger.Debug("const", zap.Int("IntAuthTokenTTLSeconds", Constants.Player.IntAuthTokenTTLSeconds))
}

View File

@@ -0,0 +1,64 @@
package common
type constants struct {
AuthChannel struct {
Sms int `json:"SMS"`
Wechat int `json:"WECHAT"`
WechatGame int `json:"WECHAT_GAME"`
} `json:"AUTH_CHANNEL"`
Player struct {
Diamond int `json:"DIAMOND"`
Energy int `json:"ENERGY"`
Gold int `json:"GOLD"`
IntAuthTokenTTLSeconds int `json:"INT_AUTH_TOKEN_TTL_SECONDS"`
SmsExpiredSeconds int `json:"SMS_EXPIRED_SECONDS"`
SmsValidResendPeriodSeconds int `json:"SMS_VALID_RESEND_PERIOD_SECONDS"`
} `json:"PLAYER"`
RetCode struct {
Duplicated int `json:"DUPLICATED"`
FailedToCreate int `json:"FAILED_TO_CREATE"`
FailedToDelete int `json:"FAILED_TO_DELETE"`
FailedToUpdate int `json:"FAILED_TO_UPDATE"`
IncorrectCaptcha int `json:"INCORRECT_CAPTCHA"`
IncorrectHandle int `json:"INCORRECT_HANDLE"`
IncorrectPassword int `json:"INCORRECT_PASSWORD"`
IncorrectPhoneCountryCode int `json:"INCORRECT_PHONE_COUNTRY_CODE"`
IncorrectPhoneNumber int `json:"INCORRECT_PHONE_NUMBER"`
InsufficientMemToAllocateConnection int `json:"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION"`
InvalidEmailLiteral int `json:"INVALID_EMAIL_LITERAL"`
InvalidRequestParam int `json:"INVALID_REQUEST_PARAM"`
InvalidToken int `json:"INVALID_TOKEN"`
IsTestAcc int `json:"IS_TEST_ACC"`
IsBotAcc int `json:"IS_BOT_ACC"`
LackOfDiamond int `json:"LACK_OF_DIAMOND"`
LackOfEnergy int `json:"LACK_OF_ENERGY"`
LackOfGold int `json:"LACK_OF_GOLD"`
MapNotUnlocked int `json:"MAP_NOT_UNLOCKED"`
MysqlError int `json:"MYSQL_ERROR"`
GetSmsCaptchaRespErrorCode int `json:"GET_SMS_CAPTCHA_RESP_ERROR_CODE"`
NewHandleConflict int `json:"NEW_HANDLE_CONFLICT"`
NonexistentAct int `json:"NONEXISTENT_ACT"`
NonexistentActHandler int `json:"NONEXISTENT_ACT_HANDLER"`
LocallyNoAvailableRoom int `json:"LOCALLY_NO_AVAILABLE_ROOM"`
LocallyNoSpecifiedRoom int `json:"LOCALLY_NO_SPECIFIED_ROOM"`
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
PlayerNotReAddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
PlayerCheating int `json:"PLAYER_CHEATING"`
NotImplementedYet int `json:"NOT_IMPLEMENTED_YET"`
NoAssociatedEmail int `json:"NO_ASSOCIATED_EMAIL"`
Ok int `json:"OK"`
PasswordResetCodeGenerationPerEmailTooFrequently int `json:"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY"`
SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"`
SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"`
SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"`
TradeCreationTooFrequently int `json:"TRADE_CREATION_TOO_FREQUENTLY"`
UnknownError int `json:"UNKNOWN_ERROR"`
WechatServerError int `json:"WECHAT_SERVER_ERROR"`
Comment string `json:"__comment__"`
} `json:"RET_CODE"`
Ws struct {
IntervalToPing int `json:"INTERVAL_TO_PING"`
WillKickIfInactiveFor int `json:"WILL_KICK_IF_INACTIVE_FOR"`
} `json:"WS"`
}

View File

@@ -0,0 +1,7 @@
{
"PLAYER": {
"SMS_EXPIRED_SECONDS":30,
"SMS_VALID_RESEND_PERIOD_SECONDS":8,
"INT_AUTH_TOKEN_TTL_SECONDS":1800
}
}

View File

@@ -0,0 +1,23 @@
package common
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var Logger *zap.Logger
var LoggerConfig zap.Config
func init() {
LoggerConfig = zap.NewDevelopmentConfig()
LoggerConfig.Level.SetLevel(zap.InfoLevel)
LoggerConfig.Development = false
LoggerConfig.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
LoggerConfig.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
var err error
Logger, err = LoggerConfig.Build()
ErrFatal(err)
}

View File

@@ -0,0 +1,35 @@
package utils
import (
crypto_rand "crypto/rand"
"encoding/hex"
"math/rand"
"time"
)
var Rand *privateRand
type privateRand struct {
*rand.Rand
}
func init() {
Rand = &privateRand{rand.New(rand.NewSource(time.Now().UnixNano()))}
}
func (p *privateRand) Number(numberRange ...int) int {
nr := 0
if len(numberRange) > 1 {
nr = 1
nr = p.Intn(numberRange[1]-numberRange[0]) + numberRange[0]
} else {
nr = p.Intn(numberRange[0])
}
return nr
}
func TokenGenerator(len int) string {
b := make([]byte, len/2)
crypto_rand.Read(b)
return hex.EncodeToString(b)
}

View File

@@ -0,0 +1,19 @@
package utils
import "time"
func UnixtimeNano() int64 {
return time.Now().UnixNano()
}
func UnixtimeMicro() int64 {
return time.Now().UnixNano() / 1000
}
func UnixtimeMilli() int64 {
return time.Now().UnixNano() / 1000000
}
func UnixtimeSec() int64 {
return time.Now().Unix()
}

View File

@@ -0,0 +1,283 @@
package utils
import (
"bytes"
"crypto/sha1"
"encoding/json"
"fmt"
"go.uber.org/zap"
"io"
"io/ioutil"
"math/rand"
"net/http"
. "server/common"
. "server/configs"
"sort"
"time"
)
var WechatIns *wechat
var WechatGameIns *wechat
func InitWechat(conf WechatConfig) {
WechatIns = NewWechatIns(&conf, Constants.AuthChannel.Wechat)
}
func InitWechatGame(conf WechatConfig) {
WechatGameIns = NewWechatIns(&conf, Constants.AuthChannel.WechatGame)
}
func NewWechatIns(conf *WechatConfig, channel int) *wechat {
newWechat := &wechat{
config: conf,
channel: channel,
}
return newWechat
}
const ()
type wechat struct {
config *WechatConfig
channel int
}
// CommonError 微信返回的通用错误json
type CommonError struct {
ErrCode int64 `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
// ResAccessToken 获取用户授权access_token的返回结果
type resAccessToken struct {
CommonError
AccessToken string `json:"access_token"`
ExpiresIn int64 `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
}
// Config 返回给用户jssdk配置信息
type JsConfig struct {
AppID string `json:"app_id"`
Timestamp int64 `json:"timestamp"`
NonceStr string `json:"nonce_str"`
Signature string `json:"signature"`
}
// resTicket 请求jsapi_tikcet返回结果
type resTicket struct {
CommonError
Ticket string `json:"ticket"`
ExpiresIn int64 `json:"expires_in"`
}
func (w *wechat) GetJsConfig(uri string) (config *JsConfig, err error) {
config = new(JsConfig)
var ticketStr string
ticketStr, err = w.getTicket()
if err != nil {
return
}
nonceStr := randomStr(16)
timestamp := UnixtimeSec()
str := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", ticketStr, nonceStr, timestamp, uri)
sigStr := signature(str)
config.AppID = w.config.AppID
config.NonceStr = nonceStr
config.Timestamp = timestamp
config.Signature = sigStr
return
}
//TODO add cache, getTicket 获取jsapi_ticket
func (w *wechat) getTicket() (ticketStr string, err error) {
var ticket resTicket
ticket, err = w.getTicketFromServer()
if err != nil {
return
}
ticketStr = ticket.Ticket
return
}
func (w *wechat) GetOauth2Basic(authcode string) (result resAccessToken, err error) {
var accessTokenURL string
if w.channel == Constants.AuthChannel.WechatGame {
accessTokenURL = w.config.ApiProtocol + "://" + w.config.ApiGateway + "/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"
}
if w.channel == Constants.AuthChannel.Wechat {
accessTokenURL = w.config.ApiProtocol + "://" + w.config.ApiGateway + "/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
}
urlStr := fmt.Sprintf(accessTokenURL, w.config.AppID, w.config.AppSecret, authcode)
Logger.Info("urlStr", zap.Any(":", urlStr))
response, err := get(urlStr)
if err != nil {
return
}
err = json.Unmarshal(response, &result)
if err != nil {
Logger.Info("GetOauth2Basic marshal error", zap.Any("err", err))
return
}
if result.ErrCode != 0 {
err = fmt.Errorf("GetOauth2Basic error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
return
}
return
}
//UserInfo 用户授权获取到用户信息
type UserInfo struct {
CommonError
OpenID string `json:"openid"`
Nickname string `json:"nickname"`
Sex int32 `json:"sex"`
Province string `json:"province"`
City string `json:"city"`
Country string `json:"country"`
HeadImgURL string `json:"headimgurl"`
Privilege []string `json:"privilege"`
Unionid string `json:"unionid"`
}
func (w *wechat) GetMoreInfo(accessToken string, openId string) (result UserInfo, err error) {
userInfoURL := w.config.ApiProtocol + "://" + w.config.ApiGateway + "/sns/userinfo?appid=%s&access_token=%s&openid=%s&lang=zh_CN"
urlStr := fmt.Sprintf(userInfoURL, w.config.AppID, accessToken, openId)
response, err := get(urlStr)
if err != nil {
return
}
err = json.Unmarshal(response, &result)
if err != nil {
Logger.Info("GetMoreInfo marshal error", zap.Any("err", err))
return
}
if result.ErrCode != 0 {
err = fmt.Errorf("GetMoreInfo error : errcode=%v , errmsg=%v", result.ErrCode, result.ErrMsg)
return
}
return
}
//HTTPGet get 请求
func get(uri string) ([]byte, error) {
response, err := http.Get(uri)
if err != nil {
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http get error : uri=%v , statusCode=%v", uri, response.StatusCode)
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}
return body, err
}
//PostJSON post json 数据请求
func post(uri string, obj interface{}) ([]byte, error) {
jsonData, err := json.Marshal(obj)
if err != nil {
return nil, err
}
jsonData = bytes.Replace(jsonData, []byte("\\u003c"), []byte("<"), -1)
jsonData = bytes.Replace(jsonData, []byte("\\u003e"), []byte(">"), -1)
jsonData = bytes.Replace(jsonData, []byte("\\u0026"), []byte("&"), -1)
body := bytes.NewBuffer(jsonData)
response, err := http.Post(uri, "application/json;charset=utf-8", body)
if err != nil {
return nil, err
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http get error : uri=%v , statusCode=%v", uri, response.StatusCode)
}
return ioutil.ReadAll(response.Body)
}
//Signature sha1签名
func signature(params ...string) string {
sort.Strings(params)
h := sha1.New()
for _, s := range params {
io.WriteString(h, s)
}
return fmt.Sprintf("%x", h.Sum(nil))
}
//RandomStr 随机生成字符串
func randomStr(length int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < length; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}
//getTicketFromServer 强制从服务器中获取ticket
func (w *wechat) getTicketFromServer() (ticket resTicket, err error) {
var accessToken string
accessToken, err = w.getAccessTokenFromServer()
if err != nil {
return
}
getTicketURL := w.config.ApiProtocol + "://" + w.config.ApiGateway + "/cgi-bin/ticket/getticket?access_token=%s&type=jsapi"
var response []byte
url := fmt.Sprintf(getTicketURL, accessToken)
response, err = get(url)
err = json.Unmarshal(response, &ticket)
if err != nil {
return
}
if ticket.ErrCode != 0 {
err = fmt.Errorf("getTicket Error : errcode=%d , errmsg=%s", ticket.ErrCode, ticket.ErrMsg)
return
}
//jsAPITicketCacheKey := fmt.Sprintf("jsapi_ticket_%s", w.config.AppID)
//expires := ticket.ExpiresIn - 1500
//set
//err = js.Cache.Set(jsAPITicketCacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
return
}
//GetAccessTokenFromServer 强制从微信服务器获取token
func (w *wechat) getAccessTokenFromServer() (accessToken string, err error) {
AccessTokenURL := w.config.ApiProtocol + "://" + w.config.ApiGateway + "/cgi-bin/token"
url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", AccessTokenURL, w.config.AppID, w.config.AppSecret)
var body []byte
body, err = get(url)
if err != nil {
return
}
var r resAccessToken
err = json.Unmarshal(body, &r)
if err != nil {
return
}
if r.ErrMsg != "" {
err = fmt.Errorf("get access_token error : errcode=%v , errormsg=%v", r.ErrCode, r.ErrMsg)
return
}
//accessTokenCacheKey := fmt.Sprintf("access_token_%s", w.config.AppID)
//expires := r.ExpiresIn - 1500
//set to redis err = ctx.Cache.Set(accessTokenCacheKey, r.AccessToken, time.Duration(expires)*time.Second)
accessToken = r.AccessToken
return
}

31
battle_srv/common/vals.go Normal file
View File

@@ -0,0 +1,31 @@
package common
import (
"regexp"
"time"
)
var (
RE_PHONE_NUM = regexp.MustCompile(`^\+?[0-9]{8,14}$`)
RE_SMS_CAPTCHA_CODE = regexp.MustCompile(`^[0-9]{4}$`)
RE_CHINA_PHONE_NUM = regexp.MustCompile(`^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$`)
)
// 隐式导入
var ConstVals = &struct {
Player struct {
CaptchaExpire time.Duration
CaptchaMaxTTL time.Duration
}
Ws struct {
WillKickIfInactiveFor time.Duration
}
}{}
func constantsPost() {
ConstVals.Player.CaptchaExpire = time.Duration(Constants.Player.SmsExpiredSeconds) * time.Second
ConstVals.Player.CaptchaMaxTTL = ConstVals.Player.CaptchaExpire -
time.Duration(Constants.Player.SmsValidResendPeriodSeconds)*time.Second
ConstVals.Ws.WillKickIfInactiveFor = time.Duration(Constants.Ws.WillKickIfInactiveFor) * time.Millisecond
}