aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitch Riedstra <mitch@riedstra.us>2021-03-04 19:44:02 -0500
committerMitch Riedstra <mitch@riedstra.us>2021-03-04 19:48:27 -0500
commitb9bb17044a8c2b47c7e96660e27ab645f82bec9d (patch)
tree6c5bff2c5eaaebfc1ce9b01119308dcc39a75253
parent3b6f5647b0689abf04be73c3cf00297051753435 (diff)
downloadsteam-export-b9bb17044a8c2b47c7e96660e27ab645f82bec9d.tar.gz
steam-export-b9bb17044a8c2b47c7e96660e27ab645f82bec9d.tar.xz
Further refactoring.
-rw-r--r--cmd/web/app.go75
-rw-r--r--cmd/web/delete.go47
-rw-r--r--cmd/web/download.go61
-rw-r--r--cmd/web/flagSliceString.go12
-rw-r--r--cmd/web/handlers.go207
-rw-r--r--cmd/web/index.go39
-rw-r--r--cmd/web/install.go52
-rw-r--r--cmd/web/main.go171
-rw-r--r--cmd/web/serve-self.go27
-rw-r--r--cmd/web/util.go89
10 files changed, 377 insertions, 403 deletions
diff --git a/cmd/web/app.go b/cmd/web/app.go
new file mode 100644
index 0000000..8f6df89
--- /dev/null
+++ b/cmd/web/app.go
@@ -0,0 +1,75 @@
+package main
+
+import (
+ "sync"
+ "html/template"
+ "time"
+
+ "riedstra.dev/mitch/steam-export/steam"
+)
+
+type steamLib struct {
+ steam.Library
+ sync.Mutex
+}
+
+type statusInfo struct {
+ sync.RWMutex
+ Running bool
+ Error error
+ Url string
+ Transferred int64
+ Size int64
+ Start *time.Time
+}
+
+
+type App struct {
+ Library *steamLib
+ Status *statusInfo
+
+ Templates *template.Template
+
+ // Sending to this channel triggers the downloader in the background
+ download chan string
+}
+
+func NewApp(libPath string) (*App, error) {
+ lib, err := steam.NewLibrary(libPath)
+ if err != nil {
+ return nil, err
+ }
+
+ a := &App{
+ Library: &steamLib{},
+ Status: &statusInfo{},
+ download: make(chan string),
+ }
+
+ a.Library.Library = *lib
+
+ a.Templates = template.Must(template.New("index").Parse(indexTemplate))
+
+ return a, nil
+}
+
+func (a *App) LibrarySet(path string) {
+ Logger.Println("Starting library reload")
+ a.Library.Lock()
+ defer a.Library.Unlock()
+ var err error
+ l2, err := steam.NewLibrary(path)
+ if err != nil {
+ Logger.Printf("Error reopening lib: %s", err)
+ return
+ }
+ a.Library.Library = *l2
+ Logger.Println("Done reloading lib")
+}
+
+func (a *App) LibraryReload() {
+ cur := a.Library.Folder
+ a.LibrarySet(cur)
+ return
+}
+
diff --git a/cmd/web/delete.go b/cmd/web/delete.go
deleted file mode 100644
index 7fa003e..0000000
--- a/cmd/web/delete.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package main
-
-import (
- "fmt"
- "net/http"
-)
-
-func (a App) HandleDelete(w http.ResponseWriter, r *http.Request) {
- if unauthorizedIfNotLocal(w, r) {
- return
- }
-
- err := r.ParseForm()
- if err != nil {
- Logger.Printf("Installer: While parsing form: %s", err)
- http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
- return
- }
-
- game := r.PostForm.Get("name")
-
- if game == "" {
- Logger.Println("Deleter: No game specified")
- http.Error(w, "Game param required", 400)
- return
- }
-
- a.Library.Lock()
- g, ok := a.Library.Games[game]
- a.Library.Unlock()
- if !ok {
- Logger.Printf("Missing: %s", game)
- http.Error(w, "Game is missing", 404)
- return
- }
-
- err = g.Delete()
- if err != nil {
- Logger.Printf("Error removing game: %s", err)
- http.Error(w, fmt.Sprintf("Error removing game: %s", err), 500)
- return
- }
- Logger.Printf("Removed game: %s", game)
-
- a.LibraryReload()
- http.Redirect(w, r, "/", 302)
-}
diff --git a/cmd/web/download.go b/cmd/web/download.go
deleted file mode 100644
index 0238c8c..0000000
--- a/cmd/web/download.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package main
-
-import (
- "fmt"
- "io"
- "net/http"
- "time"
-
- "github.com/gorilla/mux"
-)
-
-func (a *App) HandleDownload(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- game := vars["game"]
-
- a.Library.Lock()
- g, ok := a.Library.Games[game]
- a.Library.Unlock()
- if !ok {
- Logger.Printf("Missing: %s", game)
- http.Error(w, "Game is missing", 404)
- return
- }
-
- w.Header().Add("Content-type", "application/tar")
- w.Header().Add("Estimated-size", fmt.Sprintf("%d", g.Size))
-
- Logger.Printf("Client %s is downloading: %s", r.RemoteAddr, game)
-
- // Invert the writer so we can break up the copy and get progress
- // information in here
- rdr, pwrtr := io.Pipe()
- go func() {
- err := g.Package(pwrtr)
- if err != nil {
- Logger.Println("Error in package writing: ", err)
- }
- }()
-
- var total int64
- start := time.Now()
- for {
- n, err := io.CopyN(w, rdr, 256*1024*1024)
- if err == io.EOF {
- break
- }
- if err != nil {
- Logger.Printf("Client %s Error Sending game: %s", r.RemoteAddr, err)
- // Headers already sent, don't bother sending an error
- return
- }
- total += n
- mb := float64(total / 1024 / 1024)
- rate := mb / time.Since(start).Seconds()
-
- Logger.Printf("Client %s is downloading %s: %0.1f%% done %.2f mb/s",
- r.RemoteAddr, game, float64(total)/float64(g.Size)*100, rate)
- }
-
- Logger.Printf("Client %s finished downloading: %s", r.RemoteAddr, game)
-}
diff --git a/cmd/web/flagSliceString.go b/cmd/web/flagSliceString.go
deleted file mode 100644
index ec06966..0000000
--- a/cmd/web/flagSliceString.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package main
-
-type FlagSliceString []string
-
-func (f *FlagSliceString) String() string {
- return ""
-}
-
-func (f *FlagSliceString) Set(val string) error {
- *f = append(*f, val)
- return nil
-}
diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go
new file mode 100644
index 0000000..b8fa705
--- /dev/null
+++ b/cmd/web/handlers.go
@@ -0,0 +1,207 @@
+package main
+
+import (
+ "fmt"
+ "strings"
+ "net/url"
+ "os"
+ "encoding/json"
+ "io"
+ "net/http"
+ "time"
+
+ "github.com/gorilla/mux"
+ "riedstra.dev/mitch/steam-export/steam"
+)
+
+func (a *App) HandleIndex(w http.ResponseWriter, r *http.Request) {
+ // During rendering of the template I believe it's
+ // mutating during the sort of keys, so Lib no longer
+ // is an RWMutex and we're just locking this as if
+ // we're writing to it
+ a.Library.Lock()
+ defer a.Library.Unlock()
+ a.Status.Lock()
+ defer a.Status.Unlock()
+
+ err := a.Templates.ExecuteTemplate(w, "index",
+ struct {
+ Lib *steam.Library
+ Info *statusInfo
+ Local bool
+ HostIP string
+ Port string
+ Version string
+ }{
+ &a.Library.Library,
+ a.Status,
+ isLocal(r.RemoteAddr),
+ getHostIP(),
+ getPort(),
+ Version,
+ })
+ if err != nil {
+ Logger.Printf("While Rendering template: %s", err)
+ }
+ Logger.Printf("Client %s Index page", r.RemoteAddr)
+}
+
+func (a *App) HandleInstall(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ Logger.Printf("Installer: While parsing form: %s", err)
+ http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
+ return
+ }
+
+ uri := r.Form.Get("uri")
+
+ if strings.HasPrefix(uri, "http") {
+ _, err := url.Parse(uri)
+ if err != nil {
+ Logger.Printf("Installer: While parsing url: %s", err)
+ http.Error(w, fmt.Sprintf("Invalid url: %s", err), 400)
+ return
+ }
+ } else {
+ fi, err := os.Stat(uri)
+ if err != nil || !fi.Mode().IsRegular() {
+ Logger.Printf("Installer: While parsing url/path: %s", err)
+ http.Error(w, fmt.Sprintf("Invalid uri/path: %s", err), 400)
+ return
+ }
+ }
+
+ Logger.Printf("Installer: Sending request for: %s to channel", uri)
+ a.download <- uri
+
+ http.Redirect(w, r, "/", 302)
+}
+
+func (a *App) HandleDownload(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ game := vars["game"]
+
+ a.Library.Lock()
+ g, ok := a.Library.Games[game]
+ a.Library.Unlock()
+ if !ok {
+ Logger.Printf("Missing: %s", game)
+ http.Error(w, "Game is missing", 404)
+ return
+ }
+
+ w.Header().Add("Content-type", "application/tar")
+ w.Header().Add("Estimated-size", fmt.Sprintf("%d", g.Size))
+
+ Logger.Printf("Client %s is downloading: %s", r.RemoteAddr, game)
+
+ // Invert the writer so we can break up the copy and get progress
+ // information in here
+ rdr, pwrtr := io.Pipe()
+ go func() {
+ err := g.Package(pwrtr)
+ if err != nil {
+ Logger.Println("Error in package writing: ", err)
+ }
+ }()
+
+ var total int64
+ start := time.Now()
+ for {
+ n, err := io.CopyN(w, rdr, 256*1024*1024)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ Logger.Printf("Client %s Error Sending game: %s", r.RemoteAddr, err)
+ // Headers already sent, don't bother sending an error
+ return
+ }
+ total += n
+ mb := float64(total / 1024 / 1024)
+ rate := mb / time.Since(start).Seconds()
+
+ Logger.Printf("Client %s is downloading %s: %0.1f%% done %.2f mb/s",
+ r.RemoteAddr, game, float64(total)/float64(g.Size)*100, rate)
+ }
+
+ Logger.Printf("Client %s finished downloading: %s", r.RemoteAddr, game)
+}
+
+func (a *App) HandleDelete(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ Logger.Printf("Installer: While parsing form: %s", err)
+ http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
+ return
+ }
+
+ game := r.PostForm.Get("name")
+
+ if game == "" {
+ Logger.Println("Deleter: No game specified")
+ http.Error(w, "Game param required", 400)
+ return
+ }
+
+ a.Library.Lock()
+ g, ok := a.Library.Games[game]
+ a.Library.Unlock()
+ if !ok {
+ Logger.Printf("Missing: %s", game)
+ http.Error(w, "Game is missing", 404)
+ return
+ }
+
+ err = g.Delete()
+ if err != nil {
+ Logger.Printf("Error removing game: %s", err)
+ http.Error(w, fmt.Sprintf("Error removing game: %s", err), 500)
+ return
+ }
+ Logger.Printf("Removed game: %s", game)
+
+ a.LibraryReload()
+ http.Redirect(w, r, "/", 302)
+}
+
+func (a *App) HandleStats(w http.ResponseWriter, r *http.Request) {
+ a.Status.RLock()
+ defer a.Status.RUnlock()
+
+ w.Header().Add("Content-type", "application/json")
+
+ enc := json.NewEncoder(w)
+
+ err := enc.Encode(a.Status)
+ if err != nil {
+ Logger.Println("While encoding Status: ", err)
+ }
+ return
+}
+
+func (a *App) HandleSetLib(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ if err != nil {
+ Logger.Printf("Setlib: While parsing form: %s", err)
+ http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
+ return
+ }
+
+ a.LibrarySet(r.Form.Get("path"))
+
+ http.Redirect(w, r, "/", 302)
+}
+
+func HandleQuit(w http.ResponseWriter, r *http.Request) {
+ Logger.Println("Quit was called, exiting")
+ w.Header().Add("Content-type", "text/plain")
+ w.Write([]byte("Shutting down..."))
+ go func() {
+ time.Sleep(time.Second * 2)
+ os.Exit(0)
+ }()
+ return
+}
+
diff --git a/cmd/web/index.go b/cmd/web/index.go
deleted file mode 100644
index 7291af0..0000000
--- a/cmd/web/index.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package main
-
-import (
- "net/http"
-
- "riedstra.dev/mitch/steam-export/steam"
-)
-
-func (a *App) HandleIndex(w http.ResponseWriter, r *http.Request) {
- // During rendering of the template I believe it's
- // mutating during the sort of keys, so Lib no longer
- // is an RWMutex and we're just locking this as if
- // we're writing to it
- a.Library.Lock()
- defer a.Library.Unlock()
- a.Status.Lock()
- defer a.Status.Unlock()
-
- err := a.Templates.ExecuteTemplate(w, "index",
- struct {
- Lib *steam.Library
- Info *statusInfo
- Local bool
- HostIP string
- Port string
- Version string
- }{
- &a.Library.Library,
- a.Status,
- isLocal(r.RemoteAddr),
- getHostIP(),
- getPort(),
- Version,
- })
- if err != nil {
- Logger.Printf("While Rendering template: %s", err)
- }
- Logger.Printf("Client %s Index page", r.RemoteAddr)
-}
diff --git a/cmd/web/install.go b/cmd/web/install.go
index ce8aa8d..dc85a89 100644
--- a/cmd/web/install.go
+++ b/cmd/web/install.go
@@ -1,32 +1,15 @@
package main
import (
- "encoding/json"
"fmt"
"io"
"net/http"
- "net/url"
"os"
"strconv"
"strings"
"time"
)
-func (a *App) HandleStats(w http.ResponseWriter, r *http.Request) {
- a.Status.RLock()
- defer a.Status.RUnlock()
-
- w.Header().Add("Content-type", "application/json")
-
- enc := json.NewEncoder(w)
-
- err := enc.Encode(a.Status)
- if err != nil {
- Logger.Println("While encoding Status: ", err)
- }
- return
-}
-
func (a *App) installHttp(u string) error {
Logger.Println("Installer: loading from url")
resp, err := http.Get(u)
@@ -129,38 +112,3 @@ func (a *App) installer() {
}
}
-func (a *App) HandleInstall(w http.ResponseWriter, r *http.Request) {
- if unauthorizedIfNotLocal(w, r) {
- return
- }
-
- err := r.ParseForm()
- if err != nil {
- Logger.Printf("Installer: While parsing form: %s", err)
- http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
- return
- }
-
- uri := r.Form.Get("uri")
-
- if strings.HasPrefix(uri, "http") {
- _, err := url.Parse(uri)
- if err != nil {
- Logger.Printf("Installer: While parsing url: %s", err)
- http.Error(w, fmt.Sprintf("Invalid url: %s", err), 400)
- return
- }
- } else {
- fi, err := os.Stat(uri)
- if err != nil || !fi.Mode().IsRegular() {
- Logger.Printf("Installer: While parsing url/path: %s", err)
- http.Error(w, fmt.Sprintf("Invalid uri/path: %s", err), 400)
- return
- }
- }
-
- Logger.Printf("Installer: Sending request for: %s to channel", uri)
- a.download <- uri
-
- http.Redirect(w, r, "/", 302)
-}
diff --git a/cmd/web/main.go b/cmd/web/main.go
index f0c7489..875b2d8 100644
--- a/cmd/web/main.go
+++ b/cmd/web/main.go
@@ -4,64 +4,15 @@ import (
"embed"
"flag"
"fmt"
- "html/template"
"log"
"math/rand"
- "net"
"net/http"
"os"
- "strings"
- "sync"
"time"
"github.com/gorilla/mux"
- "riedstra.dev/mitch/steam-export/steam"
)
-type App struct {
- Library *steamLib
- Status *statusInfo
-
- Templates *template.Template
-
- // Sending to this channel triggers the downloader in the background
- download chan string
-}
-
-func NewApp(libPath string) (*App, error) {
- lib, err := steam.NewLibrary(libPath)
- if err != nil {
- return nil, err
- }
-
- a := &App{
- Library: &steamLib{},
- Status: &statusInfo{},
- download: make(chan string),
- }
-
- a.Library.Library = *lib
-
- a.Templates = template.Must(template.New("index").Parse(indexTemplate))
-
- return a, nil
-}
-
-type steamLib struct {
- steam.Library
- sync.Mutex
-}
-
-type statusInfo struct {
- sync.RWMutex
- Running bool
- Error error
- Url string
- Transferred int64
- Size int64
- Start *time.Time
-}
-
var (
Version = "Development"
Logger = log.New(os.Stderr, "", log.LstdFlags)
@@ -73,116 +24,6 @@ var (
indexTemplate string
)
-func (a *App) LibrarySet(path string) {
- Logger.Println("Starting library reload")
- a.Library.Lock()
- defer a.Library.Unlock()
- var err error
- l2, err := steam.NewLibrary(path)
- if err != nil {
- Logger.Printf("Error reopening lib: %s", err)
- return
- }
- a.Library.Library = *l2
- Logger.Println("Done reloading lib")
-}
-
-func (a *App) LibraryReload() {
- cur := a.Library.Folder
- a.LibrarySet(cur)
- return
-}
-
-func (a *App) HandleSetLib(w http.ResponseWriter, r *http.Request) {
- if unauthorizedIfNotLocal(w, r) {
- return
- }
-
- err := r.ParseForm()
- if err != nil {
- Logger.Printf("Setlib: While parsing form: %s", err)
- http.Error(w, fmt.Sprintf("Invalid form: %s", err), 400)
- return
- }
-
- a.LibrarySet(r.Form.Get("path"))
-
- http.Redirect(w, r, "/", 302)
-}
-
-func (a *App) HandleQuit(w http.ResponseWriter, r *http.Request) {
- if unauthorizedIfNotLocal(w, r) {
- return
- }
-
- Logger.Println("Quit was called, exiting")
- w.Header().Add("Content-type", "text/plain")
- w.Write([]byte("Shutting down..."))
- go func() {
- time.Sleep(time.Second * 2)
- os.Exit(0)
- }()
- return
-}
-
-func unauthorizedIfNotLocal(w http.ResponseWriter, r *http.Request) bool {
- if !isLocal(r.RemoteAddr) {
- http.Error(w, "Unauthorized", http.StatusUnauthorized)
- Logger.Printf("Unauthorized request from: %s for %s",
- r.RemoteAddr, r.RequestURI)
- return true
- }
- return false
-}
-
-func isLocal(addr string) bool {
- _, localNet, _ := net.ParseCIDR("127.0.0.1/8")
- return localNet.Contains(net.ParseIP(strings.Split(addr, ":")[0]))
-}
-
-// getHostIP attempts to guess the IP address of the current machine and
-// returns that. Simply bails at the first non sane looking IP and returns it.
-// Not ideal but it should work well enough most of the time
-func getHostIP() string {
- iFaces, err := net.Interfaces()
- if err != nil {
- return "127.0.0.1"
- }
-
- // RFC 3927
- _, ipv4LinkLocal, _ := net.ParseCIDR("169.254.0.0/16")
-
- for _, iFace := range iFaces {
- addrs, err := iFace.Addrs()
- if err != nil {
- return "127.0.0.1"
- }
-
- for _, a := range addrs {
- n, ok := a.(*net.IPNet)
- if !ok {
- continue
- }
-
- if n.IP.To4() != nil && !n.IP.IsLoopback() && !ipv4LinkLocal.Contains(n.IP.To4()) {
- return n.IP.String()
- }
- }
- }
-
- return "127.0.0.1"
-}
-
-func getPort() string {
- s := strings.Split(Listen, ":")
-
- if len(s) != 2 {
- return Listen
- }
-
- return s[1]
-}
-
func main() {
fl := flag.NewFlagSet("steam-export", flag.ExitOnError)
debug := fl.Bool("d", false, "Print line numbers in log")
@@ -203,13 +44,13 @@ func main() {
r := mux.NewRouter()
- r.HandleFunc("/quit", a.HandleQuit)
- r.HandleFunc("/setLib", a.HandleSetLib)
- r.HandleFunc("/delete", a.HandleDelete)
- r.HandleFunc("/install", a.HandleInstall)
+ r.HandleFunc("/quit", HandleQuit)
+ r.Handle("/setLib", UnauthorizedIfNotLocal(http.HandlerFunc(a.HandleSetLib)))
+ r.Handle("/delete", UnauthorizedIfNotLocal(http.HandlerFunc(a.HandleDelete)))
+ r.Handle("/install", UnauthorizedIfNotLocal(http.HandlerFunc(a.HandleInstall)))
r.HandleFunc("/steam-export-web.exe", serveSelf)
r.HandleFunc("/download/{game}", a.HandleDownload)
- r.HandleFunc("/status", a.HandleStats)
+ r.Handle("/status", UnauthorizedIfNotLocal(http.HandlerFunc(a.HandleStats)))
r.PathPrefix("/static").Handler(
http.FileServer(http.FS(embeddedStatic)))
r.HandleFunc("/", a.HandleIndex)
@@ -226,7 +67,7 @@ func main() {
if err != nil {
Logger.Printf("Encountered: %s", err)
rand.Seed(time.Now().UnixNano())
- Listen = fmt.Sprintf(":%d", rand.Intn(63000)+1024)
+ Listen = fmt.Sprintf(":%d", rand.Intn(9000)+1024)
Logger.Printf("Trying: %s", Listen)
s.Addr = Listen
}
diff --git a/cmd/web/serve-self.go b/cmd/web/serve-self.go
deleted file mode 100644
index 8abb830..0000000
--- a/cmd/web/serve-self.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package main
-
-import (
- "io"
- "net/http"
- "os"
-)
-
-func serveSelf(w http.ResponseWriter, r *http.Request) {
- s, err := os.Executable()
- if err != nil {
- Logger.Println("While trying to get my executable path: ", err)
- http.Error(w, "Internal server error", http.StatusInternalServerError)
- return
- }
-
- fh, err := os.Open(s)
- if err != nil {
- Logger.Println("While opening my own executable for reading: ", err)
- http.Error(w, "Internal server error", http.StatusInternalServerError)
- return
- }
-
- _, err = io.Copy(w, fh)
- fh.Close()
- return
-}
diff --git a/cmd/web/util.go b/cmd/web/util.go
new file mode 100644
index 0000000..1252c66
--- /dev/null
+++ b/cmd/web/util.go
@@ -0,0 +1,89 @@
+package main
+
+import (
+ "io"
+ "os"
+ "net/http"
+ "net"
+ "strings"
+)
+
+func UnauthorizedIfNotLocal(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !isLocal(r.RemoteAddr) {
+ http.Error(w, "Unauthorized", http.StatusUnauthorized)
+ Logger.Printf("Unauthorized request from: %s for %s",
+ r.RemoteAddr, r.RequestURI)
+ return
+ }
+ h.ServeHTTP(w, r)
+ })
+}
+
+func isLocal(addr string) bool {
+ _, localNet, _ := net.ParseCIDR("127.0.0.1/8")
+ return localNet.Contains(net.ParseIP(strings.Split(addr, ":")[0]))
+}
+
+// getHostIP attempts to guess the IP address of the current machine and
+// returns that. Simply bails at the first non sane looking IP and returns it.
+// Not ideal but it should work well enough most of the time
+func getHostIP() string {
+ iFaces, err := net.Interfaces()
+ if err != nil {
+ return "127.0.0.1"
+ }
+
+ // RFC 3927
+ _, ipv4LinkLocal, _ := net.ParseCIDR("169.254.0.0/16")
+
+ for _, iFace := range iFaces {
+ addrs, err := iFace.Addrs()
+ if err != nil {
+ return "127.0.0.1"
+ }
+
+ for _, a := range addrs {
+ n, ok := a.(*net.IPNet)
+ if !ok {
+ continue
+ }
+
+ if n.IP.To4() != nil && !n.IP.IsLoopback() && !ipv4LinkLocal.Contains(n.IP.To4()) {
+ return n.IP.String()
+ }
+ }
+ }
+
+ return "127.0.0.1"
+}
+
+func getPort() string {
+ s := strings.Split(Listen, ":")
+
+ if len(s) != 2 {
+ return Listen
+ }
+
+ return s[1]
+}
+
+func serveSelf(w http.ResponseWriter, r *http.Request) {
+ s, err := os.Executable()
+ if err != nil {
+ Logger.Println("While trying to get my executable path: ", err)
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ fh, err := os.Open(s)
+ if err != nil {
+ Logger.Println("While opening my own executable for reading: ", err)
+ http.Error(w, "Internal server error", http.StatusInternalServerError)
+ return
+ }
+
+ _, err = io.Copy(w, fh)
+ fh.Close()
+ return
+}