diff options
| -rw-r--r-- | cmd/patreon-saasproxy/main.go | 22 | ||||
| -rw-r--r-- | cmd/xesite/api.go | 44 | ||||
| -rw-r--r-- | cmd/xesite/internalapi.go | 35 | ||||
| -rw-r--r-- | cmd/xesite/main.go | 6 | ||||
| -rw-r--r-- | go.mod | 11 | ||||
| -rw-r--r-- | go.sum | 21 | ||||
| -rw-r--r-- | gomod2nix.toml | 33 | ||||
| -rw-r--r-- | internal/lume/lume.go | 24 | ||||
| -rw-r--r-- | pb/generate.go | 8 | ||||
| -rw-r--r-- | pb/openapi.json | 61 | ||||
| -rw-r--r-- | pb/xesite.pb.go | 39 | ||||
| -rw-r--r-- | pb/xesite.proto | 2 | ||||
| -rw-r--r-- | pb/xesite.twirp.go | 123 | ||||
| -rw-r--r-- | tools.go | 7 |
14 files changed, 340 insertions, 96 deletions
diff --git a/cmd/patreon-saasproxy/main.go b/cmd/patreon-saasproxy/main.go index ef83302..6901ee3 100644 --- a/cmd/patreon-saasproxy/main.go +++ b/cmd/patreon-saasproxy/main.go @@ -3,7 +3,6 @@ package main import ( "context" "encoding/base64" - "encoding/json" "flag" "log" "log/slog" @@ -14,6 +13,7 @@ import ( "github.com/facebookgo/flagenv" _ "github.com/joho/godotenv/autoload" + "github.com/twitchtv/twirp" "golang.org/x/oauth2" "google.golang.org/protobuf/types/known/emptypb" "google.golang.org/protobuf/types/known/timestamppb" @@ -80,8 +80,6 @@ func main() { cts: cts, } - http.HandleFunc("/give-token", s.GiveToken) - ph := adminpb.NewPatreonServer(s) http.Handle(adminpb.PatreonPathPrefix, ph) @@ -104,7 +102,7 @@ func (s *Server) GetToken(ctx context.Context, _ *emptypb.Empty) (*adminpb.Patre token, err := s.cts.Token() if err != nil { slog.Error("token fetch failed", "err", err) - return nil, err + return nil, twirp.InternalErrorWith(err) } return &adminpb.PatreonToken{ @@ -114,19 +112,3 @@ func (s *Server) GetToken(ctx context.Context, _ *emptypb.Empty) (*adminpb.Patre Expiry: timestamppb.New(token.Expiry), }, nil } - -func (s *Server) GiveToken(w http.ResponseWriter, r *http.Request) { - token, err := s.cts.Token() - if err != nil { - slog.Error("token fetch failed", "err", err) - http.Error(w, "token fetch failed", http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - - if err := json.NewEncoder(w).Encode(token); err != nil { - slog.Error("token encode failed", "err", err) - return - } -} diff --git a/cmd/xesite/api.go b/cmd/xesite/api.go new file mode 100644 index 0000000..35bb5ae --- /dev/null +++ b/cmd/xesite/api.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "os" + "os/exec" + "runtime" + + "github.com/twitchtv/twirp" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + "xeiaso.net/v4/internal/lume" + "xeiaso.net/v4/pb" +) + +type MetaServer struct { + fs *lume.FS +} + +func (ms *MetaServer) Metadata(ctx context.Context, _ *emptypb.Empty) (*pb.BuildInfo, error) { + deno, err := exec.LookPath("deno") + if err != nil { + return nil, twirp.InternalErrorf("can't find deno in $PATH: %w", err) + } + + commit, err := ms.fs.Commit() + if err != nil { + return nil, twirp.InternalErrorf("can't get commit hash: %w", err) + } + + result := &pb.BuildInfo{ + Commit: commit, + GoVersion: runtime.Version(), + DenoVersion: deno, + XesiteVersion: os.Args[0], + BuildTime: timestamppb.New(ms.fs.BuildTime()), + } + + if *devel { + result.XesiteVersion = "devel" + } + + return result, nil +} diff --git a/cmd/xesite/internalapi.go b/cmd/xesite/internalapi.go index 7d1ebcb..99516fc 100644 --- a/cmd/xesite/internalapi.go +++ b/cmd/xesite/internalapi.go @@ -6,9 +6,17 @@ import ( "log" "net" "net/http" + "os" + "os/exec" "path/filepath" + "runtime" + "github.com/twitchtv/twirp" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + "xeiaso.net/v4/internal/adminpb" "xeiaso.net/v4/internal/lume" + "xeiaso.net/v4/pb" ) func internalAPI(fs *lume.FS) { @@ -26,6 +34,8 @@ func internalAPI(fs *lume.FS) { http.ServeFile(w, r, filepath.Join(*dataDir, "site.zip")) }) + mux.Handle(adminpb.AdminPathPrefix, adminpb.NewAdminServer(&AdminAPI{fs: fs})) + ln, err := net.Listen("tcp", ":80") if err != nil { log.Fatal(err) @@ -33,3 +43,28 @@ func internalAPI(fs *lume.FS) { http.Serve(ln, mux) } + +type AdminAPI struct { + fs *lume.FS +} + +func (aa *AdminAPI) Rebuild(ctx context.Context, _ *emptypb.Empty) (*pb.BuildInfo, error) { + deno, err := exec.LookPath("deno") + if err != nil { + return nil, twirp.InternalErrorf("can't find deno in $PATH: %w", err) + } + + result := &pb.BuildInfo{ + GoVersion: runtime.Version(), + DenoVersion: deno, + XesiteVersion: os.Args[0], + } + + if err := aa.fs.Update(ctx); err != nil { + return nil, twirp.InternalErrorWith(err) + } + + result.BuildTime = timestamppb.Now() + + return result, nil +} diff --git a/cmd/xesite/main.go b/cmd/xesite/main.go index 4635a71..a70ddc7 100644 --- a/cmd/xesite/main.go +++ b/cmd/xesite/main.go @@ -13,8 +13,10 @@ import ( "github.com/donatj/hmacsig" "github.com/facebookgo/flagenv" _ "github.com/joho/godotenv/autoload" + "github.com/twitchtv/twirp" "xeiaso.net/v4/internal" "xeiaso.net/v4/internal/lume" + "xeiaso.net/v4/pb" ) var ( @@ -77,6 +79,10 @@ func main() { mux := http.NewServeMux() mux.Handle("/", http.FileServer(http.FS(fs))) + mux.Handle("/api/defs/", http.StripPrefix("/api/defs/", http.FileServer(http.FS(pb.Proto)))) + + ms := pb.NewMetaServer(&MetaServer{fs}, twirp.WithServerPathPrefix("/api")) + mux.Handle(ms.PathPrefix(), ms) mux.HandleFunc("/blog.atom", func(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/blog.rss", http.StatusMovedPermanently) @@ -24,17 +24,27 @@ require ( dario.cat/mergo v1.0.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/blockthrough/twirp-openapi-gen v0.0.0-20231107141308-45a52eb7d856 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/emicklei/proto v1.11.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect + github.com/getkin/kin-openapi v0.120.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-openapi/jsonpointer v0.20.0 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/invopop/yaml v0.2.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/skeema/knownhosts v1.2.1 // indirect @@ -48,4 +58,5 @@ require ( golang.org/x/tools v0.17.0 // indirect google.golang.org/appengine v1.6.8 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) @@ -11,6 +11,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/blockthrough/twirp-openapi-gen v0.0.0-20231107141308-45a52eb7d856 h1:7m7Q6EErVZWPIp1UeVSb5zUTFzV6m7ZUcUIpbWffBfs= +github.com/blockthrough/twirp-openapi-gen v0.0.0-20231107141308-45a52eb7d856/go.mod h1:UN1OFH6gXrM9qKvXPcs4dOAAMB1tC4kw/eUzdA/bmI8= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= @@ -24,6 +26,8 @@ github.com/donatj/hmacsig v1.1.0 h1:DbBIW1ZTMfJoJhDGPVpkatYyxhrR2xVoHAokPTrlw50= github.com/donatj/hmacsig v1.1.0/go.mod h1:rh/7q72Fo5oYc7bcKgvGHWsfHcs8jKhJdFgCZcvZ/G0= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emicklei/proto v1.11.2 h1:DiIeyTJ+gPSyJI+RIAqvuTeKb0tLUmaGXbYg6aFKsnE= +github.com/emicklei/proto v1.11.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= @@ -36,6 +40,8 @@ github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpm github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getkin/kin-openapi v0.120.0 h1:MqJcNJFrMDFNc07iwE8iFC5eT2k/NPUFDIpNeiZv8Jg= +github.com/getkin/kin-openapi v0.120.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-faker/faker/v4 v4.3.0 h1:UXOW7kn/Mwd0u6MR30JjUKVzguT20EB/hBOddAAO+DY= @@ -48,6 +54,10 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -57,10 +67,14 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -70,8 +84,14 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -182,6 +202,7 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= tailscale.com v1.58.2 h1:5trkhh/fpUn7f6TUcGUQYJ0GokdNNfNrjh9ONJhoc5A= diff --git a/gomod2nix.toml b/gomod2nix.toml index 602d6f0..58c026d 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -13,6 +13,9 @@ schema = 3 [mod."github.com/bep/debounce"] version = "v1.2.1" hash = "sha256-7qHOp4vB0ifEseXXBuSH6W5YNImVcb8PTWSJJAMaGcU=" + [mod."github.com/blockthrough/twirp-openapi-gen"] + version = "v0.0.0-20231107141308-45a52eb7d856" + hash = "sha256-i0K4rM/A36eTIG86zibtaA40WoT2M+ptReRCDy+EYGs=" [mod."github.com/cloudflare/circl"] version = "v1.3.7" hash = "sha256-AkOpcZ+evLxLJStvvr01+TLeWDqcLxY3e/AhGggzh40=" @@ -22,6 +25,9 @@ schema = 3 [mod."github.com/donatj/hmacsig"] version = "v1.1.0" hash = "sha256-/T7mWqQwZt+AFD/2QAYCAW/TsZptawFMl8CGWPmyhtE=" + [mod."github.com/emicklei/proto"] + version = "v1.11.2" + hash = "sha256-1j9oAuZbq5F+eY0emvivv4G/46YRoL/QzqwomuFElsw=" [mod."github.com/emirpasic/gods"] version = "v1.18.1" hash = "sha256-hGDKddjLj+5dn2woHtXKUdd49/3xdsqnhx7VEdCu1m4=" @@ -34,6 +40,9 @@ schema = 3 [mod."github.com/facebookgo/subset"] version = "v0.0.0-20200203212716-c811ad88dec4" hash = "sha256-oBhWz9Haw/ZuqJofQ7psThNrr1f6GHHgxq8agev7TOo=" + [mod."github.com/getkin/kin-openapi"] + version = "v0.120.0" + hash = "sha256-x5BjdRncVOy3t7HqmA6IwfYDg/xy3BsGjFawrnrXcko=" [mod."github.com/go-faker/faker/v4"] version = "v4.3.0" hash = "sha256-Y70kJJAMfQ6CBvZO+28gpKGSni/EFMNIGKUzc299Sss=" @@ -46,21 +55,42 @@ schema = 3 [mod."github.com/go-git/go-git/v5"] version = "v5.11.0" hash = "sha256-2yUM/FlV+nYxacVynJCnDZeMub4Iu8JL2WBHmlnwOkE=" + [mod."github.com/go-openapi/jsonpointer"] + version = "v0.20.0" + hash = "sha256-31YT6a8u7adrtEOV62066BrrNfPT5kg5uUUo9ULW0Qk=" + [mod."github.com/go-openapi/swag"] + version = "v0.22.4" + hash = "sha256-a3iJF2d9pJVTBMNpxWIOA8S1+qTbQQ+ToFcXypQ5Tec=" [mod."github.com/golang/groupcache"] version = "v0.0.0-20210331224755-41bb18bfe9da" hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0=" [mod."github.com/golang/protobuf"] version = "v1.5.3" hash = "sha256-svogITcP4orUIsJFjMtp+Uv1+fKJv2Q5Zwf2dMqnpOQ=" + [mod."github.com/invopop/yaml"] + version = "v0.2.0" + hash = "sha256-RxeDuvwOSWYaLc8Q7T39rfFT3bZX3g9Bu0RFwxH6sLw=" [mod."github.com/jbenet/go-context"] version = "v0.0.0-20150711004518-d14ea06fba99" hash = "sha256-VANNCWNNpARH/ILQV9sCQsBWgyL2iFT+4AHZREpxIWE=" [mod."github.com/joho/godotenv"] version = "v1.5.1" hash = "sha256-kA0osKfsc6Kp+nuGTRJyXZZlJt1D/kuEazKMWYCWcQ8=" + [mod."github.com/josharian/intern"] + version = "v1.0.0" + hash = "sha256-LJR0QE2vOQ2/2shBbO5Yl8cVPq+NFrE3ers0vu9FRP0=" [mod."github.com/kevinburke/ssh_config"] version = "v1.2.0" hash = "sha256-Ta7ZOmyX8gG5tzWbY2oES70EJPfI90U7CIJS9EAce0s=" + [mod."github.com/mailru/easyjson"] + version = "v0.7.7" + hash = "sha256-NVCz8MURpxgOjHXqxOZExqV4bnpHggpeAOyZDArjcy4=" + [mod."github.com/mohae/deepcopy"] + version = "v0.0.0-20170929034955-c48cc78d4826" + hash = "sha256-TQMmKqIYwVhmMVh4RYQkAui97Eyj7poLmcAuDcHXsEk=" + [mod."github.com/perimeterx/marshmallow"] + version = "v1.1.5" + hash = "sha256-fFWjg0FNohDSV0/wUjQ8fBq1g8h6yIqTrHkxqL2Tt0s=" [mod."github.com/pjbgf/sha1cd"] version = "v0.3.0" hash = "sha256-kX9BdLh2dxtGNaDvc24NORO+C0AZ7JzbrXrtecCdB7w=" @@ -115,6 +145,9 @@ schema = 3 [mod."gopkg.in/warnings.v0"] version = "v0.1.2" hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8=" + [mod."gopkg.in/yaml.v3"] + version = "v3.0.1" + hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" [mod."tailscale.com"] version = "v1.58.2" hash = "sha256-ok+xgZRbFkQcH9VR75bhHx+bRn8ymoYQeBYsMpvfGss=" diff --git a/internal/lume/lume.go b/internal/lume/lume.go index d4139c0..dd12cf1 100644 --- a/internal/lume/lume.go +++ b/internal/lume/lume.go @@ -69,6 +69,8 @@ type FS struct { fs fs.FS lock sync.Mutex + + lastBuildTime time.Time } func (f *FS) Close() error { @@ -86,6 +88,27 @@ func (f *FS) Close() error { return nil } +func (f *FS) Commit() (string, error) { + f.lock.Lock() + defer f.lock.Unlock() + + commit, err := f.repo.Head() + if err != nil { + return "", fmt.Errorf("lume: can't get head: %w", err) + } + + result := commit.Hash().String() + + return result, nil +} + +func (f *FS) BuildTime() time.Time { + f.lock.Lock() + defer f.lock.Unlock() + + return f.lastBuildTime +} + func (f *FS) Open(name string) (fs.File, error) { fin, err := f.fs.Open(name) if err != nil { @@ -205,6 +228,7 @@ func New(ctx context.Context, o *Options) (*FS, error) { } }() } + fs.lastBuildTime = time.Now() return fs, nil } diff --git a/pb/generate.go b/pb/generate.go index 5adfc1a..db5295f 100644 --- a/pb/generate.go +++ b/pb/generate.go @@ -1,5 +1,13 @@ package pb +import ( + "embed" +) + func init() {} //go:generate protoc --proto_path=. --go_out=. --go_opt=paths=source_relative --twirp_out=. --twirp_opt=paths=source_relative xesite.proto +//go:generate go run github.com/blockthrough/twirp-openapi-gen/cmd/twirp-openapi-gen --in=xesite.proto --path-prefix=/api --servers=https://xeiaso.net --title="xeiaso.net API" --out openapi.json + +//go:embed xesite.proto openapi.json +var Proto embed.FS diff --git a/pb/openapi.json b/pb/openapi.json new file mode 100644 index 0000000..8db285c --- /dev/null +++ b/pb/openapi.json @@ -0,0 +1,61 @@ +{ + "components": { + "schemas": { + "xeiaso.net.BuildInfo": { + "properties": { + "build_time": { + "format": "date-time", + "type": "string" + }, + "commit": { + "type": "string" + }, + "deno_version": { + "type": "string" + }, + "go_version": { + "type": "string" + }, + "xesite_version": { + "type": "string" + } + }, + "type": "object" + } + } + }, + "info": { + "title": "xeiaso.net API", + "version": "0.1" + }, + "openapi": "3.0.0", + "paths": { + "/api/xeiaso.net.Meta/Metadata": { + "post": { + "requestBody": { + "content": { + "application/json": {} + } + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/xeiaso.net.BuildInfo" + } + } + }, + "description": "Success" + } + }, + "summary": "Metadata" + } + } + }, + "servers": [ + { + "url": "https://xeiaso.net" + } + ] +}
\ No newline at end of file diff --git a/pb/xesite.pb.go b/pb/xesite.pb.go index 1691ffd..0073d07 100644 --- a/pb/xesite.pb.go +++ b/pb/xesite.pb.go @@ -27,10 +27,11 @@ type BuildInfo struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Commit string `protobuf:"bytes,1,opt,name=commit,proto3" json:"commit,omitempty"` - BuildTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=build_time,json=buildTime,proto3" json:"build_time,omitempty"` - GoVersion string `protobuf:"bytes,3,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` - DenoVersion string `protobuf:"bytes,4,opt,name=deno_version,json=denoVersion,proto3" json:"deno_version,omitempty"` + Commit string `protobuf:"bytes,1,opt,name=commit,proto3" json:"commit,omitempty"` + BuildTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=build_time,json=buildTime,proto3" json:"build_time,omitempty"` + GoVersion string `protobuf:"bytes,3,opt,name=go_version,json=goVersion,proto3" json:"go_version,omitempty"` + DenoVersion string `protobuf:"bytes,4,opt,name=deno_version,json=denoVersion,proto3" json:"deno_version,omitempty"` + XesiteVersion string `protobuf:"bytes,5,opt,name=xesite_version,json=xesiteVersion,proto3" json:"xesite_version,omitempty"` } func (x *BuildInfo) Reset() { @@ -93,6 +94,13 @@ func (x *BuildInfo) GetDenoVersion() string { return "" } +func (x *BuildInfo) GetXesiteVersion() string { + if x != nil { + return x.XesiteVersion + } + return "" +} + var File_xesite_proto protoreflect.FileDescriptor var file_xesite_proto_rawDesc = []byte{ @@ -101,7 +109,7 @@ var file_xesite_proto_rawDesc = []byte{ 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa0, 0x01, 0x0a, 0x09, 0x42, 0x75, 0x69, + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, @@ -111,13 +119,16 @@ var file_xesite_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x6e, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0x41, 0x0a, 0x04, 0x4c, - 0x75, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, - 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x12, - 0x5a, 0x10, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x34, 0x2f, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x65, 0x6e, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x78, + 0x65, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x78, 0x65, 0x73, 0x69, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x32, 0x41, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x08, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, + 0x2e, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x12, 0x5a, 0x10, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, 0x2e, + 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -140,8 +151,8 @@ var file_xesite_proto_goTypes = []interface{}{ } var file_xesite_proto_depIdxs = []int32{ 1, // 0: xeiaso.net.BuildInfo.build_time:type_name -> google.protobuf.Timestamp - 2, // 1: xeiaso.net.Lume.Metadata:input_type -> google.protobuf.Empty - 0, // 2: xeiaso.net.Lume.Metadata:output_type -> xeiaso.net.BuildInfo + 2, // 1: xeiaso.net.Meta.Metadata:input_type -> google.protobuf.Empty + 0, // 2: xeiaso.net.Meta.Metadata:output_type -> xeiaso.net.BuildInfo 2, // [2:3] is the sub-list for method output_type 1, // [1:2] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name diff --git a/pb/xesite.proto b/pb/xesite.proto index 9dbaabf..8644aa1 100644 --- a/pb/xesite.proto +++ b/pb/xesite.proto @@ -5,7 +5,7 @@ option go_package = "xeiaso.net/v4/pb"; import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; -service Lume { rpc Metadata(google.protobuf.Empty) returns (BuildInfo); } +service Meta { rpc Metadata(google.protobuf.Empty) returns (BuildInfo); } message BuildInfo { string commit = 1; diff --git a/pb/xesite.twirp.go b/pb/xesite.twirp.go index a1b59be..8548b7f 100644 --- a/pb/xesite.twirp.go +++ b/pb/xesite.twirp.go @@ -30,27 +30,27 @@ import url "net/url" const _ = twirp.TwirpPackageMinVersion_8_1_0 // ============== -// Lume Interface +// Meta Interface // ============== -type Lume interface { +type Meta interface { Metadata(context.Context, *google_protobuf.Empty) (*BuildInfo, error) } // ==================== -// Lume Protobuf Client +// Meta Protobuf Client // ==================== -type lumeProtobufClient struct { +type metaProtobufClient struct { client HTTPClient urls [1]string interceptor twirp.Interceptor opts twirp.ClientOptions } -// NewLumeProtobufClient creates a Protobuf client that implements the Lume interface. +// NewMetaProtobufClient creates a Protobuf client that implements the Meta interface. // It communicates using Protobuf and can be configured with a custom HTTPClient. -func NewLumeProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Lume { +func NewMetaProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Meta { if c, ok := client.(*http.Client); ok { client = withoutRedirects(c) } @@ -70,12 +70,12 @@ func NewLumeProtobufClient(baseURL string, client HTTPClient, opts ...twirp.Clie // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> serviceURL := sanitizeBaseURL(baseURL) - serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Lume") + serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Meta") urls := [1]string{ serviceURL + "Metadata", } - return &lumeProtobufClient{ + return &metaProtobufClient{ client: client, urls: urls, interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), @@ -83,9 +83,9 @@ func NewLumeProtobufClient(baseURL string, client HTTPClient, opts ...twirp.Clie } } -func (c *lumeProtobufClient) Metadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { +func (c *metaProtobufClient) Metadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { ctx = ctxsetters.WithPackageName(ctx, "xeiaso.net") - ctx = ctxsetters.WithServiceName(ctx, "Lume") + ctx = ctxsetters.WithServiceName(ctx, "Meta") ctx = ctxsetters.WithMethodName(ctx, "Metadata") caller := c.callMetadata if c.interceptor != nil { @@ -112,7 +112,7 @@ func (c *lumeProtobufClient) Metadata(ctx context.Context, in *google_protobuf.E return caller(ctx, in) } -func (c *lumeProtobufClient) callMetadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { +func (c *metaProtobufClient) callMetadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { out := new(BuildInfo) ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { @@ -130,19 +130,19 @@ func (c *lumeProtobufClient) callMetadata(ctx context.Context, in *google_protob } // ================ -// Lume JSON Client +// Meta JSON Client // ================ -type lumeJSONClient struct { +type metaJSONClient struct { client HTTPClient urls [1]string interceptor twirp.Interceptor opts twirp.ClientOptions } -// NewLumeJSONClient creates a JSON client that implements the Lume interface. +// NewMetaJSONClient creates a JSON client that implements the Meta interface. // It communicates using JSON and can be configured with a custom HTTPClient. -func NewLumeJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Lume { +func NewMetaJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Meta { if c, ok := client.(*http.Client); ok { client = withoutRedirects(c) } @@ -162,12 +162,12 @@ func NewLumeJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOp // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> serviceURL := sanitizeBaseURL(baseURL) - serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Lume") + serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Meta") urls := [1]string{ serviceURL + "Metadata", } - return &lumeJSONClient{ + return &metaJSONClient{ client: client, urls: urls, interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), @@ -175,9 +175,9 @@ func NewLumeJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOp } } -func (c *lumeJSONClient) Metadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { +func (c *metaJSONClient) Metadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { ctx = ctxsetters.WithPackageName(ctx, "xeiaso.net") - ctx = ctxsetters.WithServiceName(ctx, "Lume") + ctx = ctxsetters.WithServiceName(ctx, "Meta") ctx = ctxsetters.WithMethodName(ctx, "Metadata") caller := c.callMetadata if c.interceptor != nil { @@ -204,7 +204,7 @@ func (c *lumeJSONClient) Metadata(ctx context.Context, in *google_protobuf.Empty return caller(ctx, in) } -func (c *lumeJSONClient) callMetadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { +func (c *metaJSONClient) callMetadata(ctx context.Context, in *google_protobuf.Empty) (*BuildInfo, error) { out := new(BuildInfo) ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) if err != nil { @@ -222,11 +222,11 @@ func (c *lumeJSONClient) callMetadata(ctx context.Context, in *google_protobuf.E } // =================== -// Lume Server Handler +// Meta Server Handler // =================== -type lumeServer struct { - Lume +type metaServer struct { + Meta interceptor twirp.Interceptor hooks *twirp.ServerHooks pathPrefix string // prefix for routing @@ -234,10 +234,10 @@ type lumeServer struct { jsonCamelCase bool // JSON fields are serialized as lowerCamelCase rather than keeping the original proto names } -// NewLumeServer builds a TwirpServer that can be used as an http.Handler to handle +// NewMetaServer builds a TwirpServer that can be used as an http.Handler to handle // HTTP requests that are routed to the right method in the provided svc implementation. // The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). -func NewLumeServer(svc Lume, opts ...interface{}) TwirpServer { +func NewMetaServer(svc Meta, opts ...interface{}) TwirpServer { serverOpts := newServerOpts(opts) // Using ReadOpt allows backwards and forwards compatibility with new options in the future @@ -250,8 +250,8 @@ func NewLumeServer(svc Lume, opts ...interface{}) TwirpServer { pathPrefix = "/twirp" // default prefix } - return &lumeServer{ - Lume: svc, + return &metaServer{ + Meta: svc, hooks: serverOpts.Hooks, interceptor: twirp.ChainInterceptors(serverOpts.Interceptors...), pathPrefix: pathPrefix, @@ -262,12 +262,12 @@ func NewLumeServer(svc Lume, opts ...interface{}) TwirpServer { // writeError writes an HTTP response with a valid Twirp error format, and triggers hooks. // If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) -func (s *lumeServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { +func (s *metaServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { writeError(ctx, resp, err, s.hooks) } // handleRequestBodyError is used to handle error when the twirp server cannot read request -func (s *lumeServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { +func (s *metaServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { if context.Canceled == ctx.Err() { s.writeError(ctx, resp, twirp.NewError(twirp.Canceled, "failed to read request: context canceled")) return @@ -279,16 +279,16 @@ func (s *lumeServer) handleRequestBodyError(ctx context.Context, resp http.Respo s.writeError(ctx, resp, twirp.WrapError(malformedRequestError(msg), err)) } -// LumePathPrefix is a convenience constant that may identify URL paths. +// MetaPathPrefix is a convenience constant that may identify URL paths. // Should be used with caution, it only matches routes generated by Twirp Go clients, // with the default "/twirp" prefix and default CamelCase service and method names. // More info: https://twitchtv.github.io/twirp/docs/routing.html -const LumePathPrefix = "/twirp/xeias |
