Run any Executable as Systemd Service in Linux

Creating our own systemd service

Create a unit file with the name of your service (under directory named “/etc/systemd/system”):

$ touch govdrive.service

Now Edit this file and add following lines:

[Unit]
Description=Test service
ConditionPathExists=/root/GovDrive/GovDrive
After=network.target

[Service]
Type=simple
Restart=on-failure
RestartSec=10
startLimitIntervalSec=60

WorkingDirectory=/root/GovDrive/
ExecStart=/root/GovDrive/GovDrive --name=govdrive

# make sure log directory exists and owned by syslog
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/log/govdrive
ExecStartPre=/bin/chown root:root /var/log/govdrive
ExecStartPre=/bin/chmod 755 /var/log/govdrive.log
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=govdrive

[Install]
WantedBy=multi-user.target

Running the Service and monitoring it

Next, let us reload systemctl to make our new unit file visible,

systemctl daemon-reload

Now enable your service using the command below,

systemctl enable govdrive.service

If everything is set up correctly, you should get an output like this saying created symlink:

Now finally you can start your service using this command,

systemctl start govdrive.service

This won’t print any output on the terminal.

Next, try to check the status of the service using this command,

systemctl status govdrive.service

If everything works correctly, you’ll be able to see the service status as active and running. See below:

If you want to see the logs of the service,

$ journalctl -f -u govdrive.service

You can stop your service using this command,

systemctl stop govdrive.service

Backup and Restore MongoDB Databases on Windows

In this tutorial, we are going to backup and restore mongo dump files in windows.

First of all open command prompt, and navigate to the folder where you want to save the backup, then type the following command.

Backup single database:

Restore single database:

(In this case, **** represents any name for the database)

Backup all databases:

Restore all databases:

Converting map[string]interface{} to JSON and Vice-Versa:

Convert map[string]interface{} to JSON string:

package main

import (
    "encoding/json"
"fmt"
)

func main() {

    // map data
    mapData := map[string]interface{}{
        "Name": "TestUser",
        "Age": 20,
        "Admin": true,
        "Hobbies": []string{"IT","Travel"},
        "Address": map[string]interface{}{
            "PostalCode": 112233,
            "Country": "India",
        },
    }

    // Convert map to json string
    jsonStr, err := json.Marshal(mapData)
    if err != nil {
        fmt.Println(err)
    }

    // Output
    fmt.Println(string(jsonStr))
}

Convert JSON string to map[string]interface{}:

package main

import (
"fmt"
"net/http"
)

func main() {

    // json string
    jsonStr := `{
        "Name":"TestUser",
        "Age":20,
        "Admin":true,
        "Hobbies":["IT","Travel"],
        "Address":{
            "PostalCode":112233,
            "Country":"India"
        }
    }`

    // Convert json string to map[string]interface{}
    var mapData map[string]interface{}
    if err := json.Unmarshal([]byte(jsonStr), &mapData); err != nil {
        fmt.Println(err)
    }

    // Output
    fmt.Printf("Name: %v | Age: %v | Admin: %v | Hobbies: %v | Address: %v",
        mapData["Name"], mapData["Age"], mapData["Admin"], mapData["Hobbies"], mapData["Address"])

}

Configuring a Simple Redis Server on Windows

In this tutorial, we are going to create a 6-node Redis cluster with 3 masters and 3 slave nodes and assign 3 separate slot ranges for each master as shown in the following figure:

Redis Cluster

1. First get the latest Redis for the windows zip from here

2. Create 6 seperate folders for each nodes (viz. M1, M2, M3, S1, S2, S3) and paste the Redis binaries.

3. Update and uncomment the following fields in Redis.windows.conf for each folder; Change the port for each master and slave. M1-7000,M2-7001,M3-7002,S1-7003,S2-7004,S5-7006 (sample config below)

4. Now open the CMD for each folder location and Redis-server.exe Redis.windows.conf to start the Redis servers. You have to execute following commands which enables to run all the Redis servers:

5. Now we have 6 running Redis instances. All we need is to initiating the cluster. For that you can run the following command:

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1 
In here we’re using --cluster-replicas 1 which means for every master created, Redis will create a replica. Redis-cli will show the current setup and you can type YES to proceed and create the cluser. If everything goes correctly you will receive below message,

[OK] All 16384 slots covered

