func (fieldContext *FieldContextDef) sendSingleAvatarObject(websocketConnectionContext *websocketConnectionContextDef, fieldObject *fieldObjectDef) *gkerr.GkErrDef { var gkErr *gkerr.GkErrDef var svgJsonData *message.SvgJsonDataDef = new(message.SvgJsonDataDef) svgJsonData.Id = fieldObject.id svgJsonData.IsoXYZ = fieldObject.isoXYZ gklog.LogTrace("sourceSessionId: " + fieldObject.sourceSessionId) if fieldObject.sourceSessionId != websocketConnectionContext.sessionId { var singleSession *ses.SingleSessionDef singleSession = fieldContext.sessionContext.GetSessionFromId(fieldObject.sourceSessionId) svgJsonData.UserName = singleSession.GetUserName() gklog.LogTrace("going to send to ws userName: " + singleSession.GetUserName()) } var messageToClient *message.MessageToClientDef = new(message.MessageToClientDef) gkErr = messageToClient.BuildSvgMessageToClient(fieldContext.avatarSvgDir, message.AddSvgReq, fieldObject.fileName, svgJsonData) if gkErr != nil { return gkErr } fieldContext.queueMessageToClient(websocketConnectionContext.sessionId, messageToClient) return nil }
func (tokenContext *tokenContextDef) getUserFromToken(token string) string { var ok bool var tokenEntry *tokenEntryDef tokenContext.purgeOldTokenEntries() tokenContext.tokenMutex.Lock() defer tokenContext.tokenMutex.Unlock() gklog.LogTrace(fmt.Sprintf("getting token entry: %+v", token)) tokenEntry, ok = tokenContext.tokenMap[token] if !ok { gklog.LogTrace("did not find") return "" } var userName string userName = tokenEntry.userName gklog.LogTrace("found " + userName) // token cannot be reused // but for now we allow it to be reused :) //delete(tokenContext.tokenMap,tokenEntry.tokenId) return userName }
// an avatar is moving from one pod to another // so delete any object matching by sessionId from old pod // then add them to the new pod func (fieldContext *FieldContextDef) moveAllAvatarBySessionId(sessionId string, oldPodId int32, newPodId int32, destinationX int16, destinationY int16, destinationZ int16) *gkerr.GkErrDef { gklog.LogTrace("moving all object by session id") var gkErr *gkerr.GkErrDef for _, fieldObject := range fieldContext.podMap[oldPodId].avatarMap { if fieldObject.sourceSessionId == sessionId { var messageToClient *message.MessageToClientDef = new(message.MessageToClientDef) messageToClient.Command = message.DelSvgReq messageToClient.JsonData = []byte(fmt.Sprintf("{ \"id\": \"%s\"}", fieldObject.id)) messageToClient.Data = make([]byte, 0, 0) for _, websocketConnectionContext := range fieldContext.podMap[oldPodId].websocketConnectionMap { if sessionId == websocketConnectionContext.sessionId { fieldObject.isoXYZ.X = destinationX fieldObject.isoXYZ.Y = destinationY fieldObject.isoXYZ.Z = destinationZ gklog.LogTrace(fmt.Sprintf("moveAllAvatarBySessionId new destination: %d,%d,%d", fieldObject.isoXYZ.X, fieldObject.isoXYZ.Y, fieldObject.isoXYZ.Z)) } fieldContext.queueMessageToClient(websocketConnectionContext.sessionId, messageToClient) } for _, websocketConnectionContext := range fieldContext.podMap[newPodId].websocketConnectionMap { gkErr = fieldContext.sendSingleAvatarObject(websocketConnectionContext, fieldObject) if gkErr != nil { return gkErr } } delete(fieldContext.podMap[oldPodId].avatarMap, fieldObject.id) fieldContext.podMap[newPodId].avatarMap[fieldObject.id] = fieldObject } } return nil }
func (httpContext *httpContextDef) handleGameInitial(res http.ResponseWriter, req *http.Request) { var gameData gameDataDef var gkErr *gkerr.GkErrDef var singleSession *ses.SingleSessionDef var token string token = req.Form.Get(_tokenParam) gklog.LogTrace("got token: " + token) var userName string userName = httpContext.tokenContext.getUserFromToken(token) gklog.LogTrace("got username: "******"not valid token", res, req) return } var lastPodId int32 lastPodId, gkErr = httpContext.persistenceContext.GetLastPodId(userName) if gkErr != nil { errorMessage := "persistenceContext.getLastPodName" gklog.LogGkErr(errorMessage, gkErr) httpContext.redirectToError(errorMessage, res, req) return } singleSession = httpContext.sessionContext.NewSingleSession(userName, lastPodId, req.RemoteAddr) gameData.Title = "game" gameData.WebAddressPrefix = httpContext.gameConfig.WebAddressPrefix gameData.WebsocketAddressPrefix = httpContext.gameConfig.WebsocketAddressPrefix gameData.AudioAddressPrefix = httpContext.gameConfig.AudioAddressPrefix gameData.WebsocketPath = httpContext.gameConfig.WebsocketPath gameData.SessionId = singleSession.GetSessionId() gkErr = _gameTemplate.Build(gameData) if gkErr != nil { errorMessage := "_gameTemplate.Build" gklog.LogGkErr(errorMessage, gkErr) httpContext.redirectToError(errorMessage, res, req) return } gkErr = _gameTemplate.Send(res, req) if gkErr != nil { gklog.LogGkErr("_gameTemplate.Send", gkErr) return } }
func (tokenContext *tokenContextDef) ServeHTTP(res http.ResponseWriter, req *http.Request) { path := req.URL.Path gklog.LogTrace(req.Method) gklog.LogTrace(path) if req.Method == _methodGet || req.Method == _methodPost { if gknet.RequestMatches(path, _tokenRequest) { tokenContext.handleTokenRequest(res, req) } else { http.NotFound(res, req) } } else { http.NotFound(res, req) } }
func (fieldContext *FieldContextDef) queueMessageToClient(sessionId string, messageToClient *message.MessageToClientDef) { var websocketConnectionContext *websocketConnectionContextDef var gkErr *gkerr.GkErrDef gklog.LogTrace("queu up message " + messageToClient.Command) websocketConnectionContext, gkErr = fieldContext.getWebsocketConnectionContextById(sessionId) if gkErr != nil { gklog.LogGkErr("", gkErr) } else { var localSize int websocketConnectionContext.toClientQueue.mutex.Lock() localSize = websocketConnectionContext.toClientQueue.queueSize websocketConnectionContext.toClientQueue.mutex.Unlock() if localSize > MAX_MESSAGES_TO_CLIENT_QUEUE { gkErr = gkerr.GenGkErr("messageToClient queue overflow, dropping message", nil, ERROR_ID_MESSAGE_TO_CLIENT_QUEUE_OVERFLOW) gklog.LogGkErr("", gkErr) } else { websocketConnectionContext.toClientQueue.mutex.Lock() websocketConnectionContext.toClientQueue.queueSize += 1 websocketConnectionContext.toClientQueue.mutex.Unlock() websocketConnectionContext.toClientQueue.messagesChan <- messageToClient } } }
func (websocketConnectionContext *websocketConnectionContextDef) runQueue() { var done bool done = false for !done { var messageToClient *message.MessageToClientDef select { case messageToClient = <-websocketConnectionContext.toClientQueue.messagesChan: case done = <-websocketConnectionContext.toClientQueue.doneChan: } if !done { gklog.LogTrace("got message to send: " + messageToClient.Command) select { case websocketConnectionContext.messageToClientChan <- messageToClient: case done = <-websocketConnectionContext.toClientQueue.doneChan: } if !done { websocketConnectionContext.toClientQueue.mutex.Lock() websocketConnectionContext.toClientQueue.queueSize -= 1 websocketConnectionContext.toClientQueue.mutex.Unlock() } } } }
// purge any expired tokens func checkTokenExpire() { expireTime := time.Now().Add(time.Duration(-1) * _tokenExpiry) for k, v := range _tokenMap { if expireTime.After(v.createdDate) { gklog.LogTrace(fmt.Sprintf("removing map entry (timeout) k: %+v v: %+v", k, v)) delete(_tokenMap, k) } } }
func NewTemplate(templateDir string, templateName string) (*TemplateDef, *gkerr.GkErrDef) { var gkTemplate *TemplateDef = new(TemplateDef) gkTemplate.tmpl = template.New(templateName) var file *os.File var templateListFileName string var err error templateListFileName = templateDir + string(os.PathSeparator) + templateName + ".txt" file, err = os.Open(templateListFileName) if err != nil { return nil, gkerr.GenGkErr("os.Open", err, ERROR_ID_OPEN_TEMPLATE_LIST) } defer file.Close() var br *bufio.Reader localFileNames := make([]string, 0, 0) br = bufio.NewReader(file) for { var line string line, err = br.ReadString('\n') line = strings.Trim(line, "\r\n\t ") if line != "" { localFileNames = append(localFileNames, templateDir+string(os.PathSeparator)+line) } if err != nil { if err == io.EOF { break } return nil, gkerr.GenGkErr("br.ReadString", err, ERROR_ID_READ_TEMPLATE_LIST) } } // localFileNames = make([]string, len(fileNames), len(fileNames)) // for i := 0; i < len(fileNames); i++ { // localFileNames[i] = templateDir + string(os.PathSeparator) + fileNames[i] + ".html" // } gklog.LogTrace(fmt.Sprintf("localFileNames: %+v", localFileNames)) _, err = gkTemplate.tmpl.ParseFiles(localFileNames...) if err != nil { return nil, gkerr.GenGkErr("tmpl.ParseFiles", err, ERROR_ID_PARSE_FILES) } return gkTemplate, nil }
// check if the token / userName is valid func CheckToken(token string, userName string) bool { _tokenMapMutex.Lock() defer _tokenMapMutex.Unlock() checkTokenExpire() var tokenEntry tokenEntryDef var ok bool tokenEntry, ok = _tokenMap[token] gklog.LogTrace(fmt.Sprintf("check map entry k: %+v v: %+v", token, ok)) if ok { gklog.LogTrace(fmt.Sprintf("check map entry k: %+v v: %+v", token, tokenEntry)) if tokenEntry.userName == userName { return true } } return false }
func (httpContext *httpContextDef) ServeHTTP(res http.ResponseWriter, req *http.Request) { if _gameTemplate == nil { gklog.LogError("missing call to gameInit") } path := req.URL.Path gklog.LogTrace(req.Method) gklog.LogTrace(path) if req.Method == _methodGet || req.Method == _methodPost { if gknet.RequestMatches(path, _gameRequest) { httpContext.handleGameRequest(res, req) } else { http.NotFound(res, req) } } else { http.NotFound(res, req) } }
func (fieldContext *FieldContextDef) setAllAvatars(sessionId string, fieldObject *fieldObjectDef) { var messageToClient *message.MessageToClientDef = new(message.MessageToClientDef) messageToClient.Command = message.SetSvgReq messageToClient.JsonData = []byte(fmt.Sprintf("{ \"id\": \"%s\", \"x\": %d, \"y\": %d, \"z\": %d }", fieldObject.id, fieldObject.isoXYZ.X, fieldObject.isoXYZ.Y, fieldObject.isoXYZ.Z)) var singleSession *ses.SingleSessionDef singleSession = fieldContext.sessionContext.GetSessionFromId(sessionId) var podId int32 = singleSession.GetCurrentPodId() for _, websocketConnectionContext := range fieldContext.podMap[podId].websocketConnectionMap { gklog.LogTrace("compare session " + websocketConnectionContext.sessionId + " " + sessionId) if websocketConnectionContext.sessionId != sessionId { gklog.LogTrace("Trace about to queue up move command") fieldContext.queueMessageToClient(websocketConnectionContext.sessionId, messageToClient) } } }
func (tokenContext *tokenContextDef) purgeOldTokenEntries() { tokenContext.tokenMutex.Lock() defer tokenContext.tokenMutex.Unlock() for tokenId, tokenEntry := range tokenContext.tokenMap { if tokenEntry.createdDate.Add(time.Second * _tokenTimeoutSeconds).Before(time.Now()) { gklog.LogTrace(fmt.Sprintf("purge token entry: %+v", tokenEntry)) delete(tokenContext.tokenMap, tokenId) } } }
func (loginConfig *loginConfigDef) ServeHTTP(res http.ResponseWriter, req *http.Request) { if _loginTemplate == nil { gklog.LogError("missing call to loginInit") } path := req.URL.Path gklog.LogTrace(req.Method) gklog.LogTrace(path) if req.Method == _methodGet || req.Method == _methodPost { if gknet.RequestMatches(path, _loginServer) { handleLogin(loginConfig, res, req) } else { http.NotFound(res, req) } } else { http.NotFound(res, req) } }
func (fieldContext *FieldContextDef) handleSetAvatarSvgReq(messageFromClient *message.MessageFromClientDef) *gkerr.GkErrDef { var gkErr *gkerr.GkErrDef var err error var setSvg setSvgDef gklog.LogTrace("json raw: " + string(messageFromClient.JsonData)) err = json.Unmarshal(messageFromClient.JsonData, &setSvg) if err != nil { gkErr = gkerr.GenGkErr("json.Unmarshal", err, ERROR_ID_JSON_UNMARSHAL) return gkErr } var singleSession *ses.SingleSessionDef singleSession = fieldContext.sessionContext.GetSessionFromId(messageFromClient.SessionId) var podId int32 = singleSession.GetCurrentPodId() var fieldObject *fieldObjectDef var ok bool fieldObject, ok = fieldContext.podMap[podId].avatarMap[setSvg.Id] if ok { var cord int cord, _ = strconv.Atoi(setSvg.X) fieldObject.isoXYZ.X = int16(cord) cord, _ = strconv.Atoi(setSvg.Y) fieldObject.isoXYZ.Y = int16(cord) cord, _ = strconv.Atoi(setSvg.Z) fieldObject.isoXYZ.Z = int16(cord) gklog.LogTrace("one") fieldContext.setAllAvatars(messageFromClient.SessionId, fieldObject) } else { gkErr = gkerr.GenGkErr("move object", nil, ERROR_ID_COULD_NOT_FIND_OBJECT_TO_MOVE) gklog.LogGkErr("", gkErr) } return nil }
// add a new token / userName to the list of tokens func AddNewToken(token string, userName string) { _tokenMapMutex.Lock() defer _tokenMapMutex.Unlock() checkTokenExpire() var tokenEntry tokenEntryDef tokenEntry.userName = userName tokenEntry.createdDate = time.Now() _tokenMap[token] = tokenEntry gklog.LogTrace(fmt.Sprintf("add map entry k: %+v v: %+v", token, tokenEntry)) }
func (gkTemplate *TemplateDef) Build(buildData interface{}) *gkerr.GkErrDef { gkTemplate.dataBuffer = bytes.NewBuffer(make([]byte, 0, 0)) var err error gklog.LogTrace(fmt.Sprintf("buildData: %+v", buildData)) err = gkTemplate.tmpl.ExecuteTemplate(gkTemplate.dataBuffer, "main", buildData) if err != nil { return gkerr.GenGkErr("tmpl.ExecuteTemplate", err, ERROR_ID_EXECUTE_TEMPLATE) } return nil }
// put the avatar back func (fieldContext *FieldContextDef) reAddAvatarBySessionId(sessionId string, newPodId int32) *gkerr.GkErrDef { gklog.LogTrace("re adding an avatar by session id") var gkErr *gkerr.GkErrDef for _, fieldObject := range fieldContext.podMap[newPodId].avatarMap { if fieldObject.sourceSessionId == sessionId { websocketConnectionContext := fieldContext.podMap[newPodId].websocketConnectionMap[sessionId] gklog.LogTrace(fmt.Sprintf("reAddAvatarBySessionId new destination: %d,%d,%d", fieldObject.isoXYZ.X, fieldObject.isoXYZ.Y, fieldObject.isoXYZ.Z)) gkErr = fieldContext.sendSingleAvatarObject(websocketConnectionContext, fieldObject) if gkErr != nil { return gkErr } // for _, websocketConnectionContext := range fieldContext.podMap[newPodId].websocketConnectionMap { // if (sessionId == websocketConnectionContext.sessionId) { // } // } } } return nil }
func (fieldContext *FieldContextDef) handleSaveTerrainEditReq(messageFromClient *message.MessageFromClientDef) *gkerr.GkErrDef { var saveTerrainEditReq saveTerrainEditReqDef var gkErr *gkerr.GkErrDef var err error var singleSession *ses.SingleSessionDef singleSession = fieldContext.sessionContext.GetSessionFromId(messageFromClient.SessionId) gklog.LogTrace("handleSaveTerrainEditReq") gklog.LogTrace(fmt.Sprintf("singleSession: %+v", singleSession)) gklog.LogTrace(fmt.Sprintf("messageFromClient.JsonData: %s", string(messageFromClient.JsonData))) err = json.Unmarshal(messageFromClient.JsonData, &saveTerrainEditReq) if err != nil { gkErr = gkerr.GenGkErr("json.Unmarshal", err, ERROR_ID_JSON_UNMARSHAL) return gkErr } for k, v := range saveTerrainEditReq.TerrainMapMap { gklog.LogTrace(fmt.Sprintf("k: %+v", k)) gklog.LogTrace(fmt.Sprintf("v: %+v", v)) // v has: // x, y, zlist, terrainName, Field } // // gkErr = fieldContext.persistenceContext.SetSaveTerrainEdit(singleSession.GetUserName(), saveTerrainEditReq.PrefName, saveTerrainEditReq.PrefValue) // if gkErr != nil { // // inserting user preferences is non critical // // so just log the error // gklog.LogGkErr("fieldContext.persistenceContext.SetSaveTerrainEdit", gkErr) // } return nil }
func NewFieldContext(avatarSvgDir string, terrainSvgDir string, sessionContext *ses.SessionContextDef, persistenceContext *persistence.PersistenceContextDef) (*FieldContextDef, *gkerr.GkErrDef) { var fieldContext *FieldContextDef = new(FieldContextDef) var gkErr *gkerr.GkErrDef fieldContext.avatarSvgDir = avatarSvgDir fieldContext.terrainSvgDir = terrainSvgDir fieldContext.sessionContext = sessionContext fieldContext.persistenceContext = persistenceContext fieldContext.WebsocketOpenedChan = make(chan WebsocketOpenedMessageDef) fieldContext.WebsocketClosedChan = make(chan WebsocketClosedMessageDef) fieldContext.MessageFromClientChan = make(chan *message.MessageFromClientDef) var podList []database.DbPodDef podList, gkErr = persistenceContext.GetPodsList() if gkErr != nil { return nil, gkErr } fieldContext.podMap = make(map[int32]*podEntryDef) for _, dbPod := range podList { gklog.LogTrace(fmt.Sprintf("populate pod %+v", dbPod)) var podEntry *podEntryDef = new(podEntryDef) podEntry.podId = dbPod.Id podEntry.title = dbPod.Title podEntry.websocketConnectionMap = make(map[string]*websocketConnectionContextDef) podEntry.avatarMap = make(map[string]*fieldObjectDef) podEntry.objectMap = make(map[string]*fieldObjectDef) podEntry.terrainJson, gkErr = fieldContext.newTerrainMap(podEntry.podId) if gkErr != nil { return nil, gkErr } fieldContext.podMap[podEntry.podId] = podEntry } fieldContext.savedChatMutex = new(sync.Mutex) fieldContext.savedChat = list.New() // fieldContext.terrainMap, gkErr = fieldContext.newTerrainMap(fieldContext, fieldContext.terrainSvgDir, fieldContext.persistenceContext) // if gkErr != nil { // return nil, gkErr // } return fieldContext, nil }
func goGetMessage(ws *websocket.Conn, ch chan *receiveWebsocketDef) { var receiveWebsocket *receiveWebsocketDef var err error for { var message []byte message = make([]byte, 0, 0) err = websocket.Message.Receive(ws, &message) receiveWebsocket = new(receiveWebsocketDef) receiveWebsocket.message = message receiveWebsocket.err = err ch <- receiveWebsocket if err != nil { gklog.LogTrace("exit goGetMessage due to error") break } } }
func (tokenContext *tokenContextDef) handleTokenRequest(res http.ResponseWriter, req *http.Request) { req.ParseForm() var tokenEntry *tokenEntryDef = new(tokenEntryDef) var userName string = req.Form.Get(_userNameParam) if len(userName) > 2 { tokenEntry.tokenId = tokenContext.getSessionToken() tokenEntry.createdDate = time.Now() tokenEntry.userName = userName tokenContext.tokenMutex.Lock() tokenContext.tokenMap[tokenEntry.tokenId] = tokenEntry tokenContext.tokenMutex.Unlock() gklog.LogTrace(fmt.Sprintf("adding token entry: %+v", tokenEntry)) } else { tokenEntry.tokenId = "" } res.Write([]byte(tokenEntry.tokenId)) }
func (fieldContext *FieldContextDef) removeAllAvatarBySessionId(sessionId string) { gklog.LogTrace("removing all object by session id") var singleSession *ses.SingleSessionDef singleSession = fieldContext.sessionContext.GetSessionFromId(sessionId) var podId int32 = singleSession.GetCurrentPodId() for _, fieldObject := range fieldContext.podMap[podId].avatarMap { if fieldObject.sourceSessionId == sessionId { var messageToClient *message.MessageToClientDef = new(message.MessageToClientDef) messageToClient.Command = message.DelSvgReq messageToClient.JsonData = []byte(fmt.Sprintf("{ \"id\": \"%s\"}", fieldObject.id)) messageToClient.Data = make([]byte, 0, 0) //fieldContext.removeSendRemoveAvatarBySessionId(podId, messageToClient) for _, websocketConnectionContext := range fieldContext.podMap[podId].websocketConnectionMap { fieldContext.queueMessageToClient(websocketConnectionContext.sessionId, messageToClient) } delete(fieldContext.podMap[podId].avatarMap, fieldObject.id) } } }
func GameServerStart() { var fileName *string = flag.String("config", "", "config file name") var gameConfig *config.GameConfigDef var gkErr *gkerr.GkErrDef flag.Parse() if *fileName == "" { flag.PrintDefaults() return } gameConfig, gkErr = config.LoadConfigFile(*fileName) if gkErr != nil { fmt.Print(gkErr.String()) return } gklog.LogInit(gameConfig.LogDir) var randContext *gkrand.GkRandContextDef var persistenceContext *persistence.PersistenceContextDef var tokenContext *tokenContextDef var sessionContext *ses.SessionContextDef var httpContext *httpContextDef randContext = gkrand.NewGkRandContext() persistenceContext, gkErr = persistence.NewPersistenceContext(gameConfig) if gkErr != nil { gklog.LogGkErr("persistence.NewPersisenceContext", gkErr) return } tokenContext = NewTokenContext(gameConfig, randContext, sessionContext) sessionContext = ses.NewSessionContext(randContext) httpContext = NewHttpContext(gameConfig, persistenceContext, sessionContext, tokenContext) gkErr = httpContext.gameInit() if gkErr != nil { gklog.LogGkErr("httpContext.gameInit", gkErr) return } gkErr = tokenContext.gameInit() if gkErr != nil { gklog.LogGkErr("tokenContext.gameInit", gkErr) return } gklog.LogTrace("game server started") var wsContext *ws.WsContextDef var fieldContext *field.FieldContextDef fieldContext, gkErr = field.NewFieldContext(gameConfig.AvatarSvgDir, gameConfig.TerrainSvgDir, sessionContext, persistenceContext) if gkErr != nil { gklog.LogGkErr("field.NewFieldContext", gkErr) return } wsContext = ws.NewWsContext(gameConfig, sessionContext, fieldContext) ws.SetGlobalWsContext(wsContext) go fieldContext.StartFieldHandler() httpAddress := fmt.Sprintf(":%d", gameConfig.HttpPort) tokenAddress := fmt.Sprintf(":%d", gameConfig.TokenPort) var err error go func() { err = http.ListenAndServe(tokenAddress, tokenContext) if err != nil { gkErr = gkerr.GenGkErr("http.ListenAndServer token", err, ERROR_ID_TOKEN_SERVER_START) gklog.LogGkErr("", gkErr) return } gklog.LogTrace("token listener ended, this is probably bad") }() go func() { err = http.ListenAndServe(httpAddress, httpContext) if err != nil { gkErr = gkerr.GenGkErr("http.ListenAndServer http", err, ERROR_ID_HTTP_SERVER_START) gklog.LogGkErr("", gkErr) return } gklog.LogTrace("http listener ended, this is probably bad") }() go func() { websocketAddress := fmt.Sprintf(":%d", gameConfig.WebsocketPort) gklog.LogTrace("starting web socket listener") if gameConfig.CertificatePath == "" { err = http.ListenAndServe(websocketAddress, websocket.Handler(ws.WebsocketHandler)) } else { err = http.ListenAndServeTLS(websocketAddress, gameConfig.CertificatePath, gameConfig.PrivateKeyPath, websocket.Handler(ws.WebsocketHandler)) } if err != nil { gkErr = gkerr.GenGkErr("http.ListenAndServer websocket", err, ERROR_ID_WEBSOCKET_SERVER_START) gklog.LogGkErr("", gkErr) return } gklog.LogTrace("websocket listener ended, this is probably bad") }() // give it time for the servers to start time.Sleep(time.Second * 60) // wait for all go routines to finish select {} gklog.LogTrace("game server ended") }
func WebsocketHandler(ws *websocket.Conn) { var url *url.URL = ws.Request().URL var gkErr *gkerr.GkErrDef defer ws.Close() gklog.LogTrace("WebsocketHandler start") defer gklog.LogTrace("WebsocketHandler end") // var websocketConfig *websocket.Config // websocketConfig = ws.Config() if url.Path != _wsContext.gameConfig.WebsocketPath { gkErr = gkerr.GenGkErr("invalid websocket path: "+url.Path, nil, ERROR_ID_WEBSOCKET_INVALID_PATH) gklog.LogGkErr("", gkErr) return } var sessionId string sessionId = _wsContext.sessionContext.OpenSessionWebsocket(url.RawQuery, ws.Request().RemoteAddr) if sessionId == "" { gkErr = gkerr.GenGkErr("session not valid", nil, ERROR_ID_WEBSOCKET_INVALID_SESSION) gklog.LogGkErr("", gkErr) return } defer func() { _wsContext.sessionContext.CloseSessionWebsocket(sessionId) }() var singleSession *ses.SingleSessionDef var singleWs *singleWsDef singleSession = _wsContext.sessionContext.GetSessionFromId(sessionId) singleWs = _wsContext.newSingleWs(singleSession) var websocketOpenedMessage field.WebsocketOpenedMessageDef websocketOpenedMessage.SessionId = sessionId websocketOpenedMessage.MessageToClientChan = singleWs.messageToClientChan _wsContext.fieldContext.WebsocketOpenedChan <- websocketOpenedMessage defer func() { var websocketClosedMessage field.WebsocketClosedMessageDef websocketClosedMessage.SessionId = sessionId _wsContext.fieldContext.WebsocketClosedChan <- websocketClosedMessage }() var receiveWebsocketChan chan *receiveWebsocketDef = make(chan *receiveWebsocketDef) go goGetMessage(ws, receiveWebsocketChan) var done bool = false for !done { var receiveWebsocket *receiveWebsocketDef select { case receiveWebsocket = <-receiveWebsocketChan: if receiveWebsocket.err != nil { if receiveWebsocket.err == io.EOF { gklog.LogTrace(fmt.Sprintf("closing websocket got eof sessionId: %s", sessionId)) done = true break } gkErr = gkerr.GenGkErr(fmt.Sprintf("got websocket input error sessionId %s", sessionId), receiveWebsocket.err, ERROR_ID_WEBSOCKET_RECEIVE) gklog.LogGkErr("websocket error", gkErr) return } else { var messageFromClient *message.MessageFromClientDef = new(message.MessageFromClientDef) messageFromClient.PopulateFromMessage(sessionId, receiveWebsocket.message) _wsContext.fieldContext.MessageFromClientChan <- messageFromClient } case messageToClient := <-singleWs.messageToClientChan: gkErr = sendWebsocketMessage(ws, messageToClient) if gkErr != nil { gklog.LogGkErr(fmt.Sprintf("sendWebsocketMessage sessionId: %s", sessionId), gkErr) return } } } }
func handleLogin(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request) { var act string var userName string var password string var email string var token string req.ParseForm() act = req.Form.Get(_actParam) userName = req.Form.Get(_userNameParam) password = req.Form.Get(_passwordParam) email = req.Form.Get(_emailParam) token = req.Form.Get(_tokenParam) // for security sleep on password attempt time.Sleep(sec.GetSleepDurationPasswordAttempt()) gklog.LogTrace("act: " + act) switch act { case "": var login string login = req.Form.Get(_loginParam) if login != "" { handleLoginLogin(loginConfig, res, req, userName, password) return } handleLoginInitial(loginConfig, res, req) return case "login": var register string var forgotPassword string register = req.Form.Get(_registerParam) forgotPassword = req.Form.Get(_forgotPasswordParam) if register != "" { handleLoginRegisterInitial(loginConfig, res, req, userName) return } if forgotPassword != "" { handleLoginForgotPasswordInitial(loginConfig, res, req) return } if userName == "" { handleLoginInitial(loginConfig, res, req) return } handleLoginLogin(loginConfig, res, req, userName, password) return case "register": handleLoginRegister(loginConfig, res, req, userName, password, email) case "forgot_password": handleLoginForgotPassword(loginConfig, res, req, userName) case "reset_password": handleLoginResetPassword(loginConfig, res, req, token, userName, password) default: gklog.LogError("unknown act") redirectToError("unknown act", res, req) return } }
func handleLoginLogin(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, userName string, password string) { var loginData loginDataDef var gkErr *gkerr.GkErrDef var gotError bool loginData.Title = "login" loginData.UserName = userName loginData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix if loginData.UserName == "" { loginData.ErrorList = append(loginData.ErrorList, "invalid user name") loginData.UserNameError = genErrorMarker() gotError = true } if password == "" { loginData.ErrorList = append(loginData.ErrorList, "invalid password") loginData.PasswordError = genErrorMarker() gotError = true } var passwordHashFromUser []byte var dbUser *database.DbUserDef var gkDbCon *database.GkDbConDef if !gotError { gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase) if gkErr != nil { gklog.LogGkErr("database.NewGkDbCon", gkErr) redirectToError("database.NewGkDbCon", res, req) return } defer gkDbCon.Close() dbUser, gkErr = gkDbCon.GetUser(loginData.UserName) if gkErr != nil { if gkErr.GetErrorId() == database.ERROR_ID_NO_ROWS_FOUND { var passwordSalt string password = "******" passwordSalt = "abc123QWE." // make it take the same amount of time // between no user and invalid password passwordHashFromUser = sec.GenPasswordHashSlow([]byte(password), []byte(passwordSalt)) loginData.ErrorList = append(loginData.ErrorList, "invalid username/password") loginData.UserNameError = genErrorMarker() loginData.PasswordError = genErrorMarker() gotError = true } else { gklog.LogGkErr("gkDbCon.GetPasswordHashAndSalt", gkErr) redirectToError("gkDbCon.GetPasswordhashAndSalt", res, req) return } } } if !gotError { passwordHashFromUser = sec.GenPasswordHashSlow([]byte(password), []byte(dbUser.PasswordSalt)) gklog.LogTrace(fmt.Sprintf("dbUser: %v fromUser: %s", dbUser, passwordHashFromUser)) if dbUser.PasswordHash != string(passwordHashFromUser) { loginData.ErrorList = append(loginData.ErrorList, "invalid username/password") loginData.UserNameError = genErrorMarker() loginData.PasswordError = genErrorMarker() gotError = true } } if gotError { // for security, to slow down an attack that is guessing passwords, // sleep between 100 and 190 milliseconds time.Sleep(sec.GetSleepDurationPasswordInvalid()) gkErr = _loginTemplate.Build(loginData) if gkErr != nil { gklog.LogGkErr("_loginTemplate.Build", gkErr) redirectToError("_loginTemplate.Build", res, req) return } gkErr = _loginTemplate.Send(res, req) if gkErr != nil { gklog.LogGkErr("_loginTemplate.Send", gkErr) return } } else { gkErr = gkDbCon.UpdateUserLoginDate(dbUser.UserName) if gkErr != nil { // this error is going to be logged // but the user is not going to be redirected to an error // because they are going to be redirected to the game server // and it is not critical that their login date be updated. gklog.LogGkErr("_loginTemplate.Send", gkErr) } var gameRedirect string gameRedirect, gkErr = getGameRedirect(loginConfig, loginData.UserName) if gkErr != nil { gklog.LogGkErr("getGameRedirect", gkErr) return } http.Redirect(res, req, gameRedirect, http.StatusFound) } }
func handleLoginForgotPassword(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, userName string) { var forgotPasswordData forgotPasswordDataDef var gkErr *gkerr.GkErrDef forgotPasswordData.Title = "forgotPassword" forgotPasswordData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix forgotPasswordData.UserName = userName forgotPasswordData.ErrorList = make([]string, 0, 0) var gotError bool if userName == "" { forgotPasswordData.ErrorList = append(forgotPasswordData.ErrorList, "user name cannot be blank") forgotPasswordData.UserNameError = genErrorMarker() gotError = true } var dbUser *database.DbUserDef if !gotError { var gkDbCon *database.GkDbConDef gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase) if gkErr != nil { gklog.LogGkErr("database.NewGkDbCon", gkErr) redirectToError("database.NewGkDbCon", res, req) return } defer gkDbCon.Close() dbUser, gkErr = gkDbCon.GetUser( forgotPasswordData.UserName) if gkErr != nil { if gkErr.GetErrorId() == database.ERROR_ID_NO_ROWS_FOUND { forgotPasswordData.ErrorList = append(forgotPasswordData.ErrorList, "no such user") forgotPasswordData.UserNameError = genErrorMarker() gotError = true } else { gklog.LogGkErr("gbDbCon.GetUser", gkErr) redirectToError("gbDbCon.GetUser", res, req) return } } } var err error if !gotError { // create temporary forgot password token //var token []byte var forgotPasswordEmailData forgotPasswordEmailDataDef forgotPasswordEmailData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix forgotPasswordEmailData.UserName = userName var token []byte token, err = sec.GenForgotPasswordToken() if err != nil { gkErr = gkerr.GenGkErr("GenForgotPasswordToken", err, ERROR_ID_GEN_TOKEN) gklog.LogGkErr("GenForgotPasswordToken", gkErr) redirectToError("GenForgotPasswordToken", res, req) return } forgotPasswordEmailData.Token = string(token) gkErr = _forgotPasswordEmailTemplate.Build(forgotPasswordEmailData) if gkErr != nil { gklog.LogGkErr("_forgotPasswordEmailTemplate.Build", gkErr) redirectToError("_forgotPasswordEmailTemplate.Build", res, req) return } var message []byte message, gkErr = _forgotPasswordEmailTemplate.GetBytes() if gkErr != nil { gklog.LogGkErr("_forgotPasswordEmailTemplate.GetBytes", gkErr) redirectToError("_forgotPasswordEmailTemplate.GetBytes", res, req) return } toArray := make([]string, 1, 1) toArray[0] = dbUser.Email var sendId string AddNewToken(string(token), userName) sendId, gkErr = gknet.SendEmail(loginConfig.EmailServer, loginConfig.ServerFromEmail, toArray, "gourdian knot forgotten password", message) if gkErr != nil { gklog.LogGkErr("gknet.SendEmail", gkErr) } else { gklog.LogTrace("forgot email sent to: " + toArray[0] + " sendId: [" + sendId + "]") } } if gotError { gkErr = _forgotPasswordTemplate.Build(forgotPasswordData) if gkErr != nil { gklog.LogGkErr("_forgotPasswordTemplate.Build", gkErr) redirectToError("_forgotPasswordTemplate.Build", res, req) return } gkErr = _forgotPasswordTemplate.Send(res, req) if gkErr != nil { gklog.LogGkErr("_forgotPasswordTemplate.send", gkErr) } } else { http.Redirect(res, req, _loginServer, http.StatusFound) } }
func handleLoginResetPassword(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, token string, userName string, password string) { var resetPasswordData resetPasswordDataDef var gkErr *gkerr.GkErrDef resetPasswordData.Title = "resetPassword" resetPasswordData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix resetPasswordData.Token = token resetPasswordData.UserName = userName if !CheckToken(token, userName) { redirectToError("token expired", res, req) return } gklog.LogTrace("reset password: "******"" { gklog.LogTrace("password blank") gkErr = _resetPasswordTemplate.Build(resetPasswordData) if gkErr != nil { gklog.LogGkErr("_resetPasswordTemplate.Build", gkErr) redirectToError("_resetPasswordTemplate.Build", res, req) return } gkErr = _resetPasswordTemplate.Send(res, req) if gkErr != nil { gklog.LogGkErr("_resetPasswordTemplate.send", gkErr) } return } var gkDbCon *database.GkDbConDef gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase) if gkErr != nil { gklog.LogGkErr("database.NewGkDbCon", gkErr) redirectToError("database.NewGkDbCon", res, req) return } defer gkDbCon.Close() var passwordHash, passwordSalt []byte var err error passwordSalt, err = sec.GenSalt() if err != nil { gkErr = gkerr.GenGkErr("sec.GenSalt", err, ERROR_ID_GEN_SALT) gklog.LogGkErr("sec.GenSalt", gkErr) redirectToError("sec.GenSalt", res, req) } passwordHash = sec.GenPasswordHashSlow([]byte(password), passwordSalt) gklog.LogTrace("change password") gkDbCon.ChangePassword(userName, string(passwordHash), string(passwordSalt)) if gkErr != nil { gklog.LogGkErr("gkDbCon.ChangePassword", gkErr) redirectToError("gbDbCon.ChangePassword", res, req) return } gklog.LogTrace("redirect to login") http.Redirect(res, req, loginConfig.LoginWebAddressPrefix+_loginServer, http.StatusFound) }