Esempio n. 1
0
        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));
            }
        }
Esempio n. 2
0
 public static List <object> arrayListFromJson(this string json)
 {
     return(MiniJSON.jsonDecode(json) as List <object>);
 }
Esempio n. 3
0
 public static Dictionary <string, object> hashtableFromJson(this string json)
 {
     return(MiniJSON.jsonDecode(json) as Dictionary <string, object>);
 }
Esempio n. 4
0
 public static string toJson(this Dictionary <string, string> obj)
 {
     return(MiniJSON.jsonEncode(obj));
 }