add reconnect to websocket, add get world json object
This commit is contained in:
@@ -5,22 +5,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (app *application) ShowText(w http.ResponseWriter, r *http.Request) {
|
func (app *application) ShowText(w http.ResponseWriter, r *http.Request) {
|
||||||
data, err := app.foundryApp.HandleWSRequest("/join")
|
data, err := app.foundryApp.Test()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.slogger.Error("", "error", err)
|
app.slogger.Error("", "error", err)
|
||||||
w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
return
|
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)
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ func (app *application) healthcheckHandler(w http.ResponseWriter, r *http.Reques
|
|||||||
"status": app.foundryApp.Status,
|
"status": app.foundryApp.Status,
|
||||||
"is_available": app.foundryApp.IsAvailable,
|
"is_available": app.foundryApp.IsAvailable,
|
||||||
},
|
},
|
||||||
|
"config": app.foundryApp.GetHTTP(),
|
||||||
}
|
}
|
||||||
err := app.writeJSON(w, http.StatusOK, env, nil)
|
err := app.writeJSON(w, http.StatusOK, env, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"net/http/cookiejar"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ func (app *application) parseFlags() *requests.FoundryHttpRequest {
|
|||||||
var mode string
|
var mode string
|
||||||
flag.StringVar(&mode, "service_mode", "api", "Type of service mode(api|discord|tg)")
|
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.Host, "foundry_host", "127.0.0.1", "Address to connect to Foundry")
|
||||||
flag.StringVar(&foundryHttpData.Password, "foundry_pass", "", "Password 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{}}
|
app := application{foundryApp: &foundry.FoundryApi{}}
|
||||||
|
|
||||||
foundryHttpData := app.parseFlags()
|
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)
|
app.slogger.Info("", "dsn", app.cfg.db.dsn)
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (app *application) serve() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.slogger.Info("Stopped server", "addr", srv.Addr)
|
app.slogger.Info("Stopped server", "addr", srv.Addr)
|
||||||
err = <-shutdownError
|
// err = <-shutdownError
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WsSessionMsg struct {
|
type WsSessionMsg struct {
|
||||||
SessionId string `json:"sessionId"`
|
SessionId string `json:"sessionId"`
|
||||||
UserId *string `json:"userId,omitempty"`
|
UserId string `json:"userId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.FoundryStatus) error {
|
func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.FoundryStatus) error {
|
||||||
if status.IsActive {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,3 +35,15 @@ func (msg WsSessionMsg) Action(tr *transport.FoundryTransport, status *types.Fou
|
|||||||
go tr.FillDBWithFoundryData()
|
go tr.FillDBWithFoundryData()
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,18 +3,19 @@ package foundry
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"log/slog"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/actions"
|
"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/transport"
|
||||||
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types"
|
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ListenIsDone = errors.New("Listen for websocket data in foundry is stopped")
|
ListenIsDone = errors.New("Listen for websocket data in foundry is stopped")
|
||||||
ChannelIsClosed = errors.New("Channel is closed")
|
ReconnectToWebSocket = errors.New("Reconnect to websocket")
|
||||||
|
ChannelIsClosed = errors.New("Channel is closed")
|
||||||
|
|
||||||
CloseTimeoutExceed = errors.New("Timeout of websocket close is exceed")
|
CloseTimeoutExceed = errors.New("Timeout of websocket close is exceed")
|
||||||
)
|
)
|
||||||
@@ -24,7 +25,7 @@ type FoundryApi struct {
|
|||||||
transport *transport.FoundryTransport
|
transport *transport.FoundryTransport
|
||||||
IsAvailable bool
|
IsAvailable bool
|
||||||
|
|
||||||
Logger *slog.Logger
|
// Logger *slog.Logger
|
||||||
Status types.FoundryStatus
|
Status types.FoundryStatus
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
@@ -61,6 +62,7 @@ func (foundry *FoundryApi) ServeWebSocket() error {
|
|||||||
case message, ok := <-wsChannels.Msg():
|
case message, ok := <-wsChannels.Msg():
|
||||||
if !ok {
|
if !ok {
|
||||||
foundry.transport.Logger.Debug("Read channel is closed", "type", types.WebSocketCode)
|
foundry.transport.Logger.Debug("Read channel is closed", "type", types.WebSocketCode)
|
||||||
|
foundry.transport.Http.SessionID = nil
|
||||||
return ChannelIsClosed
|
return ChannelIsClosed
|
||||||
}
|
}
|
||||||
foundry.transport.Logger.Debug("Data has been received\n", "msg", message.Code, "type", types.WebSocketCode) //, "msg", message.MsgJson)
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foundry.transport.Logger.Debug("RespServerChangeCode", "data", data)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -100,13 +103,18 @@ func (foundry *FoundryApi) ServeWebSocket() error {
|
|||||||
if errors.As(err, &foundryErr) {
|
if errors.As(err, &foundryErr) {
|
||||||
if foundryErr.IsFatal {
|
if foundryErr.IsFatal {
|
||||||
foundry.transport.CloseWebSocketConn()
|
foundry.transport.CloseWebSocketConn()
|
||||||
|
foundry.transport.Http.SessionID = nil
|
||||||
return foundryErr
|
return foundryErr
|
||||||
}
|
}
|
||||||
foundry.transport.Logger.Warn("Got error when listening or served", "err", err.Error(), "type", foundryErr.Type, "direction", foundryErr.Direction)
|
foundry.transport.Logger.Warn("Got error when listening or served", "err", err.Error(), "type", foundryErr.Type, "direction", foundryErr.Direction)
|
||||||
}
|
}
|
||||||
case <-wsChannels.Done():
|
case <-wsChannels.Done():
|
||||||
foundry.transport.CloseWebSocketConn()
|
foundry.transport.CloseWebSocketConn()
|
||||||
|
foundry.transport.Http.SessionID = nil
|
||||||
return ListenIsDone
|
return ListenIsDone
|
||||||
|
case <-wsChannels.Reconnect():
|
||||||
|
foundry.transport.CloseWebSocketConn()
|
||||||
|
return ReconnectToWebSocket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,11 +159,11 @@ func (foundry *FoundryApi) ConnectToWebSocket() (bool, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err = foundry.transport.ConnectToFoundry()
|
err = foundry.transport.ConnectToFoundry()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = foundry.transport.InitWebSocketConnection()
|
err = foundry.transport.InitWebSocketConnection()
|
||||||
@@ -184,6 +192,16 @@ func (foundry *FoundryApi) StartListenFoundry() {
|
|||||||
for {
|
for {
|
||||||
ok, err := foundry.ConnectToWebSocket()
|
ok, err := foundry.ConnectToWebSocket()
|
||||||
if err != nil {
|
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())
|
foundry.transport.Logger.Error("Error raised", "err", err.Error())
|
||||||
|
|
||||||
if ok {
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"net/http/cookiejar"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/db"
|
"gitea.local.lab/Lbenedar/foundry_helper_service/internal/foundry/models/db"
|
||||||
)
|
)
|
||||||
@@ -21,6 +22,7 @@ const (
|
|||||||
PlayersPath = "/players"
|
PlayersPath = "/players"
|
||||||
SetupPath = "/setup"
|
SetupPath = "/setup"
|
||||||
UpdatePath = "/update"
|
UpdatePath = "/update"
|
||||||
|
GamePath = "/game"
|
||||||
|
|
||||||
SocketPath = "/socket.io"
|
SocketPath = "/socket.io"
|
||||||
)
|
)
|
||||||
@@ -49,23 +51,20 @@ var PathToWorldState = map[string]db.StateType{
|
|||||||
type FoundryHttpRequest struct {
|
type FoundryHttpRequest struct {
|
||||||
Host string
|
Host string
|
||||||
Password string
|
Password string
|
||||||
SessionID string
|
SessionID *string
|
||||||
|
Jar *cookiejar.Jar
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *FoundryHttpRequest) SetSessionTokenFromHeader(resp http.Header) (bool, error) {
|
func (conf *FoundryHttpRequest) SetSessionTokenFromHeader() (bool, error) {
|
||||||
setCookieHeader := resp.Get("Set-Cookie")
|
u, err := url.Parse(fmt.Sprintf("http://%s", conf.Host))
|
||||||
if setCookieHeader == "" {
|
if err != nil {
|
||||||
return false, nil
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for value := range strings.SplitSeq(setCookieHeader, ";") {
|
cookies := conf.Jar.Cookies(u)
|
||||||
if strings.Contains(value, "session") {
|
for i := range cookies {
|
||||||
sessionCookie := strings.Split(value, "=")
|
if cookies[i].Name == "session" {
|
||||||
if len(sessionCookie) != 2 {
|
conf.SessionID = &cookies[i].Value
|
||||||
return false, ErrorSidWrongFormat
|
|
||||||
}
|
|
||||||
|
|
||||||
conf.SessionID = sessionCookie[1]
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,15 +72,30 @@ func (conf *FoundryHttpRequest) SetSessionTokenFromHeader(resp http.Header) (boo
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *FoundryHttpRequest) GetRequestHeader() *http.Header {
|
func (conf *FoundryHttpRequest) GetRequestHeader(path string) *http.Header {
|
||||||
header := 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("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||||
header.Set("Connection", "keep-alive")
|
header.Set("Connection", "keep-alive")
|
||||||
header.Set("Content-Type", "application/x-www-form-urlencoded")
|
header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
header.Set("Host", conf.Host)
|
header.Set("Host", conf.Host)
|
||||||
header.Set("Origin", fmt.Sprintf("http://%s", 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
|
return &header
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,41 +11,57 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (conf *FoundryHttpRequest) GetSessionId() error {
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *FoundryHttpRequest) GetSessionToken() (bool, error) {
|
// func (conf *FoundryHttpRequest) GetSessionToken() (bool, error) {
|
||||||
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", conf.Host, AuthPath), nil)
|
// req, err := http.NewRequest("GET", fmt.Sprintf("http://%s%s", conf.Host, AuthPath), nil)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return false, err
|
// return false, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
header := 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("Connection", "keep-alive")
|
// header.Set("Connection", "keep-alive")
|
||||||
header.Set("Host", conf.Host)
|
// header.Set("Host", conf.Host)
|
||||||
header.Set("Origin", fmt.Sprintf("http://%s", 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, AuthPath))
|
||||||
|
|
||||||
req.Header = header
|
// req.Header = header
|
||||||
client := &http.Client{}
|
// client := &http.Client{Jar: conf.Jar}
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
// resp, err := client.Do(req)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return false, err
|
// return false, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
return conf.SetSessionTokenFromHeader(resp.Header)
|
// return conf.SetSessionTokenFromHeader(resp.Header)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (conf *FoundryHttpRequest) GetStatus() (*json_model.Status, error) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -64,3 +80,22 @@ func (conf *FoundryHttpRequest) GetStatus() (*json_model.Status, error) {
|
|||||||
}
|
}
|
||||||
return &status, nil
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package requests
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -17,12 +18,48 @@ func (conf *FoundryHttpRequest) PostAuthenticationData() (*http.Response, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
header := conf.GetRequestHeader()
|
header := conf.GetRequestHeader(AuthPath)
|
||||||
header.Set("Content-Length", fmt.Sprintf("%d", len(authData.Encode())))
|
header.Set("Content-Length", fmt.Sprintf("%d", len(authData.Encode())))
|
||||||
|
|
||||||
req.Header = header.Clone()
|
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)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -40,12 +77,12 @@ func (conf *FoundryHttpRequest) PostLaunchWorld(world string) (*http.Response, e
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
header := conf.GetRequestHeader()
|
header := conf.GetRequestHeader(SetupPath)
|
||||||
header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode())))
|
header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode())))
|
||||||
|
|
||||||
req.Header = header.Clone()
|
req.Header = header.Clone()
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{Jar: conf.Jar}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -62,12 +99,12 @@ func (conf *FoundryHttpRequest) PostReturnToSetup() (*http.Response, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
header := conf.GetRequestHeader()
|
header := conf.GetRequestHeader(JoinPath)
|
||||||
header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode())))
|
header.Set("Content-Length", fmt.Sprintf("%d", len(launchData.Encode())))
|
||||||
|
|
||||||
req.Header = header.Clone()
|
req.Header = header.Clone()
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{Jar: conf.Jar}
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -37,14 +37,7 @@ func (tr *FoundryTransport) LaunchWorld(worldName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tr *FoundryTransport) ConnectToFoundry() error {
|
func (tr *FoundryTransport) ConnectToFoundry() error {
|
||||||
var err error
|
if tr.Http.Password != "" {
|
||||||
|
|
||||||
ok, err := tr.Http.GetSessionToken()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tr.Http.Password != "" && !ok {
|
|
||||||
err := tr.Authenticate()
|
err := tr.Authenticate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -56,7 +49,7 @@ func (tr *FoundryTransport) ConnectToFoundry() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tr *FoundryTransport) Authenticate() error {
|
func (tr *FoundryTransport) Authenticate() error {
|
||||||
if tr.Http.SessionID == "" {
|
if tr.Http.SessionID == nil {
|
||||||
err := tr.Http.GetSessionId()
|
err := tr.Http.GetSessionId()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -74,13 +67,13 @@ func (tr *FoundryTransport) Authenticate() error {
|
|||||||
return err
|
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)
|
authBody := make([]byte, respLength)
|
||||||
|
|
||||||
_, err := r.Read(authBody)
|
_, err := body.Read(authBody)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -92,8 +85,50 @@ func (tr *FoundryTransport) CheckAuthRespAnswer(r io.Reader, respLength int) err
|
|||||||
return nil
|
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 {
|
func (tr *FoundryTransport) HasSessionId() bool {
|
||||||
return tr.Http.SessionID != ""
|
return tr.Http.SessionID != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr *FoundryTransport) InitSessionId() error {
|
func (tr *FoundryTransport) InitSessionId() error {
|
||||||
|
|||||||
@@ -19,8 +19,12 @@ type FoundryTransport struct {
|
|||||||
ReadChan types.ReadChannels
|
ReadChan types.ReadChannels
|
||||||
ExchangeChan types.ExchangeChannels
|
ExchangeChan types.ExchangeChannels
|
||||||
|
|
||||||
Http requests.FoundryHttpRequest
|
Http *requests.FoundryHttpRequest
|
||||||
IsAuth bool
|
ReconnectTimeout time.Duration
|
||||||
|
ReconnectNum int
|
||||||
|
ReconnectNumMax int
|
||||||
|
IsAuth bool
|
||||||
|
IsLogin bool
|
||||||
|
|
||||||
Models *db.Models
|
Models *db.Models
|
||||||
IsDbInit bool
|
IsDbInit bool
|
||||||
@@ -36,8 +40,12 @@ func NewFoundryTransport(dbConn *sql.DB, logger *slog.Logger, httpConfig *reques
|
|||||||
ProgressMsg: map[string]chan struct{}{},
|
ProgressMsg: map[string]chan struct{}{},
|
||||||
},
|
},
|
||||||
|
|
||||||
Http: *httpConfig,
|
Http: httpConfig,
|
||||||
IsAuth: false,
|
ReconnectTimeout: 500 * time.Millisecond,
|
||||||
|
IsAuth: false,
|
||||||
|
IsLogin: false,
|
||||||
|
ReconnectNumMax: 1,
|
||||||
|
ReconnectNum: 0,
|
||||||
|
|
||||||
Models: db.NewModels(dbConn),
|
Models: db.NewModels(dbConn),
|
||||||
IsDbInit: false,
|
IsDbInit: false,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package transport
|
package transport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -18,20 +17,39 @@ func (tr *FoundryTransport) InitWebSocketConnection() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Add("session", tr.Http.SessionID)
|
query.Add("session", *tr.Http.SessionID)
|
||||||
query.Add("EIO", "4")
|
query.Add("EIO", "4")
|
||||||
query.Add("transport", "websocket")
|
query.Add("transport", "websocket")
|
||||||
|
|
||||||
u := url.URL{Scheme: "ws", Host: tr.Http.Host, Path: fmt.Sprintf("%s/", requests.SocketPath), RawQuery: query.Encode()}
|
u := url.URL{Scheme: "ws", Host: tr.Http.Host, Path: fmt.Sprintf("%s/", requests.SocketPath), RawQuery: query.Encode()}
|
||||||
|
|
||||||
wsHeader := http.Header{}
|
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 {
|
if err != nil {
|
||||||
return err
|
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.WsConn = wsConn
|
||||||
tr.CurrWsId = 0
|
tr.CurrWsId = 0
|
||||||
tr.Logger.Info("Successefully connected to Foundry Websocket")
|
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) {
|
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())
|
err := tr.WsConn.WriteMessage(websocket.TextMessage, msg.ToByteSlice())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -52,8 +71,8 @@ func (tr *FoundryTransport) HandleWebsocketRequest(msg *types.WsMessage) ([]byte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) {
|
func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer cancel()
|
// defer cancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -64,12 +83,12 @@ func (tr *FoundryTransport) ReceiveMessage(id int) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
tr.CloseMsgChannel(id, 0)
|
tr.CloseMsgChannel(id, 0)
|
||||||
return msg, nil
|
return msg, nil
|
||||||
case <-ctx.Done():
|
// case <-ctx.Done():
|
||||||
err := ctx.Err()
|
// err := ctx.Err()
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
return nil, ErrorTimeout
|
// return nil, ErrorTimeout
|
||||||
default:
|
default:
|
||||||
time.Sleep(5 * time.Microsecond)
|
time.Sleep(5 * time.Microsecond)
|
||||||
}
|
}
|
||||||
@@ -83,6 +102,8 @@ func (tr *FoundryTransport) ListenWebSocket() {
|
|||||||
select {
|
select {
|
||||||
case <-tr.ReadChan.Done():
|
case <-tr.ReadChan.Done():
|
||||||
return
|
return
|
||||||
|
case <-tr.ReadChan.Reconnect():
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.ReaderCode, Err: err, Type: types.WebSocketCode, IsFatal: true}
|
tr.ReadChan.Err() <- &types.FoundryError{Direction: types.ReaderCode, Err: err, Type: types.WebSocketCode, IsFatal: true}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ func (channels *ExchangeChannels) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReadChannels struct {
|
type ReadChannels struct {
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
msg chan *WsMessage
|
reconnect chan struct{}
|
||||||
err chan error
|
msg chan *WsMessage
|
||||||
|
err chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (channels ReadChannels) Err() chan error {
|
func (channels ReadChannels) Err() chan error {
|
||||||
@@ -47,6 +48,10 @@ func (channels ReadChannels) Done() chan struct{} {
|
|||||||
return channels.done
|
return channels.done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (channels ReadChannels) Reconnect() chan struct{} {
|
||||||
|
return channels.reconnect
|
||||||
|
}
|
||||||
|
|
||||||
func CloseChannel[V any](channel chan V) {
|
func CloseChannel[V any](channel chan V) {
|
||||||
select {
|
select {
|
||||||
case _, ok := <-channel:
|
case _, ok := <-channel:
|
||||||
@@ -62,12 +67,14 @@ func (channels *ReadChannels) Close() {
|
|||||||
CloseChannel(channels.done)
|
CloseChannel(channels.done)
|
||||||
CloseChannel(channels.err)
|
CloseChannel(channels.err)
|
||||||
CloseChannel(channels.msg)
|
CloseChannel(channels.msg)
|
||||||
|
CloseChannel(channels.reconnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitWsChannels() *ReadChannels {
|
func InitWsChannels() *ReadChannels {
|
||||||
return &ReadChannels{
|
return &ReadChannels{
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
err: make(chan error, 10),
|
err: make(chan error, 10),
|
||||||
msg: make(chan *WsMessage, 10),
|
msg: make(chan *WsMessage, 10),
|
||||||
|
reconnect: make(chan struct{}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,3 +81,7 @@ func ParseWsRespMessage(msg string, requestCodes []string) (*WsMessage, error) {
|
|||||||
func NewWsMessageByPage(page string, currWsId int) *WsMessage {
|
func NewWsMessageByPage(page string, currWsId int) *WsMessage {
|
||||||
return &WsMessage{Code: CodesRespToReq[RespServerChangeCode], Id: currWsId, MsgJson: fmt.Sprintf("[\"%s\"]", requests.WsTypeData[page])}
|
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)}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user