package controllers
import (
"fmt"
"log"
"net/http"
"strings"
"sync"
"theskyscape.com/repo/skykit"
"theskyscape.com/repo/skyshot/models"
)
func Screenshots(defaultImg []byte) (string, skykit.Handler) {
return "screenshots", &ScreenshotsController{
defaultImg: defaultImg,
mutex: &sync.Mutex{},
capturing: make(map[string]bool),
}
}
type ScreenshotsController struct {
skykit.Controller
defaultImg []byte
mutex *sync.Mutex
capturing map[string]bool
}
func (c *ScreenshotsController) Setup(app *skykit.Application) {
c.Controller.Setup(app)
http.Handle("GET /", c.Serve("home.html", nil))
http.Handle("GET /{app}", c.Protect(c.handleScreenshot, nil))
http.Handle("POST /capture", c.Protect(c.handleCapture, nil))
}
func (c ScreenshotsController) Handle(r *http.Request) skykit.Handler {
c.Request = r
return &c
}
func (c *ScreenshotsController) RecentScreenshots() []*models.Screenshot {
screenshots, _ := models.Screenshots.Search("ORDER BY CreatedAt DESC")
return screenshots
}
func (c *ScreenshotsController) handleScreenshot(w http.ResponseWriter, r *http.Request) {
appName := strings.ToLower(r.PathValue("app"))
if appName == "" {
log.Printf("Screenshot request missing app name")
http.Error(w, "App name required", http.StatusBadRequest)
return
}
screenshot, err := models.Screenshots.Get(appName)
if err == nil && screenshot != nil {
log.Printf("Serving cached screenshot for app: %s", appName)
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "public, max-age=86400") // Cache for 24 hours
w.Write(screenshot.ImageData)
return
}
go c.captureScreenshot(appName)
w.Write(c.defaultImg)
}
func (c *ScreenshotsController) handleCapture(w http.ResponseWriter, r *http.Request) {
appName := strings.ToLower(r.FormValue("app"))
if appName == "" {
log.Printf("Capture request missing app name")
c.Render(w, r, "error.html", "App name is required")
return
}
c.mutex.Lock()
if _, ok := c.capturing[appName]; ok {
c.mutex.Unlock()
log.Printf("Capture: Already capturing for app: %s", appName)
c.Render(w, r, "warning.html", fmt.Sprintf("Screenshot for %s is being captured", appName))
return
}
c.mutex.Unlock()
go c.captureScreenshot(appName)
c.Render(w, r, "success.html", fmt.Sprintf("Screenshot for %s is being captured", appName))
}
func (c *ScreenshotsController) captureScreenshot(app string) {
c.mutex.Lock()
if _, ok := c.capturing[app]; ok {
c.mutex.Unlock()
log.Printf("Capture: Already capturing for app: %s", app)
return
}
c.capturing[app] = true
c.mutex.Unlock()
log.Printf("Background capture starting for app: %s", app)
imageData, err := models.CaptureScreenshot(app)
if err != nil {
log.Printf("Background screenshot capture failed for %s: %v", app, err)
c.mutex.Lock()
delete(c.capturing, app)
c.mutex.Unlock()
return
}
log.Printf("Successfully captured and stored screenshot for %s", imageData.ID)
c.mutex.Lock()
delete(c.capturing, app)
c.mutex.Unlock()
}