Example #1
0
 // 打开指定的清单文件 (带校验)
 public static bool OpenManifestFile(string filePath, string checksum, out Manifest manifest)
 {
     if (File.Exists(filePath))
     {
         using (var fs = File.OpenRead(filePath))
         {
             var crc = new Crc16();
             crc.Update(fs);
             if (crc.hex == checksum)
             {
                 fs.Seek(0, SeekOrigin.Begin);
                 var bytes = new byte[fs.Position];
                 var read  = fs.Read(bytes, 0, bytes.Length);
                 if (read == bytes.Length)
                 {
                     var json = Encoding.UTF8.GetString(bytes);
                     manifest = JsonUtility.FromJson <Manifest>(json);
                     return(manifest != null);
                 }
             }
         }
     }
     manifest = null;
     return(false);
 }
Example #2
0
        private void _HttpDownload(string url, int partialSize, byte[] buffer, Utils.Crc16 crc, Stream targetStream, int timeout)
        {
            PrintDebug($"downloading from {url}");
            var uri = new Uri(url);
            var req = WebRequest.CreateHttp(uri);

            req.Method           = WebRequestMethods.Http.Get;
            req.ContentType      = BundleContentType;
            req.ReadWriteTimeout = 10000;
            if (timeout > 0)
            {
                req.Timeout = timeout * 1000;
            }
            if (partialSize > 0)
            {
                req.AddRange(partialSize);
            }
            using (var rsp = req.GetResponse())
            {
                using (var webStream = rsp.GetResponseStream())
                {
                    var recvAll = 0L;
                    while (recvAll < rsp.ContentLength)
                    {
                        var recv = webStream.Read(buffer, 0, buffer.Length);
                        if (recv > 0 && _running)
                        {
                            recvAll += recv;
                            targetStream.Write(buffer, 0, recv);
                            crc.Update(buffer, 0, recv);
                            _progress = Mathf.Clamp01((float)(recvAll + partialSize) / _size);
                            if (_slow > 0)
                            {
                                Thread.Sleep(_slow); // 模拟低速下载
                            }
                            // PrintDebug($"{recvAll + partialSize}, {_size}, {_progress}");
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            // PrintDebug($"download exited");
        }
Example #3
0
        // 打开指定的清单文件 (带校验)
        public static Manifest ParseManifestFile(string filePath, FileEntry fileEntry, string password)
        {
            if (File.Exists(filePath))
            {
                using (var fs = File.OpenRead(filePath))
                {
                    var crc = new Crc16();
                    crc.Update(fs);
                    if (crc.hex == fileEntry.checksum && fs.Length == fileEntry.size)
                    {
                        fs.Seek(0, SeekOrigin.Begin);
                        return(ParseManifestStream(fs, fileEntry, password));
                    }
                }
            }

            return(null);
        }
Example #4
0
        private void DownloadExec(object state)
        {
            var        buffer     = new byte[BufferSize];
            var        tempPath   = _finalPath + PartExt;
            var        metaPath   = _finalPath + Metadata.Ext;
            var        retry      = 0;
            FileStream fileStream = null;

            while (true)
            {
                string error       = null;
                var    crc         = new Utils.Crc16();
                var    partialSize = 0;
                var    success     = true;
                if (fileStream == null)
                {
                    try
                    {
                        if (File.Exists(tempPath)) // 处理续传
                        {
                            var fileInfo = new FileInfo(tempPath);
                            fileStream  = fileInfo.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
                            partialSize = (int)fileInfo.Length;
                            if (partialSize > _size) // 目标文件超过期望大小, 直接废弃
                            {
                                fileStream.SetLength(0);
                                partialSize = 0;
                            }
                            else if (partialSize <= _size) // 续传
                            {
                                crc.Update(fileStream);
                                PrintDebug($"partial check {partialSize} && {_size} ({crc.hex})");
                            }
                        }
                        else // 创建下载文件
                        {
                            fileStream = File.Open(tempPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                            fileStream.SetLength(0);
                        }
                    }
                    catch (Exception exception)
                    {
                        // PrintError($"file exception: {exception}");
                        error   = $"file exception: {exception}";
                        success = false;
                    }
                }
                else
                {
                    fileStream.SetLength(0L);
                }

                if (success && (_size <= 0 || partialSize < _size))
                {
                    try
                    {
                        _HttpDownload(this.url, partialSize, buffer, crc, fileStream, _timeout);
                    }
                    catch (Exception exception)
                    {
                        // PrintError($"network exception: {exception}");
                        error   = $"network exception: {exception}";
                        success = false;
                    }
                }

                if (success && fileStream.Length != _size)
                {
                    if (_size > 0)
                    {
                        // PrintError($"filesize exception: {fileStream.Length} != {_size}");
                        error   = $"wrong file size: {fileStream.Length} != {_size}";
                        success = false;
                    }
                    else
                    {
                        _size = (int)fileStream.Length;
                    }
                }
                else if (success && crc.hex != _checksum)
                {
                    if (_checksum != null)
                    {
                        // PrintError($"checksum exception: {crc.hex} != {_checksum}");
                        error   = $"corrupted file: {crc.hex} != {_checksum}";
                        success = false;
                    }
                    else
                    {
                        _checksum = crc.hex;
                    }
                }

                lock (this)
                {
                    if (_isDone || _destroy)
                    {
                        success = false;
                    }
                }

                if (success)
                {
                    try
                    {
                        // _WriteStream(buffer, fileStream, finalPath);
                        fileStream.Close();
                        fileStream = null;
                        if (File.Exists(_finalPath))
                        {
                            File.Delete(_finalPath);
                        }
                        File.Move(tempPath, _finalPath);
                        _WriteMetadata(metaPath);
                        Complete(null);
                        // PrintDebug("download succeeded");
                        break;
                    }
                    catch (Exception exception)
                    {
                        // PrintError($"write exception: {exception}");
                        error   = $"write exception: {exception}";
                        success = false;
                    }
                }

                if (!Retry(++retry))
                {
                    if (fileStream != null)
                    {
                        fileStream.Close();
                        fileStream = null;
                    }
                    Complete(error ?? "unknown error");
                    PrintError($"[stop] download failed ({error})");
                    break;
                }
                Thread.Sleep(1000);
                PrintError($"[retry] ({_destroy}) download failed ({error})");
            }
            PrintDebug("download task thread exited");
        }
Example #5
0
        private void ProcessJob(JobInfo jobInfo)
        {
            Debug.LogFormat("processing job: {0} ({1})", jobInfo.name, jobInfo.comment);
            var tempPath = jobInfo.path + PartExt;

            if (_fileStream != null)
            {
                _fileStream.Close();
                _fileStream = null;
            }

            while (true)
            {
                string error       = null;
                var    partialSize = 0;
                var    success     = true;
                var    wsize       = jobInfo.size;
                var    wchecksum   = jobInfo.checksum;
                _crc.Clear();
                if (_fileStream == null)
                {
                    try
                    {
                        var fileInfo = new FileInfo(tempPath);
                        if (fileInfo.Exists) // 处理续传
                        {
                            _fileStream = fileInfo.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite);
                            partialSize = (int)fileInfo.Length;
                            if (partialSize > jobInfo.size) // 目标文件超过期望大小, 直接废弃
                            {
                                _fileStream.SetLength(0);
                                partialSize = 0;
                            }
                            else if (partialSize <= jobInfo.size) // 续传
                            {
                                _crc.Update(_fileStream);
                                Debug.LogFormat("partial check {0} && {1} ({2})", partialSize, jobInfo.size,
                                                _crc.hex);
                            }
                        }
                        else // 创建下载文件
                        {
                            if (!Directory.Exists(fileInfo.DirectoryName))
                            {
                                Directory.CreateDirectory(fileInfo.DirectoryName);
                            }

                            _fileStream = File.Open(tempPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                            _fileStream.SetLength(0);
                        }
                    }
                    catch (Exception exception)
                    {
                        Debug.LogErrorFormat("file exception: {0}\n{1}", jobInfo.path, exception);
                        error   = $"file exception: {exception}";
                        success = false;
                    }
                }
                else
                {
                    _fileStream.SetLength(0L);
                }

                if (success && (jobInfo.size <= 0 || partialSize < jobInfo.size))
                {
                    var url = GetUrl(jobInfo);
                    try
                    {
                        var uri = new Uri(url);
                        var req = WebRequest.CreateHttp(uri);
                        req.Method           = WebRequestMethods.Http.Get;
                        req.ContentType      = BundleContentType;
                        req.ReadWriteTimeout = 10000;
                        if (_timeout > 0)
                        {
                            req.Timeout = _timeout;
                        }

                        if (partialSize > 0)
                        {
                            req.AddRange(partialSize);
                        }

                        using (var rsp = req.GetResponse())
                        {
                            using (var webStream = rsp.GetResponseStream())
                            {
                                var recvAll   = 0L;
                                var recvCalc  = 0L;
                                var stopwatch = new Stopwatch();
                                stopwatch.Start();
                                while (recvAll < rsp.ContentLength)
                                {
                                    var _bpms = Math.Max(1, jobInfo.bytesPerSecond / 10);
                                    var recv  = webStream.Read(_buffer, 0, Math.Min(_bpms, _buffer.Length));
                                    if (recv > 0 && !_destroy)
                                    {
                                        recvCalc += recv;
                                        if (recvCalc >= _bpms)
                                        {
                                            var millisecs = stopwatch.ElapsedMilliseconds;
                                            var delay     = (int)(100.0 * recvCalc / _bpms - millisecs);
                                            // Debug.LogFormat("net ++ {0} {1} sbps {2} recv {3}", delay, millisecs, _bpms, recvCalc);
                                            if (delay > 0)
                                            {
                                                Thread.Sleep(delay);
                                            }
                                            stopwatch.Restart();
                                            recvCalc -= _bpms;
                                        }
                                        recvAll += recv;
                                        _fileStream.Write(_buffer, 0, recv);
                                        _crc.Update(_buffer, 0, recv);
                                        jobInfo.bytes = (int)(recvAll + partialSize);
                                        // PrintDebug($"{recvAll + partialSize}, {_size}, {_progress}");
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        Debug.LogErrorFormat("network exception: {0}\n{1}", url, exception);
                        error   = $"network exception: {exception}";
                        success = false;
                    }
                }

                if (success && _fileStream.Length != jobInfo.size)
                {
                    if (jobInfo.size > 0)
                    {
                        error = string.Format("filesize exception: {0} {1} != {2}", jobInfo.name,
                                              _fileStream.Length, jobInfo.size);
                        Debug.LogError(error);
                        success = false;
                    }
                    else
                    {
                        wsize = (int)_fileStream.Length;
                    }
                }

                if (success && _crc.hex != jobInfo.checksum)
                {
                    if (!string.IsNullOrEmpty(jobInfo.checksum))
                    {
                        error = string.Format("corrupted file: {0} {1} != {2}", jobInfo.name, _crc.hex,
                                              jobInfo.checksum);
                        Debug.LogError(error);
                        success = false;
                    }
                    else
                    {
                        wchecksum = _crc.hex;
                    }
                }

                if (_destroy)
                {
                    success = false;
                }

                if (success)
                {
                    try
                    {
                        // _WriteStream(buffer, fileStream, finalPath);
                        _fileStream.Close();
                        _fileStream = null;
                        if (File.Exists(jobInfo.path))
                        {
                            File.Delete(jobInfo.path);
                        }

                        File.Move(tempPath, jobInfo.path);
                        // 写入额外的 meta
                        var meta = new Metadata()
                        {
                            checksum = wchecksum,
                            size     = wsize,
                        };
                        var json     = JsonUtility.ToJson(meta);
                        var metaPath = jobInfo.path + Metadata.Ext;
                        File.WriteAllText(metaPath, json);
                        Complete(jobInfo);
                        break;
                    }
                    catch (Exception exception)
                    {
                        error = string.Format("write exception: {0}\n{1}", jobInfo.name, exception);
                        Debug.LogError(error);
                        success = false;
                    }
                }

                jobInfo.tried++;
                if (jobInfo.retry > 0 && jobInfo.tried >= jobInfo.retry)
                {
                    if (_fileStream != null)
                    {
                        _fileStream.Close();
                        _fileStream = null;
                    }

                    jobInfo.error = error ?? "unknown error";
                    Complete(jobInfo);
                    break;
                }

                Thread.Sleep(2000);
                Debug.LogErrorFormat("[retry] download failed: {0}\n{1}", jobInfo.name, error);
            }
        }