public async Task <bool> ExecuteAsync(int projectId, string user) { var project = await _factory .CreateAsyncQueryable(_uow.Projects.Query(p => p.Lock)) .FirstOrDefaultAsync(p => p.Id == projectId); if (project == null) { return(false); } if (project.Lock != null) { throw new ProjectLockedException(); } var projectLock = new ProjectLock { ProjectId = projectId, Username = user, LockDate = DateTime.Now }; _uow.ProjectLock.Add(projectLock); await _uow.CommitAsync(); return(true); }
public async Task <bool> ExecuteAsync(int projectId, int userId) { var project = await Context.Projects.Include(p => p.Lock).SingleOrDefaultAsync(p => p.Id == projectId); if (project == null) { return(false); } if (project.Lock != null) { throw new ProjectLockedException(); } var projectLock = new ProjectLock { ProjectId = projectId, UserId = userId, LockDateTime = DateTime.UtcNow }; Context.ProjectLocks.Add(projectLock); await Context.SaveChangesAsync(); return(true); }
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); }
public static void Push(HttpListenerRequest request, HttpListenerResponse response) { var projectName = ""; try { using (var reader = new BinaryReader(request.InputStream)) { using (var writer = new BinaryWriter(response.OutputStream)) { try { var authority = ProjectAuthority.FromJson(Encoding.UTF8.GetString( reader.ReadBytes(reader.ReadInt32()) )); projectName = authority.ProjectName; // validate project name, password and check permisions from clientData if (!Authorization.HasAuthority(authority.AccessToken, projectName)) { writer.Write("Failed - project not found!"); return; } // request project lock if (ProjectLock.TryLock(projectName, ProjectLock.LockMode.Upload) != ProjectLock.LockMode.None) { writer.Write("Failed - project is locked!"); return; } // read commit var commitData = reader.ReadBytes(reader.ReadInt32()); var commit = Commit.FromJson(Encoding.UTF8.GetString(commitData)); var hasFile = reader.ReadBoolean(); if (hasFile) { Console.WriteLine("Receiving file..."); try { // read data file using (var fs = File.Create("temp_recv.zip")) { try { int read; var buffer = new byte[64 * 1024]; while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) { fs.Write(buffer, 0, read); } } catch { // user lost connection or closed the client // before the whole data file arrived Console.WriteLine("User '" + authority.Username + "' canceled commit upload."); ProjectLock.Unlock(projectName); return; } } } catch { // user lost connection or closed the client // before the whole data file arrived Console.WriteLine("User '" + authority.Username + "' commit upload failed."); ProjectLock.Unlock(projectName); return; } } // --- from now - this part CAN'T fail, if so, the whole project may be incorrect after this! var projectDir = "data/" + projectName; // make commited files backup commit.Backup(projectDir); int commitId; try { // downloaded // now apply changes commit.Apply(projectDir, "temp_recv.zip", hasFile); // add commit to projects database var projectCollection = ServerCore.Database.GetCollection <CommitModel>(projectName); commitId = (int)projectCollection.Count(FilterDefinition <CommitModel> .Empty) + 1; // build commit var commitModel = new CommitModel { CommitId = commitId, CommitDescription = commit.Description, Files = new CommitModel.FileDiff[commit.Files.Length] }; for (var i = 0; i < commit.Files.Length; i++) { var file = commit.Files[i]; commitModel.Files[i] = new CommitModel.FileDiff { Name = file.FileName, Version = file.Version, Operation = (int)file.DiffType }; } // insert projectCollection.InsertOne(commitModel); // delete zip file if exists if (hasFile) { File.Delete("temp_recv.zip"); } } catch (Exception ex) { Console.WriteLine("Failed to apply commit from user '" + authority.Username + "'"); writer.Write("#RESTORE Failed - error when updating project! Error: " + ex); // restore backup commit.RestoreBackup(projectDir); // UNLOCK ProjectLock.Unlock(projectName); return; } // ok, we are out of the danger zone. // return message writer.Write("Done!"); writer.Write(commitId); // clean backups commit.CleanBackups(projectDir); Console.WriteLine("User '" + authority.Username + "' pushed changes!"); } catch (Exception ex) { writer.Write("Failed - invalid protocol/connection error! Error: " + ex); Console.WriteLine("PUSH failed"); ProjectLock.Unlock(projectName); } } } } catch { // this shouldn't be possible, // but anyway handle exceptions here Console.WriteLine("PUSH failed"); ProjectLock.Unlock(projectName); } Console.WriteLine("Push done"); ProjectLock.Unlock(projectName); }
public static void Pull(string body, HttpListenerResponse response) { var projectName = ""; using (var writer = new BinaryWriter(response.OutputStream)) { try { var input = JsonConvert.DeserializeObject <PullInput>(body); projectName = input.Authority.ProjectName; if (!Authorization.HasAuthority(input.Authority.AccessToken, projectName)) { writer.Write(false); writer.Write("Failed - project not found!"); return; } // request project lock if (ProjectLock.TryLock(projectName, ProjectLock.LockMode.Upload) == ProjectLock.LockMode.Any) { writer.Write(false); writer.Write("Failed - project is locked!"); return; } // find latest downloaded client-commit var commitId = input.CommitId + 1; // the first commit id which will be downloaded if exists var projectCollection = ServerCore.Database.GetCollection <CommitModel>(projectName); // find all needed commits that will be used to calculate diff var commits = projectCollection.Find(x => x.CommitId >= commitId).ToList(); // check if there is at least one commit, if not, break the pull request if (!commits.Any()) { writer.Write(false); writer.Write("No files to download."); // UNLOCK ProjectLock.Unlock(projectName); return; } writer.Write(true); // diff all commits var commit = commits[0].ToCommit(); foreach (var t in commits) { commit.Add(t.ToCommit()); } var fileNeeded = commit.IsUploadNeeded(); // build commit diff data file var dir = "data/" + projectName + "/"; var tempDataFile = "temp_send_" + input.Authority.Username + ".zip"; if (fileNeeded) // build commit zip if needed { var lastSend = DateTime.Now; commit.Build(dir, tempDataFile, delegate(int progress) { if ((DateTime.Now - lastSend).TotalSeconds >= 1.0f) { writer.Write(false); writer.Write(progress); } }); } writer.Write(true); // send commit diff var commitJson = commit.ToJson(); writer.Write(commitJson); // send commit id writer.Write(commits[commits.Count - 1].CommitId); // write file upload indicator writer.Write(fileNeeded); if (fileNeeded) { // send commit diff data file using (var file = new FileStream(tempDataFile, FileMode.Open)) { // write file size writer.Write(file.Length); int read; var buffer = new byte[64 * 1024]; try { while ((read = file.Read(buffer, 0, buffer.Length)) > 0) { response.OutputStream.Write(buffer, 0, read); } } catch { // 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); return; } } File.Delete(tempDataFile); } } catch (Exception ex) { writer.Write("Failed - invalid protocol/connection error! Error: " + ex); ProjectLock.Unlock(projectName); } } ProjectLock.Unlock(projectName); }