Channel in Go (Golang)

Overview

Channel is a data type in Go which provides synchronization and communication between goroutines. They can be thought of as pipes which is used by goroutines to communicate. This communication between goroutines doesn’t require any explicit locks. Locks are internally managed by channel themselves. Channel along with goroutine makes the go programming language concurrent. So we can say that golang has two concurrency primitives:

  • Goroutine – lightweight independent execution to achieve concurrency/parallelism.
  • Channels – provides synchronization and communication between goroutines.

Declaring Channels

Each channel variable can hold data only of a particular type. Go uses special keyword chan while declaring a channel. Below is the format for declaring a channel:

var chan

This only declares a channel which can hold data of type and it creates a nil channel as default value of a channel is nil. Let’s see a program to confirm this.

package main

import "fmt"

func main() {
    var a chan int
    fmt.Println(a)
}

Output:

{nil}

To define the channel we can use the inbuilt function make.

package main

import "fmt"

func main() {
    var a chan int
    a = make(chan int)
    fmt.Println(a)
}

Output:

0xc0000240c0

On your machine it might give a different address as output.

Operations on Channel

There are two major operations which can be done on a channel:

  • Send
  • Receive

1. Send Operation

The send operation is used to send data to the channel. Below is the format for sending to a channel:

ch <- val

where

  • ch is the channel variable
  • val is what being sent to the channel

Note that data type of val and data type of channel should match.

2. Receive Operation

The receive operation is used to read data from the channel. Below is the format for receiving from a channel:

val := <- ch

where

  • ch is the channel variable
  • val is a variable in which the read data from the channel will be stored

Let’s see an example of where we will send data from one goroutine and receive that data in another goroutine.

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)

    fmt.Println("Sending value to channel")
    go send(ch)

    fmt.Println("Receiving from channel")
    go receive(ch)

    time.Sleep(time.Second * 1)
}

func send(ch chan int) {
    ch <- 1
}

func receive(ch chan int) {
    val := <-ch
    fmt.Printf("Value Received=%d in receive function\n", val)
}

Output:

Sending value to channel
Receiving from channel
Value Received=1 in receive function

In above program, we created a channel named ch whose data type is int which means that it can only transport data of type int. Function send() and receive() are started as a goroutine. We are sending data to the channel ch in send() goroutine and receiving data from ch in the receive() goroutine.

A very important point to note about the receive operation is that a particular value sent to the channel can only be received once in any of the goroutine. As you can see there are no locks used in the goroutine while sending as well as receiving from the channel. Locks are internally managed by the channels and no explicit lock has to be used in the code.

By default when we create channel with make, it creates a unbuffered channel which essentially means that channel created cannot store any data. So any send on a channel is blocked until there is another goroutine to receive it. So in the send() function, this line will block

ch <- 1

until in receive() function the value is received

val := <-ch

Also we have kept a timeout in the main function to allow both send and receive function to complete. If we don’t have a timeout in the end of main function, then the program will exit and the two goroutine might not get scheduled.

Buffered Channel

We have seen the example of an unbuffered channel till now. Unbuffered channel does not have any storage hence for an unbuffered channel:

  • Send on a channel is block unless there is other goroutine to receive.
  • Receive is block until there is other goroutine on the other side to send.

In Go you can also create a buffered channel. A buffered channel has some capacity to hold data hence for a buffered channel:

  • Send on a buffer channel only blocks if the buffer is full
  • Receive is only block is channel is empty

This is the syntax for creating a buffered channel using the make function:

a = make(chan , capacity)

The second argument specifies the capacity of the channel. Unbuffered channel is of zero capacity .That is why sending is block if there is no receiver and receiving is block if there is no sender for unbuffered channel.

Let’s see a program for a buffered channel:

package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 1)
    ch <- 1
    fmt.Println("Sending value to channnel complete")
    val := <-ch
    fmt.Printf("Receiving value from channel finished. Value received: %d\n", val)
}

In above program we created a buffered channel of length 1 like this:

ch := make(chan int, 1)

We are sending a value and receiving the same in the main goroutine. This is possible as send to a buffered channel is not blocked if the channel is not full. So below line doesn’t block for a buffered channel.

ch <- 1

