package foundry import ( "errors" "fmt" "io" "net/http" "strconv" "strings" ) const ( authPath = "/auth" licensePath = "/license" joinPath = "/join" playersPath = "/players" setupPath = "/setup" updatePath = "/update" socketPath = "/socket.io" ) var WsTypeData = map[string]string{ authPath: "getAuthData", licensePath: "getAuthData", joinPath: "getJoinData", playersPath: "getPlayersData", setupPath: "getSetupData", updatePath: "getUpdateData", } type FoundryCode int const ( WriterCode = FoundryCode(0) ReaderCode = FoundryCode(1) RespSessionData = "0" RespPingCode = "2" RespSessionId = "40" RespCreateSessionCode = "42" RespDataCode = "43" ReqPongCode = "3" ReqCreateSessionCode = "40" ReqDataCode = "42" ) var RequestCodes = []string{ RespSessionData, RespPingCode, RespSessionId, RespCreateSessionCode, RespDataCode, } var CodesRespToReq = map[string]string{ RespSessionData: ReqCreateSessionCode, RespPingCode: ReqPongCode, RespCreateSessionCode: ReqDataCode, //ReqDataCode: RespCreateSessionCode, } type Foundry struct { config foundry_config sessionID string isAuth bool currPage string ws *webSocketUtil } type foundry_config struct { host string } func (foundry *Foundry) checkAuthRespAnswer(r io.Reader, respLength int) error { authBody := make([]byte, respLength) _, err := r.Read(authBody) if err != nil && err != io.EOF { return err } if !strings.Contains(string(authBody), "Admin authentication successful") { return ErrorAuthPassWrong } foundry.isAuth = true return nil } func (foundry *Foundry) getSessionTokenFromHeader(resp http.Header) (bool, error) { setCookieHeader := resp.Get("Set-Cookie") if setCookieHeader == "" { return false, nil } for value := range strings.SplitSeq(setCookieHeader, ";") { if strings.Contains(value, "session") { sessionCookie := strings.Split(value, "=") if len(sessionCookie) != 2 { return false, ErrorSidWrongFormat } foundry.sessionID = sessionCookie[1] return true, nil } } return false, nil } func (foundry *Foundry) Authenticate(password string) error { if foundry.sessionID == "" { err := foundry.setUpSessionId() if err != nil { return err } } req, err := createAuthRequest(foundry.config.host, foundry.sessionID, password) if err != nil { return err } client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() contentLen, err := strconv.Atoi(resp.Header.Get("Content-Length")) if err != nil { return err } return foundry.checkAuthRespAnswer(resp.Body, contentLen) } func (foundry *Foundry) StartListen() error { wsChannels := foundry.ws.InitWsChannels() defer wsChannels.Close() go foundry.ListenAndServeWS() var err error for { select { case err = <-wsChannels.Err(): var foundryErr *FoundryError if errors.As(err, &foundryErr) { if foundryErr.IsFatal { foundry.CloseWebSocketConn() return foundryErr } } case <-wsChannels.Done(): foundry.CloseWebSocketConn() return ListenIsDone } } } func (foundry *Foundry) CloseWebSocketConn() { foundry.ws.wsConn.Close() } func (foundry *Foundry) ListenAndServeWS() { go foundry.ws.ListenWebSocket() foundry.ws.ServeWebSocket() } func (foundry *Foundry) CreateWSMessageByPage(page string) *wsMessage { msgToSend := &wsMessage{code: CodesRespToReq[RespCreateSessionCode], id: foundry.ws.currWsId, msgJson: fmt.Sprintf("[\"%s\"]", WsTypeData[page])} foundry.ws.currWsId++ fmt.Printf("Msg: %s\n", msgToSend.toString()) return msgToSend } func (foundry *Foundry) HandleWebsocketRequest(msg *wsMessage) ([]byte, error) { return foundry.ws.HandleWebsocketRequest(msg) } func NewFoundry(host string) (*Foundry, error) { foundry := &Foundry{config: foundry_config{host: host}, isAuth: false, currPage: authPath, ws: NewWebSocketUtil()} err := foundry.setUpSessionId() if err != nil { return nil, err } return foundry, nil } // /** // * Poll the server to see if a World has become active, and automatically refresh if so. // * @returns {Promise} // */ // async #pollActive() { // const poll = () => { // const status = foundry.utils.getRoute("/api/status"); // this.#activePollState.last = Date.now(); // this.#activePollState.polling = foundry.utils.fetchJsonWithTimeout(status, {}, { // timeoutMs: 10000 // }).catch(() => {}); // this.#pollActive(); // }; // func (foundry *Foundry) SendPageDataRequest(page string) error { // msgToSend := &wsComm{code: CodesRespToReq[RespCreateSessionCode], id: foundry.ws.currWsId, msgJson: fmt.Sprintf("[\"%s\"]", WsTypeData[page])} // foundry.ws.currWsId++ // log.Printf("send: %s\n", msgToSend.toString()) // return foundry.ws.wsConn.WriteMessage(websocket.TextMessage, msgToSend.toByteSlice()) // } // func (foundry *Foundry) setUpWebSocketConnection() error { // err := foundry.wsConn.WriteMessage(websocket.TextMessage, []byte("40")) // if err != nil { // return err // } // return nil // } // func (foundry *Foundry) sendPageDataRequest(page string) error { // msgToSend := &wsComm{code: CodesRespToReq[RespCreateSessionCode], id: foundry.ws.currWsId, msgJson: fmt.Sprintf("[\"%s\"]", WsTypeData[page])} // foundry.ws.currWsId++ // log.Printf("send: %s\n", msgToSend.toString()) // return foundry.ws.wsConn.WriteMessage(websocket.TextMessage, msgToSend.toByteSlice()) // }