Compare commits

..

5 Commits

7 changed files with 54 additions and 26 deletions

@ -1,4 +1,4 @@
# pages # 📜 pages
`pages` provides web application / static site hosting with built-in support for simple analytics via [Prometheus][] and `pages` provides web application / static site hosting with built-in support for simple analytics via [Prometheus][] and
[Grafana][]. [Grafana][].

@ -18,6 +18,7 @@ package commands
import ( import (
"context" "context"
"mime"
"net/http" "net/http"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
@ -51,8 +52,20 @@ var (
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
log := zaputil.Extract(ctx.Context) log := zaputil.Extract(ctx.Context)
gitService := git.NewService(hostConfig.Git) // additional mime-types that need to be explicitly registered
err := gitService.Load(ctx.Context) _ = mime.AddExtensionType(".woff2", "application/font-woff2")
_ = mime.AddExtensionType(".woff", "application/font-woff")
_ = mime.AddExtensionType(".ttf", "font/ttf")
_ = mime.AddExtensionType(".yaml", "application/yaml")
_ = mime.AddExtensionType(".yml", "application/yaml")
_ = mime.AddExtensionType(".json", "application/json")
gitService, err := git.NewService(hostConfig.Git)
if err != nil {
return err
}
err = gitService.Load(ctx.Context)
if err != nil { if err != nil {
return err return err
} }

@ -58,6 +58,10 @@ type httpFile struct {
file billy.File file billy.File
} }
func (f *httpFile) Seek(offset int64, whence int) (int64, error) {
return f.file.Seek(offset, whence)
}
func (f *httpFile) Stat() (fs.FileInfo, error) { func (f *httpFile) Stat() (fs.FileInfo, error) {
return f.fileInfo, nil return f.fileInfo, nil
} }

@ -18,9 +18,10 @@ package git
import ( import (
"context" "context"
"os"
"github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/go-git/go-git/v5/plumbing/transport/http"
@ -41,11 +42,14 @@ type Config struct {
} }
// NewService constructs a Service that manages the underlying git repository. // NewService constructs a Service that manages the underlying git repository.
func NewService(config Config) *Service { func NewService(config Config) (*Service, error) {
temp, err := os.MkdirTemp(os.TempDir(), "pages-*")
if err != nil {
return nil, err
}
options := &git.CloneOptions{ options := &git.CloneOptions{
URL: config.URL, URL: config.URL,
Depth: 1,
SingleBranch: true,
} }
if config.Username != "" && config.Password != "" { if config.Username != "" && config.Password != "" {
@ -65,8 +69,8 @@ func NewService(config Config) *Service {
return &Service{ return &Service{
options: options, options: options,
Store: memory.NewStorage(), Store: memory.NewStorage(),
FS: memfs.New(), FS: osfs.New(temp),
} }, nil
} }
// Service encapsulates operations that can be performed against the target git repository. // Service encapsulates operations that can be performed against the target git repository.
@ -98,7 +102,7 @@ func (s *Service) Sync(ctx context.Context) error {
return errors.Wrap(err, "failed to obtain worktree") return errors.Wrap(err, "failed to obtain worktree")
} }
_ = wt.PullContext(ctx, &git.PullOptions{ err = wt.PullContext(ctx, &git.PullOptions{
ReferenceName: s.options.ReferenceName, ReferenceName: s.options.ReferenceName,
SingleBranch: s.options.SingleBranch, SingleBranch: s.options.SingleBranch,
Depth: s.options.Depth, Depth: s.options.Depth,
@ -106,5 +110,11 @@ func (s *Service) Sync(ctx context.Context) error {
Force: true, Force: true,
}) })
switch {
case errors.Is(err, git.NoErrAlreadyUpToDate):
case err != nil:
zaputil.Extract(ctx).Error("failed to pull", zap.Error(err))
}
return nil return nil
} }

@ -20,7 +20,6 @@ import (
"context" "context"
"net" "net"
"net/http" "net/http"
"path"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@ -95,9 +94,15 @@ func NewServer(ctx context.Context, config ServerConfig) (*Server, error) {
public.Use( public.Use(
session.Middleware( session.Middleware(
session.Exclusions(exclusions...), session.Exclusions(exclusions...),
session.JavaScriptPath(path.Join(config.Session.Prefix, "pages.js")), session.JavaScriptPath("/pages.js"),
), ),
) )
var handler http.Handler = session.Handler()
handler = http.StripPrefix(config.Session.Prefix, handler)
public.Handle("/pages.js", web.Handler()).Methods(http.MethodGet)
public.PathPrefix(config.Session.Prefix).Handler(handler)
} }
admin := public.PathPrefix(config.Admin.Prefix).Subrouter() admin := public.PathPrefix(config.Admin.Prefix).Subrouter()
@ -111,15 +116,6 @@ func NewServer(ctx context.Context, config ServerConfig) (*Server, error) {
}) })
} }
{
var handler http.Handler = session.Handler()
handler = http.StripPrefix(config.Session.Prefix, handler)
session := public.PathPrefix(config.Session.Prefix).Subrouter()
session.HandleFunc("/pages.js", web.Handler()).Methods(http.MethodGet)
session.Handle("/", handler)
}
return &Server{ return &Server{
AdminMux: admin, AdminMux: admin,

@ -21,7 +21,9 @@ import (
"time" "time"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"go.uber.org/zap"
"github.com/mjpitz/myago/zaputil"
"github.com/mjpitz/pages/internal/geoip" "github.com/mjpitz/pages/internal/geoip"
"github.com/mjpitz/pages/internal/metrics" "github.com/mjpitz/pages/internal/metrics"
) )
@ -45,9 +47,11 @@ type Handle struct {
} }
func (h *Handle) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (h *Handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log := zaputil.Extract(r.Context())
conn, err := h.upgrader.Upgrade(w, r, nil) conn, err := h.upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
// log log.Error("failed to upgrade connection", zap.Error(err))
return return
} }
@ -70,7 +74,6 @@ func (h *Handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err = conn.ReadJSON(&req) err = conn.ReadJSON(&req)
if err != nil { if err != nil {
// log
return return
} }
} }

@ -18,11 +18,13 @@
import {ulid} from 'ulid'; import {ulid} from 'ulid';
const secure = window.location.protocol === "https:";
const protocol = secure ? "wss:" : "ws:";
const sessionPrefix = "/_session"; const sessionPrefix = "/_session";
const domain = window.location.host; const domain = window.location.host + (secure ? ":443" : "");
async function main() { async function main() {
const ws = new WebSocket(`ws://${domain}${sessionPrefix}${window.location.pathname}`); const ws = new WebSocket(`${protocol}//${domain}${sessionPrefix}${window.location.pathname}`);
const message = `{"ID":"${ulid()}","FullName":"ping"}` const message = `{"ID":"${ulid()}","FullName":"ping"}`
let id = null; let id = null;