ws/ws/server/public.go

155 lines
2.7 KiB
Go
Raw Normal View History

package server
import (
"git.xdrm.io/gws/ws/message"
"git.xdrm.io/gws/ws/controller"
"git.xdrm.io/gws/ws/client"
"net"
"fmt"
"git.xdrm.io/gws/internal/uri/parser"
)
// CreateServer creates a server for a specific HOST and PORT
func Create(host string, port uint16) *T{
return &T{
addr: []byte(host),
port: port,
clients: make(map[net.Conn]*client.T, 0),
ctl: controller.Set{
Def: nil,
Uri: make([]*controller.T, 0),
},
ch: ServerChannelSet{
register: make(chan *client.T, 1),
unregister: make(chan *client.T, 1),
broadcast: make(chan message.T, 1),
},
}
}
// BindDefault binds a default controller
// it will be called if the URI does not
// match another controller
func (s *T) BindDefault(f controller.Func){
s.ctl.Def = &controller.T{
URI: nil,
Fun: f,
}
}
// Bind binds a controller to an URI scheme
func (s *T) Bind(uri string, f controller.Func) 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.T{
URI: uriScheme,
Fun: f,
} )
return nil
}
// Launch launches the websocket server
func (s *T) 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
}
/* (2) Try to create client */
cli, err := client.Create(sock, s.ctl, s.ch.unregister)
if err != nil {
fmt.Printf(" - %s\n", err)
continue
}
/* (3) Register client */
s.ch.register <- cli
}
return nil
}
// Scheduler schedules clients registration and broadcast
func (s *T) scheduler(){
for {
select {
/* (1) New client */
case client := <- s.ch.register:
2018-05-02 20:56:38 +00:00
// fmt.Printf(" + client\n")
s.clients[client.IO.Sock] = client
/* (2) New client */
case client := <- s.ch.unregister:
2018-05-02 20:56:38 +00:00
// fmt.Printf(" - client\n")
delete(s.clients, client.IO.Sock)
client.IO.Sock.Close()
/* (3) Broadcast */
case message := <- s.ch.broadcast:
fmt.Printf(" + broadcast\n")
for _, c := range s.clients{
c.Ch.Send <- message
}
}
}
fmt.Printf("+ server stopped\n")
}