Live video on the AT Protocol
1package remote
2
3import (
4 "archive/tar"
5 "compress/gzip"
6 "crypto/sha256"
7 "encoding/hex"
8 "fmt"
9 "io"
10 "net/http"
11 "os"
12 "path/filepath"
13 "strings"
14)
15
16// Streamplace team can add new files here with hack/upload-fixture.sh
17
18var fixtureURL = "https://storage.googleapis.com/streamplace-fixtures"
19
20func RemoteFixture(name string) string {
21 parts := strings.Split(name, "/")
22 if len(parts) != 2 {
23 panic("fixture name must be in format HASH/FILENAME")
24 }
25 expectedHash := parts[0]
26 filename := parts[1]
27
28 // Check if file already exists in cache
29 homeDir, err := os.UserHomeDir()
30 if err != nil {
31 panic(err)
32 }
33 cacheDir := filepath.Join(homeDir, ".streamplace-test-cache")
34 finalPath := filepath.Join(cacheDir, expectedHash, filename)
35 if _, err := os.Stat(finalPath); err == nil {
36 return finalPath
37 }
38
39 // Create temp dir if it doesn't exist
40 if err := os.MkdirAll(cacheDir, 0755); err != nil {
41 panic(err)
42 }
43
44 // Download to temporary file
45 resp, err := http.Get(fixtureURL + "/" + name)
46 if err != nil {
47 panic(err)
48 }
49 defer resp.Body.Close()
50
51 tmpFile, err := os.CreateTemp(cacheDir, "download-*")
52 if err != nil {
53 panic(err)
54 }
55 tmpPath := tmpFile.Name()
56 defer os.Remove(tmpPath)
57
58 // Calculate hash while downloading
59 hash := sha256.New()
60 writer := io.MultiWriter(tmpFile, hash)
61
62 if _, err := io.Copy(writer, resp.Body); err != nil {
63 panic(err)
64 }
65 tmpFile.Close()
66
67 // Verify hash
68 actualHash := hex.EncodeToString(hash.Sum(nil))
69 if actualHash != expectedHash {
70 panic(fmt.Sprintf("hash mismatch: expected %s, got %s", expectedHash, actualHash))
71 }
72
73 // Move to final location
74 finalDir := filepath.Join(cacheDir, expectedHash)
75 if err := os.MkdirAll(finalDir, 0755); err != nil {
76 panic(err)
77 }
78
79 if err := os.Rename(tmpPath, finalPath); err != nil {
80 panic(err)
81 }
82
83 return finalPath
84}
85
86// takes a tarball, returns a directory with the contents
87func RemoteArchive(name string) string {
88 fpath := RemoteFixture(name)
89
90 // Create extracted directory adjacent to the archive file
91 dir := filepath.Dir(fpath)
92 extractedDir := filepath.Join(dir, "extracted")
93
94 if err := os.MkdirAll(extractedDir, 0755); err != nil {
95 panic(err)
96 }
97
98 // Extract the tarball contents into the directory
99 file, err := os.Open(fpath)
100 if err != nil {
101 panic(err)
102 }
103 defer file.Close()
104
105 // Create gzip reader
106 gzr, err := gzip.NewReader(file)
107 if err != nil {
108 panic(err)
109 }
110 defer gzr.Close()
111
112 tr := tar.NewReader(gzr)
113 for {
114 header, err := tr.Next()
115 if err == io.EOF {
116 break
117 }
118 if err != nil {
119 panic(err)
120 }
121
122 target := filepath.Join(extractedDir, header.Name)
123
124 switch header.Typeflag {
125 case tar.TypeDir:
126 if err := os.MkdirAll(target, 0755); err != nil {
127 panic(err)
128 }
129 case tar.TypeReg:
130 // Create parent directories if needed
131 if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
132 panic(err)
133 }
134
135 outFile, err := os.Create(target)
136 if err != nil {
137 panic(err)
138 }
139
140 if _, err := io.Copy(outFile, tr); err != nil {
141 outFile.Close()
142 panic(err)
143 }
144 outFile.Close()
145 }
146 }
147
148 return extractedDir
149}