The channel is created with a capacity of one. Hence sending to the channel is not blocked and the value is stored in the channel’s buffer. So sending and receiving in the same goroutine is only possible for a buffered channel. Let’s see two important points we mentioned above

  • Send on a channel is blocked when the channel is full
  • Receive on a channel is blocked when the channel is empty

Goroutines in Go (Golang)

Overview

Start a go routine

Goroutines can be thought of as a lightweight thread that has a separate independent execution and which can execute concurrently with other goroutines. It is a function or method that is executing concurrently with other goroutines. It is entirely managed by the GO runtime.

Golang uses a special keyword ‘go’ for starting a goroutine. To start one just add go keyword before a function or method call. That function or method will now be executed in the goroutine. Note that it is not the function or method which determines if it is a goroutine. If we call that method or function with a go keyword then that function or method is said to be executing in a goroutine.

Let’s understand the difference between normal running a function and running a function as a goroutine.

Normal Running a function:

statement1
start()
statement2

In the normal running of a function for the above scenario.

1. First, statement1 will be executed
2. Then start() function will be called
3. Once the start() function finishes then statement2 will be executed

Running a function as a goroutine:

statement1
go start()
statement2

In running a function as a goroutine for the above scenario,

1. First, statement1 will be executed
2. Then function start() will be called as a goroutine which will execute asynchronously.
3. statement2 will be executed immediately. It will not wait for start() function to complete. The start function will be executed concurrently as a goroutine while the rest of the program continues its execution.

So basically when calling a function as a goroutine, call will return immediately the execution will continue from the next line while the goroutine will be executed concurrently in the background.

Let’s see a program to understand the above point.

package main

import (
    "fmt"
    "time"
)

func main() {
    go start()
    fmt.Println("Started")
    time.Sleep(1 * time.Second)
    fmt.Println("Finished")
}

func start() {
    fmt.Println("In Goroutine")
}

Output:

Started
In Goroutine
Finished

What happens when we remove the timeout. Let’s see a program.

package main
import (
    "fmt"
)
func main() {
    go start()
    fmt.Println("Started")
    fmt.Println("Finished")
}
func start() {
    fmt.Println("In Goroutine")
}

Output:

Started
Finished

The program above never prints

In Goroutine

That means that the goroutine never got executed . This is because the main goroutine or the program exited before the goroutine can be scheduled. That brings into discussion about the main goroutine.

Main goroutine

The main function in the main package is the main goroutine. All goroutines are started from the main goroutine. These goroutines can then start multiple other goroutine and so on.

The main goroutine represents the main program. Once it exits then it means that the program has exited.

Goroutines don’t have parents or children. When you start a goroutine it just executes alongside all other running goroutines. Each goroutine exits only when its function returns. The only exception to that is that all goroutines exit when the main goroutine (the one that runs function main) exits.

Let’s see a program to demonstrate that goroutines don’t have parents or children.

package main

import (
    "fmt"
    "time"
)

func main() {
    go start()
    fmt.Println("Started")
    time.Sleep(1 * time.Second)
    fmt.Println("Finished")
}

func start() {
    go start2()
    fmt.Println("In Goroutine")
}
func start2() {
    fmt.Println("In Goroutine2")
}

Output:

Started
In Goroutine
In Goroutine2
Finished

In the above program, the first goroutine starts the second goroutine. The first goroutine then prints “In Goroutine” and then it exits. The second goroutine then starts and prints “In Goroutine2”. It shows that goroutines don’t have parents or children and they exist as an independent execution.

Common Mistakes for New Golang Developers

1. Opening Brace Can’t Be Placed on a Separate Line

In most other languages that use braces you get to choose where you place them. Go is different. You can thank automatic semicolon injection for this behavior.

Fails:

package main

import "fmt"

func main()  
{ //error, can't have the opening brace on a separate line
    fmt.Println("hello there!")
}

Compile Error:

