Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions storage.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package deck

import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"os"
"strings"
"time"

"github.com/k1LoW/deck/template"
Expand All @@ -15,6 +14,12 @@ import (
"google.golang.org/api/drive/v3"
)

// uploadResult represents the JSON output from the external upload command.
type uploadResult struct {
URL string `json:"url"`
ID string `json:"id"`
}

// Storage is the interface for image upload/delete operations.
type Storage interface {
Upload(ctx context.Context, data []byte, mimeType string) (publicURL, uploadedID string, err error)
Expand Down Expand Up @@ -111,7 +116,7 @@ func newExternalStorage(uploadCmd, deleteCmd string) *externalStorage {
// Upload uploads an image using the external upload command.
// It passes image data via stdin and sets the environment variable DECK_UPLOAD_MIME.
// The command also supports template variables: {{mime}} and {{env.XXX}}.
// The command should output the public URL on the first line and uploaded ID on the second line.
// The command should output JSON: {"url":"...","id":"..."}
func (u *externalStorage) Upload(ctx context.Context, data []byte, mimeType string) (publicURL, uploadedID string, err error) {
const envUploadMIME = "DECK_UPLOAD_MIME"

Expand Down Expand Up @@ -149,26 +154,20 @@ func (u *externalStorage) Upload(ctx context.Context, data []byte, mimeType stri
return "", "", fmt.Errorf("failed to run upload command: %w\nstderr: %s", err, stderr.String())
}

// Parse stdout: first line is public URL, second line is uploaded ID
scanner := bufio.NewScanner(&stdout)
if !scanner.Scan() {
return "", "", fmt.Errorf("upload command did not output public URL")
// Parse JSON output
var result uploadResult
if err := json.Unmarshal(stdout.Bytes(), &result); err != nil {
return "", "", fmt.Errorf("failed to parse upload command output as JSON: %w\nstdout: %s", err, stdout.String())
}
publicURL = strings.TrimSpace(scanner.Text())

if !scanner.Scan() {
return "", "", fmt.Errorf("upload command did not output uploaded ID")
if result.URL == "" {
return "", "", fmt.Errorf("upload command returned empty URL")
}
uploadedID = strings.TrimSpace(scanner.Text())

if publicURL == "" {
return "", "", fmt.Errorf("upload command returned empty public URL")
}
if uploadedID == "" {
return "", "", fmt.Errorf("upload command returned empty uploaded ID")
if result.ID == "" {
return "", "", fmt.Errorf("upload command returned empty ID")
}

return publicURL, uploadedID, nil
return result.URL, result.ID, nil
}

// Delete deletes an uploaded image using the external delete command.
Expand Down