Skip to content

Commit

Permalink
fix: list item size, bump sdk, ios fpe
Browse files Browse the repository at this point in the history
  • Loading branch information
Dwynr committed Jun 7, 2024
1 parent 0b70ca2 commit 3248f7b
Show file tree
Hide file tree
Showing 13 changed files with 362 additions and 146 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ android {
applicationId "io.filen.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2072
versionName "2.0.72"
versionCode 2073
versionName "2.0.73"
}

splits {
Expand Down
146 changes: 38 additions & 108 deletions ios/FileProviderExt/FileProviderEnumerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ import Alamofire

class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
private let identifier: NSFileProviderItemIdentifier
private let uploadsRangeData = "\"data\":{\"uploads\":[".data(using: .utf8)!
private let foldersRangeData = "],\"folders\":[".data(using: .utf8)!
private let closingRangeData = "}".data(using: .utf8)!
private let openingRangeData = "{".data(using: .utf8)!
private let commaData = ",".data(using: .utf8)!
private let endData = "]}}".data(using: .utf8)!
private let statusFalseData = "\"status\":false".data(using: .utf8)!

init (identifier: NSFileProviderItemIdentifier) {
self.identifier = identifier
Expand Down Expand Up @@ -223,18 +216,12 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
func enumerateItems(for observer: NSFileProviderEnumerationObserver, startingAt page: NSFileProviderPage) {
Task {
do {
guard let rootFolderUUID = FileProviderUtils.shared.rootFolderUUID(), let masterKeys = FileProviderUtils.shared.masterKeys(), let apiKey = MMKVInstance.shared.instance?.string(forKey: "apiKey", defaultValue: nil), let url = URL(string: "https://gateway.filen.io/v3/dir/content") else {
guard let rootFolderUUID = FileProviderUtils.shared.rootFolderUUID(), let masterKeys = FileProviderUtils.shared.masterKeys() else {
observer.finishEnumeratingWithError(NSFileProviderError(.notAuthenticated))

return
}

let headers: HTTPHeaders = [
"Authorization": "Bearer \(apiKey)",
"Accept": "application/json",
"Content-Type": "application/json"
]

if FileProviderUtils.shared.needsFaceID() {
observer.finishEnumeratingWithError(NSFileProviderError(.notAuthenticated))

Expand Down Expand Up @@ -282,109 +269,52 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator {
}

let folderUUID = self.identifier == NSFileProviderItemIdentifier.rootContainer || self.identifier.rawValue == "root" || self.identifier.rawValue == NSFileProviderItemIdentifier.rootContainer.rawValue ? rootFolderUUID : self.identifier.rawValue
let tempJSONFileURL = try await FileProviderUtils.shared.sessionManager.download(url, method: .post, parameters: ["uuid": folderUUID], encoding: JSONEncoding.default, headers: headers){ $0.timeoutInterval = 3600 }.validate().serializingDownloadedFileURL().value
var didEnumerate = false

defer {
do {
if FileManager.default.fileExists(atPath: tempJSONFileURL.path) {
try FileManager.default.removeItem(atPath: tempJSONFileURL.path)
}
} catch {
print("[enumerateItems] error:", error)
}
let content = try await FileProviderUtils.shared.fetchFolderContents(uuid: folderUUID)

if !content.status {
observer.finishEnumeratingWithError(NSFileProviderError(.serverUnreachable))

return
}

guard let inputStream = InputStream(url: tempJSONFileURL) else {
throw NSError(domain: "enumerateItems", code: 1, userInfo: nil)
if content.data == nil {
observer.finishEnumeratingWithError(NSFileProviderError(.serverUnreachable))

return
}

inputStream.open()
var existingNames: [String: Bool] = [:]

defer {
inputStream.close()
for folder in content.data!.folders {
let processed = try self.processFolder(folder: folder, masterKeys: masterKeys)

if (processed.item.name.count > 0) {
let lowercaseName = processed.item.name.lowercased()

if (existingNames[lowercaseName] == nil) {
existingNames[lowercaseName] = true

observer.didEnumerate([processed])

didEnumerate = true
}
}
}

let bufferSize = 1024
var buffer = [UInt8](repeating: 0, count: bufferSize)
var accumulatedData = Data()
var currentState: FetchFolderContentJSONParseState = .lookingForData
var didParseFiles = false
var didEnumerate = false

while inputStream.hasBytesAvailable || accumulatedData.count > 0 {
autoreleasepool {
let bytesRead = inputStream.read(&buffer, maxLength: bufferSize)
for file in content.data!.uploads {
let processed = try self.processFile(file: file, masterKeys: masterKeys)

if (processed.item.name.count > 0) {
let lowercaseName = processed.item.name.lowercased()

if bytesRead > 0 || accumulatedData.count > 0 {
if bytesRead > 0 {
accumulatedData.append(contentsOf: buffer[0..<bytesRead])
}

switch currentState {
case .lookingForData:
if let dataRange = accumulatedData.range(of: self.statusFalseData) {
break
}

if let dataRange = accumulatedData.range(of: self.uploadsRangeData) {
accumulatedData.removeSubrange(0..<dataRange.endIndex)

currentState = .parsingData
} else {
break
}

case .parsingData:
if let foldersRange = accumulatedData.range(of: self.foldersRangeData) {
accumulatedData.removeSubrange(foldersRange.startIndex..<foldersRange.endIndex)
}

if let endRange = accumulatedData.range(of: self.endData) {
accumulatedData.removeSubrange(endRange.startIndex..<endRange.endIndex)
}

while let endIndex = accumulatedData.range(of: self.closingRangeData) {
autoreleasepool {
var data = accumulatedData[0..<endIndex.endIndex]

if data.prefix(1) == self.commaData {
data.remove(at: 0)
}

if data.prefix(1) != self.openingRangeData && data.suffix(1) != self.closingRangeData {
accumulatedData.removeSubrange(0..<endIndex.endIndex)
} else {
do {
if !didParseFiles, let file = try? FileProviderUtils.shared.jsonDecoder.decode(FetchFolderContentsFile.self, from: data) {
let processed = try self.processFile(file: file, masterKeys: masterKeys)

if (processed.item.name.count > 0) {
observer.didEnumerate([processed])

didEnumerate = true
}
} else {
if let folder = try? FileProviderUtils.shared.jsonDecoder.decode(FetchFolderContentsFolder.self, from: data) {
didParseFiles = true

let processed = try self.processFolder(folder: folder, masterKeys: masterKeys)

if (processed.item.name.count > 0) {
observer.didEnumerate([processed])

didEnumerate = true
}
}
}
} catch {
print("[enumerateItems] error:", error)
}

accumulatedData.removeSubrange(0..<endIndex.endIndex)
}
}
}
}
if (existingNames[lowercaseName] == nil) {
existingNames[lowercaseName] = true

observer.didEnumerate([processed])

didEnumerate = true
}
}
}
Expand Down
32 changes: 31 additions & 1 deletion ios/FileProviderExt/FileProviderUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class FileProviderUtils {
autoreleasepool {
let userId = self.userId()

guard let loggedIn = MMKVInstance.shared.instance?.bool(forKey: "isLoggedIn", defaultValue: false), let lockAppAfterVal = MMKVInstance.shared.instance?.double(forKey: "lockAppAfter:" + String(userId), defaultValue: 0), let lastBiometricScreen = MMKVInstance.shared.instance?.double(forKey: "lastBiometricScreen:" + String(userId), defaultValue: 0), let biometricPinAuth = MMKVInstance.shared.instance?.bool(forKey: "biometricPinAuth" + String(userId), defaultValue: false) else {
guard let loggedIn = MMKVInstance.shared.instance?.bool(forKey: "isLoggedIn", defaultValue: false), let lockAppAfterVal = MMKVInstance.shared.instance?.double(forKey: "lockAppAfter:" + String(userId), defaultValue: 0), let lastBiometricScreen = MMKVInstance.shared.instance?.double(forKey: "lastBiometricScreen:" + String(userId), defaultValue: 0), let biometricPinAuth = MMKVInstance.shared.instance?.bool(forKey: "biometricPinAuth:" + String(userId), defaultValue: false) else {
return false
}

Expand Down Expand Up @@ -586,6 +586,10 @@ class FileProviderUtils {
func signalEnumeratorForIdentifier (for identifier: NSFileProviderItemIdentifier) -> Void {
Task {
do {
guard FunctionRateLimiter.shared.shouldAllowExecution(for: identifier) else {
return
}

guard let rootFolderUUID = self.rootFolderUUID() else {
throw NSFileProviderError(.notAuthenticated)
}
Expand Down Expand Up @@ -1403,6 +1407,32 @@ class FileProviderUtils {
}
}

class FunctionRateLimiter {
private var lastExecutionTimes: [NSFileProviderItemIdentifier: Date] = [:]
private let queue = DispatchQueue(label: "io.filen.app.functionRatelimiter")

public static let shared: FunctionRateLimiter = {
let instance = FunctionRateLimiter()

return instance
}()

func shouldAllowExecution(for identifier: NSFileProviderItemIdentifier) -> Bool {
let now = Date()
let oneSecond: TimeInterval = 1.0

return queue.sync {
if let lastExecutionTime = lastExecutionTimes[identifier], now.timeIntervalSince(lastExecutionTime) < oneSecond {
return false
} else {
lastExecutionTimes[identifier] = now

return true
}
}
}
}

struct BodyStringEncoding: ParameterEncoding {
private let body: String

Expand Down
8 changes: 4 additions & 4 deletions ios/Filen.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Filen/Filen.entitlements;
CURRENT_PROJECT_VERSION = 2072;
CURRENT_PROJECT_VERSION = 2073;
DEVELOPMENT_TEAM = 7YTW5D2K7P;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Filen/Info.plist;
Expand All @@ -941,7 +941,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.0.72;
MARKETING_VERSION = 2.0.73;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -969,15 +969,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Filen/Filen.entitlements;
CURRENT_PROJECT_VERSION = 2072;
CURRENT_PROJECT_VERSION = 2073;
DEVELOPMENT_TEAM = 7YTW5D2K7P;
INFOPLIST_FILE = Filen/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 2.0.72;
MARKETING_VERSION = 2.0.73;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
launchAutomaticallySubstyle = "2"
queueDebuggingEnabled = "No"
memoryGraphOnResourceException = "Yes">
<RemoteRunnable
runnableDebuggingMode = "1"
BundleIdentifier = "com.apple.DocumentsApp"
RemotePath = "/Library/Developer/CoreSimulator/Volumes/iOS_21F79/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.5.simruntime/Contents/Resources/RuntimeRoot/Applications/Files.app">
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
Expand Down
24 changes: 12 additions & 12 deletions nodejs-assets/nodejs-project/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const pathModule = require("path")
const { Readable } = require("stream")
const heicConvert = require("heic-convert")
const progress = require("progress-stream")
const FilenSDK = require("@filen/sdk")
const { FilenSDK } = require("@filen/sdk")

const axiosClient = axios.create({
timeout: 3600000,
Expand Down Expand Up @@ -166,7 +166,7 @@ const loadItemsSemaphore = new Semaphore(32)
* @type {FilenSDK.default}
* @const
*/
let filen = new FilenSDK({})
let filen = new FilenSDK()

const buildTransfers = () => {
try {
Expand Down Expand Up @@ -2110,10 +2110,10 @@ const loadItems = async ({ url, offlinePath, thumbnailPath, uuid, receiverId, so

resolve()
})
.catch(err => {
.catch(() => {
loadItemsSemaphore.release()

reject(err)
resolve()
})
})
.catch(reject)
Expand Down Expand Up @@ -2219,10 +2219,10 @@ const loadItems = async ({ url, offlinePath, thumbnailPath, uuid, receiverId, so

resolve()
})
.catch(err => {
.catch(() => {
loadItemsSemaphore.release()

reject(err)
resolve()
})
}
})
Expand Down Expand Up @@ -2329,10 +2329,10 @@ const loadItems = async ({ url, offlinePath, thumbnailPath, uuid, receiverId, so

resolve()
})
.catch(err => {
.catch(() => {
loadItemsSemaphore.release()

reject(err)
resolve()
})
}
})
Expand Down Expand Up @@ -2411,10 +2411,10 @@ const loadItems = async ({ url, offlinePath, thumbnailPath, uuid, receiverId, so

resolve()
})
.catch(err => {
.catch(() => {
loadItemsSemaphore.release()

reject(err)
resolve()
})
})
.catch(reject)
Expand Down Expand Up @@ -2520,10 +2520,10 @@ const loadItems = async ({ url, offlinePath, thumbnailPath, uuid, receiverId, so

resolve()
})
.catch(err => {
.catch(() => {
loadItemsSemaphore.release()

reject(err)
resolve()
})
}
})
Expand Down
Loading

0 comments on commit 3248f7b

Please sign in to comment.