diff options
| author | Mitch Riedstra <mitch@riedstra.us> | 2020-11-21 15:33:57 -0500 |
|---|---|---|
| committer | Mitch Riedstra <mitch@riedstra.us> | 2020-11-21 15:33:57 -0500 |
| commit | 36dc9ff10971cf97eb077907072c519cb5349fe4 (patch) | |
| tree | faf3ff607714ee8b155c801b91a04e2cc8cb2279 /cmd | |
| parent | 4ed57528379c9d1ac0f5bc77b95439bbba3d4488 (diff) | |
| download | steam-export-36dc9ff10971cf97eb077907072c519cb5349fe4.tar.gz steam-export-36dc9ff10971cf97eb077907072c519cb5349fe4.tar.xz | |
Most of the functionality I want is there now, it's not pretty though.
Build the web server and the command line in the build script
Allow for deletion of games from the library
Move the download function out of main.go
Add more information to the index template and handler.
Allow for downloads from URLs and installation from local files.
Allow changing of the library path via a command line flag
Automatically start the web browser on windows
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/web/delete.go | 42 | ||||
| -rw-r--r-- | cmd/web/download.go | 31 | ||||
| -rw-r--r-- | cmd/web/flagSliceString.go | 12 | ||||
| -rw-r--r-- | cmd/web/index.go | 52 | ||||
| -rw-r--r-- | cmd/web/install.go | 116 | ||||
| -rw-r--r-- | cmd/web/main.go | 71 | ||||
| -rw-r--r-- | cmd/web/unix.go | 6 | ||||
| -rw-r--r-- | cmd/web/windows.go | 12 |
8 files changed, 290 insertions, 52 deletions
diff --git a/cmd/web/delete.go b/cmd/web/delete.go new file mode 100644 index 0000000..7188b45 --- /dev/null +++ b/cmd/web/delete.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + "net/http" +) + +func gameDelete(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 + } + + libMu.RLock() + g, ok := Lib.Games[game] + libMu.RUnlock() + 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 + } + + reloadLib() + http.Redirect(w, r, "/", 302) +} diff --git a/cmd/web/download.go b/cmd/web/download.go new file mode 100644 index 0000000..a640ea2 --- /dev/null +++ b/cmd/web/download.go @@ -0,0 +1,31 @@ +package main + +import ( + "net/http" + + "github.com/gorilla/mux" +) + +func gameDownloader(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + game := vars["game"] + + libMu.RLock() + g, ok := Lib.Games[game] + libMu.RUnlock() + if !ok { + Logger.Printf("Missing: %s", game) + http.Error(w, "Game is missing", 404) + return + } + + w.Header().Add("Content-type", "application/tar") + + err := g.Package(w) + if err != nil { + Logger.Printf("Error Sending game: %s", err) + // Headers already sent, don't bother sending an error + } + +} + diff --git a/cmd/web/flagSliceString.go b/cmd/web/flagSliceString.go new file mode 100644 index 0000000..ec06966 --- /dev/null +++ b/cmd/web/flagSliceString.go @@ -0,0 +1,12 @@ +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/index.go b/cmd/web/index.go index 1a2c344..2dfe20e 100644 --- a/cmd/web/index.go +++ b/cmd/web/index.go @@ -1,8 +1,10 @@ package main import ( - "net/http" "html/template" + "net/http" + + "riedstra.dev/mitch/steam-export/steam" ) var ( @@ -23,33 +25,71 @@ var ( </div> </nav> -<h2>Library: {{.Folder}}</h2> +<h2>Library: {{.Lib.Folder}}</h2> + +{{ if .Info.Running }} +<pre><code> +Currently Downloading from: {{.Info.Url}} +</pre></code> +{{ end }} + +{{ if .Info.Error }} +<pre><code> +Error {{.Info.Error}} Downloading from: {{.Info.Url}} +{{ end }} +</pre></code> <p> Installed games: + +Tip: You can right click and save link as to specify a save location, e.g. +an external hard drive </p> <ul> -{{ range $key, $val := .Games }} +{{ range $key, $val := .Lib.Games }} <li> <a href="/download/{{$key}}">{{$key}}</a> </li> {{ end }} </ul> -Install a game from a URL: +Delete a game: ( Type out exact name, case sensitive ) + +<form action="/delete" method="POST"> + <input type="text" name="name" /> + <input type="submit" value="Delete"> +</form> + +Install a game from a URL or local file path: <form action="/install" method="GET"> - <input type="text" name="url" /> + <input type="text" name="uri" /> <input type="submit" value="Install"> </form> +<p> +Note that You can also give someone a URL to install a game if they're running +this program, e.g. <br /> +http://127.0.0.1:8899/install?uri=http://my-server-ip-or-hostname/download/My Game +</p> + + </body> `)) ) func index(w http.ResponseWriter, r *http.Request) { - err := Templ.ExecuteTemplate(w, "index", Lib) + libMu.RLock() + defer libMu.RUnlock() + status.m.RLock() + defer status.m.RUnlock() + + err := Templ.ExecuteTemplate(w, "index", + struct { + Lib *steam.Library + Info *statusInfo + }{Lib, status.s}) if err != nil { Logger.Printf("While Rendering template: %s", err) } diff --git a/cmd/web/install.go b/cmd/web/install.go new file mode 100644 index 0000000..cd2f03a --- /dev/null +++ b/cmd/web/install.go @@ -0,0 +1,116 @@ +package main + +import ( + "net/url" + "os" + "strings" + "fmt" + "net/http" + "sync" +) + +type statusInfo struct { + Running bool + Error error + Url string +} + +var ( + status = struct { + m *sync.RWMutex + s *statusInfo + }{ + m: &sync.RWMutex{}, + s: &statusInfo{Running: false}, + } + + getPath = make(chan string) +) + +func installHttp(u string) error { + resp, err := http.Get(u) + if err != nil { + return fmt.Errorf("Installer: getting %w", err) + } + + err = Lib.Extract(resp.Body) + if err != nil { + return fmt.Errorf("Installer: extracting %w", err) + } + resp.Body.Close() + return nil +} + +func installPath(p string) error { + fh, err := os.Open(p) + if err != nil { + return fmt.Errorf("Installer: opening %w", err) + } + + err = Lib.Extract(fh) + if err != nil { + return fmt.Errorf("Installer: opening %w", err) + } + fh.Close() + return nil +} + +func installer(urls <-chan string) { + var err error + for u := range urls { + status.m.Lock() + status.s.Running = true + status.s.Url = u + status.m.Unlock() + + if strings.HasPrefix(u, "http") { + err = installHttp(u) + } else { + err = installPath(u) + } + + status.m.Lock() + status.s.Running = false + status.s.Error = err + status.m.Unlock() + + reloadLib() + } +} + +func gameInstaller(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 { + Logger.Printf("Installer: While parsing url: %s", err) + http.Error(w, fmt.Sprintf("Invalid uri/path: %s", err), 400) + return + } + + if !fi.Mode().IsRegular() { + Logger.Printf("Installer: While parsing url: %s", err) + http.Error(w, fmt.Sprintf("Invalid uri/path: %s", err), 400) + return + } + } + + getPath <- uri + + http.Redirect(w, r, "/", 302) +} diff --git a/cmd/web/main.go b/cmd/web/main.go index 93025e5..64321da 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -5,7 +5,7 @@ import ( "log" "net/http" "os" - "path/filepath" + "sync" "github.com/gorilla/mux" "riedstra.dev/mitch/steam-export/steam" @@ -15,75 +15,54 @@ var ( Logger = log.New(os.Stderr, "", log.LstdFlags) Listen = ":8899" - Lib = steam.NewLibraryMust(DefaultLib) + libMu = &sync.RWMutex{} + Lib *steam.Library ) -//size, err := estimateSize(g.LibraryPath + "common/" + g.Name) -//if err != nil { -// http.Error(w, "Encountered:"+err, 500) -// return -//} -func estimateSize(pth string) (int64, error) { - var size int64 = 0 - - err := filepath.Walk(pth, func(path string, info os.FileInfo, err error) error { - - if err != nil { - return err - } - - if info.Mode().IsRegular() { - size = size + info.Size() - } - - return nil - }) - - return size, err - -} - -func gameDownloader(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - game := vars["game"] - - g, ok := Lib.Games[game] - if !ok { - Logger.Printf("Missing: %s", game) - http.Error(w, "Game is missing", 404) - return - } - - w.Header().Add("Content-type", "application/tar") - - err := g.Package(w) +func reloadLib() { + libMu.Lock() + defer libMu.Unlock() + var err error + Lib, err = steam.NewLibrary(DefaultLib) if err != nil { - Logger.Printf("Error Sending game: %s", err) - // Headers already sent, don't bother sending an error + Logger.Printf("Error reopening library: %s", err) + return } - } func main() { fl := flag.NewFlagSet("steam-export", flag.ExitOnError) debug := fl.Bool("d", false, "Print line numbers in log") - listen := fl.String("l", Listen, "What address do we listen on?") + fl.StringVar(&Listen, "l", Listen, "What address do we listen on?") + fl.StringVar(&DefaultLib, "L", DefaultLib, "Full path to default library") fl.Parse(os.Args[1:]) if *debug { Logger.SetFlags(log.LstdFlags | log.Llongfile) } + var err error + Lib, err = steam.NewLibrary(DefaultLib) + if err != nil { + Logger.Fatalf("While opening library path: %s", err) + } + + go installer(getPath) + r := mux.NewRouter() + r.HandleFunc("/delete", gameDelete) + r.HandleFunc("/install", gameInstaller) r.HandleFunc("/download/{game}", gameDownloader) r.HandleFunc("/style.css", cssHandler) r.HandleFunc("/", index) s := http.Server{ Handler: r, - Addr: *listen, + Addr: Listen, } + go startBrowser() + Logger.Fatal(s.ListenAndServe()) } diff --git a/cmd/web/unix.go b/cmd/web/unix.go index 6b1b1ae..bbe6087 100644 --- a/cmd/web/unix.go +++ b/cmd/web/unix.go @@ -8,3 +8,9 @@ import ( ) var DefaultLib string = filepath.Join(os.Getenv("HOME"), ".steam/steam/steamapps") + +// TODO +func startBrowser() { + return +} + diff --git a/cmd/web/windows.go b/cmd/web/windows.go index 2effa08..9fe8ab6 100644 --- a/cmd/web/windows.go +++ b/cmd/web/windows.go @@ -2,4 +2,16 @@ package main +import ( + "os/exec" + "time" +) + var DefaultLib string = `C:\Program Files (x86)\Steam\steamapps` + +func startBrowser() { + time.Sleep(time.Second*3) + c := exec.Command("cmd", "/c", "start", "http://127.0.0.1"+Listen) + Logger.Println(c.Run()) +} + |
