Skip to content

Commit e870f65

Browse files
committed
feat: from s3 with https protocol OK
1 parent e5b84b6 commit e870f65

6 files changed

Lines changed: 471 additions & 20 deletions

File tree

go.mod

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
module github.com/GetStream/stream-cli
22

3-
go 1.22
3+
go 1.23
4+
5+
toolchain go1.24.4
46

57
require (
68
github.com/AlecAivazis/survey/v2 v2.3.4
79
github.com/GetStream/getstream-go/v3 v3.7.0
810
github.com/GetStream/stream-chat-go/v5 v5.8.1
911
github.com/MakeNowJust/heredoc v1.0.0
12+
github.com/aws/aws-sdk-go-v2/config v1.32.7
13+
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1
1014
github.com/cheynewallace/tabby v1.1.1
1115
github.com/gizak/termui/v3 v3.1.0
1216
github.com/gorilla/websocket v1.5.0
@@ -19,6 +23,23 @@ require (
1923
)
2024

2125
require (
26+
github.com/aws/aws-sdk-go-v2 v1.41.1 // indirect
27+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
28+
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 // indirect
29+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 // indirect
30+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 // indirect
31+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 // indirect
32+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
33+
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 // indirect
34+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
35+
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 // indirect
36+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 // indirect
37+
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 // indirect
38+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 // indirect
39+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 // indirect
40+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 // indirect
41+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
42+
github.com/aws/smithy-go v1.24.0 // indirect
2243
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
2344
github.com/google/uuid v1.6.0 // indirect
2445
github.com/pion/datachannel v1.6.0 // indirect

go.sum

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,44 @@ github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ
4848
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
4949
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
5050
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
51+
github.com/aws/aws-sdk-go-v2 v1.41.1 h1:ABlyEARCDLN034NhxlRUSZr4l71mh+T5KAeGh6cerhU=
52+
github.com/aws/aws-sdk-go-v2 v1.41.1/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
53+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
54+
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
55+
github.com/aws/aws-sdk-go-v2/config v1.32.7 h1:vxUyWGUwmkQ2g19n7JY/9YL8MfAIl7bTesIUykECXmY=
56+
github.com/aws/aws-sdk-go-v2/config v1.32.7/go.mod h1:2/Qm5vKUU/r7Y+zUk/Ptt2MDAEKAfUtKc1+3U1Mo3oY=
57+
github.com/aws/aws-sdk-go-v2/credentials v1.19.7 h1:tHK47VqqtJxOymRrNtUXN5SP/zUTvZKeLx4tH6PGQc8=
58+
github.com/aws/aws-sdk-go-v2/credentials v1.19.7/go.mod h1:qOZk8sPDrxhf+4Wf4oT2urYJrYt3RejHSzgAquYeppw=
59+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17 h1:I0GyV8wiYrP8XpA70g1HBcQO1JlQxCMTW9npl5UbDHY=
60+
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.17/go.mod h1:tyw7BOl5bBe/oqvoIeECFJjMdzXoa/dfVz3QQ5lgHGA=
61+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17 h1:xOLELNKGp2vsiteLsvLPwxC+mYmO6OZ8PYgiuPJzF8U=
62+
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.17/go.mod h1:5M5CI3D12dNOtH3/mk6minaRwI2/37ifCURZISxA/IQ=
63+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17 h1:WWLqlh79iO48yLkj1v3ISRNiv+3KdQoZ6JWyfcsyQik=
64+
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.17/go.mod h1:EhG22vHRrvF8oXSTYStZhJc1aUgKtnJe+aOiFEV90cM=
65+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
66+
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
67+
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17 h1:JqcdRG//czea7Ppjb+g/n4o8i/R50aTBHkA7vu0lK+k=
68+
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.17/go.mod h1:CO+WeGmIdj/MlPel2KwID9Gt7CNq4M65HUfBW97liM0=
69+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
70+
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
71+
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8 h1:Z5EiPIzXKewUQK0QTMkutjiaPVeVYXX7KIqhXu/0fXs=
72+
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.8/go.mod h1:FsTpJtvC4U1fyDXk7c71XoDv3HlRm8V3NiYLeYLh5YE=
73+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17 h1:RuNSMoozM8oXlgLG/n6WLaFGoea7/CddrCfIiSA+xdY=
74+
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.17/go.mod h1:F2xxQ9TZz5gDWsclCtPQscGpP0VUOc8RqgFM3vDENmU=
75+
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17 h1:bGeHBsGZx0Dvu/eJC0Lh9adJa3M1xREcndxLNZlve2U=
76+
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.17/go.mod h1:dcW24lbU0CzHusTE8LLHhRLI42ejmINN8Lcr22bwh/g=
77+
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1 h1:C2dUPSnEpy4voWFIq3JNd8gN0Y5vYGDo44eUE58a/p8=
78+
github.com/aws/aws-sdk-go-v2/service/s3 v1.95.1/go.mod h1:5jggDlZ2CLQhwJBiZJb4vfk4f0GxWdEDruWKEJ1xOdo=
79+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5 h1:VrhDvQib/i0lxvr3zqlUwLwJP4fpmpyD9wYG1vfSu+Y=
80+
github.com/aws/aws-sdk-go-v2/service/signin v1.0.5/go.mod h1:k029+U8SY30/3/ras4G/Fnv/b88N4mAfliNn08Dem4M=
81+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9 h1:v6EiMvhEYBoHABfbGB4alOYmCIrcgyPPiBE1wZAEbqk=
82+
github.com/aws/aws-sdk-go-v2/service/sso v1.30.9/go.mod h1:yifAsgBxgJWn3ggx70A3urX2AN49Y5sJTD1UQFlfqBw=
83+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13 h1:gd84Omyu9JLriJVCbGApcLzVR3XtmC4ZDPcAI6Ftvds=
84+
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.13/go.mod h1:sTGThjphYE4Ohw8vJiRStAcu3rbjtXRsdNB0TvZ5wwo=
85+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 h1:5fFjR/ToSOzB2OQ/XqWpZBmNvmP/pJ1jOWYlFDJTjRQ=
86+
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6/go.mod h1:qgFDZQSD/Kys7nJnVqYlWKnh0SSdMjAi0uSwON4wgYQ=
87+
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
88+
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
5189
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
5290
github.com/cheynewallace/tabby v1.1.1 h1:JvUR8waht4Y0S3JF17G6Vhyt+FRhnqVCkk8l4YrOU54=
5391
github.com/cheynewallace/tabby v1.1.1/go.mod h1:Pba/6cUL8uYqvOc9RkyvFbHGrQ9wShyrn6/S/1OYVys=

pkg/cmd/raw-recording-tool/constants.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const (
77
FlagInputS3 = "input-s3"
88
FlagOutput = "output"
99
FlagVerbose = "verbose"
10+
FlagCacheDir = "cache-dir"
1011
)
1112

1213
// Flag names for filter flags (used across multiple commands)
@@ -34,9 +35,10 @@ const (
3435
const (
3536
DescInputFile = "Raw recording zip file path"
3637
DescInputDir = "Raw recording directory path"
37-
DescInputS3 = "Raw recording S3 path"
38+
DescInputS3 = "Raw recording S3 URL (s3://bucket/path or presigned HTTPS URL)"
3839
DescOutput = "Output directory"
3940
DescVerbose = "Enable verbose logging"
41+
DescCacheDir = "Cache directory for S3 downloads"
4042
)
4143

4244
// Flag descriptions for filter flags
@@ -66,6 +68,7 @@ const (
6668
DefaultFormat = "table"
6769
DefaultCompletionType = "tracks"
6870
DefaultMedia = "both"
71+
DefaultCacheSubdir = "stream-cli/raw-recordings"
6972
)
7073

7174
// Media type values

pkg/cmd/raw-recording-tool/list_tracks.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rawrecording
22

33
import (
4+
"context"
45
"encoding/json"
56
"fmt"
67
"sort"
@@ -65,14 +66,10 @@ func runListTracks(cmd *cobra.Command, args []string) error {
6566
logger := setupLogger(globalArgs.Verbose)
6667
logger.Info("Starting list-tracks command")
6768

68-
// Parse the recording metadata using efficient metadata-only approach
69-
var inputPath string
70-
if globalArgs.InputFile != "" {
71-
inputPath = globalArgs.InputFile
72-
} else if globalArgs.InputDir != "" {
73-
inputPath = globalArgs.InputDir
74-
} else {
75-
return fmt.Errorf("S3 input not implemented yet")
69+
// Resolve input path (download from S3 if needed)
70+
inputPath, err := resolveInputPath(context.Background(), globalArgs)
71+
if err != nil {
72+
return err
7673
}
7774

7875
parser := processing.NewMetadataParser(logger)

pkg/cmd/raw-recording-tool/root.go

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rawrecording
22

33
import (
4+
"context"
45
"fmt"
56
"log"
67
"os"
@@ -19,7 +20,11 @@ type GlobalArgs struct {
1920
InputS3 string
2021
Output string
2122
Verbose bool
23+
CacheDir string
2224
WorkDir string
25+
26+
// resolvedInputPath is the local path to the input (after S3 download if needed)
27+
resolvedInputPath string
2328
}
2429

2530
func NewRootCmd() *cobra.Command {
@@ -51,6 +56,7 @@ func NewRootCmd() *cobra.Command {
5156
pf.String(FlagInputS3, "", DescInputS3)
5257
pf.String(FlagOutput, "", DescOutput)
5358
pf.Bool(FlagVerbose, false, DescVerbose)
59+
pf.String(FlagCacheDir, "", DescCacheDir)
5460

5561
// Add subcommands
5662
cmd.AddCommand(
@@ -72,13 +78,20 @@ func getGlobalArgs(cmd *cobra.Command) (*GlobalArgs, error) {
7278
inputS3, _ := cmd.Flags().GetString(FlagInputS3)
7379
output, _ := cmd.Flags().GetString(FlagOutput)
7480
verbose, _ := cmd.Flags().GetBool(FlagVerbose)
81+
cacheDir, _ := cmd.Flags().GetString(FlagCacheDir)
82+
83+
// Use default cache directory if not specified
84+
if cacheDir == "" {
85+
cacheDir = GetDefaultCacheDir()
86+
}
7587

7688
return &GlobalArgs{
7789
InputFile: inputFile,
7890
InputDir: inputDir,
7991
InputS3: inputS3,
8092
Output: output,
8193
Verbose: verbose,
94+
CacheDir: cacheDir,
8295
}, nil
8396
}
8497

@@ -109,6 +122,36 @@ func validateGlobalArgs(globalArgs *GlobalArgs, requireOutput bool) error {
109122
return nil
110123
}
111124

125+
// resolveInputPath resolves the input to a local path, downloading from S3 if necessary
126+
func resolveInputPath(ctx context.Context, globalArgs *GlobalArgs) (string, error) {
127+
// If already resolved, return cached path
128+
if globalArgs.resolvedInputPath != "" {
129+
return globalArgs.resolvedInputPath, nil
130+
}
131+
132+
var inputPath string
133+
134+
if globalArgs.InputFile != "" {
135+
inputPath = globalArgs.InputFile
136+
} else if globalArgs.InputDir != "" {
137+
inputPath = globalArgs.InputDir
138+
} else if globalArgs.InputS3 != "" {
139+
// Download from S3 (with caching)
140+
downloader := NewS3Downloader(globalArgs.CacheDir, globalArgs.Verbose)
141+
downloadedPath, err := downloader.Download(ctx, globalArgs.InputS3)
142+
if err != nil {
143+
return "", fmt.Errorf("failed to download from S3: %w", err)
144+
}
145+
inputPath = downloadedPath
146+
} else {
147+
return "", fmt.Errorf("no input specified")
148+
}
149+
150+
// Cache the resolved path
151+
globalArgs.resolvedInputPath = inputPath
152+
return inputPath, nil
153+
}
154+
112155
// validateInputArgs validates input arguments using mutually exclusive logic
113156
func validateInputArgs(globalArgs *GlobalArgs, userID, sessionID, trackID string) (*processing.RecordingMetadata, error) {
114157
// Count how many filters are specified
@@ -128,13 +171,10 @@ func validateInputArgs(globalArgs *GlobalArgs, userID, sessionID, trackID string
128171
return nil, fmt.Errorf("only one filter can be specified at a time: --%s, --%s, and --%s are mutually exclusive", FlagUserID, FlagSessionID, FlagTrackID)
129172
}
130173

131-
var inputPath string
132-
if globalArgs.InputFile != "" {
133-
inputPath = globalArgs.InputFile
134-
} else if globalArgs.InputDir != "" {
135-
inputPath = globalArgs.InputDir
136-
} else {
137-
return nil, fmt.Errorf("S3 input not implemented yet")
174+
// Resolve input path (download from S3 if needed)
175+
inputPath, err := resolveInputPath(context.Background(), globalArgs)
176+
if err != nil {
177+
return nil, err
138178
}
139179

140180
// Parse metadata to validate the single specified argument
@@ -202,9 +242,10 @@ func setupLogger(verbose bool) *processing.ProcessingLogger {
202242

203243
// prepareWorkDir extracts the recording to a temp directory and returns the working directory
204244
func prepareWorkDir(globalArgs *GlobalArgs, logger *processing.ProcessingLogger) (string, func(), error) {
205-
path := globalArgs.InputFile
206-
if path == "" {
207-
path = globalArgs.InputDir
245+
// Resolve input path (download from S3 if needed)
246+
path, err := resolveInputPath(context.Background(), globalArgs)
247+
if err != nil {
248+
return "", nil, err
208249
}
209250

210251
workingDir, cleanup, err := processing.ExtractToTempDir(path, logger)

0 commit comments

Comments
 (0)