summaryrefslogtreecommitdiff
path: root/pkg/server/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/server/server.go')
-rw-r--r--pkg/server/server.go143
1 files changed, 110 insertions, 33 deletions
diff --git a/pkg/server/server.go b/pkg/server/server.go
index ed0106b..3dedfb8 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -12,7 +12,7 @@ import (
"io"
)
-type handler func (*Server, []string, io.Writer)
+type handler func (r *request)
var handlers = map[string]handler{}
@@ -24,14 +24,54 @@ type Server struct {
m sync.Mutex
done bool
+
+ nextCid uint64
}
-func setHandler(cmd string, h handler) {
- if _, ok := handlers[cmd]; ok {
- panic(fmt.Sprintf("handler %s already registered", cmd))
- }
+type client struct {
+ s *Server
+
+ id uint64
+
+ conn net.Conn
+
+ nextRid uint64
+}
+
+type request struct {
+ c *client
+
+ id uint64
+
+ name string
+ args []string
+
+ out *bytes.Buffer
+}
- handlers[cmd] = h
+func (c *client) String() string {
+ return fmt.Sprintf("client(%d)", c.id)
+}
+
+func (r *request) String() string {
+ return fmt.Sprintf("request(%d)", r.id)
+}
+
+func setHandler(h handler, names ...string) {
+ var path []string
+
+ for _, s := range names {
+ if _, ok := handlers[s]; ok {
+ err := fmt.Sprintf("handler '%s' already registered at '%s'",
+ s, strings.Join(path, " "))
+ panic(err)
+ }
+
+ path = append(path, s)
+
+ handlers[s] = h
+ break
+ }
}
func (s *Server) isDone() bool {
@@ -66,11 +106,13 @@ func (s *Server) Run() {
continue
}
- log.Print("new client")
+ c := s.newClient(conn)
+
+ log.Println(c, "accept")
s.wg.Add(1)
- go s.handle(conn)
+ go c.handle()
}
s.wg.Wait()
@@ -84,38 +126,73 @@ func (s *Server) Stop() {
s.listen.Close()
}
-func (s *Server) handle(c net.Conn) {
- defer c.Close()
- defer s.wg.Done()
+func (s *Server) newClient(conn net.Conn) *client {
+ c := &client{
+ s: s,
+ conn: conn,
+ id: s.nextCid,
+ }
+
+ s.nextCid++
+
+ return c
+}
+
+func (c *client) newRequest(msg string) *request {
+ args := strings.Split(msg, " ")
+
+ r := &request{
+ c: c,
+ id: c.nextRid,
+ name: args[0],
+ args: args[1:],
+ out: bytes.NewBuffer(nil),
+ }
+
+ c.nextRid++
+
+ return r
+}
+
+func (c *client) handle() {
+ defer c.close()
buf := make([]byte, config.BufSize)
- nr, er := c.Read(buf)
- if er != nil {
- if er != io.EOF {
- log.Print("handle: ", er)
+ for {
+ nr, er := c.conn.Read(buf)
+ if er != nil {
+ if er != io.EOF {
+ log.Println(c, "handle:", er)
+ }
+ break
}
- return
- }
- data := string(buf[:nr])
- args := strings.Split(data, " ")
- out := bytes.NewBuffer(nil)
+ msg := string(buf[:nr])
+ r := c.newRequest(msg)
- if h, ok := handlers[args[0]]; ok {
- log.Printf("handle: run: %s", data)
- h(s, args, out)
- } else {
- fmt.Fprint(out, "unknown command")
- }
+ if h, ok := handlers[r.name]; ok {
+ log.Println(c, r, "run:", msg)
+ h(r)
+ } else {
+ fmt.Fprint(r.out, "unknown command")
+ }
- if out.Len() == 0 {
- out.Write([]byte("\n"))
- }
+ if r.out.Len() == 0 {
+ r.out.Write([]byte("\n"))
+ }
- _, ew := c.Write(out.Bytes())
- if ew != nil {
- log.Print("handle: ", ew)
- return
+ _, ew := c.conn.Write(r.out.Bytes())
+ if ew != nil {
+ log.Println(c, "handle:", ew)
+ break
+ }
}
}
+
+func (c *client) close() {
+ log.Println(c, "close")
+
+ c.conn.Close()
+ c.s.wg.Done()
+}