From dc6b391e5ad6800b87c341df92ab2da1c9c92432 Mon Sep 17 00:00:00 2001 From: Carl Pearson Date: Sun, 8 Sep 2024 05:42:49 -0600 Subject: [PATCH] Temporary public URLs for videos --- go.mod | 1 + handlers.go | 22 ++++++++++++++++- main.go | 5 ++-- models.go | 56 ++++++++++++++++++++++++++++++++++++++++++++ templates/video.html | 3 ++- 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 8e77686..463a9bd 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23 toolchain go1.23.0 require ( + github.com/google/uuid v1.6.0 github.com/gorilla/sessions v1.4.0 github.com/labstack/echo/v4 v4.10.2 golang.org/x/crypto v0.9.0 diff --git a/handlers.go b/handlers.go index ba2d8a7..15f7c09 100644 --- a/handlers.go +++ b/handlers.go @@ -9,6 +9,7 @@ import ( "path/filepath" "strconv" "strings" + "time" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" @@ -257,10 +258,18 @@ func videoHandler(c echo.Context) error { return c.Redirect(http.StatusSeeOther, "/videos") } + downloadDir := getDownloadDir() + + tempURL, err := CreateTempURL(filepath.Join(downloadDir, "video", video.VideoFilename)) + if err != nil { + return err + } + return c.Render(http.StatusOK, "video.html", map[string]interface{}{ "video": video, - "downloadDir": getDownloadDir(), + "downloadDir": downloadDir, + "tempURL": fmt.Sprintf("/temp/%s", tempURL.Token), }) } @@ -312,3 +321,14 @@ func videoDeleteHandler(c echo.Context) error { return c.Redirect(http.StatusSeeOther, "/videos") } + +func tempHandler(c echo.Context) error { + token := c.Param("token") + + var tempURL TempURL + if err := db.Where("token = ? AND expires_at > ?", token, time.Now()).First(&tempURL).Error; err != nil { + return c.JSON(http.StatusNotFound, map[string]string{"error": "Invalid or expired token"}) + } + + return c.File(tempURL.FilePath) +} diff --git a/main.go b/main.go index 0cad359..f3e461f 100644 --- a/main.go +++ b/main.go @@ -51,7 +51,8 @@ func main() { } // Migrate the schema - db.AutoMigrate(&Video{}, &User{}) + db.AutoMigrate(&Video{}, &User{}, &TempURL{}) + go PeriodicCleanup() // create a user // FIXME: only if this user doesn't exist @@ -98,7 +99,7 @@ func main() { staticGroup := e.Group("/downloads") staticGroup.Use(authMiddleware) staticGroup.Static("/", getDownloadDir()) - // e.Static("/downloads", getDownloadDir()) + e.GET("/temp/:token", tempHandler) store.Options = &sessions.Options{ Path: "/", diff --git a/models.go b/models.go index 27f6a51..9ed0084 100644 --- a/models.go +++ b/models.go @@ -1,9 +1,12 @@ package main import ( + "errors" + "fmt" "sync" "time" + "github.com/google/uuid" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) @@ -27,6 +30,12 @@ type User struct { Password string } +type TempURL struct { + Token string `gorm:"uniqueIndex"` + FilePath string + ExpiresAt time.Time +} + type DownloadStatus struct { ID uint Progress float64 @@ -81,3 +90,50 @@ func (dm *DownloadManager) RemoveStatus(id uint) { defer dm.mutex.Unlock() delete(dm.downloads, id) } + +func generateToken() string { + uuidObj := uuid.Must(uuid.NewV7()) + return uuidObj.String() +} + +func CreateTempURL(filePath string) (TempURL, error) { + + token := generateToken() + expiration := time.Now().Add(24 * time.Hour) + + tempURL := TempURL{ + Token: token, + FilePath: filePath, + ExpiresAt: expiration, + } + + if err := db.Create(&tempURL).Error; err != nil { + return TempURL{}, errors.New("failed to create temporary URL") + } + + return tempURL, nil +} + +func cleanupExpiredURLs() { + result := db.Where("expires_at < ?", time.Now()).Delete(&TempURL{}) + if result.Error != nil { + fmt.Printf("Error cleaning up expired URLs: %v\n", result.Error) + } else { + fmt.Printf("Cleaned up %d expired temporary URLs\n", result.RowsAffected) + } +} + +func vacuumDatabase() { + if err := db.Exec("VACUUM").Error; err != nil { + fmt.Println(err) + } +} + +func PeriodicCleanup() { + ticker := time.NewTicker(12 * time.Hour) + for range ticker.C { + fmt.Println("PeriodicCleanup...") + cleanupExpiredURLs() + vacuumDatabase() + } +} diff --git a/templates/video.html b/templates/video.html index 7945bae..3b5b1c0 100644 --- a/templates/video.html +++ b/templates/video.html @@ -11,7 +11,8 @@

Downloaded Video {{.video.Title}}