Code snippet for uploading to amazon aws in Golang

It took me a long time to figure this out, and searched for it myself, but now that I have a working solution, I’d like to share it here:
step 1, create a file named: .aws/credentials
with the following content:

[default]
aws_access_key_id = 
aws_secret_access_key = 

step 2, add the following line to your docker-compose file:

COPY credentials .aws/credentials

run mkdir /root/.aws
COPY credentials /root/.aws/credentials


step 3, add this to your main.go file:

import (
	"context"
	"database/sql"
	"encoding/json"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/heroiclabs/nakama-common/runtime"
	"github.com/heroiclabs/nakama-common/api"
	//    "github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var svc = s3.New(sess)

const (
	AWS_S3_REGION = "<place region here>"
	AWS_S3_BUCKET = "<place s3 bucket name here>"
)

// session start
var sess = connectAWS()

func connectAWS() *session.Session {
	sess, err := session.NewSession(&aws.Config{Region: aws.String(AWS_S3_REGION)})
	if err != nil {
		panic(err)
	}
	return sess
}

// list all files

func listFiles(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {

	svc := s3.New(sess)
	input := &s3.ListObjectsInput{
		Bucket: aws.String(AWS_S3_BUCKET),
	}

	result, err := svc.ListObjects(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			case s3.ErrCodeNoSuchBucket:
				logger.Error(s3.ErrCodeNoSuchBucket, aerr.Error())
			default:
				logger.Error(aerr.Error())
			}
		} else {
			// Print the error, cast err to awserr.Error to get the Code and
			// Message from an error.
			logger.Error(err.Error())
		}
	}

	response, err := json.Marshal(result)
	if err != nil {
		return "", err
	}

	return string(response), nil
}

// download file

func downloadFile(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {

	var input map[string]string
	err := json.Unmarshal([]byte(payload), &input)
	if err != nil {
		return "", err
	}

	// Create S3 service client
	svc := s3.New(sess)

	req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
		Bucket: aws.String(AWS_S3_BUCKET),
		Key:    aws.String(input["url"]),
	})
	url, err := req.Presign(24 * time.Hour)

	if err != nil {
		logger.Error("Failed to generate a pre-signed url: ", err)
		return "error", err
	}

	// Display the pre-signed url

	// logger.Error(string(json_data) , url)

	response := `{ "url" : "` + url + `"}`

	return response, nil

}

// upload file

func uploadFile(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {

	var input map[string]string
	err := json.Unmarshal([]byte(payload), &input)
	if err != nil {
		return "", err
	}
	// userId, ok := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)
	userId := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)

	for m := range UserList {
		if UserList[m].User_id == userId {
			UserList[m] = UserList[len(UserList)-1]
			UserList = UserList[:len(UserList)-1]
		}
	}

	var location = input["type"] + "/" + userId + "/" + input["filename"]

	svc := s3.New(sess)

	req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
		Bucket: aws.String(AWS_S3_BUCKET),
		Key:    aws.String(location),
	})
	url, err := req.Presign(15 * time.Minute)

	if err != nil {
		logger.Error("Failed to generate a pre-signed url: ", err)
		return "error", err
	}

	response := `{ "url" : "` + url + `", "location" :"` + location + `"}`

	return response, nil

}

func deleteFile(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {

	var input map[string]string
	err := json.Unmarshal([]byte(payload), &input)
	if err != nil {
		return "", err
	}
	extensions := []string{".txt", ".json", ".jpeg"}
	fileUser := input["user"]
	fileType := input["type"]
	fileName := input["name"]

	userId := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string)

	// recieve current user, userfile, filecollection, filename

	// if user is actual user

	if userId == fileUser {

		// else if user is admin or moderator or artist

		// else error

		// delete files on aws

		svc := s3.New(sess)

		for _, i := range extensions {
			var location = fileType + "/" + fileUser + "/" + fileName + i

			request := &s3.DeleteObjectInput{
				Bucket: aws.String(AWS_S3_BUCKET),
				Key:    aws.String(location),
			}
			_, err = svc.DeleteObject(request)
			if err != nil {
				logger.Error("Storage delete error.")
			}
		}
		// delete storage

		objectIds := []*runtime.StorageDelete{
			&runtime.StorageDelete{
				Collection: fileType,
				Key:        fileName,
				UserID:     fileUser,
			},
		}

		err = nk.StorageDelete(ctx, objectIds)
		if err != nil {
			logger.Error("Storage delete error.")
		}

	}

	return "succes", nil

}

Please let me know if things are unclear or have any questions :slight_smile:

Linjoe

1 Like

hello, i’m trying to run this code, but anytime i add aws sdk to my go code nakama gives me this error {“level”:“fatal”,“ts”:“2024-03-22T10:43:57.346Z”,“caller”:“v3/main.go:156”,“msg”:“Failed initializing runtime modules”,“error”:“plugin.Open("/home/ubuntu/go-project/backend"): plugin was built with a different version of package path/filepath”}

Hello @meet2play, this is likely a dependency pinning issue.