package transport import ( "fmt" "net/http" "net/url" "time" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/requests" "gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types" "github.com/gorilla/websocket" ) func (tr *FoundryTransport) InitWebSocketConnection() error { if !tr.IsAuth { return ErrorNotAuth } query := url.Values{} 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("Pragma", "no-cache") wsHeader.Set("Cache-Control", "no-cache") dialer := websocket.DefaultDialer dialer.ReadBufferSize = 128 * 1024 * 1024 dialer.WriteBufferSize = 128 * 1024 * 1024 wsConn, _, err := dialer.Dial(u.String(), wsHeader) if err != nil { return err } tr.WsConn = wsConn tr.CurrWsId = 0 tr.Logger.Info("Successefully connected to Foundry Websocket") return nil } 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 } data, err := tr.ReceiveMessage(msg.Id) if err != nil { return nil, err } return data, nil } func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) { // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // defer cancel() for { select { case msg, ok := <-tr.ExchangeChan.Msgs[id]: if !ok { time.Sleep(5 * time.Microsecond) continue } tr.CloseMsgChannel(id, 0) return msg, nil // case <-ctx.Done(): // err := ctx.Err() // if err != nil { // return nil, err // } // return nil, ErrorTimeout default: time.Sleep(5 * time.Microsecond) } } } func (tr *FoundryTransport) ListenWebSocket() { for { _, message, err := tr.WsConn.ReadMessage() if err != nil { 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} } return } data, err := types.ParseWsRespMessage(string(message), types.RequestCodes) if err != nil { tr.ReadChan.Err() <- &types.FoundryError{Direction: types.ReaderCode, Err: err, Type: types.WebSocketCode} continue } tr.ReadChan.Msg() <- data } } func (tr *FoundryTransport) ConnectToWorld() error { err := tr.LogInToWorld() if err != nil { return err } tr.Logger.Info("World is started. Succesfully logged into world") tr.LoggedInChan = make(chan bool) close(tr.ReadChan.Reconnect()) val, ok := <-tr.LoggedInChan if !ok { return ErrorChannelIsClosed } if !val { return ErrorUserIsNotConnected } return nil } func (tr *FoundryTransport) SendOnlyCodeRequest(code string) error { tr.Logger.Debug("WS: Data has been send\n", "msg", types.CodesRespToReq[code]) return tr.WsConn.WriteMessage(websocket.TextMessage, []byte(types.CodesRespToReq[code])) } func (tr *FoundryTransport) GetJsonDataByType(stateType string) ([]byte, error) { msg := types.NewWsMessageByPage(stateType, tr.CurrWsId) tr.CurrWsId++ return tr.HandleWebsocketRequest(msg) } func (tr *FoundryTransport) GetJsonData(msg string) ([]byte, error) { wsMsg := types.NewWsMessage(msg, tr.CurrWsId) tr.CurrWsId++ return tr.HandleWebsocketRequest(wsMsg) } func (tr *FoundryTransport) CloseWebSocketConn() error { tr.Logger.Debug("Websocket has been closed") return tr.WsConn.Close() }