/tmp/sandbox826898458/main.go:6: syntax error: unexpected semicolon or newline before {

Works:

import "fmt"

func main() {  
    fmt.Println("works!")
}

2. Unused Variables

If you have an unused variable your code will fail to compile. There’s an exception though. You must use variables you declare inside functions, but it’s OK if you have unused global variables. It’s also OK to have unused function arguments.

If you assign a new value to the unused variable your code will still fail to compile. You need to use the variable value somehow to make the compiler happy.

Fails:

package main

var gvar int //not an error

func main() {  
    var one int   //error, unused variable
    two := 2      //error, unused variable
    var three int //error, even though it's assigned 3 on the next line
    three = 3

    func(unused string) {
        fmt.Println("Unused arg. No compile error")
    }("what?")
}

Compile Errors:

/tmp/sandbox473116179/main.go:6: one declared and not used

/tmp/sandbox473116179/main.go:7: two declared and not used

/tmp/sandbox473116179/main.go:8: three declared and not used

Works:

func main() {  
    var one int
    _ = one

    two := 2 
    fmt.Println(two)

    var three int 
    three = 3
    one = three

    var four int
    four = four
}

3. Unused Imports

Your code will fail to compile if you import a package without using any of its exported functions, interfaces, structures, or variables.

If you really need the imported package you can use the blank identifier, _, as its package name to avoid this compilation failure. The blank identifier is used to import packages for their side effects.

Fails:

package main

import (  
    "fmt"
    "log"
    "time"
)

func main() {  
}

Compile Errors:

/tmp/sandbox627475386/main.go:4: imported and not used: “fmt”

/tmp/sandbox627475386/main.go:5: imported and not used: “log”

/tmp/sandbox627475386/main.go:6: imported and not used: “time”

Works:

package main

import (  
    _ "fmt"
    "log"
    "time"
)

var _ = log.Println

func main() {  
    _ = time.Now
}

4. Strings Can’t Be “nil”

This is a gotcha for developers who are used to assigning “nil” identifiers to string variables.

Fails:

package main

func main() {  
    var x string = nil //error

    if x == nil { //error
        x = "default"
    }
}

Compile Errors:

/tmp/sandbox630560459/main.go:4: cannot use nil as type string in assignment

/tmp/sandbox630560459/main.go:6: invalid operation: x == nil (mismatched types string and nil)

Works:

package main

func main() {  
    var x string //defaults to "" (zero value)

    if x == "" {
        x = "default"
    }
}

5. Unexpected Values in Slice and Array “range” Clauses

This can happen if you are used to the “for-in” or “foreach” statements in other languages. The “range” clause in Go is different. It generates two values: the first value is the item index while the second value is the item data.

Bad:

package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for v := range x {
        fmt.Println(v) //prints 0, 1, 2
    }
}

Good:

package main

import "fmt"

func main() {  
    x := []string{"a","b","c"}

    for _, v := range x {
        fmt.Println(v) //prints a, b, c
    }
}

6. log.Fatal and log.Panic Do More Than Log

Logging libraries often provide different log levels. Unlike those logging libraries, the log package in Go does more than log if you call its Fatal*() and Panic*() functions. When your app calls those functions Go will also terminate your app.

package main

import "log"

func main() {  
    log.Fatalln("Fatal Level: log entry") //app exits here
    log.Println("Normal Level: log entry")
}

7. Closing HTTP Response Body

When you make requests using the standard http library you get a http response variable. If you don’t read the response body you still need to close it. Note that you must do it for empty responses too. It’s very easy to forget especially for new Go developers.

Some new Go developers do try to close the response body, but they do it in the wrong place.

package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    defer resp.Body.Close()//not ok
    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

This code works for successful requests, but if the http request fails the resp variable might be nil, which will cause a runtime panic.

The most common why to close the response body is by using a defer call after the http response error check.

package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    if err != nil {
        fmt.Println(err)
        return
    }

    defer resp.Body.Close()//ok, most of the time 🙂
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

Most of the time when your http request fails the resp variable will be nil and the err variable will be non-nil. However, when you get a redirection failure both variables will be non-nil. This means you can still end up with a leak.

You can fix this leak by adding a call to close non-nil response bodies in the http response error handling block. Another option is to use one defer call to close response bodies for all failed and successful requests.

package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    resp, err := http.Get("https://api.ipify.org?format=json")
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(body))
}

8. Closing HTTP Connections

Some HTTP servers keep network connections open for a while (based on the HTTP 1.1 spec and the server “keep-alive” configurations). By default, the standard http library will close the network connections only when the target HTTP server asks for it. This means your app may run out of sockets/file descriptors under certain conditions.

You can ask the http library to close the connection after your request is done by setting the Close field in the request variable to true.

Another option is to add a Connection request header and set it to close. The target HTTP server should respond with a Connection: close header too. When the http library sees this response header it will also close the connection.

