initial wip

This commit is contained in:
Daniel Ponte 2022-09-25 11:42:36 -04:00
commit d01ea2d78e
12 changed files with 316 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
blas
Session.vim
coverage.txt

6
Makefile Normal file
View file

@ -0,0 +1,6 @@
all: build
build:
go build -o blas ./cmd/blas/
debug:
dlv debug ./cmd/blas/ ${ARGS}

12
go.mod Normal file
View file

@ -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
)

14
go.sum Normal file
View file

@ -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=

31
internal/common/common.go Normal file
View file

@ -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
}
}

14
pkg/bus/bus.go Normal file
View file

@ -0,0 +1,14 @@
package bus
import (
)
type Bus struct {
}
func New() *Bus {
bus := &Bus{
}
return bus
}

48
pkg/cmd/serve/cmd.go Normal file
View file

@ -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
}

77
pkg/config/config.go Normal file
View file

@ -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)
}

39
pkg/config/read.go Normal file
View file

@ -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
}

View file

@ -0,0 +1,5 @@
package config
type Config struct {
Bind string `yaml:"bind"`
}

50
pkg/server/server.go Normal file
View file

@ -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
}

17
pkg/server/websocket.go Normal file
View file

@ -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")
}