From 5924ded23d79f15c989fe2f69a5d6745b32a12c6 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Wed, 31 Mar 2021 21:19:57 +0000 Subject: [PATCH] go/twitterchiver/viewer: switch media to gocloud s3 --- go/twitterchiver/default.nix | 3 +++ go/twitterchiver/viewer/viewer.go | 45 ++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/go/twitterchiver/default.nix b/go/twitterchiver/default.nix index 6872f2c142..cbc25f85e7 100644 --- a/go/twitterchiver/default.nix +++ b/go/twitterchiver/default.nix @@ -23,6 +23,9 @@ depot.third_party.gopkgs."github.com".jackc.pgtype depot.third_party.gopkgs."github.com".jackc.pgx.v4.pgxpool depot.third_party.gopkgs."github.com".pomerium.sdk-go + depot.third_party.gopkgs."gocloud.dev".blob + depot.third_party.gopkgs."gocloud.dev".blob.s3blob + depot.third_party.gopkgs."gocloud.dev".gcerrors ]; dockerData = [ ( depot.pkgs.runCommand "source" {} '' diff --git a/go/twitterchiver/viewer/viewer.go b/go/twitterchiver/viewer/viewer.go index a531fc56e9..7c85e3cb4c 100644 --- a/go/twitterchiver/viewer/viewer.go +++ b/go/twitterchiver/viewer/viewer.go @@ -24,13 +24,18 @@ import ( "github.com/jackc/pgtype" "github.com/jackc/pgx/v4/pgxpool" pomerium "github.com/pomerium/sdk-go" + "gocloud.dev/blob" + "gocloud.dev/gcerrors" + + _ "gocloud.dev/blob/s3blob" ) var ( + listen = flag.String("listen", ":8080", "Listen address") databaseURL = flag.String("database_url", "", "Database URL") userMapping = userMap{} localDisableAuth = flag.String("local_auth_override_user", "", "Disable authn/authz - used for dev - set to username") - mediaDirectory = flag.String("media_dir", "/media", "Archived media directory") + mediaURL = flag.String("media_url", "s3://public-lukegb-twitterchiver?endpoint=objdump.zxcvbnm.ninja®ion=london", "Blob URL") funcMap = template.FuncMap{ "rewriteURL": rewriteURL, @@ -40,6 +45,10 @@ var ( tweetsTmpl = template.Must(template.New("tweets.html").Funcs(funcMap).ParseFiles("templates/tweets.html")) ) +const ( + redirectExpiry = 5 * time.Minute +) + func init() { flag.Var(userMapping, "user_to_twitter", "Space-separated list of :") } @@ -115,6 +124,11 @@ func main() { flag.Parse() ctx := context.Background() + mediaBucket, err := blob.OpenBucket(ctx, *mediaURL) + if err != nil { + log.Fatalf("blob.OpenBucket: %v", err) + } + pool, err := pgxpool.Connect(ctx, *databaseURL) if err != nil { log.Fatalf("pgxpool.Connect: %v", err) @@ -161,7 +175,30 @@ func main() { fmt.Fprintf(rw, "

%s

", wrap) } - authR.PathPrefix("/media/").Handler(http.StripPrefix("/media/", http.FileServer(http.Dir(*mediaDirectory)))) + authR.PathPrefix("/media/{filepath:.*}").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + _, err := userFromContext(ctx) + if err != nil { + http.Error(rw, fmt.Errorf("userFromContext: %w", err).Error(), http.StatusInternalServerError) + return + } + u, err := mediaBucket.SignedURL(ctx, vars["filepath"], &blob.SignedURLOptions{ + Expiry: redirectExpiry, + }) + switch gcerrors.Code(err) { + case gcerrors.NotFound: + // This is unlikely to get returned. + http.Error(rw, "not found", http.StatusNotFound) + return + case gcerrors.OK: + http.Redirect(rw, r, u, http.StatusFound) + return + default: + log.Printf("media SignedURL: %v", vars["filepath"], err) + } + http.Error(rw, err.Error(), http.StatusInternalServerError) + }) authR.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { ctx := r.Context() user, err := userFromContext(ctx) @@ -542,8 +579,8 @@ LIMIT $2 } }) - log.Printf("now listening on :8080") - log.Print(http.ListenAndServe(":8080", r)) + log.Printf("now listening on %s", *listen) + log.Print(http.ListenAndServe(*listen, r)) } func agoFriendly(now, at time.Time) string { ago := now.Sub(at)