/// <summary> /// Pull commits from server and apply. /// </summary> /// <param name="onProgress">This is called when there is some progress made.</param> public void Pull(Action <string> onProgress) { var commitInfo = RootDir + ".mysync/commit_info.txt"; // select current commit id var currentCommitId = File.Exists(commitInfo) ? int.Parse(File.ReadAllText(commitInfo)) : -1; // construct pull input data var dataJson = new PullInput { Authority = Authority, CommitId = currentCommitId }; // send pull request Request.Send(ServerAddress + "pull", dataJson.ToJson(), stream => { using (var reader = new BinaryReader(stream)) { if (!reader.ReadBoolean()) { // error! throw new WarningException(reader.ReadString()); } while (!reader.ReadBoolean()) { var progress = reader.ReadInt32(); if (progress >= 0) { onProgress(progress + "%"); } } var body = reader.ReadString(); Console.WriteLine(body); Commit commit; // try convert commit data try { commit = Commit.FromJson(body); } catch { throw new WarningException("There is no any changes to download."); } var commitId = reader.ReadInt32(); Console.WriteLine(@"commit id: " + commitId); var hasFile = reader.ReadBoolean(); var dataFile = RootDir + ".mysync/commit_recv.zip"; if (hasFile) { using (var fs = File.Create(dataFile)) { var totalbytes = reader.ReadInt64(); var readbytes = 0; int read; var buffer = new byte[64 * 1024]; while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) { fs.Write(buffer, 0, read); readbytes += read; var prc = (float)readbytes / totalbytes; prc *= 100.0f; if (prc >= 0) { onProgress(prc.ToString("f1") + "%"); } } } } // apply the commit commit.Apply(RootDir, dataFile, hasFile); // remove data file if (hasFile) { File.Delete(dataFile); } // update filemap _lastFilemap.AddChanges(RootDir, commit.Files); File.WriteAllText(RootDir + ".mysync/last_filemap.json", _lastFilemap.ToJson()); // save commit id File.WriteAllText(commitInfo, commitId.ToString()); // refresh Refresh(); } }); }
/// <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"); } } }); }
/// <summary> /// Push commit to the server. /// </summary> /// <param name="commit">The commit.</param> /// <param name="dataFile">The commit data file.</param> /// <param name="onProgress">This is called when there is some progress made.</param> public void Push(Commit commit, string dataFile, Action <string> onProgress) { // construct pull input data 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 push, 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 push, project is not up-to-date!"); } var clientData = Encoding.UTF8.GetBytes(Authority.ToJson()); var commitData = Encoding.UTF8.GetBytes(commit.ToJson()); var filemap = _lastFilemap; filemap.AddChanges(RootDir, commit.Files); var filemapJson = filemap.ToJson(); using (var file = new FileStream(dataFile, FileMode.Open)) { var fileNeeded = commit.IsUploadNeeded(); var datasize = (fileNeeded ? file.Length : 0) + clientData.Length + commitData.Length + 2 * sizeof(int) + sizeof(bool); // <--- // begin send var stream = Request.BeginSend(ServerAddress + "push", datasize); using (var writer = new BinaryWriter(stream)) { // write client data header writer.Write(clientData.Length); writer.Write(clientData); // write data header writer.Write(commitData.Length); writer.Write(commitData); writer.Write(fileNeeded); if (fileNeeded) { // upload commit data file var readbytes = 0; var totalbytes = (int)file.Length; int read; var buffer = new byte[64 * 1024]; while ((read = file.Read(buffer, 0, buffer.Length)) > 0) { writer.Write(buffer, 0, read); readbytes += read; var prc = (float)readbytes / totalbytes; prc *= 100.0f; onProgress(prc.ToString("f1") + "%"); } } Request.EndSend(resp => { // done! // read response data using (var reader = new BinaryReader(resp)) { var message = reader.ReadString(); // finalize everything if (message.StartsWith("#RESTORE")) { throw new Exception("Commit failed, error: " + message); } if (message.StartsWith("Failed")) { throw new Exception("Commit failed, error: " + message); } var commitId = reader.ReadInt32(); // save commit id File.WriteAllText(commitInfo, commitId.ToString()); // save filemap File.WriteAllText(RootDir + ".mysync/last_filemap.json", filemapJson); // refresh Refresh(); } }); } } // delete data file File.Delete(dataFile); // ok }