Skip to content

Commit 68bc577

Browse files
committed
init
1 parent 15794d4 commit 68bc577

File tree

18 files changed

+960
-0
lines changed

18 files changed

+960
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/main
2+
.idea
3+
/logs/run_log.txt

README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
# websocket pub/sub microservice
3+
websocket pub/sub style microservice server written in golang
4+
5+
## Usage
6+
* run server: `go run server.go`
7+
* connect to the server with arguments `?topic=<some_topic>`
8+
* send messages to the server for that topic
9+
* receive messages from the server for that topic
10+
11+
## Features
12+
* supports multiple topics
13+
* supports multiple clients per topic
14+
* optional api key define in `/utils/system_utils/system_utils.go`
15+
* multithreaded
16+
* cmd line arguments for development(bind to localhost) and production(bind to public address)
17+
* logging output to file
18+
19+
## testing
20+
basic example html served from `/test` route to test websocket connection
21+
22+
## layout
23+
* server.go: main file
24+
* starts websocket server
25+
* contains the handler function
26+
* file_utils.go: file utilities
27+
* contains functions to read and write files
28+
* time_utils.go: time utilities
29+
* contains functions to get the current time and date
30+
* http_utils.go: http utilities
31+
* contains functions to handle http requests
32+
* contains functions to handle websocket requests
33+
* system_utils.go: system utilities
34+
* handles cmd line arguments
35+
36+
## websocket server library
37+
* [gorilla websocket](https://github.com/gorilla/websocket)
38+
* Gorilla WebSocket is a Go implementation of the WebSocket protocol.
39+
40+
Cheers,
41+
Mark

go.mod

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module main
2+
3+
replace file_utils => ./utils/file_utils
4+
5+
replace time_utils => ./utils/time_utils
6+
7+
replace system_utils => ./utils/system_utils
8+
9+
replace http_utils => ./utils/http_utils
10+
11+
go 1.18
12+
13+
require (
14+
file_utils v0.0.0-00010101000000-000000000000
15+
http_utils v0.0.0-00010101000000-000000000000
16+
system_utils v0.0.0-00010101000000-000000000000
17+
)
18+
19+
require (
20+
github.com/gorilla/websocket v1.5.0 // indirect
21+
time_utils v0.0.0-00010101000000-000000000000 // indirect
22+
)

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
2+
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=

server.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import (
4+
"file_utils"
5+
"http_utils"
6+
"log"
7+
"net/http"
8+
"system_utils"
9+
)
10+
11+
func main() {
12+
// check for cmd line args
13+
system_utils.Handle_cmd_line_args()
14+
//
15+
if system_utils.Mode == "dev" {
16+
system_utils.VERBOSE = true
17+
} else {
18+
system_utils.VERBOSE = false
19+
system_utils.Host_address_and_port = http_utils.Return_host_ip_address_and_port()
20+
}
21+
//
22+
if system_utils.Api_key != "" {
23+
println("[INFO] bind server to: " + system_utils.Host_address_and_port)
24+
println("[INFO] api key: " + system_utils.Api_key)
25+
println("[INFO] test server on address: http://" + system_utils.Host_address_and_port + "/?test=1&api_key=" + system_utils.Api_key)
26+
file_utils.Log_to_file("Info", "starting server on address: "+system_utils.Host_address_and_port)
27+
} else {
28+
println("[INFO] starting server on address: http://" + system_utils.Host_address_and_port + "/?test=1")
29+
file_utils.Log_to_file("Info", "starting server on address: "+system_utils.Host_address_and_port)
30+
}
31+
//
32+
go http_utils.Hub_global.Run()
33+
http.HandleFunc("/", http_utils.RootHandler)
34+
log.Fatal(http.ListenAndServe(system_utils.Host_address_and_port, nil))
35+
}

utils/file_utils/file_utils.go

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package file_utils
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"log"
7+
"os"
8+
"time_utils"
9+
)
10+
11+
//function to check if file exists
12+
func Does_file_exist(file_path string) bool {
13+
info, err := os.Stat(file_path)
14+
if os.IsNotExist(err) {
15+
return false
16+
}
17+
return !info.IsDir()
18+
}
19+
20+
//function to check if filder exists
21+
func Does_folder_exist(folder_path string) bool {
22+
info, err := os.Stat(folder_path)
23+
if os.IsNotExist(err) {
24+
return false
25+
}
26+
return info.IsDir()
27+
}
28+
29+
//function to list all files in directory
30+
func List_all_files_in_directory(path string) []string {
31+
var files []string
32+
var err error
33+
//
34+
files_list, err := ioutil.ReadDir(path)
35+
if err != nil {
36+
Log_error_to_file(err, "List_all_files_in_directory")
37+
return files
38+
}
39+
//
40+
for _, file := range files_list {
41+
files = append(files, file.Name())
42+
}
43+
return files
44+
}
45+
46+
//function to create folder
47+
func CreateFolder(folderPath string) {
48+
if _, err := os.Stat(folderPath); os.IsNotExist(err) {
49+
err = os.MkdirAll(folderPath, 0755)
50+
if err != nil {
51+
Log_error_to_file(err, "CreateFolder")
52+
}
53+
}
54+
}
55+
56+
//function to create file
57+
func CreateFile(filePath string) {
58+
if _, err := os.Stat(filePath); os.IsNotExist(err) {
59+
file, err := os.Create(filePath)
60+
if err != nil {
61+
Log_error_to_file(err, "CreateFile")
62+
}
63+
defer file.Close()
64+
}
65+
}
66+
67+
func Read_string_from_file(path string, file_name string) string {
68+
var string_data string
69+
var err error
70+
var byte_data []byte
71+
var message string
72+
//
73+
absolute_path := path + "/" + file_name
74+
number_of_attempts := 5
75+
for i := 0; i < number_of_attempts; i++ {
76+
byte_data, err = os.ReadFile(absolute_path)
77+
if err != nil {
78+
Log_error_to_file(err, "Read_string_from_file")
79+
message = "data read error\n"
80+
return message
81+
}
82+
if len(byte_data) > 0 {
83+
break
84+
}
85+
}
86+
if len(byte_data) < 1 {
87+
return "data read error\n"
88+
}
89+
//
90+
string_data = string(byte_data)
91+
return string_data
92+
}
93+
94+
func Write_string_to_file(data_string string, path string, file_name string) bool {
95+
var err error
96+
absolute_path := path + "/" + file_name
97+
//
98+
if !Does_folder_exist(path) {
99+
CreateFolder(path)
100+
}
101+
//
102+
f, err := os.OpenFile(absolute_path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0655)
103+
if err != nil {
104+
Log_error_to_file(err, "Write_string_to_file")
105+
return false
106+
}
107+
defer func(f *os.File) {
108+
err = f.Close()
109+
if err != nil {
110+
Log_error_to_file(err, "Write_string_to_file")
111+
}
112+
}(f)
113+
//
114+
logger := log.New(f, "", 0) // used to handle concurrent writes
115+
err = logger.Output(2, data_string)
116+
if err != nil {
117+
Log_error_to_file(err, "Write_string_to_file")
118+
return false
119+
}
120+
//
121+
return true
122+
}
123+
124+
func Write_data_to_file(data []byte, path string, file_name string) bool {
125+
var err error
126+
absolute_path := path + "/" + file_name
127+
file, err := os.Create(absolute_path)
128+
if err != nil {
129+
Log_error_to_file(err, "Write_data_to_file")
130+
}
131+
//
132+
defer func(file *os.File) {
133+
err := file.Close()
134+
if err != nil {
135+
Log_error_to_file(err, "Write_data_to_file")
136+
}
137+
}(file)
138+
//
139+
_, err = file.Write(data)
140+
if err != nil {
141+
Log_error_to_file(err, "Write_data_to_file")
142+
}
143+
//
144+
return true
145+
}
146+
147+
// function for writing an error log
148+
func Log_error_to_file(err error, custom_message ...string) {
149+
var error_string string
150+
if len(custom_message) > 0 {
151+
error_string = fmt.Sprintf("[-->] Error: %v - %v", custom_message[0], err)
152+
} else {
153+
error_string = fmt.Sprintf("[-->] Error: %v", err)
154+
}
155+
cwd, _ := os.Getwd()
156+
error_log_path := cwd + "/logs"
157+
error_log_file := "error_log.txt"
158+
//
159+
f, err := os.OpenFile(error_log_path+"/"+error_log_file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0655)
160+
logger := log.New(f, "", log.LstdFlags)
161+
logger.Output(2, error_string)
162+
//Write_string_to_file(error_string, error_log_path, error_log_file)
163+
}
164+
165+
// function for writing an error log
166+
func Log_to_file(log_type string, custom_message string) {
167+
var data_string = fmt.Sprintf("[%v]: %v", log_type, custom_message)
168+
cwd, _ := os.Getwd()
169+
error_log_path := cwd + "/logs"
170+
error_log_file := "run_log.txt"
171+
//
172+
f, err := os.OpenFile(error_log_path+"/"+error_log_file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0655)
173+
if err != nil {
174+
Log_error_to_file(err, "[file_utils.go][Log_to_file]")
175+
}
176+
logger := log.New(f, "", log.LstdFlags)
177+
logger.Output(2, data_string)
178+
}
179+
180+
// function to build file name with topic and current date
181+
func Build_file_name(topic string) string {
182+
filename := topic + "_" + time_utils.Return_current_date() + ".txt"
183+
return filename
184+
}

utils/file_utils/go.mod

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module file_utils
2+
3+
replace time_utils => ../time_utils
4+
5+
go 1.18
6+
7+
require time_utils v0.0.0-00010101000000-000000000000 // indirect

0 commit comments

Comments
 (0)