Exemple #1
0
        public async Task SaveSessionAsync(Action actionAfterSaving = null)
        {
            if (!IsBackupEnabled)
            {
                LoggingService.LogInfo("[SessionManager] Session backup is disabled.");
                return;
            }

            // Serialize saves
            await _semaphoreSlim.WaitAsync();

            if (!IsBackupEnabled)
            {
                return;                   // Check again after SemaphoreSlim released
            }
            Stopwatch stopwatch = Stopwatch.StartNew();

            ITextEditor[] textEditors = _notepadsCore.GetAllTextEditors();

            if (textEditors == null || textEditors.Length == 0)
            {
                await ClearSessionDataAsync();

                actionAfterSaving?.Invoke();
                _semaphoreSlim.Release();
                return;
            }

            ITextEditor selectedTextEditor = _notepadsCore.GetSelectedTextEditor();

            NotepadsSessionDataV1 sessionData = new NotepadsSessionDataV1();

            foreach (ITextEditor textEditor in textEditors)
            {
                if (_sessionData.TryGetValue(textEditor.Id, out TextEditorSessionDataV1 textEditorData))
                {
                    // Get latest state meta data
                    textEditorData.StateMetaData = textEditor.GetTextEditorStateMetaData();
                }
                else // Text content has been changed or editor has not backed up yet
                {
                    textEditorData = new TextEditorSessionDataV1
                    {
                        Id = textEditor.Id,
                    };

                    if (textEditor.EditingFile != null)
                    {
                        // Add the opened file to FutureAccessList so we can access it next launch
                        var futureAccessToken = ToToken(textEditor.Id);
                        await FileSystemUtility.TryAddOrReplaceTokenInFutureAccessList(futureAccessToken, textEditor.EditingFile);

                        textEditorData.EditingFileFutureAccessToken = futureAccessToken;
                        textEditorData.EditingFileName = textEditor.EditingFileName;
                        textEditorData.EditingFilePath = textEditor.EditingFilePath;
                    }

                    if (textEditor.IsModified)
                    {
                        if (textEditor.EditingFile != null)
                        {
                            // Persist the last save known to the app, which might not be up-to-date (if the file was modified outside the app)
                            var lastSavedBackupFile = await SessionUtility.CreateNewFileInBackupFolderAsync(ToToken(textEditor.Id) + "-LastSaved",
                                                                                                            CreationCollisionOption.ReplaceExisting);

                            if (!await BackupTextAsync(textEditor.LastSavedSnapshot.Content,
                                                       textEditor.LastSavedSnapshot.Encoding,
                                                       textEditor.LastSavedSnapshot.LineEnding,
                                                       lastSavedBackupFile))
                            {
                                continue;
                            }

                            textEditorData.LastSavedBackupFilePath = lastSavedBackupFile.Path;
                        }

                        if (textEditor.EditingFile == null || !string.Equals(textEditor.LastSavedSnapshot.Content, textEditor.GetText()))
                        {
                            // Persist pending changes relative to the last save
                            var pendingBackupFile = await SessionUtility.CreateNewFileInBackupFolderAsync(ToToken(textEditor.Id) + "-Pending",
                                                                                                          CreationCollisionOption.ReplaceExisting);

                            if (!await BackupTextAsync(textEditor.GetText(),
                                                       textEditor.LastSavedSnapshot.Encoding,
                                                       textEditor.LastSavedSnapshot.LineEnding,
                                                       pendingBackupFile))
                            {
                                continue;
                            }

                            textEditorData.PendingBackupFilePath = pendingBackupFile.Path;
                        }
                    }

                    textEditorData.StateMetaData = textEditor.GetTextEditorStateMetaData();

                    // We will not create new backup files for this text editor unless it has changes
                    _sessionData.TryAdd(textEditor.Id, textEditorData);
                }

                sessionData.TextEditors.Add(textEditorData);

                if (textEditor == selectedTextEditor)
                {
                    sessionData.SelectedTextEditor = textEditor.Id;
                }
            }

            sessionData.TabScrollViewerHorizontalOffset =
                _notepadsCore.GetTabScrollViewerHorizontalOffset();

            bool sessionDataSaved = false;

            try
            {
                string sessionJsonStr = JsonConvert.SerializeObject(sessionData, Formatting.Indented);

                if (_lastSessionJsonStr == null || !string.Equals(_lastSessionJsonStr, sessionJsonStr, StringComparison.OrdinalIgnoreCase))
                {
                    // write
                    await SessionUtility.SaveSerializedSessionMetaDataAsync(sessionJsonStr);

                    _lastSessionJsonStr = sessionJsonStr;
                    sessionDataSaved    = true;
                }
            }
            catch (Exception ex)
            {
                LoggingService.LogError($"[SessionManager] Failed to save session metadata: {ex.Message}");
                actionAfterSaving?.Invoke();
                _semaphoreSlim.Release();
                return; // Failed to save the session - do not proceed to delete backup files
            }

            if (sessionDataSaved)
            {
                await DeleteOrphanedBackupFilesAsync(sessionData);

                DeleteOrphanedTokensInFutureAccessList(sessionData);
            }

            stopwatch.Stop();

            if (sessionDataSaved)
            {
                LoggingService.LogInfo($"[SessionManager] Successfully saved the current session. Total time: {stopwatch.Elapsed.TotalMilliseconds} milliseconds.", consoleOnly: true);
            }

            actionAfterSaving?.Invoke();
            _semaphoreSlim.Release();
        }
