Various fixes and improvements

sync2
Laurent 10 months ago
parent b993d920a0
commit 5b63a40851
  1. 4
      LeStorage.xcodeproj/project.pbxproj
  2. 1
      LeStorage/ApiCallCollection.swift
  3. 18
      LeStorage/Notification+Name.swift
  4. 8
      LeStorage/Services.swift
  5. 5
      LeStorage/Store.swift
  6. 30
      LeStorage/StoreCenter.swift
  7. 15
      LeStorage/StoredCollection.swift
  8. 11
      LeStorage/Utils/FileManager+Extensions.swift
  9. 17
      LeStorage/WebSocketManager.swift

@ -14,6 +14,7 @@
C4339BFF2CFF86B3004E5F09 /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4339BFE2CFF86B3004E5F09 /* Dictionary+Extensions.swift */; };
C456EFE22BE52379007388E2 /* StoredSingleton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C456EFE12BE52379007388E2 /* StoredSingleton.swift */; };
C45D35912C0A1DB5000F379F /* FailedAPICall.swift in Sources */ = {isa = PBXBuildFile; fileRef = C45D35902C0A1DB5000F379F /* FailedAPICall.swift */; };
C462E0DC2D37B61100F3E6E4 /* Notification+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = C462E0DB2D37B61100F3E6E4 /* Notification+Name.swift */; };
C467AAE32CD2467500D76CD2 /* Formatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C467AAE22CD2466400D76CD2 /* Formatter.swift */; };
C488C8802CCBDC210082001F /* NetworkMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C488C87F2CCBDC210082001F /* NetworkMonitor.swift */; };
C49B6E502C2089B6002BDE1B /* ApiCallCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49B6E4F2C2089B6002BDE1B /* ApiCallCollection.swift */; };
@ -66,6 +67,7 @@
C4339BFE2CFF86B3004E5F09 /* Dictionary+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Extensions.swift"; sourceTree = "<group>"; };
C456EFE12BE52379007388E2 /* StoredSingleton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredSingleton.swift; sourceTree = "<group>"; };
C45D35902C0A1DB5000F379F /* FailedAPICall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FailedAPICall.swift; sourceTree = "<group>"; };
C462E0DB2D37B61100F3E6E4 /* Notification+Name.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Name.swift"; sourceTree = "<group>"; };
C467AAE22CD2466400D76CD2 /* Formatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Formatter.swift; sourceTree = "<group>"; };
C488C87F2CCBDC210082001F /* NetworkMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkMonitor.swift; sourceTree = "<group>"; };
C49B6E4F2C2089B6002BDE1B /* ApiCallCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiCallCollection.swift; sourceTree = "<group>"; };
@ -150,6 +152,7 @@
C49B6E4F2C2089B6002BDE1B /* ApiCallCollection.swift */,
C4A47D6C2B71364600ADC637 /* ModelObject.swift */,
C488C87F2CCBDC210082001F /* NetworkMonitor.swift */,
C462E0DB2D37B61100F3E6E4 /* Notification+Name.swift */,
C4AC9CE92CF754CC00CC13DF /* Relationship.swift */,
C4A47D602B6D3C1300ADC637 /* Services.swift */,
C425D4572B6D2519002A7B48 /* Store.swift */,
@ -348,6 +351,7 @@
C4A47D4F2B6D280200ADC637 /* StoredCollection.swift in Sources */,
C4A47D9C2B7CFFE000ADC637 /* Settings.swift in Sources */,
C4FC2E292C2B2EC30021F3BF /* StoreCenter.swift in Sources */,
C462E0DC2D37B61100F3E6E4 /* Notification+Name.swift in Sources */,
C4A47D812B7665AD00ADC637 /* Migration.swift in Sources */,
C4A47D9B2B7CFFDA00ADC637 /* ApiCall.swift in Sources */,
C4A47D942B7CF7C500ADC637 /* MicroStorage.swift in Sources */,

