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.MuhTemplates().ExecuteTemplate(w, "index.html", 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... feel free to close this")) go func() { time.Sleep(time.Second * 2) os.Exit(0) }() return }