Zonble: Use fsStreamHelper to monitor data changes.

This commit is contained in:
ShikiSuen 2022-01-31 12:29:34 +08:00
parent 115f197b72
commit 541e96ab70
6 changed files with 99 additions and 7 deletions

View File

@ -128,13 +128,23 @@ struct VersionUpdateApi {
}
@objc(AppDelegate)
class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate {
class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControllerDelegate, FSEventStreamHelperDelegate {
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event]) {
DispatchQueue.main.async {
if Preferences.shouldAutoReloadUserDataFiles {
LanguageModelManager.loadUserPhrases()
LanguageModelManager.loadUserPhraseReplacement()
}
}
}
@IBOutlet weak var window: NSWindow?
private var preferencesWindowController: PreferencesWindowController?
private var aboutWindowController: frmAboutWindow? // New About Window
private var checkTask: URLSessionTask?
private var updateNextStepURL: URL?
private var fsStreamHelper = FSEventStreamHelper(path: LanguageModelManager.dataFolderPath, queue: DispatchQueue(label: "User Phrases"))
// dealloc
deinit {
@ -149,6 +159,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NonModalAlertWindowControlle
LanguageModelManager.loadCNSData()
LanguageModelManager.loadUserPhrases()
LanguageModelManager.loadUserPhraseReplacement()
fsStreamHelper.delegate = self
_ = fsStreamHelper.start()
Preferences.setMissingDefaults()

View File

@ -0,0 +1,80 @@
/*
* FSEventStreamHelper.swift
*
* Copyright 2021-2022 vChewing Project (3-Clause BSD License).
* Derived from 2011-2022 OpenVanilla Project (MIT License).
* Some rights reserved. See "LICENSE.TXT" for details.
*/
import Cocoa
public protocol FSEventStreamHelperDelegate: AnyObject {
func helper(_ helper: FSEventStreamHelper, didReceive events: [FSEventStreamHelper.Event])
}
public class FSEventStreamHelper : NSObject {
public struct Event {
var path: String
var flags: FSEventStreamEventFlags
var id: FSEventStreamEventId
}
public let path: String
public let dispatchQueue: DispatchQueue
public weak var delegate: FSEventStreamHelperDelegate?
@objc public init(path: String, queue: DispatchQueue) {
self.path = path
self.dispatchQueue = queue
}
private var stream: FSEventStreamRef? = nil
public func start() -> Bool {
if stream != nil {
return false
}
var context = FSEventStreamContext()
context.info = Unmanaged.passUnretained(self).toOpaque()
guard let stream = FSEventStreamCreate(nil, {
(stream, clientCallBackInfo, eventCount, eventPaths, eventFlags, eventIds) in
let helper = Unmanaged<FSEventStreamHelper>.fromOpaque(clientCallBackInfo!).takeUnretainedValue()
let pathsBase = eventPaths.assumingMemoryBound(to: UnsafePointer<CChar>.self)
let pathsPtr = UnsafeBufferPointer(start: pathsBase, count: eventCount)
let flagsPtr = UnsafeBufferPointer(start: eventFlags, count: eventCount)
let eventIDsPtr = UnsafeBufferPointer(start: eventIds, count: eventCount)
let events = (0..<eventCount).map {
FSEventStreamHelper.Event(path: String(cString: pathsPtr[$0]),
flags: flagsPtr[$0],
id: eventIDsPtr[$0] )
}
helper.delegate?.helper(helper, didReceive: events)
},
&context,
[path] as CFArray,
UInt64(kFSEventStreamEventIdSinceNow),
1.0,
FSEventStreamCreateFlags(kFSEventStreamCreateFlagNone)
) else {
return false
}
FSEventStreamSetDispatchQueue(stream, dispatchQueue)
if !FSEventStreamStart(stream) {
FSEventStreamInvalidate(stream)
return false
}
self.stream = stream
return true
}
func stop() {
guard let stream = stream else {
return
}
FSEventStreamStop(stream)
FSEventStreamInvalidate(stream)
self.stream = nil
}
}

View File

@ -192,11 +192,6 @@ static double FindHighestScore(const vector<NodeAnchor>& nodes, double epsilon)
NSString *basisKeyboardLayoutID = Preferences.basisKeyboardLayout;
[client overrideKeyboardWithKeyboardNamed:basisKeyboardLayoutID];
// Load UserPhrases // 這裡今後需要改造成「驗證檔案指紋、根據驗證結果判定是否需要重新讀入」的形式。
if (Preferences.shouldAutoReloadUserDataFiles) {
[self reloadUserPhrases:(id)nil];
}
// reset the state
_currentDeferredClient = nil;
_currentCandidateClient = nil;

View File

@ -181,7 +181,7 @@ static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, vChewing
[writeFile writeData:data];
[writeFile closeFile];
[self loadUserPhrases];
// [self loadUserPhrases]; // Not Needed since AppDelegate is handling this.
return YES;
}

View File

@ -17,4 +17,5 @@
+ (void)loadCNSData;
+ (void)loadUserPhrases;
+ (void)loadUserPhraseReplacement;
@property (class, readonly, nonatomic) NSString *dataFolderPath;
@end

View File

@ -21,6 +21,7 @@
5B5F4F972792A4EA00922DC2 /* UserPhrasesLM.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B5F4F962792A4EA00922DC2 /* UserPhrasesLM.mm */; };
5B6797B52794822C004AC7CE /* PhraseReplacementMap.h in Sources */ = {isa = PBXBuildFile; fileRef = 5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */; };
5B810D9F27A3A5E50032C1A9 /* LMConsolidator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */; };
5B9DD0A927A7950D00ED335A /* FSEventStreamHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */; };
5BC2D2882793B434002C0BEC /* KeyValueBlobReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */; };
5BC2D28B2793B8FB002C0BEC /* EmacsKeyHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28A2793B8FB002C0BEC /* EmacsKeyHelper.swift */; };
5BC2D28D2793B98F002C0BEC /* PreferencesModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC2D28C2793B98F002C0BEC /* PreferencesModule.swift */; };
@ -124,6 +125,7 @@
5B9781D52763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
5B9781D72763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
5B9781D82763850700897999 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "Source/zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FSEventStreamHelper.swift; sourceTree = "<group>"; };
5BA923AC2791B7C20001323A /* vChewingInstaller-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "vChewingInstaller-Bridging-Header.h"; sourceTree = "<group>"; };
5BC2D2842793B434002C0BEC /* KeyValueBlobReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyValueBlobReader.h; sourceTree = "<group>"; };
5BC2D2862793B434002C0BEC /* KeyValueBlobReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyValueBlobReader.cpp; sourceTree = "<group>"; };
@ -264,6 +266,7 @@
5B6797B32794822C004AC7CE /* PhraseReplacementMap.h */,
5B810D9D27A3A5E50032C1A9 /* LMConsolidator.mm */,
5B810D9E27A3A5E50032C1A9 /* LMConsolidator.h */,
5B9DD0A827A7950D00ED335A /* FSEventStreamHelper.swift */,
);
path = LanguageModel;
sourceTree = "<group>";
@ -714,6 +717,7 @@
5BD0D19A27943D390008F48E /* clsSFX.swift in Sources */,
5BDD25F9279D6D1200AA18F8 /* ioapi.m in Sources */,
5BE798A72793280C00337FF9 /* NotifierController.swift in Sources */,
5B9DD0A927A7950D00ED335A /* FSEventStreamHelper.swift in Sources */,
5B5F4F93279294A300922DC2 /* LanguageModelManager.mm in Sources */,
6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */,
6A0D4ED315FC0D6400ABF4B3 /* main.swift in Sources */,