diff options
| author | Xe Iaso <me@xeiaso.net> | 2024-06-08 13:39:52 -0700 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2024-06-08 13:41:05 -0700 |
| commit | bb8a5a886c993fc943277e56b4c9065c1f3a82b2 (patch) | |
| tree | 14de5be85b83b17553092f1f1c78b2b0d0b4cba3 | |
| parent | 2f9125d0cbe232dbb0dcd64eab33af356d5d615c (diff) | |
| download | x-bb8a5a886c993fc943277e56b4c9065c1f3a82b2.tar.xz x-bb8a5a886c993fc943277e56b4c9065c1f3a82b2.zip | |
cmd: add command future-sight for preview deployments
Signed-off-by: Xe Iaso <me@xeiaso.net>
| -rw-r--r-- | .go.mod.sri | 2 | ||||
| -rw-r--r-- | cmd/future-sight/.gitignore | 1 | ||||
| -rw-r--r-- | cmd/future-sight/main.go | 325 | ||||
| -rw-r--r-- | cmd/future-sight/manifest.dev.yaml | 195 | ||||
| -rw-r--r-- | cmd/future-sight/manifest.yaml | 226 | ||||
| -rwxr-xr-x | cmd/future-sight/port-forward.sh | 10 | ||||
| -rw-r--r-- | cmd/future-sight/var/.gitignore | 2 | ||||
| -rw-r--r-- | cmd/future-sight/yeetfile.js | 5 | ||||
| -rw-r--r-- | cmd/mi/services/posse/posse.go | 3 | ||||
| -rw-r--r-- | cmd/xedn/main.go | 2 | ||||
| -rw-r--r-- | flake.nix | 15 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 10 | ||||
| -rw-r--r-- | internal/xesite/xesite.go (renamed from cmd/xedn/internal/xesite/xesite.go) | 0 | ||||
| -rw-r--r-- | proto/future-sight.proto | 5 | ||||
| -rw-r--r-- | proto/future-sight/future-sight.pb.go | 145 | ||||
| -rw-r--r-- | proto/generate.go | 1 |
17 files changed, 948 insertions, 4 deletions
diff --git a/.go.mod.sri b/.go.mod.sri index 9517b90..9efdb77 100644 --- a/.go.mod.sri +++ b/.go.mod.sri @@ -1 +1 @@ -sha256-C9WPTIYksC9AFsbIV+AAp/ylXl6tDJexlPd7gnJzfLo= +sha256-EB0G+BwyFCgu+2Z6IeUzRrDGkt6Hw+FixX+C7gIkYHI= diff --git a/cmd/future-sight/.gitignore b/cmd/future-sight/.gitignore new file mode 100644 index 0000000..abe61a7 --- /dev/null +++ b/cmd/future-sight/.gitignore @@ -0,0 +1 @@ +.env.prod
\ No newline at end of file diff --git a/cmd/future-sight/main.go b/cmd/future-sight/main.go new file mode 100644 index 0000000..4948324 --- /dev/null +++ b/cmd/future-sight/main.go @@ -0,0 +1,325 @@ +package main + +import ( + "context" + "crypto/sha256" + "encoding/base64" + "flag" + "fmt" + "io" + "log" + "log/slog" + "net/http" + "os" + "path/filepath" + "runtime" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/nats-io/nats.go" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/proto" + "within.website/x/internal" + "within.website/x/internal/xesite" + pb "within.website/x/proto/future-sight" + "within.website/x/web/useragent" +) + +var ( + apiBind = flag.String("api-bind", ":8080", "address to bind API to") + bind = flag.String("bind", ":8081", "address to bind zipserver to") + + awsAccessKeyID = flag.String("aws-access-key-id", "", "AWS access key ID") + awsSecretKey = flag.String("aws-secret-access-key", "", "AWS secret access key") + awsEndpointS3 = flag.String("aws-endpoint-url-s3", "http://localhost:9000", "AWS S3 endpoint") + awsRegion = flag.String("aws-region", "auto", "AWS region") + bucketName = flag.String("bucket-name", "xesite-preview-versions", "bucket to fetch previews from") + dataDir = flag.String("data-dir", "./var", "directory to store data in (not permanent)") + natsURL = flag.String("nats-url", "nats://localhost:4222", "nats url") + usePathStyle = flag.Bool("use-path-style", false, "use path style for S3") + valkeyHost = flag.String("valkey-host", "localhost:6379", "host:port for valkey") + valkeyPassword = flag.String("valkey-password", "", "password for valkey") +) + +func main() { + internal.HandleStartup() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + creds := credentials.NewStaticCredentialsProvider(*awsAccessKeyID, *awsSecretKey, "") + + s3c := s3.New(s3.Options{ + AppID: useragent.GenUserAgent("future-sight-push", "https://xeiaso.net"), + BaseEndpoint: awsEndpointS3, + ClientLogMode: aws.LogRetries | aws.LogRequest | aws.LogResponse, + Credentials: creds, + EndpointResolver: s3.EndpointResolverFromURL(*awsEndpointS3), + //Logger: logging.NewStandardLogger(os.Stderr), + UsePathStyle: *usePathStyle, + Region: *awsRegion, + }) + + slog.Debug("details", + "awsAccessKeyID", *awsAccessKeyID, + "awsSecretKey", *awsSecretKey, + "awsEndpointS3", *awsEndpointS3, + "awsRegion", *awsRegion, + "bucketName", *bucketName, + "natsURL", *natsURL, + "usePathStyle", *usePathStyle, + "valkeyHost", *valkeyHost, + "valkeyPassword", *valkeyPassword, + ) + + vk := redis.NewClient(&redis.Options{ + Addr: *valkeyHost, + Password: *valkeyPassword, + DB: 0, + }) + defer vk.Close() + + if _, err := vk.Ping(context.Background()).Result(); err != nil { + log.Fatal(err) + } + + nc, err := nats.Connect(*natsURL) + if err != nil { + log.Fatal(err) + } + defer nc.Close() + + zs, err := xesite.NewZipServer(filepath.Join(*dataDir, "current.zip"), *dataDir) + if err != nil { + log.Fatal(err) + } + + s := &Server{ + s3c: s3c, + vk: vk, + nc: nc, + zs: zs, + dir: *dataDir, + } + + currentVersion, err := vk.Get(ctx, "future-sight:current").Result() + if err != nil && err != redis.Nil { + log.Fatal(err) + } + + if currentVersion != "" { + nv := pb.NewVersion{ + Slug: currentVersion, + } + + if err := s.fetchVersion(ctx, &nv); err != nil { + slog.Error("can't fetch current version", "err", err) + } + } + + if _, err := nc.Subscribe("future-sight-push", s.HandleFutureSightPushMsg); err != nil { + log.Fatal(err) + } + + apiMux := http.NewServeMux() + apiMux.HandleFunc("/upload", s.UploadVersion) + apiMux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "OK") + }) + + g, _ := errgroup.WithContext(context.Background()) + + g.Go(func() error { + slog.Info("listening", "for", "api", "addr", *apiBind) + return http.ListenAndServe(*apiBind, apiMux) + }) + + g.Go(func() error { + slog.Info("listening", "for", "zipserver", "addr", *bind) + return http.ListenAndServe(*bind, zs) + }) + + if err := g.Wait(); err != nil { + slog.Error("error doing work", "err", err) + os.Exit(1) + } +} + +type Server struct { + s3c *s3.Client + vk *redis.Client + nc *nats.Conn + zs *xesite.ZipServer + dir string +} + +func (s *Server) UploadVersion(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithCancel(r.Context()) + defer cancel() + + slog.Info("uploading version") + + if err := r.ParseMultipartForm(10 << 24); err != nil { + slog.Error("failed to parse form", "err", err) + http.Error(w, "failed to parse form", http.StatusBadRequest) + return + } + + f, header, err := r.FormFile("file") + if err != nil { + slog.Error("failed to get file", "err", err) + http.Error(w, "failed to get file", http.StatusBadRequest) + return + } + defer f.Close() + + slog.Info("got file", "filename", header.Filename) + + fout, err := os.CreateTemp(s.dir, "future-sight-upload-*") + if err != nil { + slog.Error("failed to create temp file", "err", err) + http.Error(w, "failed to create temp file", http.StatusInternalServerError) + return + } + defer fout.Close() + defer os.Remove(fout.Name()) + + if _, err := io.Copy(fout, f); err != nil { + slog.Error("failed to copy file", "err", err) + http.Error(w, "failed to copy file", http.StatusInternalServerError) + return + } + + hash, err := hashFileSha256(fout) + if err != nil { + slog.Error("failed to hash file", "err", err) + http.Error(w, "failed to hash file", http.StatusInternalServerError) + return + } + + st, err := fout.Stat() + if err != nil { + slog.Error("failed to stat file", "err", err) + http.Error(w, "failed to stat file", http.StatusInternalServerError) + return + } + + slog.Info("hashed file", "hash", hash) + + if _, err := s.s3c.PutObject(ctx, &s3.PutObjectInput{ + Bucket: bucketName, + Key: aws.String(hash), + Body: fout, + ContentType: aws.String("application/zip"), + ContentLength: aws.Int64(st.Size()), + Metadata: map[string]string{ + "host_os": runtime.GOOS, + }, + }); err != nil { + slog.Error("failed to push file", "bucketName", *bucketName, "hash", hash, "err", err) + http.Error(w, "failed to push file", http.StatusInternalServerError) + return + } + + nv := &pb.NewVersion{ + Slug: hash, + } + + if err := s.PushVersion(ctx, nv); err != nil { + slog.Error("failed to push version", "slug", nv.Slug, "err", err) + http.Error(w, "failed to push version", http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) +} + +func (s *Server) PushVersion(ctx context.Context, nv *pb.NewVersion) error { + slog.Info("got new version", "version", nv) + + msg, err := proto.Marshal(nv) + if err != nil { + slog.Error("failed to marshal message", "slug", nv.Slug, "err", err) + return err + } + + if err := s.nc.Publish("future-sight-push", msg); err != nil { + slog.Error("failed to publish message", "slug", nv.Slug, "err", err) + return err + } + + if _, err := s.vk.Set(ctx, "future-sight:current", nv.Slug, 0).Result(); err != nil { + slog.Error("failed to set current version", "slug", nv.Slug, "err", err) + return err + } + + return nil +} + +func (s *Server) HandleFutureSightPushMsg(msg *nats.Msg) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + nv := new(pb.NewVersion) + if err := proto.Unmarshal(msg.Data, nv); err != nil { + slog.Error("failed to unmarshal message", "err", err) + return + } + + if err := s.fetchVersion(ctx, nv); err != nil { + slog.Error("failed to handle message", "slug", nv.Slug, "err", err) + return + } + + slog.Info("handled message", "slug", nv.Slug) +} + +func (s *Server) fetchVersion(ctx context.Context, nv *pb.NewVersion) error { + os.Remove(filepath.Join(s.dir, "current.zip")) + + fout, err := os.Create(filepath.Join(s.dir, "current.zip")) + if err != nil { + return err + } + defer fout.Close() + + obj, err := s.s3c.GetObject(ctx, &s3.GetObjectInput{ + Bucket: bucketName, + Key: aws.String(nv.Slug), + }) + if err != nil { + os.Remove(filepath.Join(s.dir, "current.zip")) + slog.Error("failed to get object", "slug", nv.Slug, "err", err) + return err + } + defer obj.Body.Close() + + if _, err := io.Copy(fout, obj.Body); err != nil { + os.Remove(filepath.Join(s.dir, "current.zip")) + slog.Error("failed to copy object", "slug", nv.Slug, "err", err) + return err + } + + if err := s.zs.Update(filepath.Join(s.dir, "current.zip")); err != nil { + slog.Error("failed to update zipserver", "slug", nv.Slug, "err", err) + return err + } + + return nil +} + +// hashFileSha256 hashes a file with Sha256 and returns the hash as a base64 encoded string. +func hashFileSha256(fin *os.File) (string, error) { + h := sha256.New() + if _, err := io.Copy(h, fin); err != nil { + return "", err + } + + // rewind the file + if _, err := fin.Seek(0, io.SeekStart); err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil +} diff --git a/cmd/future-sight/manifest.dev.yaml b/cmd/future-sight/manifest.dev.yaml new file mode 100644 index 0000000..49a71f6 --- /dev/null +++ b/cmd/future-sight/manifest.dev.yaml @@ -0,0 +1,195 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: future-sight +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nats + namespace: future-sight +spec: + replicas: 1 + strategy: {} + selector: + matchLabels: + app: nats + template: + metadata: + labels: + app: nats + spec: + containers: + - name: nats + image: nats:2-alpine + ports: + - containerPort: 4222 +--- +apiVersion: v1 +kind: Service +metadata: + name: nats + namespace: future-sight +spec: + selector: + app: nats + ports: + - port: 4222 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: valkey-secret + namespace: future-sight + labels: + app: valkey +data: + VALKEY_PASSWORD: hunter2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: valkey + namespace: future-sight +spec: + replicas: 1 + selector: + matchLabels: + app: valkey + template: + metadata: + labels: + app: valkey + spec: + containers: + - name: valkey + image: 'docker.io/bitnami/valkey:latest' + imagePullPolicy: Always + ports: + - containerPort: 6379 + envFrom: + - configMapRef: + name: valkey-secret +--- +apiVersion: v1 +kind: Service +metadata: + name: valkey + namespace: future-sight + labels: + app: valkey +spec: + type: ClusterIP + ports: + - port: 6379 + selector: + app: valkey +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: minio + namespace: future-sight +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: minio + namespace: future-sight +spec: + replicas: 1 + selector: + matchLabels: + app: minio + template: + metadata: + labels: + app: minio + spec: + volumes: + - name: data + persistentVolumeClaim: + claimName: minio + containers: + - name: minio + volumeMounts: + - name: data + mountPath: /data + image: minio/minio + args: + - server + - /data + - --console-address=:9001 + env: + - name: MINIO_ACCESS_KEY + value: "minio" + - name: MINIO_SECRET_KEY + value: "minio123" + - name: MINIO_ROOT_USER + value: root + - name: MINIO_ROOT_PASSWORD + value: hunter22 + ports: + - containerPort: 9000 + name: http + - containerPort: 9001 + name: webui +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: create-bucket + namespace: future-sight +spec: + template: + spec: + containers: + - name: create-bucket + image: minio/mc + command: ["/bin/sh"] + args: + - "-c" + - | + /usr/bin/mc config host add k8s http://minio:9000 minio minio123; + /usr/bin/mc rm -r --force myminio/xesite-preview-versions; + /usr/bin/mc mb myminio/xesite-preview-versions; + /usr/bin/mc policy download myminio/xesite-preview-versions; + exit 0; + restartPolicy: Never + backoffLimit: 4 +--- +apiVersion: v1 +kind: Service +metadata: + name: minio + namespace: future-sight +spec: + type: ClusterIP + ports: + - name: http + port: 80 + targetPort: 9000 + protocol: TCP + selector: + app: minio +--- +apiVersion: v1 +kind: Service +metadata: + name: minio-webui + namespace: future-sight +spec: + type: ClusterIP + ports: + - name: webui + port: 80 + targetPort: 9001 + protocol: TCP + selector: + app: minio
\ No newline at end of file diff --git a/cmd/future-sight/manifest.yaml b/cmd/future-sight/manifest.yaml new file mode 100644 index 0000000..3260bd5 --- /dev/null +++ b/cmd/future-sight/manifest.yaml @@ -0,0 +1,226 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: future-sight +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nats + namespace: future-sight +spec: + replicas: 1 + strategy: {} + selector: + matchLabels: + app: nats + template: + metadata: + labels: + app: nats + spec: + containers: + - name: nats + image: nats:2-alpine + ports: + - containerPort: 4222 +--- +apiVersion: v1 +kind: Service +metadata: + name: nats + namespace: future-sight +spec: + selector: + app: nats + ports: + - port: 4222 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: valkey-secret + namespace: future-sight + labels: + app: valkey +data: + VALKEY_PASSWORD: hunter2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: valkey + namespace: future-sight +spec: + replicas: 1 + selector: + matchLabels: + app: valkey + template: + metadata: + labels: + app: valkey + spec: + containers: + - name: valkey + image: 'docker.io/bitnami/valkey:latest' + imagePullPolicy: Always + ports: + - containerPort: 6379 + envFrom: + - configMapRef: + name: valkey-secret +--- +apiVersion: v1 +kind: Service +metadata: + name: valkey + namespace: future-sight + labels: + app: valkey +spec: + type: ClusterIP + ports: + - port: 6379 + selector: + app: valkey +--- +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: tigris-creds + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight +spec: + itemPath: "vaults/Kubernetes/items/Tigris creds" +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: future-sight + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight +data: + BUCKET_NAME: xesite-preview-versions + DATA_DIR: /cache + NATS_URL: nats://nats:4222 + VALKEY_HOST: valkey:6379 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: future-sight + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight + annotations: + operator.1password.io/auto-restart: "true" +spec: + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: future-sight + template: + metadata: + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight + spec: + volumes: + - name: tigris + secret: + secretName: tigris-creds + - name: cache + emptyDir: {} + securityContext: + fsGroup: 1000 + containers: + - name: main + image: ghcr.io/xe/x/future-sight:latest + imagePullPolicy: Always + resources: + limits: + cpu: "250m" + memory: "512Mi" + requests: + cpu: "100m" + memory: "256Mi" + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + livenessProbe: + httpGet: + path: /healthz + port: 8080 + httpHeaders: + - name: X-Kubernetes + value: "is kinda okay" + initialDelaySeconds: 3 + periodSeconds: 3 + volumeMounts: + - name: tigris + mountPath: /run/secrets/tigris + - name: cache + mountPath: /cache + envFrom: + - configMapRef: + name: valkey-secret + - configMapRef: + name: future-sight +--- +apiVersion: v1 +kind: Service +metadata: + name: future-sight + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight +spec: + selector: + app.kubernetes.io/name: future-sight + ports: + - protocol: TCP + port: 80 + targetPort: 8081 + name: web + - protocol: TCP + port: 8080 + targetPort: 8080 + name: api + type: ClusterIP +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: future-sight + namespace: future-sight + labels: + app.kubernetes.io/name: future-sight + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" +spec: + ingressClassName: nginx + tls: + - hosts: + - preview.xeiaso.net + secretName: preview-xeiaso-net-tls + rules: + - host: preview.xeiaso.net + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: future-sight + port: + name: http
\ No newline at end of file diff --git a/cmd/future-sight/port-forward.sh b/cmd/future-sight/port-forward.sh new file mode 100755 index 0000000..984ebb7 --- /dev/null +++ b/cmd/future-sight/port-forward.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +kubectl apply -f manifest.dev.yaml + +kubectl port-forward -n future-sight svc/nats 4222:4222 & +kubectl port-forward -n future-sight deploy/minio 9000:9000 & +kubectl port-forward -n future-sight deploy/minio 9001:9001 & +kubectl port-forward -n future-sight svc/valkey 6379:6379 & + +wait
\ No newline at end of file diff --git a/cmd/future-sight/var/.gitignore b/cmd/future-sight/var/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/cmd/future-sight/var/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore
\ No newline at end of file diff --git a/cmd/future-sight/yeetfile.js b/cmd/future-sight/yeetfile.js new file mode 100644 index 0000000..1b31c6c --- /dev/null +++ b/cmd/future-sight/yeetfile.js @@ -0,0 +1,5 @@ +nix.build(".#docker.future-sight"); +docker.load("./result"); +docker.push(`ghcr.io/xe/x/future-sight`); +yeet.run("kubectl", "apply", "-f=manifest.yaml"); +yeet.run("sh", "-c", "kubectl rollout restart -n future-sight deployments/future-sight"); diff --git a/cmd/mi/services/posse/posse.go b/cmd/mi/services/posse/posse.go index 7645470..6c6702b 100644 --- a/cmd/mi/services/posse/posse.go +++ b/cmd/mi/services/posse/posse.go @@ -65,7 +65,8 @@ func New(ctx context.Context, dao *models.DAO, cfg Config) (*Announcer, error) { func (a *Announcer) Announce(ctx context.Context, it *jsonfeed.Item) (*emptypb.Empty, error) { switch { case strings.Contains(it.GetUrl(), "svc.alrest.xeserv.us"), - strings.Contains(it.GetUrl(), "shark-harmonic.ts.net"): + strings.Contains(it.GetUrl(), "shark-harmonic.ts.net"), + strings.Contains(it.GetUrl(), "preview.xeiaso.net"): slog.Info("skipping announcement", "url", it.GetUrl(), "reason", "staging URLs") return &emptypb.Empty{}, nil } diff --git a/cmd/xedn/main.go b/cmd/xedn/main.go index 5ede100..1b545d4 100644 --- a/cmd/xedn/main.go +++ b/cmd/xedn/main.go @@ -26,8 +26,8 @@ import ( "tailscale.com/metrics" "tailscale.com/tsnet" "tailscale.com/tsweb" - "within.website/x/cmd/xedn/internal/xesite" "within.website/x/internal" + "within.website/x/internal/xesite" "within.website/x/web/fly/flymachines" "within.website/x/web/stablediffusion" ) @@ -89,6 +89,13 @@ ]; }; + future-sight = pkgs.buildGo122Module { + pname = "future-sight"; + inherit version vendorHash; + src = ./.; + subPackages = [ "cmd/future-sight" ]; + }; + mi = pkgs.buildGo122Module { pname = "mi"; inherit version vendorHash; @@ -269,7 +276,7 @@ path = "make-mastodon-app"; }; - inherit xedn xedn-static robocadey2 azurda mimi mi tourian sapientwindex within-website; + inherit xedn xedn-static future-sight robocadey2 azurda mimi mi tourian sapientwindex within-website; aegis = copyFile { pname = "aegis"; }; cadeybot = copyFile { pname = "cadeybot"; }; @@ -298,6 +305,7 @@ azurda = self.packages.${system}.azurda; within-website = self.packages.${system}.within-website; hlang = self.packages.${system}.hlang; + future-sight = self.packages.${system}.future-sight; simple = { name, cmd, pkg, contents ? [ pkgs.cacert ] }: pkgs.dockerTools.buildLayeredImage { @@ -311,6 +319,11 @@ }; in { + future-sight = simple { + name = "ghcr.io/xe/x/future-sight"; + pkg = future-sight; + cmd = [ "${future-sight}/bin/future-sight" ]; + }; within-website = simple { name = "ghcr.io/xe/x/within-website"; pkg = within-website; @@ -106,6 +106,7 @@ require ( github.com/cloudflare/circl v1.3.8 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.7.1 // indirect @@ -178,12 +179,16 @@ require ( github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-varint v0.0.7 // indirect + github.com/nats-io/nats.go v1.35.0 // indirect + github.com/nats-io/nkeys v0.4.7 // indirect + github.com/nats-io/nuid v1.0.1 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/julianday v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/term v1.2.0-beta.2 // indirect github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect + github.com/redis/go-redis/v9 v9.5.3 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 // indirect @@ -261,6 +261,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= @@ -752,6 +754,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mymmrac/telego v0.29.2 h1:5+fQ/b8d8Ld6ihCJ0OLe1CwUdT3t1sIUl3RaSaSvRJs= github.com/mymmrac/telego v0.29.2/go.mod h1:BsKr+GF9BHqaVaLBwsZeDnfuJcJx2olWuDEtKm4zHMc= +github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk= +github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/ncruces/go-sqlite3 v0.16.0 h1:O7eULuEjvSBnS1QCN+dDL/ixLQZoUGWr466A02Gx1xc= github.com/ncruces/go-sqlite3 v0.16.0/go.mod h1:2TmAeD93ImsKXJRsUIKohfMvt17dZSbS6pzJ3k6YYFg= @@ -842,6 +850,8 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU= +github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= diff --git a/cmd/xedn/internal/xesite/xesite.go b/internal/xesite/xesite.go index 7ef525b..7ef525b 100644 --- a/cmd/xedn/internal/xesite/xesite.go +++ b/internal/xesite/xesite.go diff --git a/proto/future-sight.proto b/proto/future-sight.proto new file mode 100644 index 0000000..7501649 --- /dev/null +++ b/proto/future-sight.proto @@ -0,0 +1,5 @@ +syntax = "proto3"; +package within.website.x.future_sight; +option go_package = "within.website/x/proto/future-sight"; + +message NewVersion { string slug = 1; }
\ No newline at end of file diff --git a/proto/future-sight/future-sight.pb.go b/proto/future-sight/future-sight.pb.go new file mode 100644 index 0000000..cff7336 --- /dev/null +++ b/proto/future-sight/future-sight.pb.go @@ -0,0 +1,145 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.32.0 +// protoc v4.24.4 +// source: future-sight.proto + +package future_sight + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type NewVersion struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Slug string `protobuf:"bytes,1,opt,name=slug,proto3" json:"slug,omitempty"` +} + +func (x *NewVersion) Reset() { + *x = NewVersion{} + if protoimpl.UnsafeEnabled { + mi := &file_future_sight_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *NewVersion) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*NewVersion) ProtoMessage() {} + +func (x *NewVersion) ProtoReflect() protoreflect.Messag |
