Skip to content

Commit

Permalink
Merge pull request #1 from KumarVariable/feat/Client-Server-Implement…
Browse files Browse the repository at this point in the history
…ation-GoLang

Learn Go programming.Client Server implementation in Go.
KumarVariable authored Jan 30, 2024
2 parents d03a23c + c755522 commit d1fa264
Showing 8 changed files with 241 additions and 1 deletion.
84 changes: 83 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,83 @@
# go-for-url-shortner
# go-for-url-shortner

## Example ##
- Client and Server Integration in Go lang using [http package](https://pkg.go.dev/net/http).

## How to Run the sample `Go` Project ##

* Clone the project.
* Run command from terminal `go build .` to build the project.
* Run command from terminal `go run .` to run the application or use your IDE to start `main.go` in `debug or non-debug` mode.
* Open Browser, Run url `http://localhost:9999/test` to test the server is up and running.
* Change/modify the desired port number if you wish. Refer function `StartHttpServer()` at [Server Configuration](server/serverConfig.go).
* Use command `Ctrl+C` or `Stop` from IDE to shutdown server.


## Basic Go Commands ##
1. Command to check `Go` is installed on your machine.

```text
go version
```
2. Initialize/Create a `Go` project or module.Enable dependency tracking for your project.

```text
go mod init <my-project-name>
```
<strong>Note:</strong> Command will create `go.mod` file in project directory. The `go.mod` file provides information of:
- `name` of your project
- current `Go` version in use
- details of `libraries (project's dependencies)`

<u>Example to create module/project from Command line client:</u>

```text
mkdir go-for-url-shortner
cd go-for-url-shortner
go mod init github.com/KumarVariable/go-for-url-shortner
touch main.go
```

3. How to build a `Go` application ?

```text
go build main.go
```
- Command will compile packages and dependencies in a specific file (ex: main.go)
- Command generates an executable file in the current directory, (on Unix, it's typically named after the directory; on Windows, it will have an .exe suffix).

```text
go build .
```
- Here `.` (dot) represents a current directory.
- Command to compile the package that is in the current directory, along with any dependent files in that package.
- Command generates an executable file if the package is named as `main`, otherwise it compiles the package and produces a package archive.

4. How to run a `Go` application ?

```text
go run main.go
```
- Command to tell `Go` compiler to run and run `main.go` (a specific file). This command is helpful to quickly test a single file.

```text
go run .
```
- Here `.` (dot) represents a current directory.
- Command tells `Go` to compile and run the entire package in the current directory, not just a single file.
- Command also compiles multiple `.go` files which are part of package.

5. How to run executable created through command at point #3 ?

- Locate the executable and run `./go-for-url-shortner` from the terminal

```text
./go-for-url-shortner
```

6. How to tidy/clean up unnecessary dependencies from your `Go` project ?

```text
go mod tidy
```

Binary file added go-for-url-shortner
Binary file not shown.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/KumarVariable/go-for-url-shortner

go 1.21.5
61 changes: 61 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// main : defines a standalone executable program, not a library.
// The main package is neccessary for a Go program that will compile
// into a executable
package main

import (
"fmt"
"os"
"os/signal"
"syscall"

"github.com/KumarVariable/go-for-url-shortner/server"
)

// entry point of executable program.
// each program must have exactly one main function and
// must be in main package. The main function takes no arguments
// and returns no values. When we run the executable program the
// the main function get executed first.
func main() {

fmt.Println("initialize main function, run application")

server.HandleRequests()
server.StartHttpServer()

stopServerListener()

}

// 1.Implements a listener for goroutine (concurrent thread to start HTTP server)
// 2.The listener is listening for stop signal on a dedicated signals channel
// (channels in Go are used for communication between goroutines).
// 3.A separate function to gracefully shutdown server
func stopServerListener() {

// create a new channel with a capacity to hold one os.Signal
// 1 indicates buffer size of signal value at a time
signals := make(chan os.Signal, 1)

// link signals channel to incoming operating system signals
// 1. os.Interrupt: signal when Ctrl+C is pressed
// 2. syscall.SIGTERM: signal sent from OS to request the program
// to stop running
signal.Notify(signals, os.Interrupt, syscall.SIGTERM)

// loop to read signals.This loop will automatically
// block and wait for message to come into channel.
// This loop will be executed for every signal received
for signal := range signals {

fmt.Printf("Received signal: %v, shutting down server\n", signal)

// add logic to perform any code clean up

break
}

fmt.Println("Server has been stopped")

}
28 changes: 28 additions & 0 deletions server/routeHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package server

import (
"fmt"
"log"
"net/http"

"github.com/KumarVariable/go-for-url-shortner/util"
)

// Function to register the Handler/Endpoints
// for given request URLs (pattern)
func HandleRequests() {
http.HandleFunc("/test", pingTest)

}

// Request Handler - Test Server Uptime
func pingTest(w http.ResponseWriter, r *http.Request) {

serverUptime := util.GetServerUptime()
uptimeString := util.FormatDuration(serverUptime)

log.Println("response returned for ping test ", uptimeString)

// write response to Response Writer.
fmt.Fprintf(w, " server is running since : "+uptimeString)
}
36 changes: 36 additions & 0 deletions server/serverConfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package server

import (
"log"
"net/http"
"time"

"github.com/KumarVariable/go-for-url-shortner/util"
)

// Function to start HTTP server and handle incoming
// request on incoming connections
func StartHttpServer() string {

hostName := "localhost"
address := hostName + ":" + "9999"

util.SERVER_STARTED_AT = time.Now()

// non-blocking goroutine(lightweight thread) to start server
// in a separate thread
go startServer(address)

return address
}

func startServer(address string) {

// http.ListenAndServe() is a blocking call. This means that the function
// will not return until the server stops either due to an error or
// shutdown signal to server
error := http.ListenAndServe(address, nil)
if error != nil {
log.Panic("Failed to start server on address: ", address, " , Error:", error)
}
}
6 changes: 6 additions & 0 deletions util/constant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package util

import "time"

// global variable to hold the server start time
var SERVER_STARTED_AT time.Time
24 changes: 24 additions & 0 deletions util/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package util

import (
"fmt"
"time"
)

// Function to return server uptime
func GetServerUptime() time.Duration {
return time.Since(SERVER_STARTED_AT)
}

// Function to format time duration into human readable format
// into HH::MM:SS format
func FormatDuration(duration time.Duration) string {

hours := int(duration.Hours())
minutes := int(duration.Minutes()) % 60
seconds := int(duration.Seconds()) % 60

// represent time in standard "HH:MM:SS" format
return fmt.Sprintf("%02d h:%02d m:%02d s", hours, minutes, seconds)

}

0 comments on commit d1fa264

Please sign in to comment.