Beispiel #1
0
        public static FileDownloadInfo StartModBinaryDownload(Modfile modfile, string targetFilePath)
        {
            Debug.Assert(modfile.downloadLocator.dateExpires > ServerTimeStamp.Now);

            ModfileIdPair idPair = new ModfileIdPair()
            {
                modId     = modfile.modId,
                modfileId = modfile.id,
            };

            if (modfileDownloadMap.Keys.Contains(idPair))
            {
                Debug.LogWarning("[mod.io] Mod Binary for modfile is already downloading. TargetFilePath was not updated.");
            }
            else
            {
                modfileDownloadMap[idPair] = new FileDownloadInfo()
                {
                    target   = targetFilePath,
                    fileSize = modfile.fileSize,
                    request  = null,
                    isDone   = false,
                };

                DownloadClient.modfileProgressMarkers[idPair] = new DownloadProgressMarkerCollection(DownloadClient.DOWNLOAD_SPEED_MARKER_COUNT);

                DownloadModBinary_Internal(idPair, modfile.downloadLocator.binaryURL);
            }

            return(modfileDownloadMap[idPair]);
        }
Beispiel #2
0
        public static void UpdateDownloadSpeed(ModfileIdPair idPair)
        {
            FileDownloadInfo downloadInfo            = null;
            DownloadProgressMarkerCollection markers = null;

            if (DownloadClient.modfileDownloadMap.TryGetValue(idPair, out downloadInfo) &&
                DownloadClient.modfileProgressMarkers.TryGetValue(idPair, out markers) &&
                !downloadInfo.isDone)
            {
                Int64 bytesReceived = (downloadInfo.request == null ? 0
                                       : (Int64)downloadInfo.request.downloadedBytes);

                DownloadClient.AddDownloadProgressMarker(markers, bytesReceived);
                downloadInfo.bytesPerSecond = DownloadClient.CalculateAverageDownloadSpeed(markers);
            }
        }
Beispiel #3
0
        private static void DownloadModBinary_Internal(ModfileIdPair idPair, string downloadURL)
        {
            FileDownloadInfo downloadInfo = modfileDownloadMap[idPair];

            downloadInfo.request = UnityWebRequest.Get(downloadURL);

            string tempFilePath = downloadInfo.target + ".download";

            DataStorage.WriteFile(tempFilePath, new byte[0], (p, success) =>
            {
                if (success)
                {
                    downloadInfo.request.downloadHandler = new DownloadHandlerFile(tempFilePath);

                    #if PLATFORM_PS4
                    // NOTE(@jackson): This workaround addresses an issue in UnityWebRequests on the
                    //  PS4 whereby redirects fail in specific cases. Special thanks to @Eamon of
                    //  Spiderling Studios (http://spiderlinggames.co.uk/)
                    downloadInfo.request.redirectLimit = 0;
                    #endif

                    var operation = downloadInfo.request.SendWebRequest();

                    #if DEBUG
                    DebugUtilities.DebugDownload(operation, LocalUser.instance, tempFilePath);
                    #endif

                    operation.completed += (o) => DownloadClient.OnModBinaryRequestCompleted(idPair);

                    DownloadClient.StartMonitoringSpeed();

                    // notify download started
                    if (DownloadClient.modfileDownloadStarted != null)
                    {
                        DownloadClient.modfileDownloadStarted(idPair, downloadInfo);
                    }
                }
                else if (DownloadClient.modfileDownloadFailed != null)
                {
                    string warningInfo = ("Failed to create download file on disk."
                                          + "\nSource: " + downloadURL
                                          + "\nDestination: " + tempFilePath + "\n\n");

                    modfileDownloadFailed(idPair, WebRequestError.GenerateLocal(warningInfo));
                }
            });
        }
