diff options
Diffstat (limited to 'steam')
| -rw-r--r-- | steam/delete.go | 5 | ||||
| -rw-r--r-- | steam/extract.go | 27 | ||||
| -rw-r--r-- | steam/package.go | 7 | ||||
| -rw-r--r-- | steam/status.go | 27 | ||||
| -rw-r--r-- | steam/steam.go | 5 |
5 files changed, 51 insertions, 20 deletions
diff --git a/steam/delete.go b/steam/delete.go index 486b047..aa78e22 100644 --- a/steam/delete.go +++ b/steam/delete.go @@ -17,6 +17,11 @@ func (l *Library) Delete(game string) error { l.status.addJob(j) + if l.status.otherThanCurrent(j) { + j.addError(E_OperationConflict) + return E_OperationConflict + } + acf, err := FindACF(l.folder, game) if err != nil { j.addError(err) diff --git a/steam/extract.go b/steam/extract.go index 9a7a930..d93428d 100644 --- a/steam/extract.go +++ b/steam/extract.go @@ -43,9 +43,9 @@ func (l *Library) ExtractSmart(uri string) (*Game, error) { return nil, E_BadURI } -// ExtractFile is a wrapper around Extract that handles an HTTP endpoint. -// this spawns an "extractFile" on the library. Status will be updated there -// as this goes along. Non fatal and fatal errors will be populated there +// ExtractFile is a wrapper around Extract that handles local files. this +// spawns an "extractFile" on the library. Status will be updated there as this +// goes along. Non fatal and fatal errors will be populated there func (l *Library) ExtractFile(fn string) (*Game, error) { g := &Game{} j := newJob("extractFile", g) @@ -66,10 +66,13 @@ func (l *Library) ExtractFile(fn string) (*Game, error) { return g, err } - return l.extractUpdate(j, g, fh) + g, err = l.extractUpdate(j, g, fh) + fh.Close() + + return g, err } -// Extract will read a tarball from the io.Reader and install the game into +// Extract will read a tarball from the io.ReadCloser and install the game into // the current library path. This offers no visibility into the progress, // as it does not update the job status on the progress, though it will // populate errors. @@ -87,25 +90,23 @@ func (l *Library) Extract(r io.Reader) (*Game, error) { // extractUpdate takes care of updating the job as it goes along at updateEveryNBytes // it will be reported back to the Job's status. -func (l *Library) extractUpdate(j *Job, g *Game, rdr io.ReadCloser) (*Game, error) { - rdr, wrtr := io.Pipe() +func (l *Library) extractUpdate(j *Job, g *Game, rdr io.Reader) (*Game, error) { + prdr, pwrtr := io.Pipe() go func() { var err error - g, err = l.extractPrimitive(j, g, rdr) + g, err = l.extractPrimitive(j, g, prdr) if err != nil { j.addError(fmt.Errorf("Installer: extracting %s", err)) } - // resp.Body.Close() - rdr.Close() }() var total int64 var err error + var n int64 for { - var n int64 - n, err = io.CopyN(wrtr, rdr, updateEveryNBytes) + n, err = io.CopyN(pwrtr, rdr, updateEveryNBytes) if err == io.EOF { break } else if err != nil { @@ -143,6 +144,7 @@ func (l *Library) extractUpdate(j *Job, g *Game, rdr io.ReadCloser) (*Game, erro } func (l *Library) extractPrimitive(j *Job, g *Game, r io.Reader) (*Game, error) { + treader := tar.NewReader(r) for { @@ -189,6 +191,7 @@ func (l *Library) extractPrimitive(j *Job, g *Game, r io.Reader) (*Game, error) // Create a file handle to work with f, err := os.OpenFile(fileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFileMode) + if err != nil { j.addError(err) return nil, err diff --git a/steam/package.go b/steam/package.go index 5b0c618..db3d6cf 100644 --- a/steam/package.go +++ b/steam/package.go @@ -3,7 +3,6 @@ package steam import ( "archive/tar" "errors" - "fmt" "io" "path/filepath" "time" @@ -56,7 +55,7 @@ func (l *Library) Package(game string, wr io.Writer) error { rate := float64(total) / elapsedSeconds - fmt.Println("rate in bytes/second: ", formatBytes(int64(rate))) + // fmt.Println("rate in bytes/second: ", formatBytes(int64(rate))) estSize := j.GetSize() @@ -66,12 +65,12 @@ func (l *Library) Package(game string, wr io.Writer) error { } remainingBytes := float64(*estSize - total) - fmt.Println("remaining bytes: ", formatBytes(int64(remainingBytes))) + // fmt.Println("remaining bytes: ", formatBytes(int64(remainingBytes))) seconds := (remainingBytes / rate) duration := time.Duration(seconds * 1000 * 1000 * 1000) - fmt.Println("Raw duration: ", duration) + // fmt.Println("Raw duration: ", duration) j.setETA(duration) } diff --git a/steam/status.go b/steam/status.go index 9d70655..9ebf20f 100644 --- a/steam/status.go +++ b/steam/status.go @@ -42,7 +42,7 @@ type Job struct { func (j Job) MarshalJSON() ([]byte, error) { return json.Marshal( struct { - Action string `json:"action"` + Action string `json:"Action"` Target *Game `json:"Target"` Running bool `json:"Running"` Start *time.Time `json:"Start"` @@ -80,7 +80,7 @@ func (j *Job) Target() *Game { return j.target } -// IsRunning returns true if the job is currently running, otherwise false +// IsRunning returns true if a job is currently running, otherwise false func (j *Job) IsRunning() bool { j.m.Lock() defer j.m.Unlock() @@ -233,6 +233,29 @@ func (jobs *Jobs) scan() { jobs.running = running } +// otherThanCurrent will return true if there's another job running on the +// game specified. It's the caller's responsibility to check that the provided +// job has a game of not nil, otherwise a panic will occur +func (jobs *Jobs) otherThanCurrent(j *Job) bool { + for _, job := range jobs.GetRunningJobs() { + if job == j { + continue + } + + g := job.Target() + + if g == nil { + continue + } + + if g.Name == j.Target().Name { + return true + } + } + + return false +} + // Running returns true if any job is currently running, otherwise false func (jobs *Jobs) Running() bool { jobs.scan() diff --git a/steam/steam.go b/steam/steam.go index c477191..ae69020 100644 --- a/steam/steam.go +++ b/steam/steam.go @@ -12,8 +12,9 @@ import ( ) var ( - E_GameDoesNotExist = errors.New("Game does not exist") - E_BadURI = errors.New("The URI supplied is not understood") + E_GameDoesNotExist = errors.New("Game does not exist") + E_BadURI = errors.New("The URI supplied is not understood") + E_OperationConflict = errors.New("Another conflicting job is running on this game right now") ) // Library is used to represent the steam library, the Games map is populated |
