package server import ( "tunnel/pkg/config" "strings" "bytes" "sync" "time" "fmt" "log" "net" "io" ) type handler func (r *request) var handlers = map[string]handler{} type Server struct { listen net.Listener since time.Time wg sync.WaitGroup m sync.Mutex done bool nextCid uint64 } 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 } 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 { s.m.Lock() defer s.m.Unlock() return s.done } func New() (*Server, error) { listen, err := net.Listen(config.SockType, config.SockPath) if err != nil { return nil, err } s := &Server{ listen: listen, since: time.Now(), } return s, nil } func (s *Server) Run() { for { conn, err := s.listen.Accept() if err != nil { if s.isDone() { break } log.Print(err) continue } c := s.newClient(conn) log.Println(c, "accept") s.wg.Add(1) go c.handle() } s.wg.Wait() } func (s *Server) Stop() { s.m.Lock() s.done = true s.m.Unlock() s.listen.Close() } 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) for { nr, er := c.conn.Read(buf) if er != nil { if er != io.EOF { log.Println(c, "handle:", er) } break } msg := string(buf[:nr]) r := c.newRequest(msg) if h, ok := handlers[r.name]; ok { log.Println(c, r, "run:", msg) h(r) } else { fmt.Fprint(r.out, "unknown command") } if r.out.Len() == 0 { r.out.Write([]byte("\n")) } _, 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() }