package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    req, err := http.NewRequest("GET","http://golang.org",nil)
    if err != nil {
        fmt.Println(err)
        return
    }

    req.Close = true
    //or do this:
    //req.Header.Add("Connection", "close")

    resp, err := http.DefaultClient.Do(req)
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(len(string(body)))
}

You can also disable http connection reuse globally. You’ll need to create a custom http transport configuration for it.

package main

import (  
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {  
    tr := &http.Transport{DisableKeepAlives: true}
    client := &http.Client{Transport: tr}

    resp, err := client.Get("http://golang.org")
    if resp != nil {
        defer resp.Body.Close()
    }

    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(resp.StatusCode)

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(len(string(body)))
}

If you send a lot of requests to the same HTTP server it’s ok to keep the network connection open. However, if your app sends one or two requests to many different HTTP servers in a short period of time it’s a good idea to close the network connections right after your app receives the responses. Increasing the open file limit might be a good idea too.

Get Hours, Days, Minutes and Seconds difference between two dates in Golang

Example

package main

import (
	"fmt"
	"time"
)

func main() {
    currenttimestr := time.Now().Format("2006-01-02 15:04:05")
    pasttimestr := "2021-09-21 12:39:50"

    layout := "2006-01-02 15:04:05"

    //Converting String to Date
    pastDate, err := time.Parse(layout, pasttimestr)
    currentDate, err := time.Parse(layout, currenttimestr)
    if err != nil {
	fmt.Println(err)
    }

    fmt.Printf("Current Time: %v\n\n", currentDate)
    fmt.Printf("Past Time: %v\n", pastDate)

    //Difference between past date and current date
    diff := currentDate.Sub(pastDate)

    fmt.Printf("################################################\n")

    hrs := int(diff.Hours())
    fmt.Printf("Difference in Hours: %d Hours\n", hrs)

    mins := int(diff.Minutes())
    fmt.Printf("Difference in Minutes: %d Minutes\n", mins)

    second := int(diff.Seconds())
    fmt.Printf("Difference in Seconds: %d Seconds\n", second)

    days := int(diff.Hours() / 24)
    fmt.Printf("Difference in Days: %d days\n", days)

    fmt.Printf("################################################\n")
}

Output

Current Time: 2021-09-23 17:35:59 +0000 UTC

Past Time: 2021-09-21 12:39:50 +0000 UTC

#######################################################

Difference in Hours: 52 Hours
Difference in Minutes: 3176 Minutes
Difference in Seconds: 190569 Seconds
Difference in Days: 2 days

#######################################################

File Operations on Amazon S3 with Golang

We are going to see here how to connect to S3 with Golang, upload a file from a form to an AWS S3 bucket, download it, and list all items saved on this bucket.

I am going to suppose that you have already:

  • created an AWS account
  • created an Amazon Simple Storage (S3) Bucket
  • generated the credentials to access it (Access key ID and Secret access key)

Install the SDK

After this, we need to install the AWS SDKs for Go:

go get -u github.com/aws/aws-sdk-go/aws
go get -u github.com/aws/aws-sdk-go/aws/credentials
go get -u github.com/aws/aws-sdk-go/aws/session
go get -u github.com/aws/aws-sdk-go/service/s3/s3manager

and import the AWS packages into your Go application:

import ( 
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
)

Connect to AWS S3

I like to use this code on my main.go file or whatever other file where I can share the session (sess variable) to reuse it.

const (
    AWS_S3_URL = ""
    AWS_S3_BUCKET = ""
    AWS_S3_REGION = ""
    AWS_S3_ACCESS_KEY = ""
    AWS_S3_SECRET_KEY = ""
)

var sess = connectAWS()

func connectAWS() *session.Session {
    creds := credentials.NewStaticCredentials(AWS_S3_ACCESS_KEY, AWS_S3_SECRET_KEY, "")

    // Configuration to use AWS Server
    s3Config := &aws.Config{
	Credentials:      creds,
	Endpoint:         aws.String(AWS_S3_URL),
	Region:           aws.String(AWS_S3_REGION),
	S3ForcePathStyle: aws.Bool(true),
    }

    // Initialize a session that the SDK will use to load
    sess, err := session.NewSession(s3Config)
    if err != nil {
	panic(err)
    }
    return sess
}

Upload a file from a form to Amazon S3

First, get the file from the Form:

file, header, err := r.FormFile("file")
if err != nil {
    // Do your error handling here
    return
}
defer file.Close()

filename := header.Filename

Then, upload it to S3:

uploader := s3manager.NewUploader(sess)

_, err = uploader.Upload(&s3manager.UploadInput{
    Bucket: aws.String(AWS_S3_BUCKET), // Bucket to be used
    Key:    aws.String(filename),      // Name of the file to be saved
    Body:   file,                      // File
})
if err != nil {
    // Do your error handling here
    return
}

Download a file from Amazon S3

First, create a temporary file where to store the downloaded file:

f, err := os.Create(filename)
if err != nil {
    // Do your error handling here
    return
}

Now, download the file and do whatever you want with it (f)

downloader := s3manager.NewDownloader(sess)
_, err = downloader.Download(f, &s3.GetObjectInput{
    Bucket: aws.String(AWS_S3_BUCKET),
    Key:    aws.String(filename),
})
if err != nil {
    // Do your error handling here
    return
}

Delete a file from Amazon S3

input := &s3.DeleteObjectInput{
    Bucket: aws.String(AWS_S3_BUCKET),
    Key:    aws.String(filename),
}

_, err = s3Client.DeleteObject(input)
if err != nil {
    // Do your error handling here
    return
}

List the items of an AWS S3 Bucket

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:
            fmt.Println(s3.ErrCodeNoSuchBucket, aerr.Error())
        default:
            fmt.Println(aerr.Error())
        }
    } else {
        // Print the error, cast err to awserr.Error to get the Code and
        // Message from an error.
        fmt.Println(err.Error())
    }
    // Do your error handling here
    return
}

