From d01ea2d78eb8cd3d11e3dc6f4b4f66a46c91fb01 Mon Sep 17 00:00:00 2001 From: Daniel Ponte Date: Sun, 25 Sep 2022 11:42:36 -0400 Subject: [PATCH] initial wip --- .gitignore | 3 ++ Makefile | 6 +++ go.mod | 12 ++++++ go.sum | 14 +++++++ internal/common/common.go | 31 +++++++++++++++ pkg/bus/bus.go | 14 +++++++ pkg/cmd/serve/cmd.go | 48 +++++++++++++++++++++++ pkg/config/config.go | 77 +++++++++++++++++++++++++++++++++++++ pkg/config/read.go | 39 +++++++++++++++++++ pkg/server/config/config.go | 5 +++ pkg/server/server.go | 50 ++++++++++++++++++++++++ pkg/server/websocket.go | 17 ++++++++ 12 files changed, 316 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/common/common.go create mode 100644 pkg/bus/bus.go create mode 100644 pkg/cmd/serve/cmd.go create mode 100644 pkg/config/config.go create mode 100644 pkg/config/read.go create mode 100644 pkg/server/config/config.go create mode 100644 pkg/server/server.go create mode 100644 pkg/server/websocket.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d00a46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +blas +Session.vim +coverage.txt diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0288e42 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all: build +build: + go build -o blas ./cmd/blas/ + +debug: + dlv debug ./cmd/blas/ ${ARGS} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b517b7a --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module dynatron.me/x/blasphem + +go 1.18 + +require github.com/spf13/cobra v1.5.0 + +require ( + github.com/gorilla/websocket v1.5.0 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..068bfb5 --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/common/common.go b/internal/common/common.go new file mode 100644 index 0000000..816c4e7 --- /dev/null +++ b/internal/common/common.go @@ -0,0 +1,31 @@ +package common + +import ( + "github.com/spf13/cobra" +) + +const ( + AppName = "blasphem" +) + +type cmdOptions interface { + Options(*cobra.Command, []string) error + Execute() error +} + +func RunE(c cmdOptions) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + err := c.Options(cmd, args) + if err != nil { + cmd.SilenceUsage = true + return err + } + + err = c.Execute() + if err != nil { + cmd.SilenceUsage = true + } + + return err + } +} diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go new file mode 100644 index 0000000..c5863e4 --- /dev/null +++ b/pkg/bus/bus.go @@ -0,0 +1,14 @@ +package bus + +import ( +) + +type Bus struct { +} + +func New() *Bus { + bus := &Bus{ + } + + return bus +} diff --git a/pkg/cmd/serve/cmd.go b/pkg/cmd/serve/cmd.go new file mode 100644 index 0000000..73d0b0c --- /dev/null +++ b/pkg/cmd/serve/cmd.go @@ -0,0 +1,48 @@ +package serve + +import ( + "dynatron.me/x/blasphem/internal/common" + "dynatron.me/x/blasphem/pkg/config" + "dynatron.me/x/blasphem/pkg/server" + + "github.com/spf13/cobra" +) + +type ServeOptions struct { + cfg *config.Config +} + +func Command(cfg *config.Config) *cobra.Command { + opts := makeOptions(cfg) + serveCmd := &cobra.Command{ + Use: "serve", + Short: "starts the " + common.AppName + " server", + RunE: common.RunE(opts), + } + + return serveCmd +} + +func makeOptions(cfg *config.Config) *ServeOptions { + return &ServeOptions{ + cfg: cfg, + } +} + +func (o *ServeOptions) Options(_ *cobra.Command, args []string) error { + return nil +} + +func (o *ServeOptions) Execute() error { + server, err := server.New(o.cfg) + if err != nil { + return err + } + + err = server.Go() + if err != nil { + return err + } + + return nil +} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..e2235f1 --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,77 @@ +package config + +import ( + "errors" + "fmt" + "reflect" + "strings" + + server "dynatron.me/x/blasphem/pkg/server/config" + + "gopkg.in/yaml.v3" +) + +type Config struct { + Server *server.Config `yaml:"server"` +} + +const ( + IncludeTag = "!include" + IncludeDirNamedTag = "!include_dir_named" + IncludeDirListTag = "!include_dir_list" + IncludeDirMergeNamedTag = "!include_dir_merge_named" + SecretTag = "!secret" +) + +func (c *Config) UnmarshalYAML(y *yaml.Node) error { + if y.Kind != yaml.MappingNode { + return yerr(y, errors.New("config root must be a map")) + } + + cV := reflect.ValueOf(c).Elem() + + components := make(map[string]reflect.Value, cV.NumField()) + for i := 0; i < cV.NumField(); i++ { + if tag, ok := cV.Type().Field(i).Tag.Lookup("yaml"); ok { + tags := strings.Split(tag, ",") + components[tags[0]] = cV.Field(i) + } + } + + for i := 0; i < len(y.Content); i += 2 { + k, v := y.Content[i], y.Content[i+1] + + switch v.LongTag() { + case IncludeTag: + fallthrough + case IncludeDirNamedTag: + fallthrough + case IncludeDirMergeNamedTag: + fallthrough + case SecretTag: + panic(fmt.Errorf("tag %s not implemented", v.LongTag())) + default: + var key string + err := k.Decode(&key) + if err != nil { + return yerr(y, err) + } + + if comp, ok := components[key]; ok { + val := reflect.New(comp.Type()) + err := v.Decode(val.Interface()) + if err != nil { + return yerr(y, err) + } + + comp.Set(val.Elem()) + } + } + } + + return nil +} + +func yerr(y *yaml.Node, ye error) error { + return fmt.Errorf("line %d: %w", y.Line, ye) +} diff --git a/pkg/config/read.go b/pkg/config/read.go new file mode 100644 index 0000000..7a6130a --- /dev/null +++ b/pkg/config/read.go @@ -0,0 +1,39 @@ +package config + +import ( + "io" + "os" + "path" + + "dynatron.me/x/blasphem/internal/common" + + "gopkg.in/yaml.v3" +) + +func ReadConfig() (*Config, error) { + cfg := &Config{} + + home, err := os.UserHomeDir() + if err != nil { + return nil, err + } + + cfgPath := path.Join(home, "/." + common.AppName, "/config.yaml") + + r, err := os.Open(cfgPath) + if err != nil { + return nil, err + } + + cfgB, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + err = yaml.Unmarshal(cfgB, cfg) + if err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/pkg/server/config/config.go b/pkg/server/config/config.go new file mode 100644 index 0000000..461b9d6 --- /dev/null +++ b/pkg/server/config/config.go @@ -0,0 +1,5 @@ +package config + +type Config struct { + Bind string `yaml:"bind"` +} diff --git a/pkg/server/server.go b/pkg/server/server.go new file mode 100644 index 0000000..6f96dc5 --- /dev/null +++ b/pkg/server/server.go @@ -0,0 +1,50 @@ +package server + +import ( + "log" + "net/http" + "sync" + + "dynatron.me/x/blasphem/pkg/bus" + "dynatron.me/x/blasphem/pkg/config" +) + +type Server struct { + *bus.Bus + *http.Server + wg sync.WaitGroup + cfg *config.Config +} + +func New(cfg *config.Config) (*Server, error) { + mux := http.NewServeMux() + + s := &Server{ + Bus: bus.New(), + Server: &http.Server{ + Addr: cfg.Server.Bind, + Handler: mux, + }, + cfg: cfg, + } + + mux.HandleFunc("/api/websocket", s.wsHandler) + + return s, nil +} + +func (s *Server) Go() error { + s.wg.Add(1) + go func() { + err := s.ListenAndServe() + if err != nil { + log.Fatal(err) + } + + s.wg.Done() + }() + + s.wg.Wait() + + return nil +} diff --git a/pkg/server/websocket.go b/pkg/server/websocket.go new file mode 100644 index 0000000..be86d10 --- /dev/null +++ b/pkg/server/websocket.go @@ -0,0 +1,17 @@ +package server + +import ( + "net/http" + + "github.com/gorilla/websocket" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +func (s *Server) wsHandler(w http.ResponseWriter, req *http.Request) { + //conn, err := upgrader.Upgrade(w, req, nil) + panic("not implemented") +}