diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..919ce1f
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..639900d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..2574df2
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/spa-server.iml b/.idea/spa-server.iml
new file mode 100644
index 0000000..25ed3f6
--- /dev/null
+++ b/.idea/spa-server.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 403f7ca..ae197c2 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,21 @@ spa-server
Simple static file server for single-page application
+This fork introduces a bunch of configuration and code cleanup. You can specify a custom listening hostname and port,
+as well as custom base directory for the files. It is as simple as:
+
+```sh
+PORT=3000 HOST=127.0.0.1 BASE_DIRECTORY=/home/ubuntu/application spa-server
+```
+
+Please build the binary yourself.
+
+```sh
+# Assuming you already have Go
+go build .
+./spa-server
+```
+
```sh
$ tree
.
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..13cf7ad
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module spa-server
+
+go 1.20
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e69de29
diff --git a/main.go b/main.go
index 1116cd2..19e9535 100644
--- a/main.go
+++ b/main.go
@@ -1,61 +1,94 @@
package main
import (
- "flag"
- "fmt"
+ "context"
+ "errors"
"log"
"mime"
+ "net"
"net/http"
"os"
+ "os/signal"
+ "path"
"path/filepath"
+ "time"
)
+var baseDirectory string
+
func handler(w http.ResponseWriter, r *http.Request) {
- path := "." + r.URL.Path
- fmt.Print(r.URL.Path)
- file, err := os.Stat(path)
+ filePath := path.Join(baseDirectory, r.URL.Path)
+ file, err := os.Stat(filePath)
if err == nil && !file.IsDir() {
// file exists
- gz := path + ".gz"
+ gz := filePath + ".gz"
file, err := os.Stat(gz)
- t := mime.TypeByExtension(filepath.Ext(path))
+ t := mime.TypeByExtension(filepath.Ext(filePath))
if err == nil && !file.IsDir() && t != "" {
- fmt.Println(" => " + gz)
w.Header().Add("Content-Encoding", "gzip")
w.Header().Add("Content-Type", t)
http.ServeFile(w, r, gz)
} else {
- fmt.Println(" => " + path)
- http.ServeFile(w, r, path)
+ http.ServeFile(w, r, filePath)
}
} else {
// file does not exist
- index := "index.html"
+ index := path.Join(baseDirectory, "index.html")
file, err := os.Stat(index)
if err == nil && !file.IsDir() {
// index.html exists
- fmt.Println(" => " + index)
http.ServeFile(w, r, index)
} else {
// index.html does not exist
- fmt.Println(" => NotFound")
http.NotFound(w, r)
}
}
}
func main() {
-
- port := ":5050"
- flag.Parse()
- if flag.NArg() != 0 {
- port = ":" + flag.Arg(0)
+ listeningPort, ok := os.LookupEnv("PORT")
+ if !ok {
+ listeningPort = "5050"
}
- fmt.Println("spa-server starting on localhost" + port)
- http.HandleFunc("/", handler)
- err := http.ListenAndServe(port, nil)
- if err != nil {
- log.Fatal("spa-server: ", err)
+ listeningHost, ok := os.LookupEnv("HOST")
+ if !ok {
+ listeningHost = "127.0.0.1"
+ }
+
+ baseDirectory, ok = os.LookupEnv("BASE_DIRECTORY")
+ if !ok {
+ baseDirectory = "."
+ }
+
+ router := http.NewServeMux()
+ router.HandleFunc("/", handler)
+
+ server := &http.Server{
+ Addr: net.JoinHostPort(listeningHost, listeningPort),
+ Handler: router,
+ }
+
+ exitSignal := make(chan os.Signal, 1)
+ signal.Notify(exitSignal, os.Interrupt)
+
+ go func() {
+ <-exitSignal
+
+ log.Println("Received shutdown signal, shutting down")
+
+ ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
+ defer cancel()
+ err := server.Shutdown(ctx)
+ if err != nil {
+ log.Printf("Error occured during shutting down HTTP server: %s", err.Error())
+ }
+ }()
+
+ log.Printf("HTTP server listening on %s", server.Addr)
+
+ err := server.ListenAndServe()
+ if err != nil && !errors.Is(err, http.ErrServerClosed) {
+ log.Fatalf("Error occured during listening to HTTP server: %s", err.Error())
}
}