2020-04-06 01:00:33 +00:00
|
|
|
package router
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
2021-01-10 01:22:39 +00:00
|
|
|
"time"
|
|
|
|
|
2020-04-06 01:00:33 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
ws "github.com/gorilla/websocket"
|
2021-08-02 21:07:00 +00:00
|
|
|
|
2021-01-26 04:28:24 +00:00
|
|
|
"github.com/pterodactyl/wings/router/middleware"
|
2020-04-06 01:00:33 +00:00
|
|
|
"github.com/pterodactyl/wings/router/websocket"
|
|
|
|
)
|
|
|
|
|
2021-09-12 18:14:00 +00:00
|
|
|
var expectedCloseCodes = []int{
|
|
|
|
ws.CloseGoingAway,
|
|
|
|
ws.CloseAbnormalClosure,
|
|
|
|
ws.CloseNormalClosure,
|
|
|
|
ws.CloseNoStatusReceived,
|
|
|
|
ws.CloseServiceRestart,
|
|
|
|
}
|
|
|
|
|
2020-04-06 01:00:33 +00:00
|
|
|
// Upgrades a connection to a websocket and passes events along between.
|
|
|
|
func getServerWebsocket(c *gin.Context) {
|
2021-01-26 04:28:24 +00:00
|
|
|
manager := middleware.ExtractManager(c)
|
|
|
|
s, _ := manager.Get(c.Param("server"))
|
2020-04-06 01:00:33 +00:00
|
|
|
handler, err := websocket.GetHandler(s, c.Writer, c.Request)
|
|
|
|
if err != nil {
|
2020-12-16 05:08:00 +00:00
|
|
|
NewServerError(err, s).Abort(c)
|
2020-04-06 01:00:33 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
defer handler.Connection.Close()
|
|
|
|
|
|
|
|
// Create a context that can be canceled when the user disconnects from this
|
2021-09-12 18:14:00 +00:00
|
|
|
// socket that will also cancel listeners running in separate threads. If the
|
|
|
|
// connection itself is terminated listeners using this context will also be
|
|
|
|
// closed.
|
|
|
|
ctx, cancel := context.WithCancel(c.Request.Context())
|
2020-04-06 01:00:33 +00:00
|
|
|
defer cancel()
|
|
|
|
|
2020-12-25 21:32:41 +00:00
|
|
|
// Track this open connection on the server so that we can close them all programmatically
|
2020-10-04 03:46:29 +00:00
|
|
|
// if the server is deleted.
|
|
|
|
s.Websockets().Push(handler.Uuid(), &cancel)
|
|
|
|
defer s.Websockets().Remove(handler.Uuid())
|
|
|
|
|
2021-09-12 18:14:00 +00:00
|
|
|
// If the server is deleted we need to send a close message to the connected client
|
|
|
|
// so that they disconnect since there will be no more events sent along. Listen for
|
|
|
|
// the request context being closed to break this loop, otherwise this routine will
|
|
|
|
// be left hanging in the background.
|
|
|
|
go func() {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
break
|
|
|
|
case <-s.Context().Done():
|
|
|
|
handler.Connection.WriteControl(ws.CloseMessage, ws.FormatCloseMessage(ws.CloseGoingAway, "server deleted"), time.Now().Add(time.Second*5))
|
|
|
|
break
|
2020-10-04 03:46:29 +00:00
|
|
|
}
|
2021-09-12 18:14:00 +00:00
|
|
|
}()
|
2020-10-04 03:46:29 +00:00
|
|
|
|
2020-04-06 01:00:33 +00:00
|
|
|
go handler.ListenForServerEvents(ctx)
|
|
|
|
go handler.ListenForExpiration(ctx)
|
|
|
|
|
|
|
|
for {
|
|
|
|
j := websocket.Message{}
|
|
|
|
|
|
|
|
_, p, err := handler.Connection.ReadMessage()
|
|
|
|
if err != nil {
|
2021-09-12 18:14:00 +00:00
|
|
|
if ws.IsUnexpectedCloseError(err, expectedCloseCodes...) {
|
2020-06-13 17:26:35 +00:00
|
|
|
s.Log().WithField("error", err).Warn("error handling websocket message for server")
|
2020-04-06 01:00:33 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// Discard and JSON parse errors into the void and don't continue processing this
|
|
|
|
// specific socket request. If we did a break here the client would get disconnected
|
|
|
|
// from the socket, which is NOT what we want to do.
|
|
|
|
if err := json.Unmarshal(p, &j); err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-07-18 23:45:10 +00:00
|
|
|
go func(msg websocket.Message) {
|
|
|
|
if err := handler.HandleInbound(msg); err != nil {
|
|
|
|
handler.SendErrorJson(msg, err)
|
|
|
|
}
|
|
|
|
}(j)
|
2020-04-06 01:00:33 +00:00
|
|
|
}
|
|
|
|
}
|