diff --git a/cmds/client.go b/cmds/client.go index a4bb2bb..d281395 100644 --- a/cmds/client.go +++ b/cmds/client.go @@ -12,7 +12,8 @@ func ping() { for _, msg := range msgs { fmt.Printf("client sending: '%s'\n", msg) - resp, err := tcp.Get(":8080", "/test", map[string]string{"msg": msg}) + resp, err := tcp.Get(":8080", "/test/ping", + map[string]string{"msg": msg}) if err != nil { panic(err) } @@ -40,6 +41,9 @@ func pull() { var clientCmd = &cobra.Command{ Use: "client", Run: func(cmd *cobra.Command, args []string) { - ping() + }, } + +func init() { +} diff --git a/cmds/game.go b/cmds/game.go new file mode 100644 index 0000000..2854a72 --- /dev/null +++ b/cmds/game.go @@ -0,0 +1,32 @@ +package cmds + +import ( + "inp2025/workflows" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.uber.org/zap" +) + +var gameCmd = &cobra.Command{ + Use: "game", + Run: func(cmd *cobra.Command, args []string) { + router := workflows.GameServer() + + err := router.Listen(":" + viper.GetString("port")) + if err != nil { + panic(err) + } + + zap.L().Info("server up", + zap.String("addr", router.ListenAddr())) + if err := router.WaitFor(); err != nil { + panic(err) + } + }, +} + +func init() { + gameCmd.Flags(). + String("port", "12345", "") +} diff --git a/cmds/server.go b/cmds/server.go index 253ebd7..2f44c03 100644 --- a/cmds/server.go +++ b/cmds/server.go @@ -1,45 +1,27 @@ package cmds import ( - "fmt" - "inp2025/middlewares" - "inp2025/tcp" - "io" - "time" + "inp2025/workflows" "github.com/spf13/cobra" "github.com/spf13/viper" "go.uber.org/zap" ) -func pongHandler(w tcp.ResponseWriter, req *tcp.Request) error { - w.WriteHeader(tcp.StatusOK) - _, err := io.WriteString(w, string(req.Params["msg"])) - return err -} - -func tickHandler(w tcp.ResponseWriter, req *tcp.Request) error { - zap.L().Info("Run tickHandler") - for { - w.SocketSendString(fmt.Sprintf("time: %s", time.Now().String())) - time.Sleep(time.Second) - } - return nil -} - var serverCmd = &cobra.Command{ Use: "server", Run: func(cmd *cobra.Command, args []string) { - router := tcp.NewRouter(). - Use(middlewares.ErrorHandler). - Use(middlewares.AccessLog) + router := workflows.LobbyServer() - router.Register(tcp.MethodSOCKET, "/test", - tickHandler) - router.Register(tcp.MethodGET, "/test", - pongHandler) - - router.Listen(":" + viper.GetString("port")) + err := router.Listen(":" + viper.GetString("port")) + if err != nil { + panic(err) + } + zap.L().Info("server up", + zap.String("addr", router.ListenAddr())) + if err := router.WaitFor(); err != nil { + panic(err) + } }, } diff --git a/handlers/game/handlers.go b/handlers/game/handlers.go new file mode 100644 index 0000000..f78bb61 --- /dev/null +++ b/handlers/game/handlers.go @@ -0,0 +1,8 @@ +package game + +type Handlers struct { +} + +func NewHandlers() *Handlers { + return &Handlers{} +} diff --git a/handlers/game/postMove.go b/handlers/game/postMove.go new file mode 100644 index 0000000..9360874 --- /dev/null +++ b/handlers/game/postMove.go @@ -0,0 +1,14 @@ +package game + +import ( + "inp2025/tcp" + "inp2025/utils" +) + +func (self *Handlers) PostMove( + w tcp.ResponseWriter, + req *tcp.Request, +) error { + // TODO + return utils.Success(w) +} diff --git a/handlers/game/postReady.go b/handlers/game/postReady.go new file mode 100644 index 0000000..aa0a766 --- /dev/null +++ b/handlers/game/postReady.go @@ -0,0 +1,14 @@ +package game + +import ( + "inp2025/tcp" + "inp2025/utils" +) + +func (self *Handlers) PostReady( + w tcp.ResponseWriter, + req *tcp.Request, +) error { + // TODO + return utils.Success(w) +} diff --git a/handlers/game/socketState.go b/handlers/game/socketState.go new file mode 100644 index 0000000..0d314d4 --- /dev/null +++ b/handlers/game/socketState.go @@ -0,0 +1,14 @@ +package game + +import ( + "inp2025/tcp" + "inp2025/utils" +) + +func (self *Handlers) SocketState( + w tcp.ResponseWriter, + req *tcp.Request, +) error { + // TODO + return utils.Success(w) +} diff --git a/middlewares/nmsl.go b/middlewares/nmsl.go new file mode 100644 index 0000000..3ccab86 --- /dev/null +++ b/middlewares/nmsl.go @@ -0,0 +1,14 @@ +package middlewares + +import ( + "inp2025/tcp" + + "go.uber.org/zap" +) + +func NMSL(next tcp.Handler) tcp.Handler { + return func(w tcp.ResponseWriter, req *tcp.Request) error { + zap.L().Info("nmsl") + return next(w, req) + } +} diff --git a/tcp/router.go b/tcp/router.go index 717a409..3411691 100644 --- a/tcp/router.go +++ b/tcp/router.go @@ -4,6 +4,7 @@ import ( "encoding/json" "io" "net" + "strings" "go.uber.org/zap" ) @@ -14,11 +15,41 @@ type Middleware func(next Handler) Handler type Router struct { middlewares []Middleware routes map[Method]map[string]Handler + + listenAddr string + doneCh chan error } func NewRouter() *Router { return &Router{ routes: make(map[Method]map[string]Handler), + doneCh: make(chan error), + } +} + +type Group struct { + pRouter *Router + pGroup *Group + + path string + middlewares []Middleware +} + +func (self *Router) Group(path string) *Group { + return &Group{ + pRouter: self, + pGroup: nil, + + path: path, + } +} + +func (self *Group) Group(path string) *Group { + return &Group{ + pRouter: nil, + pGroup: self, + + path: path, } } @@ -27,6 +58,11 @@ func (self *Router) Use(middleware Middleware) *Router { return self } +func (self *Group) Use(middleware Middleware) *Group { + self.middlewares = append(self.middlewares, middleware) + return self +} + func (self *Router) Register(method Method, route string, handler Handler) { _, ok := self.routes[method] if !ok { @@ -39,26 +75,59 @@ func (self *Router) Register(method Method, route string, handler Handler) { self.routes[method][route] = handler } +func (self *Group) Register(method Method, route string, handler Handler) { + for _, middleware := range self.middlewares { + handler = middleware(handler) + } + + if self.pRouter != nil { + self.pRouter.Register(method, self.path+route, handler) + } + if self.pGroup != nil { + self.pGroup.Register(method, self.path+route, handler) + } +} + func (self *Router) GET(route string, handler Handler) { self.Register(MethodGET, route, handler) } +func (self *Group) GET(route string, handler Handler) { + self.Register(MethodGET, route, handler) +} + func (self *Router) POST(route string, handler Handler) { self.Register(MethodPOST, route, handler) } +func (self *Group) POST(route string, handler Handler) { + self.Register(MethodPOST, route, handler) +} + func (self *Router) PUT(route string, handler Handler) { self.Register(MethodPUT, route, handler) } +func (self *Group) PUT(route string, handler Handler) { + self.Register(MethodPUT, route, handler) +} + func (self *Router) DELETE(route string, handler Handler) { self.Register(MethodDELETE, route, handler) } +func (self *Group) DELETE(route string, handler Handler) { + self.Register(MethodDELETE, route, handler) +} + func (self *Router) SOCKET(route string, handler Handler) { self.Register(MethodSOCKET, route, handler) } +func (self *Group) SOCKET(route string, handler Handler) { + self.Register(MethodSOCKET, route, handler) +} + func (self *Router) run(conn net.Conn, req *Request) { handler, ok := self.routes[req.Method][req.Route] if !ok { @@ -94,42 +163,64 @@ func (self *Router) run(conn net.Conn, req *Request) { } } -func (self *Router) Listen(addr string) error { - listener, err := net.Listen("tcp", addr) - if err != nil { - return err - } +func (self *Router) listen(listener net.Listener) { defer listener.Close() - for { conn, err := listener.Accept() if err != nil { - return err + self.doneCh <- err + return } rawHeader, err := readFrame(conn) if err != nil { if err == io.EOF { - return nil + self.doneCh <- nil + return } - return err + self.doneCh <- err + return } body, err := readFrame(conn) if err != nil { if err == io.EOF { - return nil + self.doneCh <- nil + return } - return err + self.doneCh <- err + return } var header RequestHeader if err := json.Unmarshal(rawHeader, &header); err != nil { - return err + self.doneCh <- err + return } req := NewRequest(conn, header, body) go self.run(conn, req) } +} +func (self *Router) WaitFor() error { + return <-self.doneCh +} + +func (self *Router) ListenAddr() string { + conn, _ := net.Dial("udp", "8.8.8.8:80") + addr := conn.LocalAddr().(*net.UDPAddr).IP.String() + conn.Close() + ss2 := strings.Split(self.listenAddr, ":") + return addr + ":" + ss2[len(ss2)-1] +} + +func (self *Router) Listen(addr string) error { + listener, err := net.Listen("tcp", addr) + if err != nil { + return err + } + + self.listenAddr = listener.Addr().String() + go self.listen(listener) return nil } diff --git a/workflows/databaseServer.go b/workflows/databaseServer.go new file mode 100644 index 0000000..d693fb6 --- /dev/null +++ b/workflows/databaseServer.go @@ -0,0 +1,14 @@ +package workflows + +import ( + "inp2025/middlewares" + "inp2025/tcp" +) + +func DatabaseServer() *tcp.Router { + router := tcp.NewRouter(). + Use(middlewares.ErrorHandler). + Use(middlewares.AccessLog) + + return router +} diff --git a/workflows/gameServer.go b/workflows/gameServer.go new file mode 100644 index 0000000..48d97aa --- /dev/null +++ b/workflows/gameServer.go @@ -0,0 +1,24 @@ +package workflows + +import ( + "inp2025/handlers/game" + "inp2025/middlewares" + "inp2025/tcp" +) + +func GameServer() *tcp.Router { + router := tcp.NewRouter(). + Use(middlewares.ErrorHandler). + Use(middlewares.AccessLog) + + handlers := game.NewHandlers() + + // before start + router.POST("/ready", handlers.PostReady) + + // game start + router.POST("/move", handlers.PostMove) + router.SOCKET("/state", handlers.SocketState) + + return router +} diff --git a/workflows/lobbyServer.go b/workflows/lobbyServer.go new file mode 100644 index 0000000..212f90c --- /dev/null +++ b/workflows/lobbyServer.go @@ -0,0 +1,55 @@ +package workflows + +import ( + "fmt" + "inp2025/middlewares" + "inp2025/tcp" + "io" + "time" + + "go.uber.org/zap" +) + +func pongHandler(w tcp.ResponseWriter, req *tcp.Request) error { + w.WriteHeader(tcp.StatusOK) + _, err := io.WriteString(w, string(req.Params["msg"])) + return err +} + +func tickHandler(w tcp.ResponseWriter, req *tcp.Request) error { + zap.L().Info("Run tickHandler") + for { + w.SocketSendString(fmt.Sprintf("time: %s", time.Now().String())) + time.Sleep(time.Second) + } + return nil +} + +func LobbyServer() *tcp.Router { + router := tcp.NewRouter(). + Use(middlewares.ErrorHandler). + Use(middlewares.AccessLog) + + // test + test := router.Group("/test"). + Use(middlewares.NMSL) + test.SOCKET("/tick", tickHandler) + test.GET("/ping", pongHandler) + + /* + auth := router.Group("/auth") + auth.POST("/register") + auth.POST("/login") + auth.POST("/logout") + + api := router.Group("/api") + api.GET("/online-users") + api.GET("/rooms") + api.GET("/invitations") + api.GET("/current-invitation") + api.POST("/invite") + api.POST("/accept-invitition") + */ + + return router +}