public void Start(string[] wantedCaches) { _thread = new Thread(delegate() { #if !DEBUG try { #endif SendStatus(StatusChangedEnum.Start); //SendStatus(StatusChangedEnum.CacheDownloading, "caches.xml", 0); Log.Info(String.Format("Starting Update process. Wanted caches: {0}", String.Join(", ", wantedCaches))); //Step 1. Get the remote file. var file = _wc.DownloadString(_server + "caches.xml"); var xml = XDocument.Parse(file); _remoteCache = new Caches(xml); Log.Info("Remote caches have been downloaded."); var versions = _remoteCache.Versions(); foreach (var a in versions) { Log.Info(String.Format("Cache: {0} Version: {1}", a.Key, a.Value)); } SendStatus(StatusChangedEnum.CacheDownloaded, new object[] {"caches.xml", versions}, 0); //populate this with all possible caches var cachesToUpdate = new List<string>(wantedCaches); //step 2. Get the local file, and compare if (_localCacheLocation != "" && File.Exists(_localCacheLocation)) { file = File.ReadAllText(_localCacheLocation); xml = XDocument.Parse(file); _localCache = new Caches(xml); Log.Info("Local caches:"); foreach (var a in _localCache.Versions()) { Log.Info(String.Format("Cache: {0} Version: {1}", a.Key, a.Value)); } //step 2a. Compare version numbers. var localVersions = _localCache.Versions(); foreach (var wantedCache in wantedCaches) { if (versions.ContainsKey(wantedCache)) { if (localVersions.ContainsKey(wantedCache) && versions[wantedCache] <= localVersions[wantedCache]) { //update is not needed for this cache. cachesToUpdate.Remove(wantedCache); } } else { cachesToUpdate.Remove(wantedCache); } } } else { Log.Info("Local caches are not found or unused. Downloading all wanted caches."); SendStatus(StatusChangedEnum.LocalCachesNotFound); } //cachesToUpdate now contains a list of all caches to get. if (cachesToUpdate.Count == 0) { //success - no update needed tasksDone = 0; tasksTotal = 1; Log.Info("no update needed"); SendStatus(StatusChangedEnum.NoUpdateNeeded); SendStatus(StatusChangedEnum.Finish); return; } tasksDone = 0; tasksTotal = cachesToUpdate.Count; Log.Info(String.Format("Caches to download: {0}", String.Join(", ", cachesToUpdate.ToArray()))); //step 3. Get the CacheInfo for each wanted cache. var cacheContentFileList = new List<CacheContentFile>(); foreach (var cache in cachesToUpdate) { SendStatus(StatusChangedEnum.CacheDownloading, cache, 1); file = _wc.DownloadString(_server + cache + "/info.xml"); xml = XDocument.Parse(file); var ci = new CacheInfo(this, Location, cache, xml); var files = ci.Files(); cacheContentFileList.AddRange(files); SendStatus(StatusChangedEnum.CacheDownloaded, new object[] {cache, files}, 0); } tasksDone = 0; tasksTotal = cacheContentFileList.Sum(cifile => cifile.CompressedSize); if (tasksTotal != 0) { SendStatus(StatusChangedEnum.DownloadsStart); foreach (var cifile in cacheContentFileList) { //step 4. Download and decompress. Log.Info(String.Format("Downloading {0}", cifile.Cache + "/" + cifile.Name)); int retries = 0; int maxRetries = 3; int rampUpTime = 2; bool success = false; while (!success && retries <= maxRetries) { //totalProgress = cifile.CompressedSize; SendStatus(StatusChangedEnum.FileStart, cifile.Cache + "/" + cifile.Name, 0); success = Download(cifile); if (!success) { SendStatus(StatusChangedEnum.FileFailed, cifile.Cache + "/" + cifile.Name, -cifile.CompressedSize); //backtrack the progress retries++; if (retries <= maxRetries) { int waitTime = (int) (Math.Pow(rampUpTime, retries))*1000; SendStatus(StatusChangedEnum.FileRedownload, new object[] {cifile.Cache + "/" + cifile.Name, waitTime}, 0); Log.Warn(string.Format("Redownloading {0} (sleeping {1} ms)", cifile.Name, waitTime)); Thread.Sleep(waitTime); } } } if (!success) { SendStatus(StatusChangedEnum.Fail, _lastException, 0); return; } SendStatus(StatusChangedEnum.FileFinish, cifile.Cache + "/" + cifile.Name, 0); } SendStatus(StatusChangedEnum.DownloadsFinish); } //step 5. Save remote cache as local cache. if(_localCacheLocation != "") { file = _remoteCache.ToString(); var path = Path.Combine(Location, _localCacheLocation); File.WriteAllText(path, file); SendStatus(StatusChangedEnum.LocalCacheSaved); } SendStatus(StatusChangedEnum.Finish); #if !DEBUG } catch (Exception e){ SendStatus(StatusChangedEnum.Fail, e, 0); } #endif }); _thread.Start(); }