@ -195,6 +195,7 @@ actor ApiCallCollection<T: SyncedStorable>: SomeCallCollection {
StoreCenter.main.updateLocalInstances(success)
}
}
self._attemptLoops = -1
} catch {
Logger.error(error)
}

@ -0,0 +1,18 @@
//
// Notification+Name.swift
// LeStorage
//
// Created by Laurent Morvillier on 15/01/2025.
//
extension Notification.Name {
public static let CollectionDidLoad: Notification.Name = Notification.Name.init(
"notification.collectionDidLoad")
public static let CollectionDidChange: Notification.Name = Notification.Name.init(
"notification.collectionDidChange")
public static let LeStorageDidSynchronize: Notification.Name = Notification.Name.init(
"notification.leStorageDidSynchronize")
}

@ -86,7 +86,7 @@ public class Services {
let debugURL = request.url?.absoluteString ?? ""
// print("Run \(request.httpMethod ?? "") \(debugURL)")
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request)
print("\(apiCall.method.rawValue) \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")")
// print("\(apiCall.method.rawValue) \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")")
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode
@ -142,7 +142,7 @@ public class Services {
let debugURL = request.url?.absoluteString ?? ""
// print("Run \(request.httpMethod ?? "") \(debugURL)")
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request)
print("\(request.httpMethod ?? "") \(debugURL) => \(String(data: task.0, encoding: .utf8) ?? "")")
// print("\(request.httpMethod ?? "") \(debugURL) => \(String(data: task.0, encoding: .utf8) ?? "")")
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode
@ -268,7 +268,7 @@ public class Services {
let debugURL = request.url?.absoluteString ?? ""
// print("Run \(request.httpMethod ?? "") \(debugURL)")
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request)
print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")")
// print("sync POST \(String(describing: T.self)) => \(String(data: task.0, encoding: .utf8) ?? "")")
var rescheduleApiCalls: Bool = false
var success: [T] = []
@ -434,7 +434,7 @@ public class Services {
// print("Run \(request.httpMethod ?? "") \(debugURL)")
let task: (Data, URLResponse) = try await URLSession.shared.data(for: request)
print("\(request.httpMethod ?? "") \(debugURL) => \(String(data: task.0, encoding: .utf8) ?? "")")
// print("\(request.httpMethod ?? "") \(debugURL) => \(String(data: task.0, encoding: .utf8) ?? "")")
if let response = task.1 as? HTTPURLResponse {
let statusCode = response.statusCode

@ -46,9 +46,6 @@ final public class Store {
/// The store identifier, used to name the store directory, and to perform filtering requests to the server
public fileprivate(set) var identifier: String? = nil
/// Indicates whether the store directory has been created at the init
fileprivate var _created: Bool = false
public init() {
self._createDirectory(directory: Store.storageDirectory)
}
@ -63,7 +60,7 @@ final public class Store {
/// - Parameters:
/// - directory: the name of the directory
fileprivate func _createDirectory(directory: String) {
self._created = FileManager.default.createDirectoryInDocuments(directoryName: directory)
FileManager.default.createDirectoryInDocuments(directoryName: directory)
}
/// A method to provide ids corresponding to the django storage

@ -96,6 +96,17 @@ public class StoreCenter {
Logger.log("websocket configured: \(url)")
}
public var hasWebSocketManager: Bool {
return self._webSocketManager != nil
}
public var websocketPingStatus: Bool {
return self._webSocketManager?.pingStatus ?? false
}
public var websocketFailure: Bool {
return self._webSocketManager?.failure ?? true
}
public var apiURL: String? {
return self._urlManager?.api
}
@ -193,6 +204,9 @@ public class StoreCenter {
self.resetApiCalls()
self._failedAPICallsCollection?.reset()
self._stores.removeAll()
self._dataAccess?.reset()
self._settingsStorage.update { settings in
settings.username = nil
settings.userId = nil
@ -516,6 +530,10 @@ public class StoreCenter {
StoreCenter.main.log(message: error.localizedDescription)
Logger.error(error)
}
NotificationCenter.default.post(
name: NSNotification.Name.LeStorageDidSynchronize, object: self)
}
/// Processes data that should be inserted or updated inside the app
@ -721,12 +739,12 @@ public class StoreCenter {
}
/// Resets all registered collection
public func reset() {
Store.main.reset()
for store in self._stores.values {
store.reset()
}
}
// public func reset() {
// Store.main.reset()
// for store in self._stores.values {
// store.reset()
// }
// }
/// Returns whether any collection has pending API calls
public func hasPendingAPICalls() async -> Bool {

@ -28,13 +28,6 @@ protocol SomeSyncedCollection: SomeCollection {
func loadCollectionsFromServerIfNoFile() async throws
}
extension Notification.Name {
public static let CollectionDidLoad: Notification.Name = Notification.Name.init(
"notification.collectionDidLoad")
public static let CollectionDidChange: Notification.Name = Notification.Name.init(
"notification.collectionDidChange")
}
public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollection, CollectionHolder
{
@ -302,14 +295,6 @@ public class StoredCollection<T: Storable>: RandomAccessCollection, SomeCollecti
if let index = self.items.firstIndex(where: { $0.id == item.id }) {
self.items.remove(at: index)
}
// Task {
// do {
// try await StoreCenter.main.deleteApiCallByDataId(type: T.self, id: item.stringId)
// } catch {
// Logger.error(error)
// }
// }
}
}

@ -9,18 +9,23 @@ import Foundation
extension FileManager {
func createDirectoryInDocuments(directoryName: String) -> Bool {
@discardableResult func createDirectoryInDocuments(directoryName: String) -> Bool {
let documentsDirectory = self.urls(for: .documentDirectory, in: .userDomainMask).first!
let directoryURL = documentsDirectory.appendingPathComponent(directoryName)
if !self.fileExists(atPath: directoryURL.path) {
do {
try self.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
try self.createDirectory(at: directoryURL,
withIntermediateDirectories: true,
attributes: nil)
Logger.log("directory created : \(directoryURL)")
return true
} catch {
Logger.error(error)
return false
}
return true
} else {
Logger.log("directory exists : \(directoryURL)")
return false
}
}

@ -16,6 +16,8 @@ class WebSocketManager: ObservableObject {
fileprivate var _url: String
fileprivate var _reconnectAttempts = 0
fileprivate var _failure = false
fileprivate var _pingOk = false
init(urlString: String) {
self._url = urlString
@ -52,9 +54,11 @@ class WebSocketManager: ObservableObject {
_webSocketTask?.receive { result in
switch result {
case .failure(let error):
self._failure = true
print("Error in receiving message: \(error)")
self._handleWebSocketError(error)
case .success(let message):
self._failure = false
switch message {
case .string(let deviceId):
print("device id = \(StoreCenter.main.deviceId()), origin id: \(deviceId)")
@ -107,11 +111,14 @@ class WebSocketManager: ObservableObject {
private func _ping() {
self._webSocketTask?.sendPing { error in
// Logger.log("ping sent. Error?: \(error?.localizedDescription ?? "none") ")
if let error: NSError = error as NSError?,
error.domain == NSPOSIXErrorDomain && error.code == 57 {
Logger.log("ping sent. Error?: \(error.localizedDescription) ")
self._setupWebSocket()
self._pingOk = false
} else {
self._pingOk = true
}
}
}
@ -120,5 +127,11 @@ class WebSocketManager: ObservableObject {
self._webSocketTask?.cancel(with: .goingAway, reason: nil)
self._timer?.invalidate()
}
var pingStatus: Bool {
return self._pingOk
}
var failure: Bool {
return self._failure
}
}

Loading…
Cancel
Save