From 49548b0388444c32769ee2a0b579f501c02b742a Mon Sep 17 00:00:00 2001 From: Tyler J Cvetan Date: Sun, 21 Jul 2024 17:11:01 +0000 Subject: [PATCH] feat: wip project setup --- README.md | 2 + internal/chronicle/adapter/http.go | 29 +++++++ internal/chronicle/core/README.md | 1 + internal/chronicle/core/game/adapter/http.go | 83 +++++++++++++++++++ .../core/game/application/application.go | 18 ++++ .../game/application/command/create_game.go | 30 +++++++ internal/chronicle/core/game/domain/game.go | 6 ++ internal/chronicle/core/game/port/service.go | 11 +++ internal/chronicle/go.mod | 6 ++ internal/chronicle/go.sum | 6 ++ internal/chronicle/main.go | 13 +++ internal/chronicle/port/server.go | 7 ++ internal/chronicle/service/application.go | 23 +++++ 13 files changed, 235 insertions(+) create mode 100644 internal/chronicle/adapter/http.go create mode 100644 internal/chronicle/core/README.md create mode 100644 internal/chronicle/core/game/adapter/http.go create mode 100644 internal/chronicle/core/game/application/application.go create mode 100644 internal/chronicle/core/game/application/command/create_game.go create mode 100644 internal/chronicle/core/game/domain/game.go create mode 100644 internal/chronicle/core/game/port/service.go create mode 100644 internal/chronicle/go.sum create mode 100644 internal/chronicle/main.go create mode 100644 internal/chronicle/port/server.go create mode 100644 internal/chronicle/service/application.go diff --git a/README.md b/README.md index e8aad76..de3c3b7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Untitled TTRPG discord bot service thingie +For now setting this up as monorepo of services but might only have one. + ## .devcontainer See diff --git a/internal/chronicle/adapter/http.go b/internal/chronicle/adapter/http.go new file mode 100644 index 0000000..cbb4512 --- /dev/null +++ b/internal/chronicle/adapter/http.go @@ -0,0 +1,29 @@ +package port + +import ( + "net/http" + + "github.com/SomethingSexy/chronicle/internal/chronicle/service" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +type HttpServer struct { + app service.Application +} + +func NewHttpServer(application service.Application) HttpServer { + return HttpServer{ + app: application, + } +} + +func (h HttpServer) Start() { + // This should be responsible for running and starting the http service but it should be given the routes + r := chi.NewRouter() + r.Use(middleware.Logger) + + // TODO: Given the application, this should mount all of the route handlers + + http.ListenAndServe(":3000", r) +} diff --git a/internal/chronicle/core/README.md b/internal/chronicle/core/README.md new file mode 100644 index 0000000..8ab5b70 --- /dev/null +++ b/internal/chronicle/core/README.md @@ -0,0 +1 @@ +This might have a bunch of folders for separated domains diff --git a/internal/chronicle/core/game/adapter/http.go b/internal/chronicle/core/game/adapter/http.go new file mode 100644 index 0000000..7fe8770 --- /dev/null +++ b/internal/chronicle/core/game/adapter/http.go @@ -0,0 +1,83 @@ +package adapter + +import ( + "errors" + "net/http" + + "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/domain" + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" +) + +// TODO: Do something with this error shit +type ErrResponse struct { + Err error `json:"-"` // low-level runtime error + HTTPStatusCode int `json:"-"` // http response status code + + StatusText string `json:"status"` // user-level status message + AppCode int64 `json:"code,omitempty"` // application-specific error code + ErrorText string `json:"error,omitempty"` // application-level error message, for debugging +} + +func (e *ErrResponse) Render(w http.ResponseWriter, r *http.Request) error { + render.Status(r, e.HTTPStatusCode) + return nil +} + +func ErrInvalidRequest(err error) render.Renderer { + return &ErrResponse{ + Err: err, + HTTPStatusCode: 400, + StatusText: "Invalid request.", + ErrorText: err.Error(), + } +} + +func ErrRender(err error) render.Renderer { + return &ErrResponse{ + Err: err, + HTTPStatusCode: 422, + StatusText: "Error rendering response.", + ErrorText: err.Error(), + } +} + +var ErrNotFound = &ErrResponse{HTTPStatusCode: 404, StatusText: "Resource not found."} + +type GameHttpServer struct { +} + +func NewHttpServer() GameHttpServer { + return GameHttpServer{} +} + +func (h GameHttpServer) Routes() chi.Router { + r := chi.NewRouter() + r.Post("/", CreateGame) + return r +} + +func CreateGame(w http.ResponseWriter, r *http.Request) { + data := &GameRequest{} + if err := render.Bind(r, data); err != nil { + render.Render(w, r, ErrInvalidRequest(err)) + return + } + + render.Status(r, http.StatusCreated) + // render.Render(w, r, NewGameResponse(article)) +} + +type GameRequest struct { + *domain.Game +} + +func (a *GameRequest) Bind(r *http.Request) error { + // a.Article is nil if no Article fields are sent in the request. Return an + // error to avoid a nil pointer dereference. + if a.Game == nil { + return errors.New("missing required game fields") + } + + return nil +} diff --git a/internal/chronicle/core/game/application/application.go b/internal/chronicle/core/game/application/application.go new file mode 100644 index 0000000..5c0a760 --- /dev/null +++ b/internal/chronicle/core/game/application/application.go @@ -0,0 +1,18 @@ +package application + +import "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/application/command" + +type GameApplication struct { + Commands GameCommands + Queries GameQueries +} + +type GameCommands struct { + CreateGame command.CreateGameHander +} + +type GameQueries struct { +} + +// TODO: This should have a New function to setup the commands, repositories +// and routes for this domain diff --git a/internal/chronicle/core/game/application/command/create_game.go b/internal/chronicle/core/game/application/command/create_game.go new file mode 100644 index 0000000..b564950 --- /dev/null +++ b/internal/chronicle/core/game/application/command/create_game.go @@ -0,0 +1,30 @@ +package command + +import ( + "context" + "log" + + "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/domain" +) + +// TODO: Move this to a common spot +// TODO: Name this Command or CommandHandler +type CommandHandler[C any] interface { + Handle(ctx context.Context, cmd C) error +} + +type CreateGame struct { + Game domain.Game +} + +type CreateGameHander struct{} + +func NewCreateGameCommand() CommandHandler[CreateGame] { + + return CreateGameHander{} +} + +func (c CreateGameHander) Handle(ctx context.Context, cmd CreateGame) error { + log.Printf("Create game %s", cmd.Game.Name) + return nil +} diff --git a/internal/chronicle/core/game/domain/game.go b/internal/chronicle/core/game/domain/game.go new file mode 100644 index 0000000..60eb0cc --- /dev/null +++ b/internal/chronicle/core/game/domain/game.go @@ -0,0 +1,6 @@ +package domain + +type Game struct { + Name string + Type string +} diff --git a/internal/chronicle/core/game/port/service.go b/internal/chronicle/core/game/port/service.go new file mode 100644 index 0000000..4734210 --- /dev/null +++ b/internal/chronicle/core/game/port/service.go @@ -0,0 +1,11 @@ +package port + +import ( + "context" + + "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/domain" +) + +type GameService interface { + CreateUser(ctx context.Context, game domain.Game) error +} diff --git a/internal/chronicle/go.mod b/internal/chronicle/go.mod index fc12d16..ee9007b 100644 --- a/internal/chronicle/go.mod +++ b/internal/chronicle/go.mod @@ -1,3 +1,9 @@ module github.com/SomethingSexy/chronicle/internal/chronicle go 1.22.1 + +require ( + github.com/ajg/form v1.5.1 // indirect + github.com/go-chi/chi/v5 v5.1.0 // indirect + github.com/go-chi/render v1.0.3 // indirect +) diff --git a/internal/chronicle/go.sum b/internal/chronicle/go.sum new file mode 100644 index 0000000..0b7bdf6 --- /dev/null +++ b/internal/chronicle/go.sum @@ -0,0 +1,6 @@ +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= +github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= diff --git a/internal/chronicle/main.go b/internal/chronicle/main.go new file mode 100644 index 0000000..b85ed7b --- /dev/null +++ b/internal/chronicle/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "log" + + chronicleService "github.com/SomethingSexy/chronicle/internal/chronicle/service" +) + +func main() { + + chronicleService.NewService() + log.Println("verify running") +} diff --git a/internal/chronicle/port/server.go b/internal/chronicle/port/server.go new file mode 100644 index 0000000..c5dcb6a --- /dev/null +++ b/internal/chronicle/port/server.go @@ -0,0 +1,7 @@ +package port + +import "github.com/go-chi/chi/v5" + +type HttpServer interface { + Routes() chi.Router +} diff --git a/internal/chronicle/service/application.go b/internal/chronicle/service/application.go new file mode 100644 index 0000000..0c21ad6 --- /dev/null +++ b/internal/chronicle/service/application.go @@ -0,0 +1,23 @@ +package service + +import ( + "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/adapter" + gameApplication "github.com/SomethingSexy/chronicle/internal/chronicle/core/game/application" +) + +type Application struct { + Commands Commands + Queries Queries +} + +type Commands struct { + gameApplication.GameCommands +} + +type Queries struct { + gameApplication.GameQueries +} + +func NewService() { + adapter.NewHttpServer() +}