You could now list the items showing the name like this:

w.Header().Set("Content-Type", "text/html")

for _, item := range result.Contents {
    fmt.Fprintf(w, "<li>File %s</li>", *item.Key)
}

Examples of creating base64 hashes using HMAC SHA256 in different languages

Javascript HMAC SHA256

Dependent upon an open source js library called http://code.google.com/p/crypto-js/.

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/hmac-sha256.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/enc-base64.min.js"></script>

<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
  document.write(hashInBase64);
</script>

PHP HMAC SHA256

PHP has built in methods for hash_hmac (PHP 5) and base64_encode (PHP 4, PHP 5) resulting in no outside dependencies.

$s = hash_hmac('sha256', 'Message', 'secret', true);
echo base64_encode($s);

Java HMAC SHA256

Dependent on Apache Commons Codec to encode in base64.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class ApiSecurityExample {
  public static void main(String[] args) {
    try {
     String secret = "secret";
     String message = "Message";

     Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
     SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
     sha256_HMAC.init(secret_key);

     String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
     System.out.println(hash);
    }
    catch (Exception e){
     System.out.println("Error");
    }
   }
}

C# HMAC SHA256

using System.Security.Cryptography;

namespace Test
{
  public class MyHmac
  {
    private string CreateToken(string message, string secret)
    {
      secret = secret ?? "";
      var encoding = new System.Text.ASCIIEncoding();
      byte[] keyByte = encoding.GetBytes(secret);
      byte[] messageBytes = encoding.GetBytes(message);
      using (var hmacsha256 = new HMACSHA256(keyByte))
      {
        byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
        return Convert.ToBase64String(hashmessage);
      }
    }
  }
}

Golang HMAC SHA256

package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
)

func ComputeHmac256(message string, secret string) string {
    key := []byte(secret)
    h := hmac.New(sha256.New, key)
    h.Write([]byte(message))
    return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func main() {
    fmt.Println(ComputeHmac256("Message", "secret"))
}

Python (2.7) HMAC SHA256

import hashlib
import hmac
import base64

message = bytes("Message").encode('utf-8')
secret = bytes("secret").encode('utf-8')

signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
print(signature)

Python (3.7) HMAC SHA256

import hashlib
import hmac
import base64

message = bytes('Message', 'utf-8')
secret = bytes('secret', 'utf-8')

signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
print(signature)

Ruby HMAC SHA256

Requires openssl and base64.

require 'openssl'
require "base64"

hash  = OpenSSL::HMAC.digest('sha256', "secret", "Message")
puts Base64.encode64(hash)