Exemple #2
0
        private async Task <ITextEditor> RecoverTextEditorAsync(TextEditorSessionDataV1 editorSessionData)
        {
            StorageFile editingFile = null;

            if (editorSessionData.EditingFileFutureAccessToken != null)
            {
                editingFile = await FileSystemUtility.GetFileFromFutureAccessList(editorSessionData.EditingFileFutureAccessToken);
            }

            string lastSavedFile = editorSessionData.LastSavedBackupFilePath;
            string pendingFile   = editorSessionData.PendingBackupFilePath;

            ITextEditor textEditor;

            if (editingFile == null && lastSavedFile == null && pendingFile == null)
            {
                textEditor = null;
            }
            else if (editingFile != null && lastSavedFile == null && pendingFile == null) // File without pending changes
            {
                textEditor = await _notepadsCore.CreateTextEditor(editorSessionData.Id, editingFile, ignoreFileSizeLimit : true);

                textEditor.ResetEditorState(editorSessionData.StateMetaData);
            }
            else // File with pending changes
            {
                string lastSavedText = string.Empty;
                string pendingText   = null;

                if (lastSavedFile != null)
                {
                    TextFile lastSavedTextFile = await FileSystemUtility.ReadFile(lastSavedFile, ignoreFileSizeLimit : true,
                                                                                  EncodingUtility.GetEncodingByName(editorSessionData.StateMetaData.LastSavedEncoding));

                    lastSavedText = lastSavedTextFile.Content;
                }

                var textFile = new TextFile(lastSavedText,
                                            EncodingUtility.GetEncodingByName(editorSessionData.StateMetaData.LastSavedEncoding),
                                            LineEndingUtility.GetLineEndingByName(editorSessionData.StateMetaData.LastSavedLineEnding),
                                            editorSessionData.StateMetaData.DateModifiedFileTime);

                textEditor = _notepadsCore.CreateTextEditor(
                    editorSessionData.Id,
                    textFile,
                    editingFile,
                    editorSessionData.StateMetaData.IsModified);

                if (pendingFile != null)
                {
                    TextFile pendingTextFile = await FileSystemUtility.ReadFile(pendingFile,
                                                                                ignoreFileSizeLimit : true,
                                                                                EncodingUtility.GetEncodingByName(editorSessionData.StateMetaData.LastSavedEncoding));

                    pendingText = pendingTextFile.Content;
                }

                textEditor.ResetEditorState(editorSessionData.StateMetaData, pendingText);
            }

            return(textEditor);
        }
Exemple #3
0
        private async Task <TextEditorSessionDataV1> BuildTextEditorSessionData(ITextEditor textEditor)
        {
            TextEditorSessionDataV1 textEditorData = new TextEditorSessionDataV1
            {
                Id = textEditor.Id,
            };

            if (textEditor.EditingFile != null)
            {
                // Add the opened file to FutureAccessList so we can access it next launch
                var futureAccessToken = ToToken(textEditor.Id);
                await FileSystemUtility.TryAddOrReplaceTokenInFutureAccessList(futureAccessToken, textEditor.EditingFile);

                textEditorData.EditingFileFutureAccessToken = futureAccessToken;
                textEditorData.EditingFileName = textEditor.EditingFileName;
                textEditorData.EditingFilePath = textEditor.EditingFilePath;
            }

            if (textEditor.IsModified)
            {
                if (textEditor.EditingFile != null)
                {
                    // Persist the last save known to the app, which might not be up-to-date (if the file was modified outside the app)
                    var lastSavedBackupFile = await SessionUtility.CreateNewFileInBackupFolderAsync(
                        ToToken(textEditor.Id) + "-LastSaved",
                        CreationCollisionOption.ReplaceExisting,
                        _backupFolderName);

                    if (!await BackupTextAsync(textEditor.LastSavedSnapshot.Content,
                                               textEditor.LastSavedSnapshot.Encoding,
                                               textEditor.LastSavedSnapshot.LineEnding,
                                               lastSavedBackupFile))
                    {
                        return(null); // Error: Failed to write backup text to file
                    }

                    textEditorData.LastSavedBackupFilePath = lastSavedBackupFile.Path;
                }

                if (textEditor.EditingFile == null ||
                    !string.Equals(textEditor.LastSavedSnapshot.Content, textEditor.GetText()))
                {
                    // Persist pending changes relative to the last save
                    var pendingBackupFile = await SessionUtility.CreateNewFileInBackupFolderAsync(
                        ToToken(textEditor.Id) + "-Pending",
                        CreationCollisionOption.ReplaceExisting,
                        _backupFolderName);

                    if (!await BackupTextAsync(textEditor.GetText(),
                                               textEditor.LastSavedSnapshot.Encoding,
                                               textEditor.LastSavedSnapshot.LineEnding,
                                               pendingBackupFile))
                    {
                        return(null); // Error: Failed to write backup text to file
                    }

                    textEditorData.PendingBackupFilePath = pendingBackupFile.Path;
                }
            }

            textEditorData.StateMetaData = textEditor.GetTextEditorStateMetaData();

            return(textEditorData);
        }