Beispiel #4
0
        private static System.Collections.IEnumerator SpeedMonitorCoroutine()
        {
            while (DownloadClient.modfileDownloadMap.Count > 0)
            {
                int downloadCount          = DownloadClient.modfileDownloadMap.Count;
                int monitoredDownloadCount = 0;
                FileDownloadInfo[] infos
                    = new FileDownloadInfo[downloadCount];
                DownloadProgressMarkerCollection[] markerCollections
                    = new DownloadProgressMarkerCollection[downloadCount];

                // collect downloads to update
                foreach (var kvp in DownloadClient.modfileDownloadMap)
                {
                    DownloadProgressMarkerCollection markers = null;

                    if (!kvp.Value.isDone &&
                        DownloadClient.modfileProgressMarkers.TryGetValue(kvp.Key, out markers))
                    {
                        infos[monitoredDownloadCount]             = kvp.Value;
                        markerCollections[monitoredDownloadCount] = markers;

                        ++monitoredDownloadCount;
                    }
                }

                // update progress
                for (int i = 0;
                     i < monitoredDownloadCount;
                     ++i)
                {
                    FileDownloadInfo downloadInfo            = infos[i];
                    DownloadProgressMarkerCollection markers = markerCollections[i];

                    Int64 bytesReceived = (downloadInfo.request == null ? 0
                                           : (Int64)downloadInfo.request.downloadedBytes);

                    DownloadClient.AddDownloadProgressMarker(markers, bytesReceived);
                    downloadInfo.bytesPerSecond = DownloadClient.CalculateAverageDownloadSpeed(markers);
                }

                yield return(new WaitForSecondsRealtime(DownloadClient.DOWNLOAD_SPEED_UPDATE_INTERVAL));
            }

            DownloadClient.monitorBehaviour.coroutine = null;
        }
Beispiel #5
0
        private static void FinalizeDownload(ModfileIdPair idPair, FileDownloadInfo downloadInfo)
        {
            downloadInfo.bytesPerSecond = 0;
            downloadInfo.isDone         = true;

            if (downloadInfo.error == null && DownloadClient.modfileDownloadSucceeded != null)
            {
                DownloadClient.modfileDownloadSucceeded(idPair, downloadInfo);
            }
            else if (downloadInfo.error != null && DownloadClient.modfileDownloadFailed != null)
            {
                DownloadClient.modfileDownloadFailed(idPair, downloadInfo.error);
            }

            modfileDownloadMap.Remove(idPair);
            DownloadClient.modfileProgressMarkers.Remove(idPair);
        }
Beispiel #6
0
        public static FileDownloadInfo StartModBinaryDownload(int modId, int modfileId,
                                                              string targetFilePath)
        {
            ModfileIdPair idPair = new ModfileIdPair()
            {
                modId     = modId,
                modfileId = modfileId,
            };

            if (modfileDownloadMap.Keys.Contains(idPair))
            {
                Debug.LogWarning("[mod.io] Mod Binary with matching ids already downloading. TargetFilePath was not updated.");
            }
            else
            {
                modfileDownloadMap[idPair] = new FileDownloadInfo()
                {
                    target   = targetFilePath,
                    fileSize = -1,
                    request  = null,
                    isDone   = false,
                };

                DownloadClient.modfileProgressMarkers[idPair] = new DownloadProgressMarkerCollection(DownloadClient.DOWNLOAD_SPEED_MARKER_COUNT);

                // - Acquire Download URL -
                APIClient.GetModfile(modId, modfileId,
                                     (mf) =>
                {
                    // NOTE(@jackson): May have been cancelled
                    FileDownloadInfo downloadInfo = GetActiveModBinaryDownload(modId, modfileId);
                    if (downloadInfo != null)
                    {
                        modfileDownloadMap[idPair].fileSize = mf.fileSize;
                        DownloadModBinary_Internal(idPair, mf.downloadLocator.binaryURL);
                    }
                },
                                     (e) => { if (modfileDownloadFailed != null)
                                              {
                                                  modfileDownloadFailed(idPair, e);
                                              }
                                     });
            }
            return(modfileDownloadMap[idPair]);
        }
Beispiel #7
0
        private static void CancelModfileDownload_Internal(ModfileIdPair idPair)
        {
            FileDownloadInfo downloadInfo = null;

            if (modfileDownloadMap.TryGetValue(idPair, out downloadInfo))
            {
                if (downloadInfo.request != null)
                {
                    downloadInfo.request.Abort();
                }
                else
                {
                    downloadInfo.wasAborted = true;
                    downloadInfo.isDone     = true;

                    modfileDownloadMap.Remove(idPair);
                }
            }
        }
Beispiel #8
0
        public static FileDownloadInfo StartModBinaryDownload(int modId, int modfileId,
                                                              string targetFilePath)
        {
            ModfileIdPair idPair = new ModfileIdPair()
            {
                modId     = modId,
                modfileId = modfileId,
            };

            if (modfileDownloadMap.Keys.Contains(idPair))
            {
                Debug.LogWarning("[mod.io] Mod Binary with matching ids already downloading. TargetFilePath was not updated.");
            }
            else
            {
                modfileDownloadMap[idPair] = new FileDownloadInfo()
                {
                    target   = targetFilePath,
                    fileSize = -1,
                    request  = null,
                    isDone   = false,
                };

                // - Acquire Download URL -
                APIClient.GetModfile(modId, modfileId,
                                     (mf) =>
                {
                    modfileDownloadMap[idPair].fileSize = mf.fileSize;
                    DownloadModBinary_Internal(idPair, mf.downloadLocator.binaryURL);
                },
                                     (e) => { if (modfileDownloadFailed != null)
                                              {
                                                  modfileDownloadFailed(idPair, e);
                                              }
                                     });
            }
            return(modfileDownloadMap[idPair]);
        }
