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") }