From 297c5a2dbb809acf1aeb90014029276efcec71d2 Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 3 Jun 2025 19:59:28 -0600 Subject: [PATCH] disable SQLite in Java & Swift (since they don't compile) & add SQL queueing on startup At this point, the app compiles and runs in Android & iOS but DB operations fail. --- BUILDING.md | 2 + .../java/app/timesafari/MainActivity.java | 4 +- .../java/timesafari/app/MainActivity.java | 5 - ios/App/App.xcodeproj/project.pbxproj | 57 +++-- ios/App/App/AppDelegate.swift | 4 +- ios/App/Podfile | 5 + ios/App/Podfile.lock | 20 +- package-lock.json | 40 +--- package.json | 2 +- pkgx.yaml | 1 + src/db/databaseUtil.ts | 5 + .../platforms/CapacitorPlatformService.ts | 219 ++++++++++++++---- .../platforms/ElectronPlatformService.ts | 13 +- src/views/LogView.vue | 9 + 14 files changed, 273 insertions(+), 113 deletions(-) delete mode 100644 android/app/src/main/java/timesafari/app/MainActivity.java diff --git a/BUILDING.md b/BUILDING.md index d9debb77..62fb27e8 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -369,6 +369,8 @@ Prerequisites: macOS with Xcode installed 6. Use Xcode to build and run on simulator or device. + * Select Product -> Destination with some Simulator version. Then click the run arrow. + 7. Release * Under "General" renamed a bunch of things to "Time Safari" diff --git a/android/app/src/main/java/app/timesafari/MainActivity.java b/android/app/src/main/java/app/timesafari/MainActivity.java index 6fbf940e..12429d63 100644 --- a/android/app/src/main/java/app/timesafari/MainActivity.java +++ b/android/app/src/main/java/app/timesafari/MainActivity.java @@ -2,7 +2,7 @@ package app.timesafari; import android.os.Bundle; import com.getcapacitor.BridgeActivity; -import com.getcapacitor.community.sqlite.SQLite; +//import com.getcapacitor.community.sqlite.SQLite; public class MainActivity extends BridgeActivity { @Override @@ -10,6 +10,6 @@ public class MainActivity extends BridgeActivity { super.onCreate(savedInstanceState); // Initialize SQLite - registerPlugin(SQLite.class); + //registerPlugin(SQLite.class); } } \ No newline at end of file diff --git a/android/app/src/main/java/timesafari/app/MainActivity.java b/android/app/src/main/java/timesafari/app/MainActivity.java deleted file mode 100644 index cb343faa..00000000 --- a/android/app/src/main/java/timesafari/app/MainActivity.java +++ /dev/null @@ -1,5 +0,0 @@ -package timesafari.app; - -import com.getcapacitor.BridgeActivity; - -public class MainActivity extends BridgeActivity {} diff --git a/ios/App/App.xcodeproj/project.pbxproj b/ios/App/App.xcodeproj/project.pbxproj index 1766f7e7..0c89bf53 100644 --- a/ios/App/App.xcodeproj/project.pbxproj +++ b/ios/App/App.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; }; 504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; }; 50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; }; - A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; }; + 97EF2DC6FD76C3643D680B8D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90DCAFB4D8948F7A50C13800 /* Pods_App.framework */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -27,9 +27,9 @@ 504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = ""; }; - AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; - FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; + 90DCAFB4D8948F7A50C13800 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2E9297D5D02C549106C77F9 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = ""; }; + EAEC6436E595F7CD3A1C9E96 /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -37,17 +37,17 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */, + 97EF2DC6FD76C3643D680B8D /* Pods_App.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = { + 4B546315E668C7A13939F417 /* Frameworks */ = { isa = PBXGroup; children = ( - AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */, + 90DCAFB4D8948F7A50C13800 /* Pods_App.framework */, ); name = Frameworks; sourceTree = ""; @@ -57,8 +57,8 @@ children = ( 504EC3061FED79650016851F /* App */, 504EC3051FED79650016851F /* Products */, - 7F8756D8B27F46E3366F6CEA /* Pods */, - 27E2DDA53C4D2A4D1A88CE4A /* Frameworks */, + BA325FFCDCE8D334E5C7AEBE /* Pods */, + 4B546315E668C7A13939F417 /* Frameworks */, ); sourceTree = ""; }; @@ -85,13 +85,14 @@ path = App; sourceTree = ""; }; - 7F8756D8B27F46E3366F6CEA /* Pods */ = { + BA325FFCDCE8D334E5C7AEBE /* Pods */ = { isa = PBXGroup; children = ( - FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */, - AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */, + EAEC6436E595F7CD3A1C9E96 /* Pods-App.debug.xcconfig */, + E2E9297D5D02C549106C77F9 /* Pods-App.release.xcconfig */, ); name = Pods; + path = Pods; sourceTree = ""; }; /* End PBXGroup section */ @@ -101,12 +102,12 @@ isa = PBXNativeTarget; buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */; buildPhases = ( - 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */, + 92977BEA1068CC097A57FC77 /* [CP] Check Pods Manifest.lock */, 504EC3001FED79650016851F /* Sources */, 504EC3011FED79650016851F /* Frameworks */, 504EC3021FED79650016851F /* Resources */, - 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */, 012076E8FFE4BF260A79B034 /* Fix Privacy Manifest */, + 3525031ED1C96EF4CF6E9959 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -189,37 +190,41 @@ shellScript = "\"${PROJECT_DIR}/app_privacy_manifest_fixer/fixer.sh\" "; showEnvVarsInLog = 0; }; - 6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = { + 3525031ED1C96EF4CF6E9959 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = { + 92977BEA1068CC097A57FC77 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -375,11 +380,12 @@ }; 504EC3171FED79650016851F /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */; + baseConfigurationReference = EAEC6436E595F7CD3A1C9E96 /* Pods-App.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 18; + DEVELOPMENT_TEAM = GM3FS5JQPH; ENABLE_APP_SANDBOX = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = App/Info.plist; @@ -401,11 +407,12 @@ }; 504EC3181FED79650016851F /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */; + baseConfigurationReference = E2E9297D5D02C549106C77F9 /* Pods-App.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 18; + DEVELOPMENT_TEAM = GM3FS5JQPH; ENABLE_APP_SANDBOX = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = App/Info.plist; diff --git a/ios/App/App/AppDelegate.swift b/ios/App/App/AppDelegate.swift index c1c6a182..7a1b41b3 100644 --- a/ios/App/App/AppDelegate.swift +++ b/ios/App/App/AppDelegate.swift @@ -9,8 +9,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Initialize SQLite - let sqlite = SQLite() - sqlite.initialize() + //let sqlite = SQLite() + //sqlite.initialize() // Override point for customization after application launch. return true diff --git a/ios/App/Podfile b/ios/App/Podfile index 228eeecb..da98dfe6 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -27,4 +27,9 @@ end post_install do |installer| assertDeploymentTarget(installer) + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64' + end + end end diff --git a/ios/App/Podfile.lock b/ios/App/Podfile.lock index f513a8ba..fdd82e86 100644 --- a/ios/App/Podfile.lock +++ b/ios/App/Podfile.lock @@ -5,6 +5,10 @@ PODS: - Capacitor - CapacitorCamera (6.1.2): - Capacitor + - CapacitorCommunitySqlite (6.0.2): + - Capacitor + - SQLCipher + - ZIPFoundation - CapacitorCordova (6.2.1) - CapacitorFilesystem (6.0.3): - Capacitor @@ -73,11 +77,18 @@ PODS: - nanopb/decode (2.30910.0) - nanopb/encode (2.30910.0) - PromisesObjC (2.4.0) + - SQLCipher (4.9.0): + - SQLCipher/standard (= 4.9.0) + - SQLCipher/common (4.9.0) + - SQLCipher/standard (4.9.0): + - SQLCipher/common + - ZIPFoundation (0.9.19) DEPENDENCIES: - "Capacitor (from `../../node_modules/@capacitor/ios`)" - "CapacitorApp (from `../../node_modules/@capacitor/app`)" - "CapacitorCamera (from `../../node_modules/@capacitor/camera`)" + - "CapacitorCommunitySqlite (from `../../node_modules/@capacitor-community/sqlite`)" - "CapacitorCordova (from `../../node_modules/@capacitor/ios`)" - "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)" - "CapacitorMlkitBarcodeScanning (from `../../node_modules/@capacitor-mlkit/barcode-scanning`)" @@ -98,6 +109,8 @@ SPEC REPOS: - MLKitVision - nanopb - PromisesObjC + - SQLCipher + - ZIPFoundation EXTERNAL SOURCES: Capacitor: @@ -106,6 +119,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/@capacitor/app" CapacitorCamera: :path: "../../node_modules/@capacitor/camera" + CapacitorCommunitySqlite: + :path: "../../node_modules/@capacitor-community/sqlite" CapacitorCordova: :path: "../../node_modules/@capacitor/ios" CapacitorFilesystem: @@ -121,6 +136,7 @@ SPEC CHECKSUMS: Capacitor: c95400d761e376be9da6be5a05f226c0e865cebf CapacitorApp: e1e6b7d05e444d593ca16fd6d76f2b7c48b5aea7 CapacitorCamera: 9bc7b005d0e6f1d5f525b8137045b60cffffce79 + CapacitorCommunitySqlite: 0299d20f4b00c2e6aa485a1d8932656753937b9b CapacitorCordova: 8d93e14982f440181be7304aa9559ca631d77fff CapacitorFilesystem: 59270a63c60836248812671aa3b15df673fbaf74 CapacitorMlkitBarcodeScanning: 7652be9c7922f39203a361de735d340ae37e134e @@ -138,7 +154,9 @@ SPEC CHECKSUMS: MLKitVision: 90922bca854014a856f8b649d1f1f04f63fd9c79 nanopb: 438bc412db1928dac798aa6fd75726007be04262 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + SQLCipher: 31878d8ebd27e5c96db0b7cb695c96e9f8ad77da + ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c -PODFILE CHECKSUM: 7e7e09e6937de7f015393aecf2cf7823645689b3 +PODFILE CHECKSUM: f987510f7383b04a1b09ea8472bdadcd88b6c924 COCOAPODS: 1.16.2 diff --git a/package-lock.json b/package-lock.json index c0e0569a..579ccd38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "timesafari", "version": "0.4.6", "dependencies": { - "@capacitor-community/sqlite": "^6.0.2", + "@capacitor-community/sqlite": "6.0.2", "@capacitor-mlkit/barcode-scanning": "^6.0.0", "@capacitor/android": "^6.2.0", "@capacitor/app": "^6.0.0", @@ -2516,7 +2516,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/@capacitor-community/sqlite/-/sqlite-6.0.2.tgz", "integrity": "sha512-sj+2SPLu7E/3dM3xxcWwfNomG+aQHuN96/EFGrOtp4Dv30/2y5oIPyi6hZGjQGjPc5GDNoTQwW7vxWNzybjuMg==", - "license": "MIT", "dependencies": { "jeep-sqlite": "^2.7.2" }, @@ -8195,7 +8194,6 @@ "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -8208,7 +8206,6 @@ "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -8277,7 +8274,6 @@ "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -8290,7 +8286,6 @@ "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -8373,7 +8368,6 @@ "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -8386,7 +8380,6 @@ "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -8399,7 +8392,6 @@ "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -8426,7 +8418,6 @@ "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -8818,10 +8809,9 @@ } }, "node_modules/@stencil/core": { - "version": "4.31.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.31.0.tgz", - "integrity": "sha512-Ei9MFJ6LPD9BMFs+klkHylbVOOYhG10Jv4bvoFf3GMH15kA41rSYkEdr4DiX84ZdErQE2qtFV/2SUyWoXh0AhA==", - "license": "MIT", + "version": "4.33.1", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.33.1.tgz", + "integrity": "sha512-12k9xhAJBkpg598it+NRmaYIdEe6TSnsL/v6/KRXDcUyTK11VYwZQej2eHnMWtqot+znJ+GNTqb5YbiXi+5Low==", "bin": { "stencil": "bin/stencil" }, @@ -12173,8 +12163,7 @@ "node_modules/browser-fs-access": { "version": "0.35.0", "resolved": "https://registry.npmjs.org/browser-fs-access/-/browser-fs-access-0.35.0.tgz", - "integrity": "sha512-sLoadumpRfsjprP8XzVjpQc0jK8yqHBx0PtUTGYj2fftT+P/t+uyDAQdMgGAPKD011in/O+YYGh7fIs0oG/viw==", - "license": "Apache-2.0" + "integrity": "sha512-sLoadumpRfsjprP8XzVjpQc0jK8yqHBx0PtUTGYj2fftT+P/t+uyDAQdMgGAPKD011in/O+YYGh7fIs0oG/viw==" }, "node_modules/browserify-aes": { "version": "1.2.0", @@ -18144,8 +18133,7 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/import-fresh": { "version": "3.3.1", @@ -19090,7 +19078,6 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/jeep-sqlite/-/jeep-sqlite-2.8.0.tgz", "integrity": "sha512-FWNUP6OAmrUHwiW7H1xH5YUQ8tN2O4l4psT1sLd7DQtHd5PfrA1nvNdeKPNj+wQBtu7elJa8WoUibTytNTaaCg==", - "license": "MIT", "dependencies": { "@stencil/core": "^4.20.0", "browser-fs-access": "^0.35.0", @@ -19591,7 +19578,6 @@ "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -19602,20 +19588,17 @@ "node_modules/jszip/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "node_modules/jszip/node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -19629,14 +19612,12 @@ "node_modules/jszip/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/jszip/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -20159,7 +20140,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -20526,7 +20506,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", - "license": "Apache-2.0", "dependencies": { "lie": "3.1.1" } @@ -20535,7 +20514,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", - "license": "MIT", "dependencies": { "immediate": "~3.0.5" } diff --git a/package.json b/package.json index 9d87540b..b9fafaae 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "electron:build-mac-universal": "npm run build:electron-prod && electron-builder --mac --universal" }, "dependencies": { - "@capacitor-community/sqlite": "^6.0.2", + "@capacitor-community/sqlite": "6.0.2", "@capacitor-mlkit/barcode-scanning": "^6.0.0", "@capacitor/android": "^6.2.0", "@capacitor/app": "^6.0.0", diff --git a/pkgx.yaml b/pkgx.yaml index 08559bf2..89c92cb2 100644 --- a/pkgx.yaml +++ b/pkgx.yaml @@ -2,5 +2,6 @@ dependencies: - gradle - java - pod + - rubygems.org # other dependencies are discovered via package.json & requirements.txt & Gemfile (I'm guessing). diff --git a/src/db/databaseUtil.ts b/src/db/databaseUtil.ts index f8079c97..a0fdd87e 100644 --- a/src/db/databaseUtil.ts +++ b/src/db/databaseUtil.ts @@ -124,6 +124,7 @@ export async function retrieveSettingsForActiveAccount(): Promise { } let lastCleanupDate: string | null = null; +export let memoryLogs: string[] = []; /** * Logs a message to the database with proper handling of concurrent writes @@ -136,6 +137,7 @@ export async function logToDb(message: string): Promise { const nowKey = new Date().toISOString(); try { + memoryLogs.push(`${new Date().toISOString()} ${message}`); // Try to insert first, if it fails due to UNIQUE constraint, update instead await platform.dbExec("INSERT INTO logs (date, message) VALUES (?, ?)", [ nowKey, @@ -148,6 +150,9 @@ export async function logToDb(message: string): Promise { const sevenDaysAgo = new Date( new Date().getTime() - 7 * 24 * 60 * 60 * 1000, ); + memoryLogs = memoryLogs.filter( + (log) => log.split(" ")[0] > sevenDaysAgo.toDateString(), + ); await platform.dbExec("DELETE FROM logs WHERE date < ?", [ sevenDaysAgo.toDateString(), ]); diff --git a/src/services/platforms/CapacitorPlatformService.ts b/src/services/platforms/CapacitorPlatformService.ts index 8df1985f..cd237dfe 100644 --- a/src/services/platforms/CapacitorPlatformService.ts +++ b/src/services/platforms/CapacitorPlatformService.ts @@ -10,10 +10,9 @@ import { SQLiteConnection, SQLiteDBConnection, CapacitorSQLite, - Changes, } from "@capacitor-community/sqlite"; import { logger } from "../../utils/logger"; -import { QueryExecResult, SqlValue } from "@/interfaces/database"; +import { QueryExecResult } from "@/interfaces/database"; import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app"; interface Migration { @@ -21,6 +20,14 @@ interface Migration { sql: string; } +interface QueuedOperation { + type: "run" | "query" | "getOneRow" | "getAll"; + sql: string; + params: unknown[]; + resolve: (value: unknown) => void; + reject: (reason: unknown) => void; +} + /** * Platform service implementation for Capacitor (mobile) platform. * Provides native mobile functionality through Capacitor plugins for: @@ -34,12 +41,40 @@ export class CapacitorPlatformService implements PlatformService { private db: SQLiteDBConnection | null = null; private dbName = "timesafari.db"; private initialized = false; + private initializationPromise: Promise | null = null; + private operationQueue: Array = []; + private isProcessingQueue: boolean = false; constructor() { this.sqlite = new SQLiteConnection(CapacitorSQLite); } private async initializeDatabase(): Promise { + // If already initialized, return immediately + if (this.initialized) { + return; + } + + // If initialization is in progress, wait for it + if (this.initializationPromise) { + return this.initializationPromise; + } + + // Start initialization + this.initializationPromise = this._initialize(); + try { + await this.initializationPromise; + } catch (error) { + logger.error( + "[CapacitorPlatformService] Initialize method failed:", + error, + ); + this.initializationPromise = null; // Reset on failure + throw error; + } + } + + private async _initialize(): Promise { if (this.initialized) { return; } @@ -57,16 +92,142 @@ export class CapacitorPlatformService implements PlatformService { await this.db.open(); // Set journal mode to WAL for better performance - await this.db.execute("PRAGMA journal_mode=WAL;"); + // await this.db.execute("PRAGMA journal_mode=WAL;"); // Run migrations await this.runMigrations(); this.initialized = true; - logger.log("SQLite database initialized successfully"); + logger.log( + "[CapacitorPlatformService] SQLite database initialized successfully", + ); + + // Start processing the queue after initialization + this.processQueue(); } catch (error) { - logger.error("Error initializing SQLite database:", error); - throw new Error("Failed to initialize database"); + logger.error( + "[CapacitorPlatformService] Error initializing SQLite database:", + error, + ); + throw new Error( + "[CapacitorPlatformService] Failed to initialize database", + ); + } + } + + private async processQueue(): Promise { + if (this.isProcessingQueue || !this.initialized || !this.db) { + return; + } + + this.isProcessingQueue = true; + + while (this.operationQueue.length > 0) { + const operation = this.operationQueue.shift(); + if (!operation) continue; + + try { + let result: unknown; + switch (operation.type) { + case "run": { + const runResult = await this.db.run( + operation.sql, + operation.params, + ); + result = { + changes: runResult.changes?.changes || 0, + lastId: runResult.changes?.lastId, + }; + break; + } + case "query": { + const queryResult = await this.db.query( + operation.sql, + operation.params, + ); + result = { + columns: [], // SQLite plugin doesn't provide column names + values: queryResult.values || [], + }; + break; + } + case "getOneRow": { + const oneRowResult = await this.db.query( + operation.sql, + operation.params, + ); + result = oneRowResult.values?.[0]; + break; + } + case "getAll": { + const allResult = await this.db.query( + operation.sql, + operation.params, + ); + result = allResult.values || []; + break; + } + } + operation.resolve(result); + } catch (error) { + logger.error( + "[CapacitorPlatformService] Error while processing SQL queue:", + error, + " ... for sql:", + operation.sql, + " ... with params:", + operation.params, + ); + operation.reject(error); + } + } + + this.isProcessingQueue = false; + } + + private async queueOperation( + type: QueuedOperation["type"], + sql: string, + params: unknown[] = [], + ): Promise { + return new Promise((resolve, reject) => { + const operation: QueuedOperation = { + type, + sql, + params, + resolve: (value: unknown) => resolve(value as R), + reject, + }; + this.operationQueue.push(operation); + + // If we're already initialized, start processing the queue + if (this.initialized && this.db) { + this.processQueue(); + } + }); + } + + private async waitForInitialization(): Promise { + // If we have an initialization promise, wait for it + if (this.initializationPromise) { + await this.initializationPromise; + return; + } + + // If not initialized and no promise, start initialization + if (!this.initialized) { + await this.initializeDatabase(); + return; + } + + // If initialized but no db, something went wrong + if (!this.db) { + logger.error( + "[CapacitorPlatformService] Database not properly initialized after await waitForInitialization() - initialized flag is true but db is null", + ); + throw new Error( + "[CapacitorPlatformService] The database could not be initialized. We recommend you restart or reinstall.", + ); } } @@ -166,7 +327,7 @@ export class CapacitorPlatformService implements PlatformService { CREATE INDEX IF NOT EXISTS idx_contacts_name ON contacts(name); CREATE TABLE IF NOT EXISTS logs ( - date TEXT PRIMARY KEY, + date TEXT, message TEXT NOT NULL ); @@ -660,24 +821,8 @@ export class CapacitorPlatformService implements PlatformService { * @see PlatformService.dbQuery */ async dbQuery(sql: string, params?: unknown[]): Promise { - await this.initializeDatabase(); - if (!this.db) { - throw new Error("Database not initialized"); - } - - try { - const result = await this.db.query(sql, params || []); - const values = result.values || []; - return { - columns: [], // SQLite plugin doesn't provide column names in query result - values: values as SqlValue[][], - }; - } catch (error) { - logger.error("Error executing query:", error); - throw new Error( - `Database query failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } + await this.waitForInitialization(); + return this.queueOperation("query", sql, params || []); } /** @@ -687,23 +832,11 @@ export class CapacitorPlatformService implements PlatformService { sql: string, params?: unknown[], ): Promise<{ changes: number; lastId?: number }> { - await this.initializeDatabase(); - if (!this.db) { - throw new Error("Database not initialized"); - } - - try { - const result = await this.db.run(sql, params || []); - const changes = result.changes as Changes; - return { - changes: changes?.changes || 0, - lastId: changes?.lastId, - }; - } catch (error) { - logger.error("Error executing statement:", error); - throw new Error( - `Database execution failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } + await this.waitForInitialization(); + return this.queueOperation<{ changes: number; lastId?: number }>( + "run", + sql, + params || [], + ); } } diff --git a/src/services/platforms/ElectronPlatformService.ts b/src/services/platforms/ElectronPlatformService.ts index 5bdd455f..5700f7d6 100644 --- a/src/services/platforms/ElectronPlatformService.ts +++ b/src/services/platforms/ElectronPlatformService.ts @@ -60,10 +60,17 @@ export class ElectronPlatformService implements PlatformService { await this.runMigrations(); this.initialized = true; - logger.log("SQLite database initialized successfully"); + logger.log( + "[ElectronPlatformService] SQLite database initialized successfully", + ); } catch (error) { - logger.error("Error initializing SQLite database:", error); - throw new Error("Failed to initialize database"); + logger.error( + "[ElectronPlatformService] Error initializing SQLite database:", + error, + ); + throw new Error( + "[ElectronPlatformService] Failed to initialize database", + ); } } diff --git a/src/views/LogView.vue b/src/views/LogView.vue index deecbb56..8ef7bc39 100644 --- a/src/views/LogView.vue +++ b/src/views/LogView.vue @@ -42,6 +42,13 @@ > +
+

Memory Logs

+
{{ memoryLogs.join("\n") }}
+
@@ -70,6 +77,7 @@ export default class LogView extends Vue { loading = true; logs: Log[] = []; error: string | null = null; + memoryLogs: string[] = []; async mounted() { await this.loadLogs(); @@ -78,6 +86,7 @@ export default class LogView extends Vue { async loadLogs() { try { this.error = null; // Clear any previous errors + this.memoryLogs = databaseUtil.memoryLogs; let allLogs: Log[] = []; const platformService = PlatformServiceFactory.getInstance();