233 lines
5.4 KiB
Go
233 lines
5.4 KiB
Go
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<void>}
|
|
// */
|
|
// 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())
|
|
// }
|