private IEnumerator download(string bundleId) { // Do we have a partial download? createDataPathIfNecessary(bundleId); if (!File.Exists(getZipPath(bundleId))) { logger.Log(bundleId); string downloadToken = ""; // Get a download token. { Dictionary <string, string> parameters = new Dictionary <string, string> (); try { parameters.Add("receipt", getReceipt(bundleId)); } catch (IOException) { onDownloadFailedPermanently(bundleId, string.Format("Bundle {0} no longer defined in inventory!", bundleId)); yield break; } parameters.Add("appId", appId); parameters.Add("bundleName", bundleId); parameters.Add("platform", platform.ToString()); parameters.Add("appSecret", appSecret); parameters.Add("version", getVersionToDownload(bundleId)); parameters.Add("unibillVersion", AnalyticsReporter.UNIBILL_VERSION); yield return(fetcher.doPost(DOWNLOAD_TOKEN_URL, parameters)); var response = fetcher.getResponse(); if (!string.IsNullOrEmpty(response.error)) { logger.Log("Error downloading content: {0}. Unibill will retry later.", response.error); yield return(getRandomSleep()); yield break; } var downloadTokenHash = (Dictionary <string, object>)MiniJSON.jsonDecode(response.contentString); if (null == downloadTokenHash) { logger.Log("Error fetching download token. Unibill will retry later."); yield return(getRandomSleep()); yield break; } bool success = bool.Parse(downloadTokenHash ["success"].ToString()); if (!success) { logger.LogError("Error downloading bundle {0}. Download abandoned.", bundleId); var errorString = ""; if (downloadTokenHash.ContainsKey("error")) { errorString = downloadTokenHash ["error"].ToString(); logger.LogError(errorString); } onDownloadFailedPermanently(bundleId, errorString); yield break; } if (!downloadTokenHash.ContainsKey("url")) { logger.LogError("Error fetching download token. Missing URL. Will retry"); yield return(getRandomSleep()); yield break; } downloadToken = downloadTokenHash ["url"].ToString(); // Persist this version token for resumed downloads. if (!downloadTokenHash.ContainsKey("version")) { logger.LogError("Error fetching download token. Missing version. Will retry"); yield return(getRandomSleep()); yield break; } var version = downloadTokenHash ["version"].ToString(); saveVersion(bundleId, version); } // Figure out the content length. // We can't do a HEAD because of Unity's wonderful // WWW class, so we do a 2 byte range GET and look at the headers. Dictionary <string, string> headers = new Dictionary <string, string> (); // These headers are required since on iOS // Unity wrongly adds if-modified headers that cause google to (rightly) // return content not modified. headers ["If-Modified-Since"] = "Tue, 1 Jan 1980 00:00:00 GMT"; headers ["If-None-Match"] = "notanetag"; long contentLength; { headers ["Range"] = "bytes=0-1"; yield return(fetcher.doGet(downloadToken, headers)); IHTTPRequest response = fetcher.getResponse(); if (isContentNotFound(response)) { string error = string.Format("404 - Downloadable Content missing for bundle {0}!", bundleId); logger.LogError(error); onDownloadFailedPermanently(bundleId, error); yield break; } if (!response.responseHeaders.ContainsKey("CONTENT-RANGE")) { logger.LogError("Malformed server response. Missing content-range"); logger.LogError(response.error); yield return(getRandomSleep()); yield break; } string contentRange = response.responseHeaders ["CONTENT-RANGE"].ToString(); contentLength = long.Parse(contentRange.Split(new char[] { '/' }, 2) [1]); } #if !UNITY_METRO //// Fetch the content. { using (fileStream = openDownload(bundleId)) { long rangeStart = fileStream.Length; if (rangeStart > 0) { fileStream.Seek(0, SeekOrigin.End); } long rangeEnd = Math.Min(rangeStart + bufferSize, contentLength); int lastProgress = -1; while (rangeStart < rangeEnd) { string header = string.Format("bytes={0}-{1}", rangeStart, rangeEnd); headers ["Range"] = header; yield return(fetcher.doGet(downloadToken, headers)); var response = fetcher.getResponse(); if (!string.IsNullOrEmpty(response.error)) { logger.LogError("Error downloading content. Will retry."); logger.LogError(response.error); yield return(getRandomSleep()); yield break; } int progress = (int)(((float)rangeEnd / (float)contentLength) * 100.0f); progress = Math.Min(99, progress); if (null != onDownloadProgressedEvent && lastProgress != progress) { onDownloadProgressedEvent(bundleId, progress); lastProgress = progress; } // This should never happen, but avoids crashing our coroutine. if (response.bytes.Length > BUFFER.Length) { logger.LogError("Malformed content. Unexpected length. Will retry."); yield return(getRandomSleep()); yield break; } // Copy the data into our writer thread's buffer. // Writing the data to disk on the main thread takes too long. Buffer.BlockCopy(response.bytes, 0, BUFFER, 0, response.bytes.Length); bytesReceived = response.bytes.Length; DATA_FLUSHED = false; // Notify our writer and wait for it to complete. DATA_READY.Set(); while (!DATA_FLUSHED) { yield return(waiter); } // Advance our range. rangeStart = rangeEnd + 1; rangeEnd = rangeStart + bufferSize; rangeEnd = Math.Min(rangeEnd, contentLength); } } } #endif File.Move(getPartialPath(bundleId), getZipPath(bundleId)); File.Delete(getVersionPath(bundleId)); } UNPACK_FINISHED = false; util.RunOnThreadPool(() => { Unpack(bundleId); }); while (!UNPACK_FINISHED) { yield return(waiter); } removeDownloadFromQueues(bundleId); if (null != onDownloadCompletedEvent) { onDownloadCompletedEvent(bundleId, getContentPath(bundleId)); } }
public static List <object> arrayListFromJson(this string json) { return(MiniJSON.jsonDecode(json) as List <object>); }
public static Dictionary <string, object> hashtableFromJson(this string json) { return(MiniJSON.jsonDecode(json) as Dictionary <string, object>); }
public static string toJson(this Dictionary <string, string> obj) { return(MiniJSON.jsonEncode(obj)); }