Beispiel #9
0
        private static void OnModBinaryRequestCompleted(ModfileIdPair idPair)
        {
            FileDownloadInfo downloadInfo = DownloadClient.modfileDownloadMap[idPair];
            UnityWebRequest  request      = downloadInfo.request;

            downloadInfo.bytesPerSecond = 0;

            if (request.isNetworkError || request.isHttpError)
            {
                if (request.error.ToUpper() == "USER ABORTED" ||
                    request.error.ToUpper() == "REQUEST ABORTED")
                {
                    downloadInfo.wasAborted = true;

                    DownloadClient.FinalizeDownload(idPair, downloadInfo);
                }

                // NOTE(@jackson): This workaround addresses an issue in UnityWebRequests on the
                //  PS4 whereby redirects fail in specific cases. Special thanks to @Eamon of
                //  Spiderling Studios (http://spiderlinggames.co.uk/)
                #if UNITY_PS4 || MODIO_DEV
                else if (downloadInfo.error.webRequest.responseCode == 302) // Redirect limit exceeded
                {
                    string headerLocation = string.Empty;
                    if (downloadInfo.error.webRequest.GetResponseHeaders().TryGetValue("location", out headerLocation) &&
                        !request.url.Equals(headerLocation))
                    {
                        if (PluginSettings.REQUEST_LOGGING.logAllResponses)
                        {
                            Debug.LogFormat("[mod.io] Caught PS4 redirection error. Reattempting.\nURL: {0}", headerLocation);
                        }

                        downloadInfo.error  = null;
                        downloadInfo.isDone = false;
                        DownloadModBinary_Internal(idPair, headerLocation);
                        return;
                    }
                }
                #endif // UNITY_PS4

                else
                {
                    downloadInfo.error = WebRequestError.GenerateFromWebRequest(request);

                    DownloadClient.FinalizeDownload(idPair, downloadInfo);
                }
            }
            else
            {
                DataStorage.MoveFile(downloadInfo.target + ".download", downloadInfo.target,
                                     (src, dst, success) =>
                {
                    if (!success)
                    {
                        string errorMessage = ("Download succeeded but failed to rename from"
                                               + " temporary file name."
                                               + "\nTemporary file name: "
                                               + downloadInfo.target + ".download");

                        downloadInfo.error = WebRequestError.GenerateLocal(errorMessage);
                    }

                    DownloadClient.FinalizeDownload(idPair, downloadInfo);
                });
            }
        }
