/// <summary> /// Discard selected files. /// </summary> /// <param name="files">Files selected for discard.</param> /// <param name="onProgress">This is called when there is some progress made.</param> public void Discard(Filemap.FileDiff[] files, Action <string> onProgress) { var dataJson = new PullInput { Authority = Authority }; var lastCommitId = -1; Request.Send(ServerAddress + "getcommit", dataJson.ToJson(), stream => { using (var reader = new BinaryReader(stream)) { var message = reader.ReadString(); if (message == "Done") { lastCommitId = reader.ReadInt32(); } else { throw new Exception("Cannot discard, Error: <br>" + message); } } }); // select current commit id var commitInfo = RootDir + ".mysync/commit_info.txt"; var currentCommitId = File.Exists(commitInfo) ? int.Parse(File.ReadAllText(commitInfo)) : -1; if (lastCommitId > currentCommitId) { throw new Exception("Cannot discard, project is not up-to-date!"); } // select all files that are not 'created' var filesToDownload = new List <Filemap.File>(); foreach (var file in files) { if (file.DiffType != Filemap.FileDiff.Type.Created) { filesToDownload.Add(new Filemap.File { FileName = file.FileName }); } } var input = new DiscardInput { Authority = Authority, Files = filesToDownload.ToArray() }; // remove new files var toDelete = 0; foreach (var file in files) { if (file.DiffType == Filemap.FileDiff.Type.Created) // delete all 'created' files { var fileName = RootDir + file.FileName; // delete file File.Delete(fileName); DirectoryHelper.DeleteIfEmpty(fileName); toDelete++; } } // check if there are files only for delete if (toDelete == files.Length) { return; } // download original files from server Request.Send(ServerAddress + "discard", input.ToJson(), stream => { using (var reader = new BinaryReader(stream)) { var commitJson = reader.ReadString(); while (true) { var state = reader.ReadBoolean(); if (state) { break; } var progress = reader.ReadInt32(); if (progress >= 0) { onProgress("Building commit..."); } } // download var dataFile = RootDir + ".mysync/commit_recv.zip"; // send commit diff data file using (var nfs = new NetFileStream(dataFile, onError: delegate { // throw error throw new Exception("Error when downloading commit data file"); })) { nfs.Download(stream, delegate(long bytes, long sentBytes) { // show progress var prc = (sentBytes / (float)bytes) * 100; onProgress?.Invoke(prc.ToString("f1") + "%"); }); } var commit = Commit.FromJson(commitJson); try { // downloaded // now apply changes commit.Apply(RootDir, dataFile, true); } catch (Exception ex) { throw new Exception("Error when applying commit data file"); } } }); }
public static void Discard(string body, HttpListenerResponse response) { var projectName = ""; using (var writer = new BinaryWriter(response.OutputStream)) { try { var input = DiscardInput.FromJson(body); projectName = input.Authority.ProjectName; if (!Authorization.HasAuthority(input.Authority.AccessToken, projectName)) { writer.Write("Failed - project not found!"); return; } // request project lock if (ProjectLock.TryLock(projectName, ProjectLock.LockMode.Upload) == ProjectLock.LockMode.Any) { writer.Write("Failed - project is locked!"); return; } var projectCollection = ServerCore.Database.GetCollection <CommitModel>(projectName); var commits = projectCollection.Find(x => x.CommitId >= 0).ToList().OrderBy(x => x.CommitId).ToArray(); // select files then pack them // and send to the client var diff = new List <Filemap.FileDiff>(); foreach (var file in input.Files) { // select commits which contains this file(which is not removed by the commit) then order by commit and select the first commit. var validCommit = commits.Where(x => x.Files.Any(n => n.Name == file.FileName && n.Operation != 2)).OrderByDescending(x => x.CommitId).FirstOrDefault(); if (validCommit != null) { // select the file var validFile = validCommit.Files.First(x => x.Name == file.FileName); diff.Add(new Filemap.FileDiff { FileName = validFile.Name, DiffType = Filemap.FileDiff.Type.Changed, Version = validFile.Version }); } else { Console.WriteLine("Commit not found for file " + file.FileName); } } // create commit var commit = Commit.FromDiff(diff.ToArray()); // write commit in json format var commitJson = commit.ToJson(); writer.Write(commitJson); // build commit diff data file var dir = "data/" + projectName + "/"; var tempDataFile = "temp_send_" + input.Authority.Username + ".zip"; commit.Build(dir, tempDataFile, delegate(int progress) { var lastSend = DateTime.Now; if ((DateTime.Now - lastSend).TotalSeconds >= 1.0f) { writer.Write(false); writer.Write(progress); } }); writer.Write(true); // send commit diff data file using (var nfs = new NetFileStream(tempDataFile, onError: delegate { // user lost connection or closed the client // before the whole data file is sent Console.WriteLine("User '" + input.Authority.Username + "' canceled commit download."); ProjectLock.Unlock(projectName); })) { nfs.Upload(response.OutputStream); } File.Delete(tempDataFile); } catch (Exception ex) { writer.Write("Failed - invalid protocol/connection error! Error: " + ex); Console.WriteLine(ex); ProjectLock.Unlock(projectName); } } ProjectLock.Unlock(projectName); }