ws/server.go

163 lines
2.8 KiB
Go
Raw Permalink Normal View History

package websocket
import (
"fmt"
"net"
2021-05-14 14:47:02 +00:00
"git.xdrm.io/go/ws/internal/uri/parser"
)
2021-05-14 14:47:02 +00:00
// All channels that a server features
type serverChannelSet struct {
register chan *client
unregister chan *client
broadcast chan Message
}
2021-05-14 14:47:02 +00:00
// Server is 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
}
2021-05-14 14:47:02 +00:00
// CreateServer 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,
2021-05-14 14:47:02 +00:00
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,
}
}
2021-05-14 14:47:02 +00:00
// Bind 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 */
2021-05-14 14:47:02 +00:00
s.ctl.URI = append(s.ctl.URI, &Controller{
URI: uriScheme,
Fun: f,
})
return nil
}
2021-05-14 14:47:02 +00:00
// Launch 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 {
2021-05-14 14:47:02 +00:00
/* (1) Create client */
case client := <-s.ch.register:
s.clients[client.io.sock] = client
2021-05-14 14:47:02 +00:00
/* (2) Remove client */
case client := <-s.ch.unregister:
delete(s.clients, client.io.sock)
/* (3) Broadcast */
case msg := <-s.ch.broadcast:
for _, c := range s.clients {
c.ch.send <- msg
}
}
}
}