-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from KumarVariable/feat/Client-Server-Implement…
…ation-GoLang Learn Go programming.Client Server implementation in Go.
Showing
8 changed files
with
241 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
|
||
} |