diff --git a/Gopkg.lock b/Gopkg.lock index 16f2128..dac039c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1,6 +1,40 @@ # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. +[[projects]] + name = "github.com/aws/aws-sdk-go" + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/stscreds", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/sdkio", + "internal/sdkrand", + "internal/shareddefaults", + "private/protocol", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/restxml", + "private/protocol/xml/xmlutil", + "service/s3", + "service/sts" + ] + revision = "9b0098a71f6d4d473a26ec8ad3c2feaac6eb1da6" + version = "v1.13.32" + [[projects]] name = "github.com/dgrijalva/jwt-go" packages = ["."] @@ -13,6 +47,12 @@ revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" version = "v1.4.7" +[[projects]] + name = "github.com/go-ini/ini" + packages = ["."] + revision = "5e9692864e22d02ac79e2fa499cffb00520b4fea" + version = "v1.34.0" + [[projects]] name = "github.com/go-sql-driver/mysql" packages = ["."] @@ -51,6 +91,11 @@ packages = ["."] revision = "04140366298a54a039076d798123ffa108fff46c" +[[projects]] + name = "github.com/jmespath/go-jmespath" + packages = ["."] + revision = "0b12d6b5" + [[projects]] name = "github.com/labstack/echo" packages = [ @@ -201,6 +246,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "6cea9612726a43a151f6c5859d8ded9b589231fe737403e760943a7a35cda293" + inputs-digest = "619dcc41e7c57d8a8b16b061417d659d011979b9efb2bcf84036882c5da4d3d2" solver-name = "gps-cdcl" solver-version = 1 diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index fe13f8d..d76689d 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -34,15 +34,20 @@ func main() { Name: "time, t", Usage: "set airtime", }, + cli.StringFlag{ + Name: "storage", + Value: "", + Usage: "use external storage or not(default is local)", + }, }, Action: func(c *cli.Context) error { switch c.String("station") { case "ag": recorder := ag.Ag{} - return recorder.Start(c.Int("id"), c.Int("time")) + return recorder.Start(c.Int("id"), c.Int("time"), c.String("storage")) case "radiko": recorder := radiko.Radiko{} - return recorder.Start(c.Int("id"), c.Int("time")) + return recorder.Start(c.Int("id"), c.Int("time"), c.String("storage")) default: return fmt.Errorf("radio station not found(e.g -s ag)") } diff --git a/internal/recorder/ag/ag.go b/internal/recorder/ag/ag.go index 3988801..28b324e 100644 --- a/internal/recorder/ag/ag.go +++ b/internal/recorder/ag/ag.go @@ -10,6 +10,7 @@ import ( type Ag struct { programID int airtime int + storage string } // ProgramID is method to fill recorder.Recorder interface. @@ -22,6 +23,11 @@ func (a *Ag) Airtime() int { return a.airtime } +// Storage is method to fill recorder.Recorder interface. +func (a *Ag) Storage() string { + return a.storage +} + // RecordCommand is method to fill recorder.Recorder interface. // It returns rtmpdump command to record during airtime. func (a *Ag) RecordCommand(outputPath string) string { @@ -29,9 +35,10 @@ func (a *Ag) RecordCommand(outputPath string) string { } // Start : record ag program -func (a *Ag) Start(programID int, airtime int) error { +func (a *Ag) Start(programID int, airtime int, storage string) error { ag := &Ag{} ag.programID = programID ag.airtime = airtime + ag.storage = storage return recorder.Record(ag) } diff --git a/internal/recorder/radiko/radiko.go b/internal/recorder/radiko/radiko.go index bbca1f2..b3312dc 100644 --- a/internal/recorder/radiko/radiko.go +++ b/internal/recorder/radiko/radiko.go @@ -27,6 +27,7 @@ var ( type Radiko struct { programID int airtime int + storage string } // ProgramID is method to fill recorder.Recorder interface. @@ -39,6 +40,11 @@ func (r *Radiko) Airtime() int { return r.airtime } +// Storage is method to fill recorder.Recorder interface. +func (r *Radiko) Storage() string { + return r.storage +} + // RecordCommand is method to fill recorder.Recorder interface. // It returns rtmpdump command to record during airtime. func (r *Radiko) RecordCommand(outputPath string) string { @@ -47,10 +53,11 @@ func (r *Radiko) RecordCommand(outputPath string) string { } // Start : record ag program -func (r *Radiko) Start(programID int, airtime int) error { +func (r *Radiko) Start(programID int, airtime int, storage string) error { radiko := &Radiko{} radiko.programID = programID radiko.airtime = airtime + radiko.storage = storage return recorder.Record(radiko) } diff --git a/internal/recorder/recorder.go b/internal/recorder/recorder.go index ef8591b..87b3b12 100644 --- a/internal/recorder/recorder.go +++ b/internal/recorder/recorder.go @@ -8,6 +8,7 @@ import ( "github.com/YuheiNakasaka/radiorec/internal/db" "github.com/YuheiNakasaka/radiorec/internal/filemanager" + "github.com/YuheiNakasaka/radiorec/internal/uploader/s3" "github.com/mattn/go-shellwords" ) @@ -15,6 +16,7 @@ import ( type Recorder interface { ProgramID() int Airtime() int + Storage() string RecordCommand(string) string } @@ -89,8 +91,11 @@ func Record(r Recorder) error { fmt.Println("Registering...") mydb.InsertProgramContent(programID, fileManager.FilePath+".mp4") - // S3にアップロード - // uploader.Upload(outputPath+".mp4", filePath+".mp4") + // upload file to external storage + if r.Storage() == "s3" { + awsS3 := s3.AwsS3{} + err = awsS3.Upload(fileManager.OutputPath+".mp4", fileManager.FilePath+".mp4") + } wg.Done() }() diff --git a/internal/uploader/s3/s3.go b/internal/uploader/s3/s3.go new file mode 100644 index 0000000..dee9ba6 --- /dev/null +++ b/internal/uploader/s3/s3.go @@ -0,0 +1,63 @@ +package s3 + +import ( + "fmt" + "log" + "os" + + "github.com/YuheiNakasaka/radiorec/config" + "github.com/YuheiNakasaka/radiorec/internal/uploader" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awsutil" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/s3" +) + +// AwsS3 is struct to upload to aws s3, which fill uploader interface. +type AwsS3 struct { + uploader.Uploader +} + +// Upload : upload to s3 +func (s *AwsS3) Upload(path string, filename string) error { + fmt.Println("Uploading...") + + // Read config file + myconf := config.Config{} + err := myconf.Init() + if err != nil { + return fmt.Errorf("Failed to load config %v", err) + } + + accessKeyID := fmt.Sprintf("%v", myconf.List.Get("aws.s3.access_key_id")) + secretAccessKey := fmt.Sprintf("%v", myconf.List.Get("aws.s3.secret_access_key")) + region := fmt.Sprintf("%v", myconf.List.Get("aws.s3.region")) + bucketName := fmt.Sprintf("%v", myconf.List.Get("aws.s3.bucket")) + + file, err := os.Open(path) + if err != nil { + return fmt.Errorf("Failed to open file: %v", err) + } + defer file.Close() + + cli := s3.New(session.New(), &aws.Config{ + Credentials: credentials.NewStaticCredentials(accessKeyID, secretAccessKey, ""), + Region: aws.String(region), + }) + + resp, err := cli.PutObject(&s3.PutObjectInput{ + Bucket: aws.String(bucketName), + Key: aws.String(filename), + ACL: aws.String("public-read"), + ContentType: aws.String("video/mp4"), + Body: file, + }) + if err != nil { + return fmt.Errorf("Failed to upload: %v", err) + } + + log.Println(awsutil.StringValue(resp)) + + return err +} diff --git a/internal/uploader/uploader.go b/internal/uploader/uploader.go new file mode 100644 index 0000000..c00fd0a --- /dev/null +++ b/internal/uploader/uploader.go @@ -0,0 +1,6 @@ +package uploader + +// Uploader is interface of uploading tasks +type Uploader interface { + Upload(string, string) error +}