From 973fd170c52ddebe8459cd4293d583c653623ffe Mon Sep 17 00:00:00 2001 From: Mason Payne Date: Fri, 9 May 2025 19:24:23 -0600 Subject: [PATCH] basic functionality - terrible performance Grok didn't do a terribly greate job on this one. I'll clean it up with actually good code later. --- .idea/.gitignore | 8 ++ .idea/modules.xml | 8 ++ .idea/stereograph.iml | 9 +++ .idea/vcs.xml | 6 ++ go.mod | 7 ++ go.sum | 14 ++++ main.go | 155 +++++++++++++++++++++++++++++++++++++ web/index.html | 175 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 382 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/stereograph.iml create mode 100644 .idea/vcs.xml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 web/index.html diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..be2c0ad --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/stereograph.iml b/.idea/stereograph.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/stereograph.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e9b072e --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module stereograph + +go 1.23 + +require github.com/aws/aws-sdk-go v1.55.7 + +require github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ef80a70 --- /dev/null +++ b/go.sum @@ -0,0 +1,14 @@ +github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= +github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..d1e9d10 --- /dev/null +++ b/main.go @@ -0,0 +1,155 @@ +package main + +import ( + "encoding/json" + "flag" + "log" + "net/http" + "os" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" +) + +var ( + useS3 bool + s3Bucket string + s3Region string + localDir string + port string +) + +func init() { + flag.BoolVar(&useS3, "s3", false, "Use S3") + flag.StringVar(&s3Bucket, "bucket", "", "S3 bucket name") + flag.StringVar(&s3Region, "region", "", "S3 region") + flag.StringVar(&localDir, "dir", "", "Local directory") + flag.StringVar(&port, "port", "8080", "Server port") + flag.Parse() +} + +func main() { + if useS3 && (s3Bucket == "" || s3Region == "") { + log.Fatal("S3 bucket and region must be provided when using S3") + } + if !useS3 && localDir == "" { + log.Fatal("Local directory must be provided when not using S3") + } + + http.HandleFunc("/api/pairs", pairsHandler) + if !useS3 { + http.Handle("/images/", http.StripPrefix("/images/", http.FileServer(http.Dir(localDir)))) + } + http.Handle("/", http.FileServer(http.Dir("web"))) // Serve static files from 'web' directory + log.Println("Server starting on port", port) + log.Fatal(http.ListenAndServe(":"+port, nil)) +} + +func pairsHandler(w http.ResponseWriter, r *http.Request) { + var pairs []Pair + if useS3 { + pairs = listS3Pairs() + } else { + pairs = listLocalPairs(r.Host) + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(pairs) +} + +type Pair struct { + Name string `json:"name"` + Left string `json:"left"` + Right string `json:"right"` +} + +func listS3Pairs() []Pair { + sess, err := session.NewSession(&aws.Config{ + Region: aws.String(s3Region), + }) + if err != nil { + log.Println("Error creating AWS session:", err) + return nil + } + s3Client := s3.New(sess) + resp, err := s3Client.ListObjectsV2(&s3.ListObjectsV2Input{ + Bucket: aws.String(s3Bucket), + }) + if err != nil { + log.Println("Error listing S3 objects:", err) + return nil + } + + pairMap := make(map[string][2]string) + for _, obj := range resp.Contents { + key := *obj.Key + if strings.HasSuffix(key, "_left.jpg") { + prefix := strings.TrimSuffix(key, "_left.jpg") + pairMap[prefix] = [2]string{key, ""} + } else if strings.HasSuffix(key, "_right.jpg") { + prefix := strings.TrimSuffix(key, "_right.jpg") + if val, ok := pairMap[prefix]; ok { + pairMap[prefix] = [2]string{val[0], key} + } else { + pairMap[prefix] = [2]string{"", key} + } + } + } + + var pairs []Pair + for prefix, keys := range pairMap { + if keys[0] != "" && keys[1] != "" { + leftReq, _ := s3Client.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(s3Bucket), + Key: aws.String(keys[0]), + }) + leftURL, _ := leftReq.Presign(1 * time.Hour) + rightReq, _ := s3Client.GetObjectRequest(&s3.GetObjectInput{ + Bucket: aws.String(s3Bucket), + Key: aws.String(keys[1]), + }) + rightURL, _ := rightReq.Presign(1 * time.Hour) + pairs = append(pairs, Pair{Name: prefix, Left: leftURL, Right: rightURL}) + } + } + return pairs +} + +func listLocalPairs(host string) []Pair { + files, err := os.ReadDir(localDir) + if err != nil { + log.Println("Error reading local directory:", err) + return nil + } + + pairMap := make(map[string][2]string) + for _, file := range files { + name := file.Name() + if strings.HasSuffix(name, "_left.jpg") { + prefix := strings.TrimSuffix(name, "_left.jpg") + pairMap[prefix] = [2]string{name, ""} + } else if strings.HasSuffix(name, "_right.jpg") { + prefix := strings.TrimSuffix(name, "_right.jpg") + if val, ok := pairMap[prefix]; ok { + pairMap[prefix] = [2]string{val[0], name} + } else { + pairMap[prefix] = [2]string{"", name} + } + } + } + + baseURL := "http://" + host + "/images/" + var pairs []Pair + for prefix, names := range pairMap { + if names[0] != "" && names[1] != "" { + pairs = append(pairs, Pair{ + Name: prefix, + Left: baseURL + names[0], + Right: baseURL + names[1], + }) + } + } + return pairs +} diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..4d8b84f --- /dev/null +++ b/web/index.html @@ -0,0 +1,175 @@ + + + + + + Stereo Image Viewer + + + +

Stereo Image Viewer

+ +
+ +
+ +
+
+ + + +