/// <summary> /// Downloads given file asynchronously. /// </summary> private async Task DownloadFile(HandledFile hf) { if (c.SubElText("Main", "FileProcessingOutputs") == "1") { o.Output(c.SubElText("Messages", "DownloadingFrom") + hf.fullServerPath, true); o.Output(c.SubElText("Messages", "DownloadingTo") + hf.fullLocalPath); } try { using (var client = new AmWebClient(3000)) { if (!Directory.Exists(cwd + hf.localPath)) { Directory.CreateDirectory(cwd + hf.localPath); } if (File.Exists(hf.fullLocalPath) && File.Exists(hf.fullLocalPath + "_") && c.SubElText("Main", "KeepBackups") == "1") { File.Delete(hf.fullLocalPath + "_"); } if (File.Exists(hf.fullLocalPath)) { File.Move(hf.fullLocalPath, hf.fullLocalPath + "_"); } await client.DownloadFileTaskAsync(hf.fullServerPath, hf.fullLocalPath); if (IsFileOK(hf)) { UnZip(hf.fullLocalPath); filesDownloaded++; } } } catch (WebException e) { o.Output(c.SubElText("Messages", "DownloadError") + hf.name, e); } }
/// <summary> /// Checks if given file was completely downloaded. /// </summary> private bool IsFileOK(HandledFile hf) { if (File.Exists(hf.fullLocalPath)) { return(new FileInfo(hf.fullLocalPath).Length == hf.size); } else { return(false); } }
/// <summary> /// Checks which optional files need to be downloaded, based on optional checkbox list. /// </summary> private void FinalizeDownloadList() { // If any optional group isn't checked, remove its elements from download list. foreach (OptionalGroup og in optionalGroups) { if (!og.isChecked) { foreach (HandledFile hf in og.files) { HandledFile matching = null; foreach (HandledFile file in toBeDownloaded) { if (file.serverPath == hf.serverPath) { matching = file; } } if (matching != null) { toBeDownloaded.Remove(matching); } // MPQ files which were downloaded as optional and are no longer wanted should be deleted as well. if (File.Exists(hf.fullLocalPath)) { if (hf.name.Contains('.')) { if (hf.name.Substring(hf.name.LastIndexOf('.')).ToLower() == ".mpq") { outdated.Add(hf.fullLocalPath); } } } } } } }
/// <summary> /// Gets size of given file from web and sets its value to it and checks if file actually exists and is reachable at the same time. /// </summary> /// /// <returns>Was size acquired?</returns> private bool SetFileSize(HandledFile hf) { HttpWebRequest req = (HttpWebRequest)WebRequest.Create(hf.fullServerPath); req.Method = "HEAD"; req.Timeout = 3000; try { using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse()) { long contentLength; if (long.TryParse(resp.Headers.Get("Content-Length"), out contentLength)) { hf.size = contentLength; } } } catch (WebException e) { o.Output(c.SubElText("Messages", "FileOnsWebMissing") + hf.fullServerPath, e); return(false); } return(true); }
/// <summary> /// Checks which files need to be downloaded. Ignores optional flag. /// Optional files which aren't chosen are being removed from download list in FinalizeDownloadList method. /// </summary> private void PreBuildDownloadList() { // Get all MPQs in Data directory. var MPQFiles = Directory.GetFiles(cwd + @"\data\", "*.mpq", SearchOption.TopDirectoryOnly); // Check all MPQs in Data directory. foreach (string mpqFile in MPQFiles) { // Ignore blizzlike MPQs. Note that if KeepBlizzlikeMPQs in config is 0, blizzlikeMPQs list is empty and thus no files are ignored. if (!blizzlikeMPQs.Contains(mpqFile.ToLower())) { HandledFile onServer = null; // Find server side file which matches this file. foreach (HandledFile hf in serverSideFiles) { if (hf.fullLocalPath.ToLower() == mpqFile.ToLower()) { onServer = hf; } } // If no matching server side file is found, this file should be deleted, its outdated or from different project. if (onServer == null) { outdated.Add(mpqFile); } // If matching file on server side was found, but its size is different, new version will be downloaded. else if (onServer.size != new FileInfo(mpqFile).Length) { toBeDownloaded.Add(onServer); } } } // Check files on server side. If they are missing or outdated in local files, add them into download list. foreach (HandledFile hf in serverSideFiles) { if (File.Exists(hf.fullLocalPath)) { if (new FileInfo(hf.fullLocalPath).Length != hf.size) { toBeDownloaded.Add(hf); } } else { toBeDownloaded.Add(hf); } // If a directory with zip's name doesn't exist, download a zip file as well. if (hf.name.Contains('.')) { if (hf.name.Substring(hf.name.LastIndexOf('.')).ToLower() == ".zip") { if (!Directory.Exists(hf.fullLocalPath.Substring(0, hf.fullLocalPath.LastIndexOf('.')))) { toBeDownloaded.Add(hf); } } } } // Get total size of outdated non-optional content. long totalSize = 0; foreach (HandledFile hf in toBeDownloaded) { if (!hf.optional) { totalSize += hf.size; } } nonOptionalOutdatedSize = Size(totalSize); }
/// <summary> /// Attempts to build List of server-side files based on patchlist. /// </summary> /// <returns>Was build succesful?</returns> private bool BuildFilelist() { // Attempt to download filelist's content. string filelistString = null; try { filelistString = (new AmWebClient(3000)).DownloadString(c.SubElText("Paths", "FilelistPath")); } catch (WebException e) { o.Messagebox(c.SubElText("Messages", "FilelistOpeningFailed"), e); return(false); } // Attempt to read filelist's content (without comments, only first comments on rows with filelist entries are being kept for getting optional group names). List <string> filelistContent = new List <string>(); List <string> comments = new List <string>(); if (filelistString != null) { // Read only lines which have at least 6 characters. Save first found comments of each correct line as well. foreach (string s in filelistString.Split('\n')) { string firstComment = ""; if (s.Split('#').Length > 1) { firstComment = s.Split('#')[1].Trim(); } string tmp = Regex.Replace(s, @"\s+", ""); if (tmp.Split('#')[0].Length >= 6) { filelistContent.Add(tmp.Split('#')[0]); comments.Add(firstComment); } } // Verify that filelist is correct and readable, and save its data as objects. Otherwise end for safety reasons. int index = 0; foreach (string s in filelistContent) { bool isCorrect = true; var arr = s.Split(';'); if (arr.Length == 4 && // Name;Optional?;LocalPath;LinkedList - 4 pieces of information. arr[0].Length > 0 && // Name can't be empty. (arr[1] == "0" || arr[1] == "1") && // Optional? must be either 0 or 1. arr[2].Length > 0) // LocalPath must always be at least '/'. { foreach (string a in arr[3].Split(',')) // No element in LinkedList should be empty. { if (a.Length == 0) { isCorrect = false; } } } if (arr[3].Length == 0) // However, if whole LinkedList is empty, its OK. { isCorrect = true; } if (!isCorrect) { o.Output(c.SubElText("Messages", "FilelistReadingFailed")); return(false); } else { string serverPath; if (arr[0][0] == '/') { serverPath = arr[0].Substring(1); } else { serverPath = arr[0]; } string localPath = ""; if (arr[2][0] != '/') { localPath += '/'; } localPath += arr[2]; if (localPath[localPath.Length - 1] != '/') { localPath += '/'; } serverSideFiles.Add(new HandledFile(serverPath, 0, arr[1], localPath, arr[3], comments[index])); } index++; } // Build lists of linked files for every file on server. List <HandledFile> linked = new List <HandledFile>(); foreach (HandledFile hf in serverSideFiles) { if (hf.linked != "") { foreach (string s in hf.linked.Split(',')) { var namePathArr = s.Split('|'); string localPath = ""; // Use specified LocalPath behind | character. If its not set or empty, use LocalPath of file its linked from. if (namePathArr.Length == 2) { if (namePathArr[1] != "") { if (namePathArr[1][0] != '/') { localPath += '/'; } localPath += namePathArr[1]; } else { localPath = hf.localPath; } } else { localPath = hf.localPath; } string serverPath; if (namePathArr[0][0] == '/') { serverPath = namePathArr[0].Substring(1); } else { serverPath = namePathArr[0]; } HandledFile linkedFile = new HandledFile(serverPath, 0, "1", localPath, "", ""); linkedFile.optional = hf.optional; // LinkedLists should still be used ONLY for optional files though. linked.Add(linkedFile); hf.linkedList.Add(linkedFile); } } } // Add all files which are linked in LinkedLists to server side file list as well. // If any of linked files is already in server side file list, remove its previous version. LinkedList is preffered over filelist. foreach (HandledFile link in linked) { HandledFile alreadyThere = null; foreach (HandledFile hf in serverSideFiles) { if (hf.serverPath == link.serverPath) { alreadyThere = hf; } } if (alreadyThere != null) { serverSideFiles.Remove(alreadyThere); } serverSideFiles.Add(link); } // Check if all files in filelist exist and get their sizes. bool filesOK = true; foreach (HandledFile hf in serverSideFiles) { if (!SetFileSize(hf)) { filesOK = false; } } if (!filesOK) { return(false); } } return(true); }
/// <summary> /// Adds a file into optional group. /// </summary> public void Add(HandledFile file) { files.Add(file); }