mirror of
https://github.com/kataras/iris.git
synced 2026-01-08 04:21:57 +00:00
Update to 4.0.0-alpha.3 - Response Engines, 'inject' the context.JSON/JSONP/Text/Data/Markdown/Render, Read HISTORY.md
## 4.0.0-alpha.2 -> 4.0.0-alpha.3
**New**
A **Response Engine** gives you the freedom to create/change the
render/response writer for
- `context.JSON`
- `context.JSONP`
- `context.XML`
- `context.Text`
- `context.Markdown`
- `context.Data`
- `context.Render("my_custom_type",mystructOrData{},
iris.RenderOptions{"gzip":false,"charset":"UTF-8"})`
- `context.MarkdownString`
- `iris.ResponseString(...)`
**Fix**
- https://github.com/kataras/iris/issues/294
**Small changes**
- `iris.Config.Charset`, before alpha.3 was `iris.Config.Rest.Charset` &
`iris.Config.Render.Template.Charset`, but you can override it at
runtime by passinth a map `iris.RenderOptions` on the `context.Render`
call .
- `iris.Config.IsDevelopment` , before alpha.1 was
`iris.Config.Render.Template.IsDevelopment`
**Websockets changes**
No need to import the `github.com/kataras/iris/websocket` to use the
`Connection` iteral, the websocket moved inside `kataras/iris` , now all
exported variables' names have the prefix of `Websocket`, so the old
`websocket.Connection` is now `iris.WebsocketConnection`.
Generally, no other changes on the 'frontend API', for response engines
examples and how you can register your own to add more features on
existing response engines or replace them, look
[here](https://github.com/iris-contrib/response).
**BAD SIDE**: E-Book is still pointing on the v3 release, but will be
updated soon.
This commit is contained in:
@@ -1,189 +0,0 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/iris-contrib/websocket"
|
||||
"github.com/kataras/iris/config"
|
||||
"github.com/kataras/iris/context"
|
||||
)
|
||||
|
||||
type (
|
||||
// ConnectionFunc is the callback which fires when a client/connection is connected to the server.
|
||||
// Receives one parameter which is the Connection
|
||||
ConnectionFunc func(Connection)
|
||||
// Rooms is just a map with key a string and value slice of string
|
||||
Rooms map[string][]string
|
||||
// Server is the websocket server
|
||||
Server interface {
|
||||
// Upgrade upgrades the client in order websocket works
|
||||
Upgrade(context.IContext) error
|
||||
// OnConnection registers a callback which fires when a connection/client is connected to the server
|
||||
OnConnection(ConnectionFunc)
|
||||
// Config returns a pointer to server's configs
|
||||
Config() *config.Websocket
|
||||
}
|
||||
|
||||
// roomPayload is used as payload from the connection to the server
|
||||
roomPayload struct {
|
||||
roomName string
|
||||
connectionID string
|
||||
}
|
||||
|
||||
// payloads, connection -> server
|
||||
messagePayload struct {
|
||||
from string
|
||||
to string
|
||||
data []byte
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
server struct {
|
||||
config *config.Websocket
|
||||
upgrader websocket.Upgrader
|
||||
put chan *connection
|
||||
free chan *connection
|
||||
connections map[string]*connection
|
||||
join chan roomPayload
|
||||
leave chan roomPayload
|
||||
rooms Rooms // by default a connection is joined to a room which has the connection id as its name
|
||||
mu sync.Mutex // for rooms
|
||||
messages chan messagePayload
|
||||
onConnectionListeners []ConnectionFunc
|
||||
//connectionPool *sync.Pool // sadly I can't make this because the websocket connection is live until is closed.
|
||||
}
|
||||
)
|
||||
|
||||
var _ Server = &server{}
|
||||
|
||||
// server implementation
|
||||
|
||||
// newServer creates a websocket server and returns it
|
||||
func newServer(c *config.Websocket) *server {
|
||||
s := &server{
|
||||
config: c,
|
||||
put: make(chan *connection),
|
||||
free: make(chan *connection),
|
||||
connections: make(map[string]*connection),
|
||||
join: make(chan roomPayload, 1), // buffered because join can be called immediately on connection connected
|
||||
leave: make(chan roomPayload),
|
||||
rooms: make(Rooms),
|
||||
messages: make(chan messagePayload, 1), // buffered because messages can be sent/received immediately on connection connected
|
||||
onConnectionListeners: make([]ConnectionFunc, 0),
|
||||
}
|
||||
|
||||
s.upgrader = websocket.Custom(s.handleConnection, s.config.ReadBufferSize, s.config.WriteBufferSize, false)
|
||||
go s.serve() // start the server automatically
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *server) Config() *config.Websocket {
|
||||
return s.config
|
||||
}
|
||||
|
||||
func (s *server) Upgrade(ctx context.IContext) error {
|
||||
return s.upgrader.Upgrade(ctx)
|
||||
}
|
||||
|
||||
func (s *server) handleConnection(websocketConn *websocket.Conn) {
|
||||
c := newConnection(websocketConn, s)
|
||||
s.put <- c
|
||||
go c.writer()
|
||||
c.reader()
|
||||
}
|
||||
|
||||
func (s *server) OnConnection(cb ConnectionFunc) {
|
||||
s.onConnectionListeners = append(s.onConnectionListeners, cb)
|
||||
}
|
||||
|
||||
func (s *server) joinRoom(roomName string, connID string) {
|
||||
s.mu.Lock()
|
||||
if s.rooms[roomName] == nil {
|
||||
s.rooms[roomName] = make([]string, 0)
|
||||
}
|
||||
s.rooms[roomName] = append(s.rooms[roomName], connID)
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) leaveRoom(roomName string, connID string) {
|
||||
s.mu.Lock()
|
||||
if s.rooms[roomName] != nil {
|
||||
for i := range s.rooms[roomName] {
|
||||
if s.rooms[roomName][i] == connID {
|
||||
s.rooms[roomName][i] = s.rooms[roomName][len(s.rooms[roomName])-1]
|
||||
s.rooms[roomName] = s.rooms[roomName][:len(s.rooms[roomName])-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(s.rooms[roomName]) == 0 { // if room is empty then delete it
|
||||
delete(s.rooms, roomName)
|
||||
}
|
||||
}
|
||||
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
func (s *server) serve() {
|
||||
for {
|
||||
select {
|
||||
case c := <-s.put: // connection connected
|
||||
s.connections[c.id] = c
|
||||
// make and join a room with the connection's id
|
||||
s.rooms[c.id] = make([]string, 0)
|
||||
s.rooms[c.id] = []string{c.id}
|
||||
for i := range s.onConnectionListeners {
|
||||
s.onConnectionListeners[i](c)
|
||||
}
|
||||
case c := <-s.free: // connection closed
|
||||
if _, found := s.connections[c.id]; found {
|
||||
// leave from all rooms
|
||||
for roomName := range s.rooms {
|
||||
s.leaveRoom(roomName, c.id)
|
||||
}
|
||||
delete(s.connections, c.id)
|
||||
close(c.send)
|
||||
c.fireDisconnect()
|
||||
|
||||
}
|
||||
case join := <-s.join:
|
||||
s.joinRoom(join.roomName, join.connectionID)
|
||||
case leave := <-s.leave:
|
||||
s.leaveRoom(leave.roomName, leave.connectionID)
|
||||
case msg := <-s.messages: // message received from the connection
|
||||
if msg.to != All && msg.to != NotMe && s.rooms[msg.to] != nil {
|
||||
// it suppose to send the message to a room
|
||||
for _, connectionIDInsideRoom := range s.rooms[msg.to] {
|
||||
if c, connected := s.connections[connectionIDInsideRoom]; connected {
|
||||
c.send <- msg.data //here we send it without need to continue below
|
||||
} else {
|
||||
// the connection is not connected but it's inside the room, we remove it on disconnect but for ANY CASE:
|
||||
s.leaveRoom(c.id, msg.to)
|
||||
}
|
||||
}
|
||||
|
||||
} else { // it suppose to send the message to all opened connections or to all except the sender
|
||||
for connID, c := range s.connections {
|
||||
if msg.to != All { // if it's not suppose to send to all connections (including itself)
|
||||
if msg.to == NotMe && msg.from == connID { // if broadcast to other connections except this
|
||||
continue //here we do the opossite of previous block, just skip this connection when it's suppose to send the message to all connections except the sender
|
||||
}
|
||||
}
|
||||
select {
|
||||
case s.connections[connID].send <- msg.data: //send the message back to the connection in order to send it to the client
|
||||
default:
|
||||
close(c.send)
|
||||
delete(s.connections, connID)
|
||||
c.fireDisconnect()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user