react-native-kookit 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ANDROID_FTP_UPDATE.md +161 -0
- package/ANDROID_PARAMETER_FIX.md +0 -0
- package/API_UNIFICATION.md +180 -0
- package/FTP_CLIENT_API.md +301 -0
- package/FTP_EXAMPLE_IMPLEMENTATION.md +0 -0
- package/FTP_FILE_LIST_ENHANCEMENT.md +186 -0
- package/FTP_FILE_OPERATIONS.md +0 -0
- package/android/src/main/java/expo/modules/kookit/FtpClient.kt +2 -0
- package/android/src/main/java/expo/modules/kookit/ReactNativeKookitModule.kt +252 -0
- package/build/FtpClient.d.ts +97 -0
- package/build/FtpClient.d.ts.map +1 -0
- package/build/FtpClient.js +199 -0
- package/build/FtpClient.js.map +1 -0
- package/build/ReactNativeKookit.types.d.ts +13 -5
- package/build/ReactNativeKookit.types.d.ts.map +1 -1
- package/build/ReactNativeKookit.types.js.map +1 -1
- package/build/ReactNativeKookitModule.d.ts +54 -12
- package/build/ReactNativeKookitModule.d.ts.map +1 -1
- package/build/ReactNativeKookitModule.js.map +1 -1
- package/build/index.d.ts +4 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -3
- package/build/index.js.map +1 -1
- package/ios/ReactNativeKookitModule.swift +188 -36
- package/package.json +1 -1
|
@@ -803,7 +803,7 @@ public class ReactNativeKookitModule: Module {
|
|
|
803
803
|
private var volumeObserver: NSKeyValueObservation?
|
|
804
804
|
private var isVolumeKeyInterceptionEnabled = false
|
|
805
805
|
private var previousVolume: Float = 0.0
|
|
806
|
-
private var
|
|
806
|
+
private var ftpClients: [String: FtpClient] = [:] // Store multiple FTP clients by ID
|
|
807
807
|
|
|
808
808
|
// Each module class must implement the definition function. The definition consists of components
|
|
809
809
|
// that describes the module's functionality and behavior.
|
|
@@ -846,8 +846,31 @@ public class ReactNativeKookitModule: Module {
|
|
|
846
846
|
self.disableVolumeKeyInterception()
|
|
847
847
|
}
|
|
848
848
|
|
|
849
|
-
// FTP
|
|
850
|
-
AsyncFunction("
|
|
849
|
+
// New FTP Client API - Create new FTP client instance
|
|
850
|
+
AsyncFunction("createFtpClient") { (clientId: String, promise: Promise) in
|
|
851
|
+
if self.ftpClients[clientId] != nil {
|
|
852
|
+
promise.reject("FTP_CLIENT_EXISTS", "FTP client with ID '\(clientId)' already exists")
|
|
853
|
+
return
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
let ftpClient = FtpClient()
|
|
857
|
+
let progressDelegate = FtpProgressDelegateImpl(module: self, clientId: clientId)
|
|
858
|
+
ftpClient.setProgressDelegate(progressDelegate)
|
|
859
|
+
self.ftpClients[clientId] = ftpClient
|
|
860
|
+
|
|
861
|
+
promise.resolve([
|
|
862
|
+
"clientId": clientId,
|
|
863
|
+
"created": true
|
|
864
|
+
])
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Connect FTP client
|
|
868
|
+
AsyncFunction("ftpClientConnect") { (clientId: String, config: [String: Any], promise: Promise) in
|
|
869
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
870
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
871
|
+
return
|
|
872
|
+
}
|
|
873
|
+
|
|
851
874
|
Task {
|
|
852
875
|
do {
|
|
853
876
|
let ftpConfig = FtpConnectionConfig(
|
|
@@ -859,30 +882,60 @@ public class ReactNativeKookitModule: Module {
|
|
|
859
882
|
timeout: config["timeout"] as? TimeInterval ?? 30.0
|
|
860
883
|
)
|
|
861
884
|
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
promise.resolve()
|
|
885
|
+
try await ftpClient.connect(config: ftpConfig)
|
|
886
|
+
promise.resolve([
|
|
887
|
+
"clientId": clientId,
|
|
888
|
+
"connected": true
|
|
889
|
+
])
|
|
868
890
|
} catch {
|
|
869
891
|
promise.reject("FTP_CONNECT_ERROR", error.localizedDescription)
|
|
870
892
|
}
|
|
871
893
|
}
|
|
872
894
|
}
|
|
873
895
|
|
|
874
|
-
|
|
896
|
+
// Disconnect FTP client
|
|
897
|
+
AsyncFunction("ftpClientDisconnect") { (clientId: String, promise: Promise) in
|
|
898
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
899
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
900
|
+
return
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
Task {
|
|
904
|
+
await ftpClient.disconnect()
|
|
905
|
+
promise.resolve([
|
|
906
|
+
"clientId": clientId,
|
|
907
|
+
"disconnected": true
|
|
908
|
+
])
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// Dispose FTP client
|
|
913
|
+
AsyncFunction("disposeFtpClient") { (clientId: String, promise: Promise) in
|
|
914
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
915
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
916
|
+
return
|
|
917
|
+
}
|
|
918
|
+
|
|
875
919
|
Task {
|
|
876
|
-
await
|
|
877
|
-
self.
|
|
878
|
-
promise.resolve(
|
|
920
|
+
await ftpClient.disconnect()
|
|
921
|
+
self.ftpClients.removeValue(forKey: clientId)
|
|
922
|
+
promise.resolve([
|
|
923
|
+
"clientId": clientId,
|
|
924
|
+
"disposed": true
|
|
925
|
+
])
|
|
879
926
|
}
|
|
880
927
|
}
|
|
881
928
|
|
|
882
|
-
|
|
929
|
+
// List files
|
|
930
|
+
AsyncFunction("ftpClientList") { (clientId: String, path: String?, promise: Promise) in
|
|
931
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
932
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
933
|
+
return
|
|
934
|
+
}
|
|
935
|
+
|
|
883
936
|
Task {
|
|
884
937
|
do {
|
|
885
|
-
let files = try await
|
|
938
|
+
let files = try await ftpClient.listFiles(path: path)
|
|
886
939
|
let result = files.map { file in
|
|
887
940
|
[
|
|
888
941
|
"name": file.name,
|
|
@@ -899,72 +952,163 @@ public class ReactNativeKookitModule: Module {
|
|
|
899
952
|
}
|
|
900
953
|
}
|
|
901
954
|
|
|
902
|
-
|
|
955
|
+
// Download file
|
|
956
|
+
AsyncFunction("ftpClientDownload") { (clientId: String, remotePath: String, localPath: String, promise: Promise) in
|
|
957
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
958
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
959
|
+
return
|
|
960
|
+
}
|
|
961
|
+
|
|
903
962
|
Task {
|
|
904
963
|
do {
|
|
905
|
-
try await
|
|
906
|
-
promise.resolve(
|
|
964
|
+
try await ftpClient.downloadFile(remotePath: remotePath, localPath: localPath)
|
|
965
|
+
promise.resolve([
|
|
966
|
+
"clientId": clientId,
|
|
967
|
+
"remotePath": remotePath,
|
|
968
|
+
"localPath": localPath,
|
|
969
|
+
"downloaded": true
|
|
970
|
+
])
|
|
907
971
|
} catch {
|
|
908
972
|
promise.reject("FTP_DOWNLOAD_ERROR", error.localizedDescription)
|
|
909
973
|
}
|
|
910
974
|
}
|
|
911
975
|
}
|
|
912
976
|
|
|
913
|
-
|
|
977
|
+
// Upload file
|
|
978
|
+
AsyncFunction("ftpClientUpload") { (clientId: String, localPath: String, remotePath: String, promise: Promise) in
|
|
979
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
980
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
981
|
+
return
|
|
982
|
+
}
|
|
983
|
+
|
|
914
984
|
Task {
|
|
915
985
|
do {
|
|
916
|
-
try await
|
|
917
|
-
promise.resolve(
|
|
986
|
+
try await ftpClient.uploadFile(localPath: localPath, remotePath: remotePath)
|
|
987
|
+
promise.resolve([
|
|
988
|
+
"clientId": clientId,
|
|
989
|
+
"localPath": localPath,
|
|
990
|
+
"remotePath": remotePath,
|
|
991
|
+
"uploaded": true
|
|
992
|
+
])
|
|
918
993
|
} catch {
|
|
919
994
|
promise.reject("FTP_UPLOAD_ERROR", error.localizedDescription)
|
|
920
995
|
}
|
|
921
996
|
}
|
|
922
997
|
}
|
|
923
998
|
|
|
924
|
-
|
|
999
|
+
// Delete file
|
|
1000
|
+
AsyncFunction("ftpClientDelete") { (clientId: String, remotePath: String, isDirectory: Bool?, promise: Promise) in
|
|
1001
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
1002
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
1003
|
+
return
|
|
1004
|
+
}
|
|
1005
|
+
|
|
925
1006
|
Task {
|
|
926
1007
|
do {
|
|
927
|
-
try await
|
|
928
|
-
promise.resolve(
|
|
1008
|
+
try await ftpClient.deleteFile(remotePath: remotePath, isDirectory: isDirectory ?? false)
|
|
1009
|
+
promise.resolve([
|
|
1010
|
+
"clientId": clientId,
|
|
1011
|
+
"remotePath": remotePath,
|
|
1012
|
+
"deleted": true
|
|
1013
|
+
])
|
|
929
1014
|
} catch {
|
|
930
1015
|
promise.reject("FTP_DELETE_ERROR", error.localizedDescription)
|
|
931
1016
|
}
|
|
932
1017
|
}
|
|
933
1018
|
}
|
|
934
1019
|
|
|
935
|
-
|
|
1020
|
+
// Create directory
|
|
1021
|
+
AsyncFunction("ftpClientCreateDirectory") { (clientId: String, remotePath: String, promise: Promise) in
|
|
1022
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
1023
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
1024
|
+
return
|
|
1025
|
+
}
|
|
1026
|
+
|
|
936
1027
|
Task {
|
|
937
1028
|
do {
|
|
938
|
-
try await
|
|
939
|
-
promise.resolve(
|
|
1029
|
+
try await ftpClient.createDirectory(remotePath: remotePath)
|
|
1030
|
+
promise.resolve([
|
|
1031
|
+
"clientId": clientId,
|
|
1032
|
+
"remotePath": remotePath,
|
|
1033
|
+
"created": true
|
|
1034
|
+
])
|
|
940
1035
|
} catch {
|
|
941
1036
|
promise.reject("FTP_CREATE_DIR_ERROR", error.localizedDescription)
|
|
942
1037
|
}
|
|
943
1038
|
}
|
|
944
1039
|
}
|
|
945
1040
|
|
|
946
|
-
|
|
1041
|
+
// Change directory
|
|
1042
|
+
AsyncFunction("ftpClientChangeDirectory") { (clientId: String, remotePath: String, promise: Promise) in
|
|
1043
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
1044
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
1045
|
+
return
|
|
1046
|
+
}
|
|
1047
|
+
|
|
947
1048
|
Task {
|
|
948
1049
|
do {
|
|
949
|
-
try await
|
|
950
|
-
promise.resolve(
|
|
1050
|
+
try await ftpClient.changeDirectory(remotePath: remotePath)
|
|
1051
|
+
promise.resolve([
|
|
1052
|
+
"clientId": clientId,
|
|
1053
|
+
"currentDirectory": remotePath,
|
|
1054
|
+
"changed": true
|
|
1055
|
+
])
|
|
951
1056
|
} catch {
|
|
952
1057
|
promise.reject("FTP_CHANGE_DIR_ERROR", error.localizedDescription)
|
|
953
1058
|
}
|
|
954
1059
|
}
|
|
955
1060
|
}
|
|
956
1061
|
|
|
957
|
-
|
|
1062
|
+
// Get current directory
|
|
1063
|
+
AsyncFunction("ftpClientGetCurrentDirectory") { (clientId: String, promise: Promise) in
|
|
1064
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
1065
|
+
promise.reject("FTP_CLIENT_NOT_FOUND", "FTP client with ID '\(clientId)' not found")
|
|
1066
|
+
return
|
|
1067
|
+
}
|
|
1068
|
+
|
|
958
1069
|
Task {
|
|
959
1070
|
do {
|
|
960
|
-
let currentDir = try await
|
|
961
|
-
promise.resolve(
|
|
1071
|
+
let currentDir = try await ftpClient.getCurrentDirectory()
|
|
1072
|
+
promise.resolve([
|
|
1073
|
+
"clientId": clientId,
|
|
1074
|
+
"currentDirectory": currentDir
|
|
1075
|
+
])
|
|
962
1076
|
} catch {
|
|
963
1077
|
promise.reject("FTP_PWD_ERROR", error.localizedDescription)
|
|
964
1078
|
}
|
|
965
1079
|
}
|
|
966
1080
|
}
|
|
967
1081
|
|
|
1082
|
+
// Get FTP client status
|
|
1083
|
+
AsyncFunction("getFtpClientStatus") { (clientId: String, promise: Promise) in
|
|
1084
|
+
guard let ftpClient = self.ftpClients[clientId] else {
|
|
1085
|
+
promise.resolve([
|
|
1086
|
+
"exists": false,
|
|
1087
|
+
"connected": false
|
|
1088
|
+
])
|
|
1089
|
+
return
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
promise.resolve([
|
|
1093
|
+
"exists": true,
|
|
1094
|
+
"connected": ftpClient.isConnected
|
|
1095
|
+
])
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// List all FTP clients
|
|
1099
|
+
AsyncFunction("listFtpClients") { (promise: Promise) in
|
|
1100
|
+
let clientsInfo = self.ftpClients.mapValues { client in
|
|
1101
|
+
[
|
|
1102
|
+
"connected": client.isConnected
|
|
1103
|
+
]
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
promise.resolve([
|
|
1107
|
+
"clients": clientsInfo,
|
|
1108
|
+
"count": self.ftpClients.count
|
|
1109
|
+
])
|
|
1110
|
+
}
|
|
1111
|
+
|
|
968
1112
|
// Enables the module to be used as a native view. Definition components that are accepted as part of
|
|
969
1113
|
// the view definition: Prop, Events.
|
|
970
1114
|
View(ReactNativeKookitView.self) {
|
|
@@ -1063,14 +1207,17 @@ public class ReactNativeKookitModule: Module {
|
|
|
1063
1207
|
// Helper class to handle FTP progress callbacks
|
|
1064
1208
|
private class FtpProgressDelegateImpl: FtpProgressDelegate {
|
|
1065
1209
|
weak var module: ReactNativeKookitModule?
|
|
1210
|
+
let clientId: String
|
|
1066
1211
|
|
|
1067
|
-
init(module: ReactNativeKookitModule) {
|
|
1212
|
+
init(module: ReactNativeKookitModule, clientId: String) {
|
|
1068
1213
|
self.module = module
|
|
1214
|
+
self.clientId = clientId
|
|
1069
1215
|
}
|
|
1070
1216
|
|
|
1071
1217
|
func onProgress(transferred: Int64, total: Int64) {
|
|
1072
1218
|
let percentage = total > 0 ? Int((transferred * 100) / total) : 0
|
|
1073
1219
|
module?.sendEvent("onFtpProgress", [
|
|
1220
|
+
"clientId": clientId,
|
|
1074
1221
|
"transferred": transferred,
|
|
1075
1222
|
"total": total,
|
|
1076
1223
|
"percentage": percentage
|
|
@@ -1078,10 +1225,15 @@ private class FtpProgressDelegateImpl: FtpProgressDelegate {
|
|
|
1078
1225
|
}
|
|
1079
1226
|
|
|
1080
1227
|
func onComplete() {
|
|
1081
|
-
module?.sendEvent("onFtpComplete"
|
|
1228
|
+
module?.sendEvent("onFtpComplete", [
|
|
1229
|
+
"clientId": clientId
|
|
1230
|
+
])
|
|
1082
1231
|
}
|
|
1083
1232
|
|
|
1084
1233
|
func onError(error: String) {
|
|
1085
|
-
module?.sendEvent("onFtpError", [
|
|
1234
|
+
module?.sendEvent("onFtpError", [
|
|
1235
|
+
"clientId": clientId,
|
|
1236
|
+
"error": error
|
|
1237
|
+
])
|
|
1086
1238
|
}
|
|
1087
1239
|
}
|
package/package.json
CHANGED