Skip to content

Commit

Permalink
add serverless to proccess and storage image
Browse files Browse the repository at this point in the history
  • Loading branch information
jechav committed Apr 18, 2018
1 parent 0d94f8c commit a92b342
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 26 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.serverless/
vendor/
bin/
*.swp
config.json
67 changes: 67 additions & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"


[[constraint]]
name = "github.com/aws/aws-lambda-go"
version = "^1.0.1"
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build:
dep ensure
env GOOS=linux go build -ldflags="-s -w" -o bin/leviathan main.go
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# resize image

### dependencies


- [go](https://golang.org/)

- [deb](https://github.com/golang/dep)

- [aws cli]() setup with credentials

- [serverless](https://serverless.com/blog/framework-example-golang-lambda-support/)

### build
> Make sure you're in your ```${GOPATH}/src``` directory, then run:
```bash
make
sls deploy
```

### Use

Path: /upload
Method: POST
Paramethers:

```php
'file' => $file,
's3_store' => [
'key' => config('filesystems.disks.s3.key'),
'secret' => config('filesystems.disks.s3.secret'),
'bucket' => config('filesystems.disks.s3.bucket'),
'region' => config('filesystems.disks.s3.region'),
'path' => /img/,
'acl' => 'public_read',
'headers' => [
"Cache-Control" => "max-age=630700000000",
"Expires" => 2535321600, //year 2050
],
],
```

### Todo

[ ] - endpoint to upload image to s3
[ ] - - save image to s3
[ ] - - save metadata (image, user, s3 destination credentials)
[x] - lambda function to resize image on s3
[ ] - lambda function save results to s3 destination storaged
[ ] - control and register user requests (API keys)

6 changes: 6 additions & 0 deletions config.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"SOURCE_S3_BUCKET_NAME": "{unique upload bucket name}",
"DEST_S3_BUCKET_NAME": "{unique upload bucket name}",
}


159 changes: 133 additions & 26 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package main

import (
"github.com/nfnt/resize"
"image/jpeg"
"log"
"os"
"bytes"
"fmt"
"strings"
"strconv"
"os"
"context"
"image/jpeg"
"strings"
"strconv"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
// "github.com/nfnt/resize"
//"gopkg.in/h2non/bimg.v1"

//"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/service/s3"
//"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var sizes = [17]string{
var sizes = [17]string {
"2048x1536",
"640x480",
"480x360",
Expand All @@ -32,38 +45,132 @@ var sizes = [17]string{
"136x102",
}

func main() {
// open "test.jpg"
file, err := os.Open("test.jpg")
if err != nil {
log.Fatal(err)
}

// decode jpeg into image.Image
img, err := jpeg.Decode(file)
if err != nil {
log.Fatal(err)
}
file.Close()
func Handler(ctx context.Context, s3Event events.S3Event) {

destBucket := "leviathan-det"
bucket := s3Event.Records[0].S3.Bucket.Name
item := s3Event.Records[0].S3.Object.Key

fmt.Println("%s - %s => %s", bucket, item, destBucket)

sess, err := session.NewSession()

if err != nil {
exitErrorf("Error session %v", err)
}

downloader := s3manager.NewDownloader(sess)

buff := &aws.WriteAtBuffer{}
numBytes, err := downloader.Download(buff,
&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(item),
})

if err != nil {
exitErrorf("Unable to download item %q, %v", item, err)
}

fmt.Println("Downloaded", numBytes, "bytes")

tmp := bytes.NewReader(buff.Bytes());
img, err := jpeg.Decode(tmp)
if err != nil {
exitErrorf("Unable to decode", err)
}

uploader := s3manager.NewUploader(sess)

for i, v := range sizes {
//get the width and height
size := strings.Split(v, "x")
w, _ := strconv.ParseUint(size[0], 10, 64)
//h, _ := strconv.ParseUint(size[1], 10, 64)
fmt.Printf("%d. resizing to %s \n", i, v)
fmt.Println("%d. resizing to %s => %T, %T", i, v, w, img)

// resize to especific size using Nearest-neighbor interpolation
// and preserve aspect ratio
m := resize.Resize(uint(w), 0, img, resize.NearestNeighbor)

out, err := os.Create("test_resized_" + v + ".jpg")
buffer := make([]byte, 0)
file := bytes.NewBuffer(buffer);
jpeg.Encode(file, m, nil)

filename := item + "resized_" + v + ".jpg"

_, err = uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(destBucket),
Key: aws.String(filename),
Body: file,
})

if err != nil {
log.Fatal(err)
// Print the error and exit.
exitErrorf("Unable to upload %q to %q, %v", filename, destBucket, err)
}
defer out.Close()

// write new image to file
jpeg.Encode(out, m, nil)
fmt.Printf("Successfully uploaded %q to %q\n", filename, destBucket)
}


/*
*aws_access_key_id := "Insert Key ID here"
*aws_secret_access_key := "Insert Secret Here"
*token := ""
*creds := credentials.NewStaticCredentials(aws_access_key_id, aws_secret_access_key, token)
*_, err := creds.Get()
*if err != nil {
* fmt.Printf("bad credentials: %s", err)
*}
*cfg := aws.NewConfig().WithRegion("us-west-1").WithCredentials(creds)
*svc := s3.New(session.New(), cfg)
*/


/*
*
* // open "test.jpg"
* file, err := os.Open("test.jpg")
* if err != nil {
* log.Fatal(err)
* }
*
* // decode jpeg into image.Image
* img, err := jpeg.Decode(file)
* if err != nil {
* log.Fatal(err)
* }
* file.Close()
*
* for i, v := range sizes {
* //get the width and height
* size := strings.Split(v, "x")
* w, _ := strconv.ParseUint(size[0], 10, 64)
* //h, _ := strconv.ParseUint(size[1], 10, 64)
* fmt.Printf("%d. resizing to %s \n", i, v)
*
* // resize to especific size using Nearest-neighbor interpolation
* // and preserve aspect ratio
* m := resize.Resize(uint(w), 0, img, resize.NearestNeighbor)
*
* out, err := os.Create("test_resized_" + v + ".jpg")
* if err != nil {
* log.Fatal(err)
* }
* defer out.Close()
*
* // write new image to file
* jpeg.Encode(out, m, nil)
* }
*/
}

func main() {
lambda.Start(Handler)
}

func exitErrorf(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(1)
}
40 changes: 40 additions & 0 deletions serverless.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Welcome to Serverless!

service: Leviathan

custom:
config: ${file(config.json)}

provider:
name: aws
runtime: go1.x
iamRoleStatements:
- Effect: Allow
Action:
- "s3:*"
Resource: "*"
environment:
SOURCE_S3_BUCKET_NAME: ${self:custom.config.SOURCE_S3_BUCKET_NAME}
DEST_S3_BUCKET_NAME: ${self:custom.config.DEST_S3_BUCKET_NAME}

package:
exclude:
- ./**
include:
- ./bin/**

functions:
leviathan:
handler: bin/leviathan
events:
- s3:
bucket: ${self:custom.config.SOURCE_S3_BUCKET_NAME}
event: s3:ObjectCreated:*

resources:
Resources:
DestImageBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.config.DEST_S3_BUCKET_NAME}

0 comments on commit a92b342

Please sign in to comment.