Beispiel #10
0
        private static void OnModBinaryRequestCompleted(ModfileIdPair idPair)
        {
            FileDownloadInfo downloadInfo = DownloadClient.modfileDownloadMap[idPair];
            UnityWebRequest  request      = downloadInfo.request;
            bool             succeeded    = false;

            downloadInfo.isDone         = true;
            downloadInfo.bytesPerSecond = 0;

            if (request.isNetworkError || request.isHttpError)
            {
                if (request.error.ToUpper() == "USER ABORTED" ||
                    request.error.ToUpper() == "REQUEST ABORTED")
                {
                    #if DEBUG
                    if (PluginSettings.data.logAllRequests)
                    {
                        Debug.Log("DOWNLOAD ABORTED"
                                  + "\nDownload aborted at: " + ServerTimeStamp.Now
                                  + "\nURL: " + request.url);
                    }
                    #endif

                    downloadInfo.wasAborted = true;
                }

                // NOTE(@jackson): This workaround addresses an issue in UnityWebRequests on the
                //  PS4 whereby redirects fail in specific cases. Special thanks to @Eamon of
                //  Spiderling Studios (http://spiderlinggames.co.uk/)
                #if UNITY_PS4
                else if (downloadInfo.error.responseCode == 302) // Redirect limit exceeded
                {
                    string headerLocation = string.Empty;
                    if (downloadInfo.error.responseHeaders.TryGetValue("location", out headerLocation) &&
                        !request.url.Equals(headerLocation))
                    {
                        if (PluginSettings.data.logAllRequests)
                        {
                            Debug.LogFormat("CAUGHT DOWNLOAD REDIRECTION\nURL: {0}", headerLocation);
                        }

                        downloadInfo.error  = null;
                        downloadInfo.isDone = false;
                        DownloadModBinary_Internal(idPair, headerLocation);
                        return;
                    }
                }
                #endif

                else
                {
                    downloadInfo.error = WebRequestError.GenerateFromWebRequest(request);

                    if (PluginSettings.data.logAllRequests)
                    {
                        WebRequestError.LogAsWarning(downloadInfo.error);
                    }

                    if (modfileDownloadFailed != null)
                    {
                        modfileDownloadFailed(idPair, downloadInfo.error);
                    }
                }
            }
            else
            {
                try
                {
                    if (File.Exists(downloadInfo.target))
                    {
                        File.Delete(downloadInfo.target);
                    }

                    File.Move(downloadInfo.target + ".download", downloadInfo.target);

                    succeeded = true;
                }
                catch (Exception e)
                {
                    string warningInfo = ("Failed to save mod binary."
                                          + "\nFile: " + downloadInfo.target + "\n\n");

                    Debug.LogWarning("[mod.io] " + warningInfo + Utility.GenerateExceptionDebugString(e));

                    downloadInfo.error = WebRequestError.GenerateLocal(warningInfo);

                    if (modfileDownloadFailed != null)
                    {
                        modfileDownloadFailed(idPair, downloadInfo.error);
                    }
                }
            }

            if (succeeded)
            {
                #if DEBUG
                if (PluginSettings.data.logAllRequests)
                {
                    var responseTimeStamp = ServerTimeStamp.Now;
                    Debug.Log("DOWNLOAD SUCEEDED"
                              + "\nDownload completed at: " + ServerTimeStamp.ToLocalDateTime(responseTimeStamp)
                              + "\nURL: " + request.url
                              + "\nFilePath: " + downloadInfo.target);
                }
                #endif

                if (modfileDownloadSucceeded != null)
                {
                    modfileDownloadSucceeded(idPair, downloadInfo);
                }
            }

            modfileDownloadMap.Remove(idPair);
            DownloadClient.modfileProgressMarkers.Remove(idPair);
        }
Beispiel #11
0
        private static void DownloadModBinary_Internal(ModfileIdPair idPair, string downloadURL)
        {
            FileDownloadInfo downloadInfo = modfileDownloadMap[idPair];

            downloadInfo.request = UnityWebRequest.Get(downloadURL);

            string tempFilePath = downloadInfo.target + ".download";

            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(tempFilePath));
                downloadInfo.request.downloadHandler = new DownloadHandlerFile(tempFilePath);

                #if PLATFORM_PS4
                // NOTE(@jackson): This workaround addresses an issue in UnityWebRequests on the
                //  PS4 whereby redirects fail in specific cases. Special thanks to @Eamon of
                //  Spiderling Studios (http://spiderlinggames.co.uk/)
                downloadInfo.request.redirectLimit = 0;
                #endif
            }
            catch (Exception e)
            {
                string warningInfo = ("Failed to create download file on disk."
                                      + "\nFile: " + tempFilePath + "\n\n");

                Debug.LogWarning("[mod.io] " + warningInfo + Utility.GenerateExceptionDebugString(e));

                if (modfileDownloadFailed != null)
                {
                    modfileDownloadFailed(idPair, WebRequestError.GenerateLocal(warningInfo));
                }

                return;
            }

            var operation = downloadInfo.request.SendWebRequest();

            #if DEBUG
            if (PluginSettings.data.logAllRequests)
            {
                string        requestHeaders = "";
                List <string> requestKeys    = new List <string>(APIClient.UNITY_REQUEST_HEADER_KEYS);
                requestKeys.AddRange(APIClient.MODIO_REQUEST_HEADER_KEYS);

                foreach (string headerKey in requestKeys)
                {
                    string headerValue = downloadInfo.request.GetRequestHeader(headerKey);
                    if (headerValue != null)
                    {
                        requestHeaders += "\n" + headerKey + ": " + headerValue;
                    }
                }

                int timeStamp = ServerTimeStamp.Now;
                Debug.Log("DOWNLOAD REQUEST SENT"
                          + "\nTimeStamp: [" + timeStamp.ToString() + "] "
                          + ServerTimeStamp.ToLocalDateTime(timeStamp).ToString()
                          + "\nURL: " + downloadInfo.request.url
                          + "\nHeaders: " + requestHeaders);
            }
            #endif

            operation.completed += (o) => DownloadClient.OnModBinaryRequestCompleted(idPair);

            DownloadClient.StartMonitoringSpeed();

            // notify download started
            if (DownloadClient.modfileDownloadStarted != null)
            {
                DownloadClient.modfileDownloadStarted(idPair, downloadInfo);
            }
        }