mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
147 lines
5.4 KiB
Go
147 lines
5.4 KiB
Go
package iris
|
|
|
|
import (
|
|
irisWebsocket "github.com/iris-contrib/websocket"
|
|
"github.com/kataras/go-websocket"
|
|
)
|
|
|
|
// conversionals
|
|
const (
|
|
// All is the string which the Emmiter use to send a message to all
|
|
All = websocket.All
|
|
// NotMe is the string which the Emmiter use to send a message to all except this websocket.Connection
|
|
NotMe = websocket.NotMe
|
|
// Broadcast is the string which the Emmiter use to send a message to all except this websocket.Connection, same as 'NotMe'
|
|
Broadcast = websocket.Broadcast
|
|
)
|
|
|
|
// Note I keep this code only to no change the front-end API, we could only use the go-websocket and set our custom upgrader
|
|
|
|
type (
|
|
// WebsocketServer is the iris websocket server, expose the websocket.Server
|
|
// the below code is a wrapper and bridge between iris-contrib/websocket and kataras/go-websocket
|
|
WebsocketServer struct {
|
|
websocket.Server
|
|
upgrader irisWebsocket.Upgrader
|
|
|
|
// the only fields we need at runtime here for iris-specific error and check origin funcs
|
|
// they comes from WebsocketConfiguration
|
|
|
|
// Error specifies the function for generating HTTP error responses.
|
|
Error func(ctx *Context, status int, reason string)
|
|
// CheckOrigin returns true if the request Origin header is acceptable. If
|
|
// CheckOrigin is nil, the host in the Origin header must not be set or
|
|
// must match the host of the request.
|
|
CheckOrigin func(ctx *Context) bool
|
|
}
|
|
)
|
|
|
|
// NewWebsocketServer returns an empty WebsocketServer, nothing special here.
|
|
func NewWebsocketServer() *WebsocketServer {
|
|
return &WebsocketServer{}
|
|
}
|
|
|
|
// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
|
|
//
|
|
// The responseHeader is included in the response to the client's upgrade
|
|
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
|
|
// application negotiated subprotocol (Sec-Websocket-Protocol).
|
|
//
|
|
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
|
|
// response.
|
|
func (s *WebsocketServer) Upgrade(ctx *Context) error {
|
|
return s.upgrader.Upgrade(ctx.RequestCtx)
|
|
}
|
|
|
|
// Handler is the iris Handler to upgrade the request
|
|
// used inside RegisterRoutes
|
|
func (s *WebsocketServer) Handler(ctx *Context) {
|
|
// first, check origin
|
|
if !s.CheckOrigin(ctx) {
|
|
s.Error(ctx, StatusForbidden, "websocket: origin not allowed")
|
|
return
|
|
}
|
|
|
|
// all other errors comes from the underline iris-contrib/websocket
|
|
if err := s.Upgrade(ctx); err != nil {
|
|
if ctx.framework.Config.IsDevelopment {
|
|
ctx.Log("Websocket error while trying to Upgrade the connection. Trace: %s", err.Error())
|
|
}
|
|
|
|
statusErrCode := StatusBadRequest
|
|
if herr, isHandshake := err.(irisWebsocket.HandshakeError); isHandshake {
|
|
statusErrCode = herr.Status()
|
|
}
|
|
// if not handshake error just fire the custom(if any) StatusBadRequest
|
|
// with the websocket's error message in the ctx.Get("WsError")
|
|
DefaultWebsocketError(ctx, statusErrCode, err.Error())
|
|
|
|
}
|
|
}
|
|
|
|
// RegisterTo creates the client side source route and the route path Endpoint with the correct Handler
|
|
// receives the websocket configuration and the iris station
|
|
func (s *WebsocketServer) RegisterTo(station *Framework, c WebsocketConfiguration) {
|
|
|
|
// Note: s.Server should be initialize on the first OnConnection, which is called before this func when Default websocket server.
|
|
// When not: when calling this function before OnConnection, when we have more than one websocket server running
|
|
if s.Server == nil {
|
|
s.Server = websocket.New()
|
|
}
|
|
// is just a conversional type for kataras/go-websocket.Connection
|
|
s.upgrader = irisWebsocket.Custom(s.Server.HandleConnection, c.ReadBufferSize, c.WriteBufferSize, c.Headers)
|
|
|
|
// set the routing for client-side source (javascript) (optional)
|
|
clientSideLookupName := "iris-websocket-client-side"
|
|
station.Get(c.Endpoint, s.Handler)
|
|
// check if client side already exists
|
|
if station.Lookup(clientSideLookupName) == nil {
|
|
// serve the client side on domain:port/iris-ws.js
|
|
station.StaticContent("/iris-ws.js", contentJavascript, websocket.ClientSource)(clientSideLookupName)
|
|
}
|
|
|
|
s.Server.Set(websocket.Config{
|
|
WriteTimeout: c.WriteTimeout,
|
|
PongTimeout: c.PongTimeout,
|
|
PingPeriod: c.PingPeriod,
|
|
MaxMessageSize: c.MaxMessageSize,
|
|
BinaryMessages: c.BinaryMessages,
|
|
ReadBufferSize: c.ReadBufferSize,
|
|
WriteBufferSize: c.WriteBufferSize,
|
|
})
|
|
|
|
s.Error = c.Error
|
|
s.CheckOrigin = c.CheckOrigin
|
|
|
|
if s.Error == nil {
|
|
s.Error = DefaultWebsocketError
|
|
}
|
|
|
|
if s.CheckOrigin == nil {
|
|
s.CheckOrigin = DefaultWebsocketCheckOrigin
|
|
}
|
|
|
|
// run the ws server
|
|
s.Server.Serve()
|
|
|
|
}
|
|
|
|
// WebsocketConnection is the front-end API that you will use to communicate with the client side
|
|
type WebsocketConnection interface {
|
|
websocket.Connection
|
|
}
|
|
|
|
// OnConnection this is the main event you, as developer, will work with each of the websocket connections
|
|
func (s *WebsocketServer) OnConnection(connectionListener func(WebsocketConnection)) {
|
|
if s.Server == nil {
|
|
// for default webserver this is the time when the websocket server will be init
|
|
// let's initialize here the ws server, the user/dev is free to change its config before this step.
|
|
s.Server = websocket.New() // we need that in order to use the Iris' WebsocketConnnection, which
|
|
// config is empty here because are setted on the RegisterTo
|
|
// websocket's configuration is optional on New because it doesn't really used before the websocket.Serve
|
|
}
|
|
s.Server.OnConnection(func(c websocket.Connection) {
|
|
connectionListener(c)
|
|
})
|
|
}
|