refactorment and addition of code.
This commit is contained in:
7
server/build.sh
Executable file
7
server/build.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Building..."
|
||||
cd src/ || exit 1
|
||||
go build -o ../
|
||||
cd ..
|
||||
echo "Done."
|
||||
29
server/cert/cert.pem
Normal file
29
server/cert/cert.pem
Normal file
@@ -0,0 +1,29 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFCTCCAvGgAwIBAgIUfKEEZwKU9u9YgeHe6hkJTis6UQwwDQYJKoZIhvcNAQEL
|
||||
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDUxNTA2NDg0OFoXDTI2MDUx
|
||||
NTA2NDg0OFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAg8AMIICCgKCAgEAxWiPe1gQn8ac1DZR/jvzFxMcCq4Wyh0mNWaI0Yi57tiE
|
||||
4ZpaTVhUGYmcN7woDjIJH/db1MeeCtWPZQswVfH3XK2p3UAU+eVie4C/ydAktG4R
|
||||
EhfDjixVDhcGfQ0aAMPod4/Qeelk0ffAW2oUCltGKfm+pHR3fbFbtPTtI1r1bA9n
|
||||
GDIMMIAwzEklkw96VZiZzJGWTV3KTyDZ0an6fWftFixiy99oqyrD60YP7uuVpbnu
|
||||
A1sUzOiPL3ZiMd9KXZ3I6wMnI9EUc4Z4Rm4sd3KdEWcCalZsd8JJOM4r8mnSImJe
|
||||
7VWLFlJz/dmbY0AYqkhF/e/NlHQx9SoardLLeykuOvs2M5V/uwOlQpanv4A8HzPK
|
||||
cGysNvz5C7L1hkwyGdYQ83IJK2PvV4kR28+e0Z7tqdnR19tuKd47FLbKq3DB1vni
|
||||
zPzBeJteyC4Z/l3su8x1NJL9vNe4xVycywk2dq7oZKxse4jP9N0VBKoSUGn+1vVn
|
||||
L6UvYlnZJpDvZ2TXSpCQd8Ru9nbQu3k5kG8fCfwK5EAWQ/k6hRJKoDBpEaYe5ENa
|
||||
qYF02s04zGRNAPvDlljbninJn9we0f9gTHbo3u5RELqI9M7FKEO78Wl3qnst4YKa
|
||||
icmp4U9f3JrhR4NM5HGSQ65phwGK1kC7VNUxItV2vV0YFWLnIqnwX09esKJJXAEC
|
||||
AwEAAaNTMFEwHQYDVR0OBBYEFDYoFgMXo/MEmTf/QK8FBEoYsafzMB8GA1UdIwQY
|
||||
MBaAFDYoFgMXo/MEmTf/QK8FBEoYsafzMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
||||
hvcNAQELBQADggIBACnhI7xTPTGoL0adHQtdicYO7UdgMBcpVPTdoFigFwhq+cxz
|
||||
2Jk/8fJbD6srBW9iiNFET4vOYtjCxOpAuMJkEBl+dWIBZOa2QaRjgiguXNZe4yu1
|
||||
egTbUTr8qgB5oU+kMXYLuHIe+QAJ8Yz4XdGa0kYm/K8YSF6C9n7z8dk9I0In789z
|
||||
VFUP6HTuYS6q0LmstJ/op4J549FZm3IF5bwZTnYTAcWKyk6Gx9nofWtYhfOGnB7E
|
||||
m7K3qDUcPRdU8hmTDLdPCh07BTVpPbLyzgCslahQiMQuFVOBNh0xtgwjYt60wo6n
|
||||
lvgi5MOQty+unLX28Hn7NnMawEkAhoQMLGjidTNsHGvtxRLTVwXjWJH2cQ5L/Vch
|
||||
apu72JJjkFofsDV+lE9U93YWwULzodVW7hAlx0gfop834PJmmX/IwCNvrF69+qMh
|
||||
EsU/dHgyI6Rt3Xa8SYu/yoEsNMIX1EAFFrh9W3BUr12GSIyYoJdamIWUshDiGz4J
|
||||
JTYHNNfswEa4QwcXMAS+ZHAXQxZxz995IOYZlAdpSJlCVz5vXvgaykEDo7g3KuDO
|
||||
E3RazsW9iPhlUskgnmFFxVQW4AxGTplFzMcNQoMXhs/LjnLb2zkeDyW2o9H9I8Ow
|
||||
GNUA5CXEGfrTcpt5ujRvH/x34GEN2NfPLPweDTVrgJLA2xuXMfWYauKg2vhV
|
||||
-----END CERTIFICATE-----
|
||||
52
server/cert/key.pem
Normal file
52
server/cert/key.pem
Normal file
@@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
bqf33hxozZ2xpA+19JwXMvyAiEtbiDM=
|
||||
-----END PRIVATE KEY-----
|
||||
8
server/conf/ghostserver.conf
Normal file
8
server/conf/ghostserver.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
[ghostserver]
|
||||
address = 0.0.0.0:19070
|
||||
|
||||
secure = true
|
||||
certfile = ./cert/cert.pem
|
||||
keyfile = ./cert/key.pem
|
||||
|
||||
interval = 600
|
||||
BIN
server/ghostrunner-server
Executable file
BIN
server/ghostrunner-server
Executable file
Binary file not shown.
@@ -2,4 +2,9 @@ module ghostrunner-server
|
||||
|
||||
go 1.24.3
|
||||
|
||||
require github.com/gorilla/mux v1.8.1
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
gopkg.in/ini.v1 v1.67.0
|
||||
)
|
||||
|
||||
require github.com/stretchr/testify v1.10.0 // indirect
|
||||
|
||||
@@ -1,2 +1,12 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"ghostrunner-server/modules/confread"
|
||||
"ghostrunner-server/modules/restapi"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Begin by trying to find the configuration file.
|
||||
confPtr := flag.String("conf", "./conf/ghostserver.conf", "Specify a config file location yourself. Relative to the program.")
|
||||
config := confread.ReadConf(*confPtr)
|
||||
|
||||
log.Println("Starting the API-Server backend.")
|
||||
restapi.InitApiServer(config)
|
||||
|
||||
fmt.Scanln()
|
||||
}
|
||||
|
||||
34
server/src/modules/confread/confread.go
Normal file
34
server/src/modules/confread/confread.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package confread
|
||||
|
||||
import (
|
||||
"ghostrunner-server/modules/utilities"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
configSection = "ghostserver"
|
||||
)
|
||||
|
||||
func ReadConf(configPath string) ConfigStruct {
|
||||
inidata, err := ini.Load(configPath)
|
||||
utilities.HandleError(err, "Trying to load the ini config file!")
|
||||
|
||||
section := inidata.Section(configSection)
|
||||
|
||||
var config ConfigStruct
|
||||
|
||||
config.Address = section.Key("address").String()
|
||||
utilities.HandleError(err, "Trying to parse apiport field into the struct!")
|
||||
|
||||
config.Secure, err = section.Key("secure").Bool()
|
||||
utilities.HandleError(err, "Trying to parse https field into the struct!")
|
||||
|
||||
config.CertFile = section.Key("certfile").String()
|
||||
config.KeyFile = section.Key("keyfile").String()
|
||||
|
||||
config.Interval, err = section.Key("interval").Int()
|
||||
utilities.HandleError(err, "Trying to parse interval field into the struct!")
|
||||
|
||||
return config
|
||||
}
|
||||
9
server/src/modules/confread/structs.go
Normal file
9
server/src/modules/confread/structs.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package confread
|
||||
|
||||
type ConfigStruct struct {
|
||||
Address string
|
||||
Secure bool
|
||||
CertFile string
|
||||
KeyFile string
|
||||
Interval int
|
||||
}
|
||||
5
server/src/modules/database/init.go
Normal file
5
server/src/modules/database/init.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package database
|
||||
|
||||
func InitSqlite() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"ghostrunner-server/modules/utilities"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func handleSchedule(w http.ResponseWriter, r *http.Request) {
|
||||
action := mux.Vars(r)["action"]
|
||||
|
||||
utilities.ConsoleLog("Funky Funky " + action)
|
||||
}
|
||||
|
||||
@@ -1,46 +1,61 @@
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"ghostrunner-server/modules/confread"
|
||||
"ghostrunner-server/modules/utilities"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMessage = "GhostRunner Server, HTTP REST API. Version: 0.0.1."
|
||||
defaultMessage = "GhostRunner Server, HTTP REST API. Version: 0.0.1."
|
||||
readWriteTimeout = 30 * time.Second //Seconds
|
||||
)
|
||||
|
||||
func rootEndpointHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func rootEndpointHandler(w http.ResponseWriter, r *http.Request) { // This endpoint handles has been placed in the init section because its basic.
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
log.Println("ROOT HIT") //Comment out later, for debugging purposes
|
||||
utilities.ConsoleLog("ROOT HIT") //Comment out later, for debugging purposes
|
||||
json.NewEncoder(w).Encode(infoResponse{
|
||||
Status: http.StatusOK,
|
||||
Message: defaultMessage,
|
||||
})
|
||||
}
|
||||
|
||||
func _initApiServer(secureServer bool, apiKey, apiCert, apiPort string) {
|
||||
apiRouter := mux.NewRouter().StrictSlash(true) // Initialize the HTTP REST API Router.
|
||||
func InitApiServer(cfg confread.ConfigStruct) {
|
||||
rtr := createRouter()
|
||||
srv := createServer(cfg, rtr)
|
||||
|
||||
apiRouter.HandleFunc("/", rootEndpointHandler).Methods("GET")
|
||||
|
||||
if secureServer { // If a secured server is wanted. Use the specified certificate files.
|
||||
httpServer := &http.Server{
|
||||
Addr: apiPort, // Specify the desired HTTPS port.
|
||||
Handler: apiRouter, // Specify the above created handler.
|
||||
TLSConfig: &tls.Config{
|
||||
Certificates: []tls.Certificate{ // Load the certificate and private key.
|
||||
loadTLSCertificate(apiCert, apiKey),
|
||||
},
|
||||
},
|
||||
go func() {
|
||||
var err error
|
||||
if cfg.Secure {
|
||||
err = srv.ListenAndServeTLS(cfg.CertFile, cfg.KeyFile)
|
||||
} else {
|
||||
err = srv.ListenAndServe()
|
||||
}
|
||||
go httpServer.ListenAndServeTLS("", "")
|
||||
} else {
|
||||
go http.ListenAndServe(":"+apiPort, apiRouter) // Transform string slightly to make the expected format.
|
||||
utilities.HandleError(err, "Initializing the HTTP REST API!")
|
||||
}()
|
||||
utilities.ConsoleLog("Successfully started the GhostServer goroutine.")
|
||||
}
|
||||
|
||||
func createRouter() *mux.Router {
|
||||
r := mux.NewRouter().StrictSlash(true)
|
||||
|
||||
r.HandleFunc("/", rootEndpointHandler).Methods("GET")
|
||||
r.HandleFunc("/schedule/{action:register|deregister}", handleSchedule).Methods("POST")
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func createServer(cfg confread.ConfigStruct, ghostHandler http.Handler) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: cfg.Address, // Specify the desired HTTPS port.
|
||||
Handler: ghostHandler, // Specify the above created handler.
|
||||
ReadTimeout: readWriteTimeout,
|
||||
WriteTimeout: readWriteTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package restapi
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
)
|
||||
|
||||
func loadTLSCertificate(certFile, keyFile string) tls.Certificate {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
24
server/src/modules/utilities/utilities.go
Normal file
24
server/src/modules/utilities/utilities.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package utilities
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
)
|
||||
|
||||
func HandleError(err error, task string) {
|
||||
if err != nil {
|
||||
log.Fatal("The program crashed unexpectedly while doing: "+task+"\nThe following exception occured:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ConsoleLog(message string) {
|
||||
log.Println(message)
|
||||
}
|
||||
|
||||
func LoadCertificate(certFile, keyFile string) tls.Certificate {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return cert
|
||||
}
|
||||
Reference in New Issue
Block a user