aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorXe <me@christine.website>2022-09-02 17:36:16 +0000
committerXe <me@christine.website>2022-09-02 17:36:16 +0000
commite6329f22d52770cc09e5268183630045e2b038d9 (patch)
tree98226898affd326c818e798a81d5fd3bb5be7f75 /cmd
parent8214faa30c03d1d127338e4a5106ce9878a66c4c (diff)
downloadx-e6329f22d52770cc09e5268183630045e2b038d9.tar.xz
x-e6329f22d52770cc09e5268183630045e2b038d9.zip
xedn
Signed-off-by: Xe <me@christine.website>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/xedn/.dockerignore1
-rw-r--r--cmd/xedn/.gitignore1
-rw-r--r--cmd/xedn/Dockerfile3
-rw-r--r--cmd/xedn/build.go25
-rw-r--r--cmd/xedn/fly.toml43
-rw-r--r--cmd/xedn/main.go131
6 files changed, 204 insertions, 0 deletions
diff --git a/cmd/xedn/.dockerignore b/cmd/xedn/.dockerignore
new file mode 100644
index 0000000..e796b66
--- /dev/null
+++ b/cmd/xedn/.dockerignore
@@ -0,0 +1 @@
+*.go
diff --git a/cmd/xedn/.gitignore b/cmd/xedn/.gitignore
new file mode 100644
index 0000000..17b2f35
--- /dev/null
+++ b/cmd/xedn/.gitignore
@@ -0,0 +1 @@
+slug.tar.gz
diff --git a/cmd/xedn/Dockerfile b/cmd/xedn/Dockerfile
new file mode 100644
index 0000000..98553ca
--- /dev/null
+++ b/cmd/xedn/Dockerfile
@@ -0,0 +1,3 @@
+FROM alpine:3.16
+ADD ./slug.tar.gz /app
+CMD /app/bin/web
diff --git a/cmd/xedn/build.go b/cmd/xedn/build.go
new file mode 100644
index 0000000..d84e89e
--- /dev/null
+++ b/cmd/xedn/build.go
@@ -0,0 +1,25 @@
+//+build ignore
+
+// Builds and deploys the application to minipaas.
+package main
+
+import (
+ "context"
+ "os"
+
+ "within.website/x/internal"
+ "within.website/x/internal/yeet"
+)
+
+func main() {
+ internal.HandleStartup()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ env := append(os.Environ(), []string{"CGO_ENABLED=0", "GOOS=linux"}...)
+ yeet.ShouldWork(ctx, env, yeet.WD, "go", "build", "-v", "-o=web")
+ yeet.ShouldWork(ctx, env, yeet.WD, "appsluggr", "-web=web")
+ os.Remove("web")
+ yeet.ShouldWork(ctx, env, yeet.WD, "flyctl", "deploy", "--now")
+}
diff --git a/cmd/xedn/fly.toml b/cmd/xedn/fly.toml
new file mode 100644
index 0000000..b0c9374
--- /dev/null
+++ b/cmd/xedn/fly.toml
@@ -0,0 +1,43 @@
+# fly.toml file generated for xedn on 2022-09-02T17:14:40Z
+
+app = "xedn"
+
+kill_signal = "SIGINT"
+kill_timeout = 5
+processes = []
+
+[build]
+ dockerfile = "./Dockerfile"
+
+[env]
+
+[experimental]
+ allowed_public_ports = []
+ auto_rollback = true
+
+[[services]]
+ http_checks = []
+ internal_port = 8080
+ processes = ["app"]
+ protocol = "tcp"
+ script_checks = []
+
+ [services.concurrency]
+ hard_limit = 25
+ soft_limit = 20
+ type = "connections"
+
+ [[services.ports]]
+ force_https = true
+ handlers = ["http"]
+ port = 80
+
+ [[services.ports]]
+ handlers = ["tls", "http"]
+ port = 443
+
+ [[services.tcp_checks]]
+ grace_period = "1s"
+ interval = "15s"
+ restart_limit = 0
+ timeout = "2s"
diff --git a/cmd/xedn/main.go b/cmd/xedn/main.go
new file mode 100644
index 0000000..b0327d4
--- /dev/null
+++ b/cmd/xedn/main.go
@@ -0,0 +1,131 @@
+// Command quiche is a little cute cache server for my B2 bucket.
+package main
+
+import (
+ "bytes"
+ "context"
+ "encoding/gob"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+
+ "github.com/golang/groupcache"
+ "github.com/sebest/xff"
+ "tailscale.com/tsnet"
+ "within.website/ln"
+ "within.website/ln/ex"
+ "within.website/ln/opname"
+ "within.website/x/internal"
+ "within.website/x/web"
+)
+
+var (
+ b2Backend = flag.String("b2-backend", "https://f001.backblazeb2.com", "Backblaze B2 base URL")
+ addr = flag.String("addr", ":8080", "server address")
+ peers = flag.String("peers", "http://localhost:8080", "server pool list")
+)
+
+const cacheSize = 128 * 1024 * 1024 // 128 mebibytes
+
+type CacheData struct {
+ Headers http.Header
+ Body []byte
+}
+
+var Group = groupcache.NewGroup("b2-bucket", cacheSize, groupcache.GetterFunc(
+ func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
+ ln.Log(context.Background(), ln.F{"key": key})
+
+ resp, err := http.Get(*b2Backend + key)
+ if err != nil {
+ return fmt.Errorf("can't fetch from b2: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return web.NewError(http.StatusOK, resp)
+ }
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return fmt.Errorf("can't read from b2: %v", err)
+ }
+
+ result := &CacheData{
+ Headers: resp.Header,
+ Body: body,
+ }
+
+ var buf bytes.Buffer
+ err = gob.NewEncoder(&buf).Encode(result)
+ if err != nil {
+ return err
+ }
+
+ dest.SetBytes(buf.Bytes())
+
+ return nil
+ },
+))
+
+func main() {
+ internal.HandleStartup()
+ ctx := opname.With(context.Background(), "startup")
+
+ go func () {
+ srv := &tsnet.Server{
+ Hostname: "xedn-" + os.Getenv("FLY_REGION"),
+ Logf: log.New(io.Discard, "", 0).Printf,
+ AuthKey: os.Getenv("TS_AUTHKEY"),
+ }
+
+ lis, err := srv.Listen("tcp", ":80")
+ if err != nil {
+ ln.FatalErr(ctx, err, ln.Action("tsnet listening"))
+ }
+
+ defer srv.Close()
+ defer lis.Close()
+ ln.FatalErr(opname.With(ctx, "metrics-tsnet"), http.Serve(lis, ex.HTTPLog(http.DefaultServeMux)))
+ } ()
+
+ xffMW, err := xff.Default()
+ if err != nil {
+ ln.FatalErr(ctx, err)
+ }
+
+ mux := http.NewServeMux()
+ mux.HandleFunc("/file/christine-static/", func(w http.ResponseWriter, r *http.Request) {
+ var b []byte
+ err := Group.Get(nil, r.URL.Path, groupcache.AllocatingByteSliceSink(&b))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+
+ var result CacheData
+ err = gob.NewDecoder(bytes.NewBuffer(b)).Decode(&result)
+ if err != nil {
+ ln.Error(r.Context(), err)
+ http.Error(w, "internal cache error", http.StatusInternalServerError)
+ return
+ }
+
+ for k, vs := range result.Headers {
+ for _, v := range vs {
+ w.Header().Add(k, v)
+ }
+ }
+ w.WriteHeader(http.StatusOK)
+ w.Write(result.Body)
+ })
+ p := strings.Split(*peers, ",")
+ pool := groupcache.NewHTTPPool(p[0])
+ pool.Set(p...)
+ ln.Log(context.Background(), ln.F{"addr": *addr})
+ http.ListenAndServe(*addr, xffMW.Handler(ex.HTTPLog(mux)))
+}