public static RepoLock Lock(AlephLogger logger, string pathLocalFolder) { var filename = Path.Combine(pathLocalFolder, ".lock"); var content = $"[[AlephNote::RepoLock::Lockfile]]\n" + $"{{\n" + $" ProcessID := {Process.GetCurrentProcess().Id}\n" + $" ProcessHandle := {Process.GetCurrentProcess().Handle.ToInt64()}\n" + $" StartTime := {Process.GetCurrentProcess().StartTime:u}\n" + $" FileName := {Path.GetFileName(Process.GetCurrentProcess().MainModule?.FileName)}\n" + $" FilePath := {Process.GetCurrentProcess().MainModule?.FileName}\n" + $" ModuleName := {Process.GetCurrentProcess().MainModule?.ModuleName}\n" + $" ProcessName := {Process.GetCurrentProcess().ProcessName}\n" + $"}}\n"; try { if (File.Exists(filename)) { try { var oldcontent = File.ReadAllText(filename); logger.Warn("RepoLock", "Old Lockfile found", $"File := {filename}\n\nContent:\n{oldcontent}"); } catch (Exception) { logger.Warn("RepoLock", "Old Lockfile found (but could not read)", $"File := {filename}"); } } logger.Debug("RepoLock", "Trying to acquire lock", $"File := {filename}\n\nContent:\n{content}"); var fs = File.Open(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read); var bytes = Encoding.UTF8.GetBytes(content); fs.SetLength(0); fs.Write(bytes, 0, bytes.Length); fs.Flush(); logger.Debug("RepoLock", "Lock acquired successfully", $"File := {filename}\n\nContent:\n{content}"); return(new RepoLock(logger, filename, fs)); } catch (Exception e1) { logger.Error("RepoLock", "Acquiring lock failed", $"File := {filename}\n\nException:\n{e1}"); try { var oldcontent = File.ReadAllText(filename); logger.Info("RepoLock", "Old lock file read", $"File := Content:\n{oldcontent}"); } catch (Exception e2) { logger.Error("RepoLock", "Cannot read existing lockfile", e2.ToString()); } throw new RepoLockedException($"Could not open Repository '{pathLocalFolder}'.\nThe repository is currently locked by a different process.", e1); } }
private void UploadNotes(IReadOnlyCollection <Tuple <INote, INote> > notesToUpload, IEnumerable <Tuple <INote, INote> > notesToResetRemoteDirty, ICollection <Tuple <string, Exception> > errors) { ExecuteInParallel( _log, "UploadNotes", _noteUploadEnableMultithreading, notesToUpload, _noteUploadParallelismLevel, _noteUploadParallelismThreshold, (e, notetuple) => { var message = string.Format("Could not upload note '{2}' ({0}) cause of {1}", notetuple.Item2.UniqueName, e.Message, notetuple.Item2.Title); _log.Error("Sync", message, e); errors.Add(Tuple.Create(message, e)); return(true); }, notetuple => { var realnote = notetuple.Item1; var clonenote = notetuple.Item2; _log.Info("Sync", string.Format("Upload note {0}", clonenote.UniqueName)); if (!realnote.IsLocalSaved) { _dispatcher.Invoke(() => { if (!realnote.IsLocalSaved) { _repo.SaveNote(realnote); } }); } var result = _repo.Connection.UploadNoteToRemote(ref clonenote, out var conflictnote, _conflictStrategy); switch (result) { case RemoteUploadResult.UpToDate: case RemoteUploadResult.Uploaded: _dispatcher.Invoke(() => { if (realnote.IsLocalSaved) { realnote.OnAfterUpload(clonenote); realnote.ResetRemoteDirty("Note was successfully uploaded (no conflict)"); _repo.SaveNote(realnote); } }); break; case RemoteUploadResult.Merged: _dispatcher.Invoke(() => { realnote.ApplyUpdatedData(clonenote); realnote.TriggerOnChanged(true); realnote.SetLocalDirty("Note was uploaded and a merge has happened"); realnote.ResetRemoteDirty("Note was successfully uploaded (auto-merge)"); }); break; case RemoteUploadResult.Conflict: _log.Warn("Sync", "Uploading note " + clonenote.UniqueName + " resulted in conflict"); ResolveUploadConflict(realnote, clonenote, conflictnote); break; default: throw new ArgumentOutOfRangeException(); } });
private static StandardFileNote CreateNote(ISimpleJsonRest web, StandardNoteConnection conn, APIResultItem encNote, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat) { if (encNote.deleted) { var nd = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { CreationDate = encNote.created_at, Text = "", InternalTitle = "", AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), }; nd.ModificationDate = encNote.updated_at; return(nd); } ContentNote content; try { var contentJson = StandardNoteCrypt.DecryptContent(encNote.content, encNote.enc_item_key, encNote.auth_hash, authToken.masterkey, authToken.masterauthkey); Logger.Debug( StandardNotePlugin.Name, $"DecryptContent of note {encNote.uuid:B}", $"[content]:\r\n{encNote.content}\r\n" + $"[enc_item_key]:\r\n{encNote.enc_item_key}\r\n" + $"[auth_hash]:\r\n{encNote.auth_hash}\r\n" + $"\r\n\r\n" + $"[contentJson]:\r\n{contentJson}\r\n"); content = web.ParseJsonWithoutConverter <ContentNote>(contentJson); } catch (RestException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e); } var n = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { Text = StandardNoteConfig.REX_LINEBREAK.Replace(content.text, Environment.NewLine), InternalTitle = content.title, AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), IsPinned = GetAppDataBool(content.appData, APPDATA_PINNED, false), IsLocked = GetAppDataBool(content.appData, APPDATA_LOCKED, false), }; var refTags = new List <StandardFileTagRef>(); foreach (var cref in content.references) { if (cref.content_type == "Note") { // ignore } else if (dat.Tags.Any(t => t.UUID == cref.uuid)) { refTags.Add(new StandardFileTagRef(cref.uuid, dat.Tags.First(t => t.UUID == cref.uuid).Title)); } else if (cref.content_type == "Tag") { Logger.Warn(StandardNotePlugin.Name, $"Reference to missing tag {cref.uuid} in note {encNote.uuid}"); } else { Logger.Error(StandardNotePlugin.Name, $"Downloaded note contains an unknown reference :{cref.uuid} ({cref.content_type}) in note {encNote.uuid}"); } } foreach (var tref in dat.Tags.Where(tag => tag.References.Any(tref => tref == encNote.uuid))) { refTags.Add(new StandardFileTagRef(tref.UUID, tref.Title)); } refTags = refTags.DistinctBy(t => t.UUID).ToList(); n.SetTags(refTags); n.SetReferences(content.references); n.CreationDate = encNote.created_at; n.ModificationDate = encNote.updated_at; return(n); }
private void UploadNotes(List <Tuple <INote, INote> > notesToUpload, List <Tuple <INote, INote> > notesToResetRemoteDirty, ref List <Tuple <string, Exception> > errors) { foreach (var notetuple in notesToUpload) { var realnote = notetuple.Item1; var clonenote = notetuple.Item2; _log.Info("Sync", string.Format("Upload note {0}", clonenote.UniqueName)); try { if (!realnote.IsLocalSaved) { dispatcher.Invoke(() => { if (!realnote.IsLocalSaved) { repo.SaveNote(realnote); } }); } var result = repo.Connection.UploadNoteToRemote(ref clonenote, out var conflictnote, conflictStrategy); switch (result) { case RemoteUploadResult.UpToDate: case RemoteUploadResult.Uploaded: dispatcher.Invoke(() => { if (realnote.IsLocalSaved) { realnote.OnAfterUpload(clonenote); realnote.ResetRemoteDirty("Note was successfully uploaded (no conflict)"); repo.SaveNote(realnote); } }); break; case RemoteUploadResult.Merged: dispatcher.Invoke(() => { realnote.ApplyUpdatedData(clonenote); realnote.TriggerOnChanged(true); realnote.SetLocalDirty("Note was uploaded and a merge has happened"); realnote.ResetRemoteDirty("Note was successfully uploaded (auto-merge)"); }); break; case RemoteUploadResult.Conflict: _log.Warn("Sync", "Uploading note " + clonenote.UniqueName + " resulted in conflict"); ResolveUploadConflict(realnote, clonenote, conflictnote); break; default: throw new ArgumentOutOfRangeException(); } } catch (Exception e) { var message = string.Format("Could not upload note '{2}' ({0}) cause of {1}", clonenote.UniqueName, e.Message, clonenote.Title); _log.Error("Sync", message, e); errors.Add(Tuple.Create(message, e)); } } foreach (var notetuple in notesToResetRemoteDirty) { var realnote = notetuple.Item1; var clonenote = notetuple.Item2; _log.Info("Sync", string.Format("Reset remote dirty of note {0} (no upload needed)", clonenote.UniqueName)); try { if (!realnote.IsLocalSaved) { dispatcher.Invoke(() => { if (!realnote.IsLocalSaved) { repo.SaveNote(realnote); } }); } dispatcher.Invoke(() => { if (realnote.IsLocalSaved) { realnote.ResetRemoteDirty("Reset remote dirty - was marked for upload but plugin says no upload is needed"); repo.SaveNote(realnote); } }); } catch (Exception e) { var message = string.Format("Could not reset remote dirty note '{2}' ({0}) cause of {1}", clonenote.UniqueName, e.Message, clonenote.Title); _log.Error("Sync", message, e); errors.Add(Tuple.Create(message, e)); } } }
private static StandardFileNote CreateNote(ISimpleJsonRest web, StandardNoteConnection conn, APIResultItem encNote, APIResultAuthorize authToken, StandardNoteConfig cfg, StandardNoteData dat) { if (encNote.deleted) { var nd = new StandardFileNote(encNote.uuid, cfg, conn.HConfig) { CreationDate = encNote.created_at, AuthHash = encNote.auth_hash, ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content), }; nd.RawModificationDate = encNote.updated_at; return(nd); } ContentNote content; string appDataContentString; try { var contentJson = StandardNoteCrypt.DecryptContent(encNote.content, encNote.enc_item_key, encNote.auth_hash, authToken.masterkey, authToken.masterauthkey); Logger.Debug( StandardNotePlugin.Name, $"DecryptContent of note {encNote.uuid:B}", $"[content]:\r\n{encNote.content}\r\n" + $"[enc_item_key]:\r\n{encNote.enc_item_key}\r\n" + $"[auth_hash]:\r\n{encNote.auth_hash}\r\n" + $"\r\n\r\n" + $"[contentJson]:\r\n{contentJson}\r\n"); content = web.ParseJsonWithoutConverter <ContentNote>(contentJson); appDataContentString = web.ParseJsonAndGetSubJson(contentJson, "appData", string.Empty); } catch (RestException) { throw; } catch (Exception e) { throw new StandardNoteAPIException("Cannot decrypt note with local masterkey", e); } var n = new StandardFileNote(encNote.uuid, cfg, conn.HConfig); using (n.SuppressDirtyChanges()) { n.Text = StandardNoteConfig.REX_LINEBREAK.Replace(content.text, Environment.NewLine); n.InternalTitle = content.title; n.AuthHash = encNote.auth_hash; n.ContentVersion = StandardNoteCrypt.GetSchemaVersion(encNote.content); n.IsPinned = GetAppDataBool(content.appData, APPDATA_PINNED, false); n.IsLocked = GetAppDataBool(content.appData, APPDATA_LOCKED, false); n.IsArchived = GetAppDataBool(content.appData, APPDATA_ARCHIVED, false); n.IsProtected = content.@protected; n.IsHidePreview = content.hidePreview; var refTags = new List <StandardFileTagRef>(); foreach (var cref in content.references) { if (cref.content_type == "Note") { // ignore } else if (dat.Tags.Any(t => t.UUID == cref.uuid)) { refTags.Add(new StandardFileTagRef(cref.uuid, dat.Tags.First(t => t.UUID == cref.uuid).Title)); } else if (cref.content_type == "Tag") { Logger.Warn(StandardNotePlugin.Name, $"Reference to missing tag {cref.uuid} in note {encNote.uuid}"); } else { Logger.Error(StandardNotePlugin.Name, $"Downloaded note contains an unknown reference :{cref.uuid} ({cref.content_type}) in note {encNote.uuid}"); } } foreach (var tref in dat.Tags.Where(tag => tag.References.Any(tref => tref == encNote.uuid))) { refTags.Add(new StandardFileTagRef(tref.UUID, tref.Title)); } refTags = refTags.DistinctBy(t => t.UUID).ToList(); n.SetTags(refTags); n.SetReferences(content.references); n.CreationDate = encNote.created_at; n.RawModificationDate = encNote.updated_at; n.ClientUpdatedAt = GetAppDataDTO(content.appData, APPDATA_CLIENTUPDATEDAT, null); n.NoteCreationDate = GetAppDataDTO(content.appData, APPDATA_NOTECDATE, null); n.NoteModificationDate = GetAppDataDTO(content.appData, APPDATA_NOTEMDATE, null); n.TextModificationDate = GetAppDataDTO(content.appData, APPDATA_TEXTMDATE, null); n.TitleModificationDate = GetAppDataDTO(content.appData, APPDATA_TITLEMDATE, null); n.TagsModificationDate = GetAppDataDTO(content.appData, APPDATA_TAGSMDATE, null); n.PathModificationDate = GetAppDataDTO(content.appData, APPDATA_PATHMDATE, null); n.RawAppData = appDataContentString; } return(n); }