From 5bb592ea8a1713cd8fd7e87a834e17d6c10a2961 Mon Sep 17 00:00:00 2001 From: lbenedar Date: Mon, 13 Apr 2026 17:40:59 +0300 Subject: [PATCH] add reconnect to websocket, add get world json object --- cmd/api/handlers.go | 11 +-- cmd/api/healthcheck.go | 1 + cmd/api/main.go | 9 ++- cmd/api/server.go | 2 +- internal/foundry/actions/session.go | 29 +++++++- internal/foundry/foundry.go | 51 +++++++++++--- internal/foundry/requests/config.go | 48 ++++++++----- internal/foundry/requests/get_requests.go | 79 ++++++++++++++++------ internal/foundry/requests/post_requests.go | 49 ++++++++++++-- internal/foundry/transport/http.go | 61 +++++++++++++---- internal/foundry/transport/transport.go | 16 +++-- internal/foundry/transport/websocket.go | 45 ++++++++---- internal/foundry/types/channels.go | 19 ++++-- internal/foundry/types/message.go | 4 ++ 14 files changed, 321 insertions(+), 103 deletions(-) diff --git a/cmd/api/handlers.go b/cmd/api/handlers.go index dfd0610..3d0c731 100644 --- a/cmd/api/handlers.go +++ b/cmd/api/handlers.go @@ -5,22 +5,13 @@ import ( ) func (app *application) ShowText(w http.ResponseWriter, r *http.Request) { - data, err := app.foundryApp.HandleWSRequest("/join") + data, err := app.foundryApp.Test() if err != nil { app.slogger.Error("", "error", err) w.Write([]byte(err.Error())) return } - // setupData, err := models.ParseSetupModel(data) - // if err != nil { - // app.slogger.Error("", "error", err) - // w.Write([]byte(err.Error())) - // return - // } - - // fmt.Printf("JSON msg: %t\n", setupData.IsAdmin) - w.Write(data) } diff --git a/cmd/api/healthcheck.go b/cmd/api/healthcheck.go index a334750..779ece1 100644 --- a/cmd/api/healthcheck.go +++ b/cmd/api/healthcheck.go @@ -13,6 +13,7 @@ func (app *application) healthcheckHandler(w http.ResponseWriter, r *http.Reques "status": app.foundryApp.Status, "is_available": app.foundryApp.IsAvailable, }, + "config": app.foundryApp.GetHTTP(), } err := app.writeJSON(w, http.StatusOK, env, nil) if err != nil { diff --git a/cmd/api/main.go b/cmd/api/main.go index 15cb1d1..e065af9 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -6,6 +6,7 @@ import ( "flag" "log" "log/slog" + "net/http/cookiejar" "os" "time" @@ -84,7 +85,7 @@ func (app *application) parseFlags() *requests.FoundryHttpRequest { var mode string flag.StringVar(&mode, "service_mode", "api", "Type of service mode(api|discord|tg)") - foundryHttpData := requests.FoundryHttpRequest{SessionID: ""} + foundryHttpData := requests.FoundryHttpRequest{SessionID: nil} flag.StringVar(&foundryHttpData.Host, "foundry_host", "127.0.0.1", "Address to connect to Foundry") flag.StringVar(&foundryHttpData.Password, "foundry_pass", "", "Password to connect to Foundry") @@ -112,6 +113,12 @@ func main() { app := application{foundryApp: &foundry.FoundryApi{}} foundryHttpData := app.parseFlags() + jar, err := cookiejar.New(nil) + if err != nil { + app.slogger.Error("Error", "text", err.Error()) + return + } + foundryHttpData.Jar = jar app.slogger.Info("", "dsn", app.cfg.db.dsn) diff --git a/cmd/api/server.go b/cmd/api/server.go index f376959..3d16b64 100644 --- a/cmd/api/server.go +++ b/cmd/api/server.go @@ -55,7 +55,7 @@ func (app *application) serve() error { } app.slogger.Info("Stopped server", "addr", srv.Addr) - err = <-shutdownError + // err = <-shutdownError if err != nil { return err } diff --git a/internal/foundry/actions/session.go b/internal/foundry/actions/session.go index fd2e99a..b2efd9b 100644 --- a/internal/foundry/actions/session.go +++ b/internal/foundry/actions/session.go @@ -6,13 +6,24 @@ import ( ) type WsSessionMsg struct { - SessionId string `json:"sessionId"` - UserId *string `json:"userId,omitempty"` + SessionId string `json:"sessionId"` + UserId string `json:"userId,omitempty"` } func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.FoundryStatus) error { if status.IsActive { - tr.Logger.Warn("World is started. Please, return to setup page to fully initialize database") + tr.Logger.Info("Session msg", "userid", msg.UserId) + if msg.UserId == "" { + err := tr.LogInToWorld() + if err != nil { + return err + } + tr.Logger.Info("World is started. Succesfully logged into world") + close(tr.ReadChan.Reconnect()) + return nil + } + // tr.Logger.Warn("World is started. Please, return to setup page to fully initialize database") + // go msg.OnActiveWorld(tr) return nil } @@ -24,3 +35,15 @@ func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.Fou go tr.FillDBWithFoundryData() return nil } + +func (msg WsSessionMsg) OnActiveWorld(tr *transport.FoundryTransport) error { + wsMsg := types.NewWsMessage("world", tr.CurrWsId) + tr.CurrWsId++ + + answer, err := tr.HandleWebsocketRequest(wsMsg) + if err != nil { + return err + } + tr.Logger.Info("World data", "answer", string(answer)) + return nil +} diff --git a/internal/foundry/foundry.go b/internal/foundry/foundry.go index a220bdd..ca838b3 100644 --- a/internal/foundry/foundry.go +++ b/internal/foundry/foundry.go @@ -3,18 +3,19 @@ package foundry import ( "context" "errors" - "log/slog" "sync" "time" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/actions" + "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/transport" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types" ) var ( - ListenIsDone = errors.New("Listen for websocket data in foundry is stopped") - ChannelIsClosed = errors.New("Channel is closed") + ListenIsDone = errors.New("Listen for websocket data in foundry is stopped") + ReconnectToWebSocket = errors.New("Reconnect to websocket") + ChannelIsClosed = errors.New("Channel is closed") CloseTimeoutExceed = errors.New("Timeout of websocket close is exceed") ) @@ -24,7 +25,7 @@ type FoundryApi struct { transport *transport.FoundryTransport IsAvailable bool - Logger *slog.Logger + // Logger *slog.Logger Status types.FoundryStatus wg sync.WaitGroup } @@ -61,6 +62,7 @@ func (foundry *FoundryApi) ServeWebSocket() error { case message, ok := <-wsChannels.Msg(): if !ok { foundry.transport.Logger.Debug("Read channel is closed", "type", types.WebSocketCode) + foundry.transport.Http.SessionID = nil return ChannelIsClosed } foundry.transport.Logger.Debug("Data has been received\n", "msg", message.Code, "type", types.WebSocketCode) //, "msg", message.MsgJson) @@ -80,6 +82,7 @@ func (foundry *FoundryApi) ServeWebSocket() error { continue } + foundry.transport.Logger.Debug("RespServerChangeCode", "data", data) if data == nil { continue } @@ -100,13 +103,18 @@ func (foundry *FoundryApi) ServeWebSocket() error { if errors.As(err, &foundryErr) { if foundryErr.IsFatal { foundry.transport.CloseWebSocketConn() + foundry.transport.Http.SessionID = nil return foundryErr } foundry.transport.Logger.Warn("Got error when listening or served", "err", err.Error(), "type", foundryErr.Type, "direction", foundryErr.Direction) } case <-wsChannels.Done(): foundry.transport.CloseWebSocketConn() + foundry.transport.Http.SessionID = nil return ListenIsDone + case <-wsChannels.Reconnect(): + foundry.transport.CloseWebSocketConn() + return ReconnectToWebSocket } } } @@ -151,11 +159,11 @@ func (foundry *FoundryApi) ConnectToWebSocket() (bool, error) { if err != nil { return false, err } - } - err = foundry.transport.ConnectToFoundry() - if err != nil { - return false, err + err = foundry.transport.ConnectToFoundry() + if err != nil { + return false, err + } } err = foundry.transport.InitWebSocketConnection() @@ -184,6 +192,16 @@ func (foundry *FoundryApi) StartListenFoundry() { for { ok, err := foundry.ConnectToWebSocket() if err != nil { + if errors.Is(err, ReconnectToWebSocket) { + if foundry.transport.ReconnectNum >= foundry.transport.ReconnectNumMax { + return + } + time.Sleep(foundry.transport.ReconnectTimeout) + foundry.transport.ReconnectNum++ + foundry.transport.Logger.Info("Reconnecting to WebSocket", "times", foundry.transport.ReconnectNum) + continue + } + foundry.transport.Logger.Error("Error raised", "err", err.Error()) if ok { @@ -199,3 +217,20 @@ func (foundry *FoundryApi) StartListenFoundry() { } }) } + +func (foundry *FoundryApi) Test() ([]byte, error) { + wsMsg := types.NewWsMessage("world", foundry.transport.CurrWsId) + foundry.transport.CurrWsId++ + + answer, err := foundry.transport.HandleWebsocketRequest(wsMsg) + if err != nil { + return nil, err + } + // foundry.transport.Logger.Info("World data", "answer", string(answer)) + return answer, nil +} + +// TODO: remove +func (foundry *FoundryApi) GetHTTP() *requests.FoundryHttpRequest { + return foundry.transport.Http +} diff --git a/internal/foundry/requests/config.go b/internal/foundry/requests/config.go index aaab9f1..4087f83 100644 --- a/internal/foundry/requests/config.go +++ b/internal/foundry/requests/config.go @@ -4,7 +4,8 @@ import ( "errors" "fmt" "net/http" - "strings" + "net/http/cookiejar" + "net/url" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/db" ) @@ -21,6 +22,7 @@ const ( PlayersPath = "/players" SetupPath = "/setup" UpdatePath = "/update" + GamePath = "/game" SocketPath = "/socket.io" ) @@ -49,23 +51,20 @@ var PathToWorldState = map[string]db.StateType{ type FoundryHttpRequest struct { Host string Password string - SessionID string + SessionID *string + Jar *cookiejar.Jar } -func (conf *FoundryHttpRequest) SetSessionTokenFromHeader(resp http.Header) (bool, error) { - setCookieHeader := resp.Get("Set-Cookie") - if setCookieHeader == "" { - return false, nil +func (conf *FoundryHttpRequest) SetSessionTokenFromHeader() (bool, error) { + u, err := url.Parse(fmt.Sprintf("http://%s", conf.Host)) + if err != nil { + return false, err } - for value := range strings.SplitSeq(setCookieHeader, ";") { - if strings.Contains(value, "session") { - sessionCookie := strings.Split(value, "=") - if len(sessionCookie) != 2 { - return false, ErrorSidWrongFormat - } - - conf.SessionID = sessionCookie[1] + cookies := conf.Jar.Cookies(u) + for i := range cookies { + if cookies[i].Name == "session" { + conf.SessionID = &cookies[i].Value return true, nil } } @@ -73,15 +72,30 @@ func (conf *FoundryHttpRequest) SetSessionTokenFromHeader(resp http.Header) (boo return false, nil } -func (conf *FoundryHttpRequest) GetRequestHeader() *http.Header { +func (conf *FoundryHttpRequest) GetRequestHeader(path string) *http.Header { header := http.Header{} - header.Set("Cookie", fmt.Sprintf("session=%s", conf.SessionID)) + header.Set("Cookie", fmt.Sprintf("session=%s", *conf.SessionID)) header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") header.Set("Connection", "keep-alive") header.Set("Content-Type", "application/x-www-form-urlencoded") header.Set("Host", conf.Host) header.Set("Origin", fmt.Sprintf("http://%s", conf.Host)) - header.Set("Referer", fmt.Sprintf("http://%s%s", conf.Host, AuthPath)) + header.Set("Referer", fmt.Sprintf("http://%s%s", conf.Host, path)) + + return &header +} + +func (conf *FoundryHttpRequest) GetRequestHeaderJson(path string) *http.Header { + header := http.Header{} + header.Set("Accept", "*/*") + header.Set("Accept-Encoding", "gzip, deflate, br, zstd") + header.Set("Connection", "keep-alive") + header.Set("Content-Type", "application/json") + header.Set("Cookie", fmt.Sprintf("session=%s", *conf.SessionID)) + header.Set("Host", conf.Host) + header.Set("Origin", fmt.Sprintf("http://%s", conf.Host)) + header.Set("Priority", "u=0") + header.Set("Referer", fmt.Sprintf("http://%s%s", conf.Host, path)) return &header } diff --git a/internal/foundry/requests/get_requests.go b/internal/foundry/requests/get_requests.go index aab393d..f5a1ad9 100644 --- a/internal/foundry/requests/get_requests.go +++ b/internal/foundry/requests/get_requests.go @@ -11,41 +11,57 @@ import ( ) func (conf *FoundryHttpRequest) GetSessionId() error { - getResp, err := http.Get(fmt.Sprintf("http://%s%s", conf.Host, AuthPath)) + path := fmt.Sprintf("http://%s%s", conf.Host, AuthPath) + + req, err := http.NewRequest("GET", path, nil) if err != nil { return err } - _, err = conf.SetSessionTokenFromHeader(getResp.Header) + client := &http.Client{Jar: conf.Jar} + _, err = client.Do(req) + if err != nil { + return err + } + + fmt.Printf("%v\n", conf.Jar) + + _, err = conf.SetSessionTokenFromHeader() return err } -func (conf *FoundryHttpRequest) GetSessionToken() (bool, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", conf.Host, AuthPath), nil) - if err != nil { - return false, err - } +// func (conf *FoundryHttpRequest) GetSessionToken() (bool, error) { +// req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", conf.Host, AuthPath), nil) +// if err != nil { +// return false, err +// } - header := http.Header{} - header.Set("Cookie", fmt.Sprintf("session=%s", conf.SessionID)) - header.Set("Connection", "keep-alive") - header.Set("Host", conf.Host) - header.Set("Origin", fmt.Sprintf("http://%s", conf.Host)) - header.Set("Referer", fmt.Sprintf("http://%s%s", conf.Host, AuthPath)) +// header := http.Header{} +// header.Set("Cookie", fmt.Sprintf("session=%s", conf.SessionID)) +// header.Set("Connection", "keep-alive") +// header.Set("Host", conf.Host) +// header.Set("Origin", fmt.Sprintf("http://%s", conf.Host)) +// header.Set("Referer", fmt.Sprintf("http://%s%s", conf.Host, AuthPath)) - req.Header = header - client := &http.Client{} +// req.Header = header +// client := &http.Client{Jar: conf.Jar} - resp, err := client.Do(req) - if err != nil { - return false, err - } +// resp, err := client.Do(req) +// if err != nil { +// return false, err +// } - return conf.SetSessionTokenFromHeader(resp.Header) -} +// return conf.SetSessionTokenFromHeader(resp.Header) +// } func (conf *FoundryHttpRequest) GetStatus() (*json_model.Status, error) { - getResp, err := http.Get(fmt.Sprintf("http://%s/api/status", conf.Host)) + req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/api/status", conf.Host), nil) + if err != nil { + return nil, err + } + + client := &http.Client{Jar: conf.Jar} + getResp, err := client.Do(req) if err != nil { return nil, err } @@ -64,3 +80,22 @@ func (conf *FoundryHttpRequest) GetStatus() (*json_model.Status, error) { } return &status, nil } + +func (conf *FoundryHttpRequest) GetGame() (bool, error) { + req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", conf.Host, GamePath), nil) + if err != nil { + return false, err + } + + header := conf.GetRequestHeader(GamePath) + + req.Header = *header + client := &http.Client{Jar: conf.Jar} + + _, err = client.Do(req) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/internal/foundry/requests/post_requests.go b/internal/foundry/requests/post_requests.go index eeb2e59..3a67843 100644 --- a/internal/foundry/requests/post_requests.go +++ b/internal/foundry/requests/post_requests.go @@ -2,6 +2,7 @@ package requests import ( "bytes" + "encoding/json" "fmt" "net/http" "net/url" @@ -17,12 +18,48 @@ func (conf *FoundryHttpRequest) PostAuthenticationData() (*http.Response, error) return nil, err } - header := conf.GetRequestHeader() + header := conf.GetRequestHeader(AuthPath) header.Set("Content-Length", fmt.Sprintf("%d", len(authData.Encode()))) req.Header = header.Clone() - client := &http.Client{} + client := &http.Client{Jar: conf.Jar} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + return resp, nil +} + +func (conf *FoundryHttpRequest) PostJoinWorld(userId, password string) (*http.Response, error) { + data := struct { + UserId string `json:"userid"` + Password string `json:"password"` + Action string `json:"action"` + Session string `json:"session"` + }{ + UserId: userId, + Password: password, + Action: "join", + Session: *conf.SessionID, + } + + byteData, err := json.Marshal(data) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("POST", fmt.Sprintf("http://%s%s", conf.Host, JoinPath), bytes.NewBuffer(byteData)) + if err != nil { + return nil, err + } + + header := conf.GetRequestHeaderJson(JoinPath) + header.Set("Content-Length", fmt.Sprintf("%d", len(byteData))) + + req.Header = header.Clone() + + client := &http.Client{Jar: conf.Jar} resp, err := client.Do(req) if err != nil { return nil, err @@ -40,12 +77,12 @@ func (conf *FoundryHttpRequest) PostLaunchWorld(world string) (*http.Response, e return nil, err } - header := conf.GetRequestHeader() + header := conf.GetRequestHeader(SetupPath) header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode()))) req.Header = header.Clone() - client := &http.Client{} + client := &http.Client{Jar: conf.Jar} resp, err := client.Do(req) if err != nil { return nil, err @@ -62,12 +99,12 @@ func (conf *FoundryHttpRequest) PostReturnToSetup() (*http.Response, error) { return nil, err } - header := conf.GetRequestHeader() + header := conf.GetRequestHeader(JoinPath) header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode()))) req.Header = header.Clone() - client := &http.Client{} + client := &http.Client{Jar: conf.Jar} resp, err := client.Do(req) if err != nil { return nil, err diff --git a/internal/foundry/transport/http.go b/internal/foundry/transport/http.go index d54b070..ff28483 100644 --- a/internal/foundry/transport/http.go +++ b/internal/foundry/transport/http.go @@ -37,14 +37,7 @@ func (tr *FoundryTransport) LaunchWorld(worldName string) error { } func (tr *FoundryTransport) ConnectToFoundry() error { - var err error - - ok, err := tr.Http.GetSessionToken() - if err != nil { - return err - } - - if tr.Http.Password != "" && !ok { + if tr.Http.Password != "" { err := tr.Authenticate() if err != nil { return err @@ -56,7 +49,7 @@ func (tr *FoundryTransport) ConnectToFoundry() error { } func (tr *FoundryTransport) Authenticate() error { - if tr.Http.SessionID == "" { + if tr.Http.SessionID == nil { err := tr.Http.GetSessionId() if err != nil { return err @@ -74,13 +67,13 @@ func (tr *FoundryTransport) Authenticate() error { return err } - return tr.CheckAuthRespAnswer(resp.Body, contentLen) + return tr.CheckAuthResponse(resp.Body, contentLen) } -func (tr *FoundryTransport) CheckAuthRespAnswer(r io.Reader, respLength int) error { +func (tr *FoundryTransport) CheckAuthResponse(body io.Reader, respLength int) error { authBody := make([]byte, respLength) - _, err := r.Read(authBody) + _, err := body.Read(authBody) if err != nil && err != io.EOF { return err } @@ -92,8 +85,50 @@ func (tr *FoundryTransport) CheckAuthRespAnswer(r io.Reader, respLength int) err return nil } +func (tr *FoundryTransport) LogInToWorld() error { + if tr.Http.SessionID == nil { + err := tr.Http.GetSessionId() + if err != nil { + return err + } + } + + // TODO: make userid and password from tr object + resp, err := tr.Http.PostJoinWorld("YpMHZge0dxBZS5Cm", "") + if err != nil { + return err + } + defer resp.Body.Close() + + contentLen, err := strconv.Atoi(resp.Header.Get("Content-Length")) + if err != nil { + return err + } + + return tr.CheckLoginResponse(resp.Body, contentLen) + + // {"userid":"YpMHZge0dxBZS5Cm","password":"","action":"join"} +} + +func (tr *FoundryTransport) CheckLoginResponse(body io.Reader, respLength int) error { + joinBody := make([]byte, respLength) + + _, err := body.Read(joinBody) + if err != nil && err != io.EOF { + return err + } + + tr.Logger.Debug("Received response", "response", string(joinBody)) + + if !strings.Contains(string(joinBody), "\"status\":\"success\"") { + return ErrorAuthPassWrong + } + // tr.IsAuth = true + return nil +} + func (tr *FoundryTransport) HasSessionId() bool { - return tr.Http.SessionID != "" + return tr.Http.SessionID != nil } func (tr *FoundryTransport) InitSessionId() error { diff --git a/internal/foundry/transport/transport.go b/internal/foundry/transport/transport.go index 767bd02..d7a7ef7 100644 --- a/internal/foundry/transport/transport.go +++ b/internal/foundry/transport/transport.go @@ -19,8 +19,12 @@ type FoundryTransport struct { ReadChan types.ReadChannels ExchangeChan types.ExchangeChannels - Http requests.FoundryHttpRequest - IsAuth bool + Http *requests.FoundryHttpRequest + ReconnectTimeout time.Duration + ReconnectNum int + ReconnectNumMax int + IsAuth bool + IsLogin bool Models *db.Models IsDbInit bool @@ -36,8 +40,12 @@ func NewFoundryTransport(dbConn *sql.DB, logger *slog.Logger, httpConfig *reques ProgressMsg: map[string]chan struct{}{}, }, - Http: *httpConfig, - IsAuth: false, + Http: httpConfig, + ReconnectTimeout: 500 * time.Millisecond, + IsAuth: false, + IsLogin: false, + ReconnectNumMax: 1, + ReconnectNum: 0, Models: db.NewModels(dbConn), IsDbInit: false, diff --git a/internal/foundry/transport/websocket.go b/internal/foundry/transport/websocket.go index c849872..4273e05 100644 --- a/internal/foundry/transport/websocket.go +++ b/internal/foundry/transport/websocket.go @@ -1,7 +1,6 @@ package transport import ( - "context" "fmt" "net/http" "net/url" @@ -18,20 +17,39 @@ func (tr *FoundryTransport) InitWebSocketConnection() error { } query := url.Values{} - query.Add("session", tr.Http.SessionID) + query.Add("session", *tr.Http.SessionID) query.Add("EIO", "4") query.Add("transport", "websocket") u := url.URL{Scheme: "ws", Host: tr.Http.Host, Path: fmt.Sprintf("%s/", requests.SocketPath), RawQuery: query.Encode()} wsHeader := http.Header{} - wsHeader.Set("Cookie", fmt.Sprintf("session=%s", tr.Http.SessionID)) + wsHeader.Set("Cookie", fmt.Sprintf("session=%s", *tr.Http.SessionID)) + wsHeader.Set("Pragma", "no-cache") + wsHeader.Set("Cache-Control", "no-cache") - wsConn, _, err := websocket.DefaultDialer.Dial(u.String(), wsHeader) + dialer := websocket.DefaultDialer + dialer.ReadBufferSize = 128 * 1024 * 1024 + dialer.WriteBufferSize = 128 * 1024 * 1024 + // dialer.Jar = tr.Http.Jar + + // ur, err := url.Parse(fmt.Sprintf("http://%s", tr.Http.Host)) + // if err != nil { + // return err + // } + // fmt.Printf("TEST:%v:%v\n", u.String(), dialer.Jar.Cookies(&u)) + wsConn, resp, err := dialer.Dial(u.String(), wsHeader) if err != nil { return err } + cookies := resp.Cookies() + for i := range cookies { + fmt.Printf("TEST%d: %v\n", i, cookies[i]) + } + // fmt.Printf("TEST1: %v\n") + // fmt.Printf("TEST2: %v\n", wsHeader) + tr.WsConn = wsConn tr.CurrWsId = 0 tr.Logger.Info("Successefully connected to Foundry Websocket") @@ -39,6 +57,7 @@ func (tr *FoundryTransport) InitWebSocketConnection() error { } func (tr *FoundryTransport) HandleWebsocketRequest(msg *types.WsMessage) ([]byte, error) { + tr.Logger.Debug("WS: Data has been send\n", "msg", msg.ToString()) err := tr.WsConn.WriteMessage(websocket.TextMessage, msg.ToByteSlice()) if err != nil { return nil, err @@ -52,8 +71,8 @@ func (tr *FoundryTransport) HandleWebsocketRequest(msg *types.WsMessage) ([]byte } func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() + // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + // defer cancel() for { select { @@ -64,12 +83,12 @@ func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) { } tr.CloseMsgChannel(id, 0) return msg, nil - case <-ctx.Done(): - err := ctx.Err() - if err != nil { - return nil, err - } - return nil, ErrorTimeout + // case <-ctx.Done(): + // err := ctx.Err() + // if err != nil { + // return nil, err + // } + // return nil, ErrorTimeout default: time.Sleep(5 * time.Microsecond) } @@ -83,6 +102,8 @@ func (tr *FoundryTransport) ListenWebSocket() { select { case <-tr.ReadChan.Done(): return + case <-tr.ReadChan.Reconnect(): + return default: tr.ReadChan.Err() <- &types.FoundryError{Direction: types.ReaderCode, Err: err, Type: types.WebSocketCode, IsFatal: true} } diff --git a/internal/foundry/types/channels.go b/internal/foundry/types/channels.go index 005fba7..e561088 100644 --- a/internal/foundry/types/channels.go +++ b/internal/foundry/types/channels.go @@ -30,9 +30,10 @@ func (channels *ExchangeChannels) Close() { } type ReadChannels struct { - done chan struct{} - msg chan *WsMessage - err chan error + done chan struct{} + reconnect chan struct{} + msg chan *WsMessage + err chan error } func (channels ReadChannels) Err() chan error { @@ -47,6 +48,10 @@ func (channels ReadChannels) Done() chan struct{} { return channels.done } +func (channels ReadChannels) Reconnect() chan struct{} { + return channels.reconnect +} + func CloseChannel[V any](channel chan V) { select { case _, ok := <-channel: @@ -62,12 +67,14 @@ func (channels *ReadChannels) Close() { CloseChannel(channels.done) CloseChannel(channels.err) CloseChannel(channels.msg) + CloseChannel(channels.reconnect) } func InitWsChannels() *ReadChannels { return &ReadChannels{ - done: make(chan struct{}), - err: make(chan error, 10), - msg: make(chan *WsMessage, 10), + done: make(chan struct{}), + err: make(chan error, 10), + msg: make(chan *WsMessage, 10), + reconnect: make(chan struct{}), } } diff --git a/internal/foundry/types/message.go b/internal/foundry/types/message.go index 4fccab4..ec4f8b2 100644 --- a/internal/foundry/types/message.go +++ b/internal/foundry/types/message.go @@ -81,3 +81,7 @@ func ParseWsRespMessage(msg string, requestCodes []string) (*WsMessage, error) { func NewWsMessageByPage(page string, currWsId int) *WsMessage { return &WsMessage{Code: CodesRespToReq[RespServerChangeCode], Id: currWsId, MsgJson: fmt.Sprintf("[\"%s\"]", requests.WsTypeData[page])} } + +func NewWsMessage(msg string, currWsId int) *WsMessage { + return &WsMessage{Code: CodesRespToReq[RespServerChangeCode], Id: currWsId, MsgJson: fmt.Sprintf("[\"%s\"]", msg)} +}