func DownloadProductionVersion() (s string, err error) { resp, err := download.Request(download.ProductionVersion) if err != nil { return } s, err = LoadVersion(resp.Body) resp.Body.Close() return }
func DownloadChanges(pso2path string, changes []*download.PatchEntry, parallel int) (errs []error) { if parallel <= 0 { parallel = 1 } changesSize := int64(0) for _, e := range changes { changesSize += e.Size } pbar := pb.New64(changesSize) pbar.SetUnits(pb.U_BYTES) pbar.SetRefreshRate(time.Second / 30) pbar.ShowSpeed = true pbar.Start() queue := make(chan *download.PatchEntry) done := make(chan bool) errlock := sync.Mutex{} complain := func(err error) bool { if err != nil { errlock.Lock() errs = append(errs, err) errlock.Unlock() return true } return false } for i := 0; i < parallel; i++ { go func() { h := md5.New() for { e, ok := <-queue if !ok { break } filepath := path.Join(pso2path, download.RemoveExtension(e.Path)) err := os.MkdirAll(path.Dir(filepath), 0777) if complain(err) { break } pathUrl, err := e.URL() if complain(err) { continue } resp, err := download.Request(pathUrl.String()) if complain(err) { continue } if resp.StatusCode != 200 { complain(errors.New(pathUrl.String() + ": " + resp.Status)) continue } if resp.ContentLength >= 0 && resp.ContentLength != e.Size { resp.Body.Close() complain(errors.New(e.Path + ": invalid file size")) continue } f, err := os.Create(filepath) if complain(err) { resp.Body.Close() continue } h.Reset() n, err := io.Copy(io.MultiWriter(f, h, pbar), resp.Body) resp.Body.Close() f.Close() if !complain(err) { if n != e.Size { complain(errors.New(pathUrl.String() + ": download finished prematurely")) } else if bytes.Compare(h.Sum(nil), e.MD5[:]) != 0 { complain(errors.New(pathUrl.String() + ": download hash mismatch")) } } } done <- true }() } for _, e := range changes { queue <- e } close(queue) for i := 0; i < parallel; i++ { <-done } pbar.Finish() return }
func DownloadEnglishFiles(pso2path string) (translationChanged bool, err error) { resp, err := download.Request(EnglishUpdateURL) if err != nil { return } var data struct { ItemTimestamp, EnglishTimestamp, TranslationTimestamp int64 ItemURL, EnglishURL, TranslationURL string } d := json.NewDecoder(resp.Body) err = d.Decode(&data) resp.Body.Close() if err != nil { return } scratch := PathScratch(pso2path) itemPath := path.Join(scratch, PathTranslateDll) translationPath := path.Join(scratch, PathTranslationBin) englishPath := path.Join(scratch, PathEnglishDb) rootUrl, _ := url.Parse(EnglishUpdateURL) updateEnglishFile := func(path string, timestamp int64, urlStr string) (bool, error) { url, err := url.Parse(urlStr) if err != nil { return false, err } st, err := os.Stat(path) if os.IsNotExist(err) || (err == nil && st.ModTime().Unix() < timestamp) { resp, err := download.Request(rootUrl.ResolveReference(url).String()) if err != nil { return false, err } f, err := os.Create(path) if err != nil { return false, err } _, err = io.Copy(f, resp.Body) f.Close() resp.Body.Close() return true, err } return false, err } translationChanged, err = updateEnglishFile(englishPath, data.EnglishTimestamp, data.EnglishURL) if err != nil { return } _, err = updateEnglishFile(translationPath, data.TranslationTimestamp, data.TranslationURL) if err != nil { return } _, err = updateEnglishFile(itemPath, data.ItemTimestamp, data.ItemURL) return }