ws/server.go

171 lines
3.0 KiB
Go

package websocket
import (
"fmt"
"git.xdrm.io/go/websocket/internal/uri/parser"
"net"
)
// Represents all channels that need a server
type serverChannelSet struct {
register chan *client
unregister chan *client
broadcast chan Message
}
// Represents a websocket server
type Server struct {
sock net.Listener // listen socket
addr []byte // server listening ip/host
port uint16 // server listening port
clients map[net.Conn]*client
ctl ControllerSet // controllers
ch serverChannelSet
}
// CreateServer creates a server for a specific HOST and PORT
func CreateServer(host string, port uint16) *Server {
return &Server{
addr: []byte(host),
port: port,
clients: make(map[net.Conn]*client, 0),
ctl: ControllerSet{
Def: nil,
Uri: make([]*Controller, 0),
},
ch: serverChannelSet{
register: make(chan *client, 1),
unregister: make(chan *client, 1),
broadcast: make(chan Message, 1),
},
}
}
// BindDefault binds a default controller
// it will be called if the URI does not
// match another controller
func (s *Server) BindDefault(f ControllerFunc) {
s.ctl.Def = &Controller{
URI: nil,
Fun: f,
}
}
// Bind binds a controller to an URI scheme
func (s *Server) Bind(uri string, f ControllerFunc) error {
/* (1) Build URI parser */
uriScheme, err := parser.Build(uri)
if err != nil {
return fmt.Errorf("Cannot build URI: %s", err)
}
/* (2) Create controller */
s.ctl.Uri = append(s.ctl.Uri, &Controller{
URI: uriScheme,
Fun: f,
})
return nil
}
// Launch launches the websocket server
func (s *Server) Launch() error {
var err error
/* (1) Listen socket
---------------------------------------------------------*/
/* (1) Build full url */
url := fmt.Sprintf("%s:%d", s.addr, s.port)
/* (2) Bind socket to listen */
s.sock, err = net.Listen("tcp", url)
if err != nil {
return fmt.Errorf("Listen socket: %s", err)
}
defer s.sock.Close()
fmt.Printf("+ listening on %s\n", url)
/* (3) Launch scheduler */
go s.scheduler()
/* (2) For each incoming connection (client)
---------------------------------------------------------*/
for {
/* (1) Wait for client */
sock, err := s.sock.Accept()
if err != nil {
break
}
go func() {
/* (2) Try to create client */
cli, err := buildClient(sock, s.ctl, s.ch)
if err != nil {
fmt.Printf(" - %s\n", err)
return
}
/* (3) Register client */
s.ch.register <- cli
}()
}
return nil
}
// Scheduler schedules clients registration and broadcast
func (s *Server) scheduler() {
for {
select {
/* (1) New client */
case client := <-s.ch.register:
// fmt.Printf(" + client\n")
s.clients[client.io.sock] = client
/* (2) New client */
case client := <-s.ch.unregister:
// fmt.Printf(" - client\n")
delete(s.clients, client.io.sock)
/* (3) Broadcast */
case msg := <-s.ch.broadcast:
fmt.Printf(" + broadcast\n")
for _, c := range s.clients {
c.ch.send <- msg
}
}
}
fmt.Printf("+ server stopped\n")
}