Initial server

This commit is contained in:
Daniel 2024-07-14 13:47:48 -04:00
parent 29a52c2ba9
commit 94e1ec4c6b
9 changed files with 302 additions and 0 deletions

3
Makefile Normal file
View file

@ -0,0 +1,3 @@
build: gordio
gordio:
go build -o gordio ./cmd/gordio/

34
cmd/gordio/main.go Normal file
View file

@ -0,0 +1,34 @@
package main
import (
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"dynatron.me/x/stillbox/pkg/gordio"
"dynatron.me/x/stillbox/pkg/gordio/config"
"github.com/spf13/cobra"
)
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
rootCmd := cobra.Command{
Use: gordio.AppName,
}
cfg, err := config.ReadConfig()
if err != nil {
log.Fatal().Err(err).Msg("Config read failed")
}
rootCmd.AddCommand(gordio.Command(cfg))
err = rootCmd.Execute()
if err != nil {
log.Fatal().Err(err).Msg("Dying")
}
}

28
go.mod Normal file
View file

@ -0,0 +1,28 @@
module dynatron.me/x/stillbox
go 1.21.12
require (
github.com/rs/zerolog v1.33.0
github.com/spf13/cobra v1.8.1
)
require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/go-chi/chi/v5 v5.1.0 // indirect
github.com/go-chi/jwtauth/v5 v5.3.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/jwx/v2 v2.0.20 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/sys v0.18.0 // indirect
)

57
go.sum Normal file
View file

@ -0,0 +1,57 @@
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
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/jwtauth/v5 v5.3.1 h1:1ePWrjVctvp1tyBq5b/2ER8Th/+RbYc7x4qNsc5rh5A=
github.com/go-chi/jwtauth/v5 v5.3.1/go.mod h1:6Fl2RRmWXs3tJYE1IQGX81FsPoGqDwq9c15j52R5q80=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.0.20 h1:sAgXuWS/t8ykxS9Bi2Qtn5Qhpakw1wrcjxChudjolCc=
github.com/lestrrat-go/jwx/v2 v2.0.20/go.mod h1:UlCSmKqw+agm5BsOBfEAbTvKsEApaGNqHAEUTv5PJC4=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

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

@ -0,0 +1,27 @@
package common
import (
"github.com/spf13/cobra"
)
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
}
}

View file

@ -0,0 +1,15 @@
package config
type Config struct {
DB string `yaml:"db"`
JWTSecret string `yaml:"jwtsecret"`
Listen string `yaml:"listen"`
Public bool `yaml:"public"`
}
func ReadConfig() (*Config, error) {
return &Config{
JWTSecret: "s3c4r",
Listen: ":3050",
}, nil
}

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

@ -0,0 +1,50 @@
package gordio
import (
"dynatron.me/x/stillbox/internal/common"
"dynatron.me/x/stillbox/pkg/gordio/config"
"dynatron.me/x/stillbox/pkg/gordio/server"
"github.com/spf13/cobra"
)
const AppName = "gordio"
type ServeOptions struct {
cfg *config.Config
}
func Command(cfg *config.Config) *cobra.Command {
opts := makeOptions(cfg)
serveCmd := &cobra.Command{
Use: "serve",
Short: "starts the" + 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 {
srv, err := server.New(o.cfg)
if err != nil {
return err
}
err = srv.Go()
if err != nil {
return err
}
return nil
}

View file

@ -0,0 +1,44 @@
package server
import (
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
)
func (s *Server) setupRoutes() {
r := s.r
r.Group(func(r chi.Router) {
r.Use(jwtauth.Verifier(s.jwt))
r.Use(jwtauth.Authenticator(s.jwt))
})
r.Group(func (r chi.Router) {
// public routes
})
r.Group(func(r chi.Router) {
r.Use(jwtauth.Verifier(s.jwt))
// optional auth routes
r.Get("/", s.routeIndex)
})
}
func (s *Server) routeIndex(w http.ResponseWriter, r *http.Request) {
if s.Authenticated(r) {
w.Write([]byte(fmt.Sprint("Welcome\n")))
// error
}
}
func (s *Server) Authenticated(r *http.Request) bool {
// TODO: check IP against ACL, or conf.Public, and against map of routes
tok, _, _ := jwtauth.FromContext(r.Context())
return tok != nil
}

View file

@ -0,0 +1,44 @@
package server
import (
"log"
"net/http"
"dynatron.me/x/stillbox/pkg/gordio/config"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/jwtauth/v5"
)
type Server struct {
conf *config.Config
r *chi.Mux
jwt *jwtauth.JWTAuth
}
func New(cfg *config.Config) (*Server, error) {
r := chi.NewRouter()
srv := &Server{
conf: cfg,
r: r,
jwt: jwtauth.New("HS256", []byte(cfg.JWTSecret), nil),
}
_, tokenString, err := srv.jwt.Encode(map[string]interface{}{"user_id": 123})
if err != nil {
panic(err)
}
log.Printf("DEBUG token is %s", tokenString)
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
srv.setupRoutes()
return srv, nil
}
func (s *Server) Go() error {
http.ListenAndServe(s.conf.Listen, s.r)
return nil
}