react-native-kookit 0.3.1 → 0.3.3
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/SMB_CLIENT_STATIC_METHODS.md +175 -0
- package/android/src/main/java/expo/modules/kookit/FtpClient.kt +56 -11
- package/android/src/main/java/expo/modules/kookit/ReactNativeKookitModule.kt +17 -0
- package/build/FtpClient.d.ts +5 -0
- package/build/FtpClient.d.ts.map +1 -1
- package/build/FtpClient.js +15 -0
- package/build/FtpClient.js.map +1 -1
- package/build/SmbClient.d.ts +40 -0
- package/build/SmbClient.d.ts.map +1 -1
- package/build/SmbClient.js +91 -0
- package/build/SmbClient.js.map +1 -1
- package/ios/ReactNativeKookitModule.swift +67 -36
- package/package.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# SMB Client 静态方法使用示例
|
|
2
|
+
|
|
3
|
+
SmbClient新增了多个静态方法来管理多个客户端实例:
|
|
4
|
+
|
|
5
|
+
## 新增的静态方法
|
|
6
|
+
|
|
7
|
+
### 1. `SmbClient.disposeClient(clientId: string)`
|
|
8
|
+
|
|
9
|
+
销毁指定客户端ID的客户端实例
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// 销毁特定的客户端
|
|
13
|
+
const disposed = await SmbClient.disposeClient("my_client_id");
|
|
14
|
+
console.log("Client disposed:", disposed); // true/false
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. `SmbClient.getClientStatus(clientId: string)`
|
|
18
|
+
|
|
19
|
+
获取指定客户端ID的状态信息
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// 获取客户端状态
|
|
23
|
+
const status = SmbClient.getClientStatus("my_client_id");
|
|
24
|
+
console.log("Client status:", status);
|
|
25
|
+
// 返回: {
|
|
26
|
+
// exists: true,
|
|
27
|
+
// isConnected: true,
|
|
28
|
+
// currentShare: 'C$',
|
|
29
|
+
// isDisposed: false
|
|
30
|
+
// }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 3. `SmbClient.getAllClientsStatus()`
|
|
34
|
+
|
|
35
|
+
获取所有活跃客户端的状态
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// 获取所有客户端状态
|
|
39
|
+
const allStatus = SmbClient.getAllClientsStatus();
|
|
40
|
+
allStatus.forEach((status, clientId) => {
|
|
41
|
+
console.log(`Client ${clientId}:`, status);
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 4. `SmbClient.getInstance(clientId: string)`
|
|
46
|
+
|
|
47
|
+
获取指定客户端ID的实例对象
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// 获取现有的客户端实例
|
|
51
|
+
const existingClient = SmbClient.getInstance("my_client_id");
|
|
52
|
+
if (existingClient) {
|
|
53
|
+
await existingClient.listFiles("/");
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 5. `SmbClient.disposeAllClients()`
|
|
58
|
+
|
|
59
|
+
销毁所有客户端实例
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// 清理所有客户端
|
|
63
|
+
const disposedCount = await SmbClient.disposeAllClients();
|
|
64
|
+
console.log(`Disposed ${disposedCount} clients`);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 使用示例
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import SmbClient from "react-native-kookit";
|
|
71
|
+
|
|
72
|
+
export class SmbManager {
|
|
73
|
+
private clients: Map<string, SmbClient> = new Map();
|
|
74
|
+
|
|
75
|
+
// 创建命名客户端
|
|
76
|
+
async createNamedClient(
|
|
77
|
+
name: string,
|
|
78
|
+
config: SmbConnectionConfig
|
|
79
|
+
): Promise<SmbClient> {
|
|
80
|
+
const client = await SmbClient.create(name);
|
|
81
|
+
await client.connect(config);
|
|
82
|
+
this.clients.set(name, client);
|
|
83
|
+
return client;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 检查客户端是否存在且连接
|
|
87
|
+
isClientReady(name: string): boolean {
|
|
88
|
+
const status = SmbClient.getClientStatus(name);
|
|
89
|
+
return status.exists && status.isConnected && !status.isDisposed;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 安全获取客户端
|
|
93
|
+
getClient(name: string): SmbClient | null {
|
|
94
|
+
if (this.isClientReady(name)) {
|
|
95
|
+
return SmbClient.getInstance(name);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 销毁指定客户端
|
|
101
|
+
async removeClient(name: string): Promise<boolean> {
|
|
102
|
+
this.clients.delete(name);
|
|
103
|
+
return await SmbClient.disposeClient(name);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 获取所有客户端状态报告
|
|
107
|
+
getStatusReport(): Record<string, any> {
|
|
108
|
+
const report: Record<string, any> = {};
|
|
109
|
+
const allStatus = SmbClient.getAllClientsStatus();
|
|
110
|
+
|
|
111
|
+
allStatus.forEach((status, clientId) => {
|
|
112
|
+
report[clientId] = {
|
|
113
|
+
...status,
|
|
114
|
+
managed: this.clients.has(clientId),
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return report;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 清理所有资源
|
|
122
|
+
async cleanup(): Promise<void> {
|
|
123
|
+
this.clients.clear();
|
|
124
|
+
await SmbClient.disposeAllClients();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 使用示例
|
|
129
|
+
const smbManager = new SmbManager();
|
|
130
|
+
|
|
131
|
+
// 创建多个客户端
|
|
132
|
+
const client1 = await smbManager.createNamedClient("server1", {
|
|
133
|
+
host: "192.168.1.100",
|
|
134
|
+
username: "user1",
|
|
135
|
+
password: "pass1",
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const client2 = await smbManager.createNamedClient("server2", {
|
|
139
|
+
host: "192.168.1.101",
|
|
140
|
+
username: "user2",
|
|
141
|
+
password: "pass2",
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// 检查状态
|
|
145
|
+
console.log("Status report:", smbManager.getStatusReport());
|
|
146
|
+
|
|
147
|
+
// 使用特定客户端
|
|
148
|
+
const client = smbManager.getClient("server1");
|
|
149
|
+
if (client) {
|
|
150
|
+
const files = await client.listFiles("/");
|
|
151
|
+
console.log("Files:", files);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 清理资源
|
|
155
|
+
await smbManager.cleanup();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 类型定义
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
export interface SmbClientStatus {
|
|
162
|
+
exists: boolean;
|
|
163
|
+
isConnected: boolean;
|
|
164
|
+
currentShare: string | null;
|
|
165
|
+
isDisposed: boolean;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface SmbClientInfo {
|
|
169
|
+
isConnected: boolean;
|
|
170
|
+
currentShare: string | null;
|
|
171
|
+
isDisposed: boolean;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
这些静态方法使得SmbClient的多实例管理变得更加简单和安全。
|
|
@@ -14,7 +14,7 @@ data class FtpConnectionConfig(
|
|
|
14
14
|
val username: String,
|
|
15
15
|
val password: String,
|
|
16
16
|
val passive: Boolean = true,
|
|
17
|
-
val timeout: Int =
|
|
17
|
+
val timeout: Int = 0
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
data class FtpFileInfo(
|
|
@@ -39,7 +39,33 @@ class FtpClient {
|
|
|
39
39
|
private var config: FtpConnectionConfig? = null
|
|
40
40
|
private var useUtf8 = false
|
|
41
41
|
|
|
42
|
-
fun isConnected(): Boolean = isConnected
|
|
42
|
+
fun isConnected(): Boolean = isConnected && isControlSocketAlive()
|
|
43
|
+
|
|
44
|
+
private fun isControlSocketAlive(): Boolean {
|
|
45
|
+
return try {
|
|
46
|
+
controlSocket?.let { socket ->
|
|
47
|
+
!socket.isClosed && socket.isConnected && !socket.isInputShutdown && !socket.isOutputShutdown
|
|
48
|
+
} ?: false
|
|
49
|
+
} catch (e: Exception) {
|
|
50
|
+
false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Throws(Exception::class)
|
|
55
|
+
suspend fun verifyConnection(): Boolean = withContext(Dispatchers.IO) {
|
|
56
|
+
if (!isConnected) return@withContext false
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// Try to send NOOP command to verify connection
|
|
60
|
+
sendCommand("NOOP")
|
|
61
|
+
val response = readResponse()
|
|
62
|
+
response.startsWith("200") || response.startsWith("250")
|
|
63
|
+
} catch (e: Exception) {
|
|
64
|
+
// Connection is dead, mark as disconnected
|
|
65
|
+
isConnected = false
|
|
66
|
+
false
|
|
67
|
+
}
|
|
68
|
+
}
|
|
43
69
|
|
|
44
70
|
@Throws(Exception::class)
|
|
45
71
|
suspend fun connect(config: FtpConnectionConfig) = withContext(Dispatchers.IO) {
|
|
@@ -128,7 +154,7 @@ class FtpClient {
|
|
|
128
154
|
|
|
129
155
|
@Throws(Exception::class)
|
|
130
156
|
suspend fun listFiles(path: String? = null): List<FtpFileInfo> = withContext(Dispatchers.IO) {
|
|
131
|
-
|
|
157
|
+
ensureConnected()
|
|
132
158
|
|
|
133
159
|
val dataSocket = enterPassiveMode()
|
|
134
160
|
|
|
@@ -171,7 +197,7 @@ class FtpClient {
|
|
|
171
197
|
|
|
172
198
|
@Throws(Exception::class)
|
|
173
199
|
suspend fun downloadFile(remotePath: String, localPath: String, listener: FtpProgressListener? = null) = withContext(Dispatchers.IO) {
|
|
174
|
-
|
|
200
|
+
ensureConnected()
|
|
175
201
|
|
|
176
202
|
val dataSocket = enterPassiveMode()
|
|
177
203
|
val localFile = File(localPath)
|
|
@@ -223,7 +249,7 @@ class FtpClient {
|
|
|
223
249
|
|
|
224
250
|
@Throws(Exception::class)
|
|
225
251
|
suspend fun uploadFile(localPath: String, remotePath: String, listener: FtpProgressListener? = null) = withContext(Dispatchers.IO) {
|
|
226
|
-
|
|
252
|
+
ensureConnected()
|
|
227
253
|
|
|
228
254
|
val localFile = File(localPath)
|
|
229
255
|
if (!localFile.exists()) {
|
|
@@ -276,7 +302,7 @@ class FtpClient {
|
|
|
276
302
|
|
|
277
303
|
@Throws(Exception::class)
|
|
278
304
|
suspend fun deleteFile(remotePath: String, isDirectory: Boolean = false) = withContext(Dispatchers.IO) {
|
|
279
|
-
|
|
305
|
+
ensureConnected()
|
|
280
306
|
|
|
281
307
|
val command = if (isDirectory) "RMD $remotePath" else "DELE $remotePath"
|
|
282
308
|
sendCommand(command)
|
|
@@ -288,7 +314,7 @@ class FtpClient {
|
|
|
288
314
|
|
|
289
315
|
@Throws(Exception::class)
|
|
290
316
|
suspend fun createDirectory(remotePath: String) = withContext(Dispatchers.IO) {
|
|
291
|
-
|
|
317
|
+
ensureConnected()
|
|
292
318
|
|
|
293
319
|
sendCommand("MKD $remotePath")
|
|
294
320
|
val response = readResponse()
|
|
@@ -299,7 +325,7 @@ class FtpClient {
|
|
|
299
325
|
|
|
300
326
|
@Throws(Exception::class)
|
|
301
327
|
suspend fun changeDirectory(remotePath: String) = withContext(Dispatchers.IO) {
|
|
302
|
-
|
|
328
|
+
ensureConnected()
|
|
303
329
|
|
|
304
330
|
sendCommand("CWD $remotePath")
|
|
305
331
|
val response = readResponse()
|
|
@@ -310,7 +336,7 @@ class FtpClient {
|
|
|
310
336
|
|
|
311
337
|
@Throws(Exception::class)
|
|
312
338
|
suspend fun getCurrentDirectory(): String = withContext(Dispatchers.IO) {
|
|
313
|
-
|
|
339
|
+
ensureConnected()
|
|
314
340
|
|
|
315
341
|
sendCommand("PWD")
|
|
316
342
|
val response = readResponse()
|
|
@@ -347,6 +373,25 @@ class FtpClient {
|
|
|
347
373
|
}
|
|
348
374
|
|
|
349
375
|
@Throws(Exception::class)
|
|
376
|
+
private suspend fun ensureConnected() {
|
|
377
|
+
if (!isConnected) {
|
|
378
|
+
throw Exception("Not connected to FTP server")
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Verify the connection is still alive
|
|
382
|
+
if (!verifyConnection()) {
|
|
383
|
+
// Try to reconnect
|
|
384
|
+
config?.let { cfg ->
|
|
385
|
+
try {
|
|
386
|
+
disconnect() // Clean up the dead connection
|
|
387
|
+
connect(cfg) // Reconnect
|
|
388
|
+
} catch (e: Exception) {
|
|
389
|
+
throw Exception("Connection lost and reconnection failed: ${e.message}")
|
|
390
|
+
}
|
|
391
|
+
} ?: throw Exception("Connection lost and no config available for reconnection")
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
350
395
|
private fun enterPassiveMode(): Socket {
|
|
351
396
|
sendCommand("PASV")
|
|
352
397
|
val response = readResponse()
|
|
@@ -365,8 +410,8 @@ class FtpClient {
|
|
|
365
410
|
val port = matcher.group(5)!!.toInt() * 256 + matcher.group(6)!!.toInt()
|
|
366
411
|
|
|
367
412
|
return Socket().apply {
|
|
368
|
-
soTimeout = config?.timeout ?:
|
|
369
|
-
connect(InetSocketAddress(host, port), config?.timeout ?:
|
|
413
|
+
soTimeout = config?.timeout ?: 0
|
|
414
|
+
connect(InetSocketAddress(host, port), config?.timeout ?: 0)
|
|
370
415
|
}
|
|
371
416
|
}
|
|
372
417
|
|
|
@@ -136,6 +136,23 @@ class ReactNativeKookitModule : Module() {
|
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
AsyncFunction("verifyFtpConnection") { clientId: String, promise: Promise ->
|
|
140
|
+
moduleScope.launch {
|
|
141
|
+
try {
|
|
142
|
+
val client = ftpClients[clientId]
|
|
143
|
+
if (client == null) {
|
|
144
|
+
promise.resolve(false)
|
|
145
|
+
return@launch
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
val isConnected = client.verifyConnection()
|
|
149
|
+
promise.resolve(isConnected)
|
|
150
|
+
} catch (e: Exception) {
|
|
151
|
+
promise.reject("FTP_VERIFY_CONNECTION_ERROR", e.message, e)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
139
156
|
AsyncFunction("listFtpClients") { promise: Promise ->
|
|
140
157
|
moduleScope.launch {
|
|
141
158
|
try {
|
package/build/FtpClient.d.ts
CHANGED
|
@@ -76,6 +76,11 @@ export declare class FtpClient {
|
|
|
76
76
|
* Check if the client is connected
|
|
77
77
|
*/
|
|
78
78
|
isConnected(): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Verify the actual FTP connection by testing communication with server
|
|
81
|
+
* This will attempt to send a NOOP command to verify the connection is alive
|
|
82
|
+
*/
|
|
83
|
+
verifyConnection(): Promise<boolean>;
|
|
79
84
|
/**
|
|
80
85
|
* Dispose the FTP client and clean up resources
|
|
81
86
|
*/
|
package/build/FtpClient.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FtpClient.d.ts","sourceRoot":"","sources":["../src/FtpClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EAIZ,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,KAAK,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,kBAAkB,CAAqC;gBAEnD,QAAQ,CAAC,EAAE,MAAM;IAO7B,OAAO,CAAC,mBAAmB;IAoC3B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAIxD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQjD;;OAEG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpE;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlE;;OAEG;IACG,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,WAAW,GAAE,OAAe,GAC3B,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAW5C;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IAUF;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAarC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB9B;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,SAAS,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QAChD,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAIF;;OAEG;WACU,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CAK3D"}
|
|
1
|
+
{"version":3,"file":"FtpClient.d.ts","sourceRoot":"","sources":["../src/FtpClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EAIZ,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,KAAK,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,kBAAkB,CAAqC;gBAEnD,QAAQ,CAAC,EAAE,MAAM;IAO7B,OAAO,CAAC,mBAAmB;IAoC3B;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAIxD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IASzD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAQjC;;OAEG;IACG,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAQjD;;OAEG;IACG,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpE;;OAEG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlE;;OAEG;IACG,MAAM,CACV,UAAU,EAAE,MAAM,EAClB,WAAW,GAAE,OAAe,GAC3B,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAW5C;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,OAAO,CAAC;KACpB,CAAC;IAUF;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAarC;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAY1C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB9B;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YAAE,SAAS,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;QAChD,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAIF;;OAEG;WACU,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;CAK3D"}
|
package/build/FtpClient.js
CHANGED
|
@@ -163,6 +163,21 @@ export class FtpClient {
|
|
|
163
163
|
return false;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Verify the actual FTP connection by testing communication with server
|
|
168
|
+
* This will attempt to send a NOOP command to verify the connection is alive
|
|
169
|
+
*/
|
|
170
|
+
async verifyConnection() {
|
|
171
|
+
if (this.isDisposed) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
return await ReactNativeKookitModule.verifyFtpConnection(this.clientId);
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
166
181
|
/**
|
|
167
182
|
* Dispose the FTP client and clean up resources
|
|
168
183
|
*/
|
package/build/FtpClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FtpClient.js","sourceRoot":"","sources":["../src/FtpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import ReactNativeKookitModule from \"./ReactNativeKookitModule\";\nimport type {\n FtpConnectionConfig,\n FtpFileInfo,\n FtpProgressEvent,\n FtpCompleteEvent,\n FtpErrorEvent,\n} from \"./ReactNativeKookit.types\";\n\nexport interface FtpClientEventHandlers {\n onProgress?: (progress: {\n transferred: number;\n total: number;\n percentage: number;\n }) => void;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport class FtpClient {\n private clientId: string;\n private isDisposed: boolean = false;\n private eventHandlers: FtpClientEventHandlers = {};\n private eventSubscriptions: Array<{ remove: () => void }> = [];\n\n constructor(clientId?: string) {\n this.clientId =\n clientId ||\n `ftp_client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.setupEventListeners();\n }\n\n private setupEventListeners() {\n // Listen to native events and filter by clientId\n const progressSub = ReactNativeKookitModule.addListener(\n \"onFtpProgress\",\n (event: FtpProgressEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onProgress) {\n this.eventHandlers.onProgress({\n transferred: event.transferred,\n total: event.total,\n percentage: event.percentage,\n });\n }\n }\n );\n\n const completeSub = ReactNativeKookitModule.addListener(\n \"onFtpComplete\",\n (event: FtpCompleteEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onComplete) {\n this.eventHandlers.onComplete();\n }\n }\n );\n\n const errorSub = ReactNativeKookitModule.addListener(\n \"onFtpError\",\n (event: FtpErrorEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onError) {\n this.eventHandlers.onError(new Error(event.error));\n }\n }\n );\n\n this.eventSubscriptions = [progressSub, completeSub, errorSub];\n }\n\n /**\n * Set event handlers\n */\n setEventHandlers(handlers: FtpClientEventHandlers): void {\n this.eventHandlers = { ...handlers };\n }\n\n /**\n * Initialize the FTP client instance\n */\n async initialize(): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.createFtpClient(this.clientId);\n }\n\n /**\n * Connect to the FTP server\n */\n async connect(config: FtpConnectionConfig): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n console.log(\"Connecting with config:\", this.clientId, config);\n\n await ReactNativeKookitModule.ftpClientConnect(this.clientId, config);\n }\n\n /**\n * Disconnect from the FTP server\n */\n async disconnect(): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDisconnect(this.clientId);\n }\n\n /**\n * List files in the specified directory\n */\n async list(path?: string): Promise<FtpFileInfo[]> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n return await ReactNativeKookitModule.ftpClientList(this.clientId, path);\n }\n\n /**\n * Download a file from the remote server\n */\n async download(remotePath: string, localPath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDownload(\n this.clientId,\n remotePath,\n localPath\n );\n }\n\n /**\n * Upload a file to the remote server\n */\n async upload(localPath: string, remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientUpload(\n this.clientId,\n localPath,\n remotePath\n );\n }\n\n /**\n * Delete a file or directory on the remote server\n */\n async delete(\n remotePath: string,\n isDirectory: boolean = false\n ): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDelete(\n this.clientId,\n remotePath,\n isDirectory\n );\n }\n\n /**\n * Create a directory on the remote server\n */\n async createDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientCreateDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Change the current working directory on the remote server\n */\n async changeDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientChangeDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Get the current working directory on the remote server\n */\n async getCurrentDirectory(): Promise<string> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n const result = await ReactNativeKookitModule.ftpClientGetCurrentDirectory(\n this.clientId\n );\n return result;\n }\n\n /**\n * Get client status information\n * @returns Client status including existence and connection state\n */\n async getStatus(): Promise<{\n clientId: string;\n exists: boolean;\n connected: boolean;\n }> {\n const status = await ReactNativeKookitModule.getFtpClientStatus(\n this.clientId\n );\n return {\n clientId: this.clientId,\n ...status,\n };\n }\n\n /**\n * Get the client ID\n */\n getClientId(): string {\n return this.clientId;\n }\n\n /**\n * Check if the client is connected\n */\n async isConnected(): Promise<boolean> {\n if (this.isDisposed) {\n return false;\n }\n\n try {\n const status = await this.getStatus();\n return status.exists && status.connected;\n } catch {\n return false;\n }\n }\n\n /**\n * Dispose the FTP client and clean up resources\n */\n async dispose(): Promise<void> {\n if (this.isDisposed) {\n return;\n }\n\n try {\n await ReactNativeKookitModule.disposeFtpClient(this.clientId);\n } catch (error) {\n // Ignore errors during disposal\n }\n\n // Remove event listeners\n this.eventSubscriptions.forEach((sub) => sub.remove());\n this.eventSubscriptions = [];\n\n this.isDisposed = true;\n }\n\n /**\n * Static method to list all FTP clients\n */\n static async listClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }> {\n return ReactNativeKookitModule.listFtpClients();\n }\n\n /**\n * Static method to create and initialize a new FTP client\n */\n static async create(clientId?: string): Promise<FtpClient> {\n const client = new FtpClient(clientId);\n await client.initialize();\n return client;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"FtpClient.js","sourceRoot":"","sources":["../src/FtpClient.ts"],"names":[],"mappings":"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","sourcesContent":["import ReactNativeKookitModule from \"./ReactNativeKookitModule\";\nimport type {\n FtpConnectionConfig,\n FtpFileInfo,\n FtpProgressEvent,\n FtpCompleteEvent,\n FtpErrorEvent,\n} from \"./ReactNativeKookit.types\";\n\nexport interface FtpClientEventHandlers {\n onProgress?: (progress: {\n transferred: number;\n total: number;\n percentage: number;\n }) => void;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport class FtpClient {\n private clientId: string;\n private isDisposed: boolean = false;\n private eventHandlers: FtpClientEventHandlers = {};\n private eventSubscriptions: Array<{ remove: () => void }> = [];\n\n constructor(clientId?: string) {\n this.clientId =\n clientId ||\n `ftp_client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.setupEventListeners();\n }\n\n private setupEventListeners() {\n // Listen to native events and filter by clientId\n const progressSub = ReactNativeKookitModule.addListener(\n \"onFtpProgress\",\n (event: FtpProgressEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onProgress) {\n this.eventHandlers.onProgress({\n transferred: event.transferred,\n total: event.total,\n percentage: event.percentage,\n });\n }\n }\n );\n\n const completeSub = ReactNativeKookitModule.addListener(\n \"onFtpComplete\",\n (event: FtpCompleteEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onComplete) {\n this.eventHandlers.onComplete();\n }\n }\n );\n\n const errorSub = ReactNativeKookitModule.addListener(\n \"onFtpError\",\n (event: FtpErrorEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onError) {\n this.eventHandlers.onError(new Error(event.error));\n }\n }\n );\n\n this.eventSubscriptions = [progressSub, completeSub, errorSub];\n }\n\n /**\n * Set event handlers\n */\n setEventHandlers(handlers: FtpClientEventHandlers): void {\n this.eventHandlers = { ...handlers };\n }\n\n /**\n * Initialize the FTP client instance\n */\n async initialize(): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.createFtpClient(this.clientId);\n }\n\n /**\n * Connect to the FTP server\n */\n async connect(config: FtpConnectionConfig): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n console.log(\"Connecting with config:\", this.clientId, config);\n\n await ReactNativeKookitModule.ftpClientConnect(this.clientId, config);\n }\n\n /**\n * Disconnect from the FTP server\n */\n async disconnect(): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDisconnect(this.clientId);\n }\n\n /**\n * List files in the specified directory\n */\n async list(path?: string): Promise<FtpFileInfo[]> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n return await ReactNativeKookitModule.ftpClientList(this.clientId, path);\n }\n\n /**\n * Download a file from the remote server\n */\n async download(remotePath: string, localPath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDownload(\n this.clientId,\n remotePath,\n localPath\n );\n }\n\n /**\n * Upload a file to the remote server\n */\n async upload(localPath: string, remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientUpload(\n this.clientId,\n localPath,\n remotePath\n );\n }\n\n /**\n * Delete a file or directory on the remote server\n */\n async delete(\n remotePath: string,\n isDirectory: boolean = false\n ): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientDelete(\n this.clientId,\n remotePath,\n isDirectory\n );\n }\n\n /**\n * Create a directory on the remote server\n */\n async createDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientCreateDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Change the current working directory on the remote server\n */\n async changeDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n await ReactNativeKookitModule.ftpClientChangeDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Get the current working directory on the remote server\n */\n async getCurrentDirectory(): Promise<string> {\n if (this.isDisposed) {\n throw new Error(\"FTP client has been disposed\");\n }\n\n const result = await ReactNativeKookitModule.ftpClientGetCurrentDirectory(\n this.clientId\n );\n return result;\n }\n\n /**\n * Get client status information\n * @returns Client status including existence and connection state\n */\n async getStatus(): Promise<{\n clientId: string;\n exists: boolean;\n connected: boolean;\n }> {\n const status = await ReactNativeKookitModule.getFtpClientStatus(\n this.clientId\n );\n return {\n clientId: this.clientId,\n ...status,\n };\n }\n\n /**\n * Get the client ID\n */\n getClientId(): string {\n return this.clientId;\n }\n\n /**\n * Check if the client is connected\n */\n async isConnected(): Promise<boolean> {\n if (this.isDisposed) {\n return false;\n }\n\n try {\n const status = await this.getStatus();\n return status.exists && status.connected;\n } catch {\n return false;\n }\n }\n\n /**\n * Verify the actual FTP connection by testing communication with server\n * This will attempt to send a NOOP command to verify the connection is alive\n */\n async verifyConnection(): Promise<boolean> {\n if (this.isDisposed) {\n return false;\n }\n\n try {\n return await ReactNativeKookitModule.verifyFtpConnection(this.clientId);\n } catch {\n return false;\n }\n }\n\n /**\n * Dispose the FTP client and clean up resources\n */\n async dispose(): Promise<void> {\n if (this.isDisposed) {\n return;\n }\n\n try {\n await ReactNativeKookitModule.disposeFtpClient(this.clientId);\n } catch (error) {\n // Ignore errors during disposal\n }\n\n // Remove event listeners\n this.eventSubscriptions.forEach((sub) => sub.remove());\n this.eventSubscriptions = [];\n\n this.isDisposed = true;\n }\n\n /**\n * Static method to list all FTP clients\n */\n static async listClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }> {\n return ReactNativeKookitModule.listFtpClients();\n }\n\n /**\n * Static method to create and initialize a new FTP client\n */\n static async create(clientId?: string): Promise<FtpClient> {\n const client = new FtpClient(clientId);\n await client.initialize();\n return client;\n }\n}\n"]}
|
package/build/SmbClient.d.ts
CHANGED
|
@@ -8,6 +8,17 @@ export interface SmbClientEventHandlers {
|
|
|
8
8
|
onComplete?: () => void;
|
|
9
9
|
onError?: (error: Error) => void;
|
|
10
10
|
}
|
|
11
|
+
export interface SmbClientStatus {
|
|
12
|
+
exists: boolean;
|
|
13
|
+
isConnected: boolean;
|
|
14
|
+
currentShare: string | null;
|
|
15
|
+
isDisposed: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface SmbClientInfo {
|
|
18
|
+
isConnected: boolean;
|
|
19
|
+
currentShare: string | null;
|
|
20
|
+
isDisposed: boolean;
|
|
21
|
+
}
|
|
11
22
|
export declare class SmbClient {
|
|
12
23
|
private clientId;
|
|
13
24
|
private isDisposed;
|
|
@@ -15,6 +26,7 @@ export declare class SmbClient {
|
|
|
15
26
|
private eventSubscriptions;
|
|
16
27
|
private _isConnected;
|
|
17
28
|
private _currentShare;
|
|
29
|
+
private static instances;
|
|
18
30
|
constructor(clientId?: string);
|
|
19
31
|
private setupEventListeners;
|
|
20
32
|
/**
|
|
@@ -121,6 +133,34 @@ export declare class SmbClient {
|
|
|
121
133
|
* @returns New SMB client instance
|
|
122
134
|
*/
|
|
123
135
|
static create(clientId?: string): Promise<SmbClient>;
|
|
136
|
+
/**
|
|
137
|
+
* Dispose a specific SMB client by client ID
|
|
138
|
+
* @param clientId Client ID to dispose
|
|
139
|
+
* @returns true if client was found and disposed, false otherwise
|
|
140
|
+
*/
|
|
141
|
+
static disposeClient(clientId: string): Promise<boolean>;
|
|
142
|
+
/**
|
|
143
|
+
* Get the status of a specific SMB client by client ID
|
|
144
|
+
* @param clientId Client ID to check
|
|
145
|
+
* @returns Client status or null if not found
|
|
146
|
+
*/
|
|
147
|
+
static getClientStatus(clientId: string): SmbClientStatus;
|
|
148
|
+
/**
|
|
149
|
+
* Get all active client IDs and their status
|
|
150
|
+
* @returns Map of client IDs to their status
|
|
151
|
+
*/
|
|
152
|
+
static getAllClientsStatus(): Map<string, SmbClientInfo>;
|
|
153
|
+
/**
|
|
154
|
+
* Get a specific SMB client instance by client ID
|
|
155
|
+
* @param clientId Client ID to retrieve
|
|
156
|
+
* @returns SMB client instance or null if not found
|
|
157
|
+
*/
|
|
158
|
+
static getInstance(clientId: string): SmbClient | null;
|
|
159
|
+
/**
|
|
160
|
+
* Dispose all SMB clients
|
|
161
|
+
* @returns Number of clients disposed
|
|
162
|
+
*/
|
|
163
|
+
static disposeAllClients(): Promise<number>;
|
|
124
164
|
}
|
|
125
165
|
export default SmbClient;
|
|
126
166
|
//# sourceMappingURL=SmbClient.d.ts.map
|
package/build/SmbClient.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmbClient.d.ts","sourceRoot":"","sources":["../src/SmbClient.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EAIZ,MAAM,2BAA2B,CAAC;AAEnC,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,KAAK,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,kBAAkB,CAAqC;IAC/D,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAuB;
|
|
1
|
+
{"version":3,"file":"SmbClient.d.ts","sourceRoot":"","sources":["../src/SmbClient.ts"],"names":[],"mappings":"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"}
|
package/build/SmbClient.js
CHANGED
|
@@ -6,10 +6,14 @@ export class SmbClient {
|
|
|
6
6
|
eventSubscriptions = [];
|
|
7
7
|
_isConnected = false;
|
|
8
8
|
_currentShare = null;
|
|
9
|
+
// 静态实例管理
|
|
10
|
+
static instances = new Map();
|
|
9
11
|
constructor(clientId) {
|
|
10
12
|
this.clientId =
|
|
11
13
|
clientId ||
|
|
12
14
|
`smb_client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
15
|
+
// 将实例添加到静态管理器
|
|
16
|
+
SmbClient.instances.set(this.clientId, this);
|
|
13
17
|
this.setupEventListeners();
|
|
14
18
|
}
|
|
15
19
|
setupEventListeners() {
|
|
@@ -225,6 +229,8 @@ export class SmbClient {
|
|
|
225
229
|
this.isDisposed = true;
|
|
226
230
|
this._isConnected = false;
|
|
227
231
|
this._currentShare = null;
|
|
232
|
+
// 从静态实例管理器中移除
|
|
233
|
+
SmbClient.instances.delete(this.clientId);
|
|
228
234
|
}
|
|
229
235
|
/**
|
|
230
236
|
* List all SMB clients
|
|
@@ -242,6 +248,91 @@ export class SmbClient {
|
|
|
242
248
|
await client.initialize();
|
|
243
249
|
return client;
|
|
244
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Dispose a specific SMB client by client ID
|
|
253
|
+
* @param clientId Client ID to dispose
|
|
254
|
+
* @returns true if client was found and disposed, false otherwise
|
|
255
|
+
*/
|
|
256
|
+
static async disposeClient(clientId) {
|
|
257
|
+
const client = SmbClient.instances.get(clientId);
|
|
258
|
+
if (client) {
|
|
259
|
+
await client.dispose();
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
// Try to dispose on native side even if not in our instances map
|
|
263
|
+
try {
|
|
264
|
+
await ReactNativeKookitModule.disposeSmbClient(clientId);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Get the status of a specific SMB client by client ID
|
|
273
|
+
* @param clientId Client ID to check
|
|
274
|
+
* @returns Client status or null if not found
|
|
275
|
+
*/
|
|
276
|
+
static getClientStatus(clientId) {
|
|
277
|
+
const client = SmbClient.instances.get(clientId);
|
|
278
|
+
if (client) {
|
|
279
|
+
return {
|
|
280
|
+
exists: true,
|
|
281
|
+
isConnected: client._isConnected,
|
|
282
|
+
currentShare: client._currentShare,
|
|
283
|
+
isDisposed: client.isDisposed,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
exists: false,
|
|
288
|
+
isConnected: false,
|
|
289
|
+
currentShare: null,
|
|
290
|
+
isDisposed: true,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get all active client IDs and their status
|
|
295
|
+
* @returns Map of client IDs to their status
|
|
296
|
+
*/
|
|
297
|
+
static getAllClientsStatus() {
|
|
298
|
+
const statusMap = new Map();
|
|
299
|
+
SmbClient.instances.forEach((client, clientId) => {
|
|
300
|
+
statusMap.set(clientId, {
|
|
301
|
+
isConnected: client._isConnected,
|
|
302
|
+
currentShare: client._currentShare,
|
|
303
|
+
isDisposed: client.isDisposed,
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
return statusMap;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Get a specific SMB client instance by client ID
|
|
310
|
+
* @param clientId Client ID to retrieve
|
|
311
|
+
* @returns SMB client instance or null if not found
|
|
312
|
+
*/
|
|
313
|
+
static getInstance(clientId) {
|
|
314
|
+
return SmbClient.instances.get(clientId) || null;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Dispose all SMB clients
|
|
318
|
+
* @returns Number of clients disposed
|
|
319
|
+
*/
|
|
320
|
+
static async disposeAllClients() {
|
|
321
|
+
const clientIds = Array.from(SmbClient.instances.keys());
|
|
322
|
+
let disposedCount = 0;
|
|
323
|
+
for (const clientId of clientIds) {
|
|
324
|
+
try {
|
|
325
|
+
await SmbClient.disposeClient(clientId);
|
|
326
|
+
disposedCount++;
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// Continue with next client even if disposal fails
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// Clear the instances map
|
|
333
|
+
SmbClient.instances.clear();
|
|
334
|
+
return disposedCount;
|
|
335
|
+
}
|
|
245
336
|
}
|
|
246
337
|
export default SmbClient;
|
|
247
338
|
//# sourceMappingURL=SmbClient.js.map
|
package/build/SmbClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SmbClient.js","sourceRoot":"","sources":["../src/SmbClient.ts"],"names":[],"mappings":"AAAA,OAAO,uBAAuB,MAAM,2BAA2B,CAAC;AAmBhE,MAAM,OAAO,SAAS;IACZ,QAAQ,CAAS;IACjB,UAAU,GAAY,KAAK,CAAC;IAC5B,aAAa,GAA2B,EAAE,CAAC;IAC3C,kBAAkB,GAAkC,EAAE,CAAC;IACvD,YAAY,GAAY,KAAK,CAAC;IAC9B,aAAa,GAAkB,IAAI,CAAC;IAE5C,YAAY,QAAiB;QAC3B,IAAI,CAAC,QAAQ;YACX,QAAQ;gBACR,cAAc,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAC7B,CAAC;IAEO,mBAAmB;QACzB,MAAM,WAAW,GAAG,uBAAuB,CAAC,WAAW,CACrD,eAAe,EACf,CAAC,KAAuB,EAAE,EAAE;YAC1B,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;gBACtE,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;oBAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,UAAU,EAAE,KAAK,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CACF,CAAC;QAEF,MAAM,WAAW,GAAG,uBAAuB,CAAC,WAAW,CACrD,eAAe,EACf,CAAC,KAAuB,EAAE,EAAE;YAC1B,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;gBACtE,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;YAClC,CAAC;QACH,CAAC,CACF,CAAC;QAEF,MAAM,QAAQ,GAAG,uBAAuB,CAAC,WAAW,CAClD,YAAY,EACZ,CAAC,KAAoB,EAAE,EAAE;YACvB,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;gBACnE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,kBAAkB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,QAAgC;QAC/C,IAAI,CAAC,aAAa,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IACvC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,MAAM,uBAAuB,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,MAA2B;QACvC,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,MAAM,uBAAuB,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACtE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,SAAiB;QAClC,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAEvE,MAAM,uBAAuB,CAAC,qBAAqB,CACjD,IAAI,CAAC,QAAQ,EACb,SAAS,CACV,CAAC;QACF,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAEvE,OAAO,uBAAuB,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,MAAM,uBAAuB,CAAC,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI,CAAC,IAAa;QACtB,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE/D,OAAO,uBAAuB,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpE,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,UAAkB,EAAE,SAAiB;QAClD,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE/D,MAAM,uBAAuB,CAAC,iBAAiB,CAC7C,IAAI,CAAC,QAAQ,EACb,UAAU,EACV,SAAS,CACV,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,UAAkB;QAChD,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE/D,MAAM,uBAAuB,CAAC,eAAe,CAC3C,IAAI,CAAC,QAAQ,EACb,SAAS,EACT,UAAU,CACX,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CACV,UAAkB,EAClB,cAAuB,KAAK;QAE5B,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE/D,MAAM,uBAAuB,CAAC,eAAe,CAC3C,IAAI,CAAC,QAAQ,EACb,UAAU,EACV,WAAW,CACZ,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,eAAe,CAAC,UAAkB;QACtC,IAAI,IAAI,CAAC,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACvE,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QAE/D,MAAM,uBAAuB,CAAC,wBAAwB,CACpD,IAAI,CAAC,QAAQ,EACb,UAAU,CACX,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QAMb,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,kBAAkB,CAC7D,IAAI,CAAC,QAAQ,CACd,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,YAAY,EAAE,IAAI,CAAC,aAAa;YAChC,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,KAAK,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;YACtC,OAAO,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC;YACH,MAAM,uBAAuB,CAAC,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW;QAItB,OAAO,uBAAuB,CAAC,cAAc,EAAE,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAiB;QACnC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAED,eAAe,SAAS,CAAC","sourcesContent":["import ReactNativeKookitModule from \"./ReactNativeKookitModule\";\nimport type {\n SmbConnectionConfig,\n SmbFileInfo,\n SmbProgressEvent,\n SmbCompleteEvent,\n SmbErrorEvent,\n} from \"./ReactNativeKookit.types\";\n\nexport interface SmbClientEventHandlers {\n onProgress?: (progress: {\n transferred: number;\n total: number;\n percentage: number;\n }) => void;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport class SmbClient {\n private clientId: string;\n private isDisposed: boolean = false;\n private eventHandlers: SmbClientEventHandlers = {};\n private eventSubscriptions: Array<{ remove: () => void }> = [];\n private _isConnected: boolean = false;\n private _currentShare: string | null = null;\n\n constructor(clientId?: string) {\n this.clientId =\n clientId ||\n `smb_client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n this.setupEventListeners();\n }\n\n private setupEventListeners() {\n const progressSub = ReactNativeKookitModule.addListener(\n \"onSmbProgress\",\n (event: SmbProgressEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onProgress) {\n this.eventHandlers.onProgress({\n transferred: event.transferred,\n total: event.total,\n percentage: event.percentage,\n });\n }\n }\n );\n\n const completeSub = ReactNativeKookitModule.addListener(\n \"onSmbComplete\",\n (event: SmbCompleteEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onComplete) {\n this.eventHandlers.onComplete();\n }\n }\n );\n\n const errorSub = ReactNativeKookitModule.addListener(\n \"onSmbError\",\n (event: SmbErrorEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onError) {\n this.eventHandlers.onError(new Error(event.error));\n }\n }\n );\n\n this.eventSubscriptions = [progressSub, completeSub, errorSub];\n }\n\n /**\n * Set event handlers for SMB operations\n */\n setEventHandlers(handlers: SmbClientEventHandlers): void {\n this.eventHandlers = { ...handlers };\n }\n\n /**\n * Initialize the SMB client\n */\n private async initialize(): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.createSmbClient(this.clientId);\n }\n\n /**\n * Connect to SMB server\n * @param config Connection configuration\n */\n async connect(config: SmbConnectionConfig): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.smbClientConnect(this.clientId, config);\n this._isConnected = true;\n this._currentShare = config.share || null;\n }\n\n /**\n * Connect to a specific share\n * @param shareName Name of the share to connect to\n */\n async connectShare(shareName: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n\n await ReactNativeKookitModule.smbClientConnectShare(\n this.clientId,\n shareName\n );\n this._currentShare = shareName;\n }\n\n /**\n * List all available shares on the SMB server\n * @returns Array of share names\n */\n async listShares(): Promise<string[]> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n\n return ReactNativeKookitModule.smbClientListShares(this.clientId);\n }\n\n /**\n * Disconnect from SMB server\n */\n async disconnect(): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.smbClientDisconnect(this.clientId);\n this._isConnected = false;\n this._currentShare = null;\n }\n\n /**\n * List files and directories in the specified path\n * @param path Path to list (empty string for share root)\n * @returns Array of file information\n */\n async list(path?: string): Promise<SmbFileInfo[]> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n return ReactNativeKookitModule.smbClientList(this.clientId, path);\n }\n\n /**\n * Download a file from SMB server\n * @param remotePath Path to the remote file\n * @param localPath Local path to save the file\n */\n async download(remotePath: string, localPath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientDownload(\n this.clientId,\n remotePath,\n localPath\n );\n }\n\n /**\n * Upload a file to SMB server\n * @param localPath Local path of the file to upload\n * @param remotePath Remote path to save the file\n */\n async upload(localPath: string, remotePath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientUpload(\n this.clientId,\n localPath,\n remotePath\n );\n }\n\n /**\n * Delete a file or directory from SMB server\n * @param remotePath Path to the file or directory to delete\n * @param isDirectory Whether the path is a directory\n */\n async delete(\n remotePath: string,\n isDirectory: boolean = false\n ): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientDelete(\n this.clientId,\n remotePath,\n isDirectory\n );\n }\n\n /**\n * Create a directory on SMB server\n * @param remotePath Path of the directory to create\n */\n async createDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientCreateDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Get the current connection status\n */\n async getStatus(): Promise<{\n clientId: string;\n exists: boolean;\n connected: boolean;\n currentShare: string | null;\n }> {\n const status = await ReactNativeKookitModule.getSmbClientStatus(\n this.clientId\n );\n return {\n clientId: this.clientId,\n currentShare: this._currentShare,\n ...status,\n };\n }\n\n /**\n * Get the client ID\n */\n getClientId(): string {\n return this.clientId;\n }\n\n /**\n * Get the current share name\n */\n getCurrentShare(): string | null {\n return this._currentShare;\n }\n\n /**\n * Check if connected to SMB server\n */\n async isConnected(): Promise<boolean> {\n if (this.isDisposed) return false;\n try {\n const status = await this.getStatus();\n return status.exists && status.connected;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if connected to SMB server (synchronous)\n */\n isConnectedSync(): boolean {\n return this._isConnected;\n }\n\n /**\n * Check if connected to a share\n */\n hasShareConnected(): boolean {\n return this._isConnected && this._currentShare !== null;\n }\n\n /**\n * Dispose the SMB client and clean up resources\n */\n async dispose(): Promise<void> {\n if (this.isDisposed) return;\n try {\n await ReactNativeKookitModule.disposeSmbClient(this.clientId);\n } catch {}\n this.eventSubscriptions.forEach((s) => s.remove());\n this.eventSubscriptions = [];\n this.isDisposed = true;\n this._isConnected = false;\n this._currentShare = null;\n }\n\n /**\n * List all SMB clients\n */\n static async listClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }> {\n return ReactNativeKookitModule.listSmbClients();\n }\n\n /**\n * Create a new SMB client instance\n * @param clientId Optional client ID\n * @returns New SMB client instance\n */\n static async create(clientId?: string): Promise<SmbClient> {\n const client = new SmbClient(clientId);\n await client.initialize();\n return client;\n }\n}\n\nexport default SmbClient;\n"]}
|
|
1
|
+
{"version":3,"file":"SmbClient.js","sourceRoot":"","sources":["../src/SmbClient.ts"],"names":[],"mappings":"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","sourcesContent":["import ReactNativeKookitModule from \"./ReactNativeKookitModule\";\nimport type {\n SmbConnectionConfig,\n SmbFileInfo,\n SmbProgressEvent,\n SmbCompleteEvent,\n SmbErrorEvent,\n} from \"./ReactNativeKookit.types\";\n\nexport interface SmbClientEventHandlers {\n onProgress?: (progress: {\n transferred: number;\n total: number;\n percentage: number;\n }) => void;\n onComplete?: () => void;\n onError?: (error: Error) => void;\n}\n\nexport interface SmbClientStatus {\n exists: boolean;\n isConnected: boolean;\n currentShare: string | null;\n isDisposed: boolean;\n}\n\nexport interface SmbClientInfo {\n isConnected: boolean;\n currentShare: string | null;\n isDisposed: boolean;\n}\n\nexport class SmbClient {\n private clientId: string;\n private isDisposed: boolean = false;\n private eventHandlers: SmbClientEventHandlers = {};\n private eventSubscriptions: Array<{ remove: () => void }> = [];\n private _isConnected: boolean = false;\n private _currentShare: string | null = null;\n\n // 静态实例管理\n private static instances: Map<string, SmbClient> = new Map();\n\n constructor(clientId?: string) {\n this.clientId =\n clientId ||\n `smb_client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n // 将实例添加到静态管理器\n SmbClient.instances.set(this.clientId, this);\n\n this.setupEventListeners();\n }\n\n private setupEventListeners() {\n const progressSub = ReactNativeKookitModule.addListener(\n \"onSmbProgress\",\n (event: SmbProgressEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onProgress) {\n this.eventHandlers.onProgress({\n transferred: event.transferred,\n total: event.total,\n percentage: event.percentage,\n });\n }\n }\n );\n\n const completeSub = ReactNativeKookitModule.addListener(\n \"onSmbComplete\",\n (event: SmbCompleteEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onComplete) {\n this.eventHandlers.onComplete();\n }\n }\n );\n\n const errorSub = ReactNativeKookitModule.addListener(\n \"onSmbError\",\n (event: SmbErrorEvent) => {\n if (event.clientId === this.clientId && this.eventHandlers.onError) {\n this.eventHandlers.onError(new Error(event.error));\n }\n }\n );\n\n this.eventSubscriptions = [progressSub, completeSub, errorSub];\n }\n\n /**\n * Set event handlers for SMB operations\n */\n setEventHandlers(handlers: SmbClientEventHandlers): void {\n this.eventHandlers = { ...handlers };\n }\n\n /**\n * Initialize the SMB client\n */\n private async initialize(): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.createSmbClient(this.clientId);\n }\n\n /**\n * Connect to SMB server\n * @param config Connection configuration\n */\n async connect(config: SmbConnectionConfig): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.smbClientConnect(this.clientId, config);\n this._isConnected = true;\n this._currentShare = config.share || null;\n }\n\n /**\n * Connect to a specific share\n * @param shareName Name of the share to connect to\n */\n async connectShare(shareName: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n\n await ReactNativeKookitModule.smbClientConnectShare(\n this.clientId,\n shareName\n );\n this._currentShare = shareName;\n }\n\n /**\n * List all available shares on the SMB server\n * @returns Array of share names\n */\n async listShares(): Promise<string[]> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n\n return ReactNativeKookitModule.smbClientListShares(this.clientId);\n }\n\n /**\n * Disconnect from SMB server\n */\n async disconnect(): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n await ReactNativeKookitModule.smbClientDisconnect(this.clientId);\n this._isConnected = false;\n this._currentShare = null;\n }\n\n /**\n * List files and directories in the specified path\n * @param path Path to list (empty string for share root)\n * @returns Array of file information\n */\n async list(path?: string): Promise<SmbFileInfo[]> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n return ReactNativeKookitModule.smbClientList(this.clientId, path);\n }\n\n /**\n * Download a file from SMB server\n * @param remotePath Path to the remote file\n * @param localPath Local path to save the file\n */\n async download(remotePath: string, localPath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientDownload(\n this.clientId,\n remotePath,\n localPath\n );\n }\n\n /**\n * Upload a file to SMB server\n * @param localPath Local path of the file to upload\n * @param remotePath Remote path to save the file\n */\n async upload(localPath: string, remotePath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientUpload(\n this.clientId,\n localPath,\n remotePath\n );\n }\n\n /**\n * Delete a file or directory from SMB server\n * @param remotePath Path to the file or directory to delete\n * @param isDirectory Whether the path is a directory\n */\n async delete(\n remotePath: string,\n isDirectory: boolean = false\n ): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientDelete(\n this.clientId,\n remotePath,\n isDirectory\n );\n }\n\n /**\n * Create a directory on SMB server\n * @param remotePath Path of the directory to create\n */\n async createDirectory(remotePath: string): Promise<void> {\n if (this.isDisposed) throw new Error(\"SMB client has been disposed\");\n if (!this._isConnected) throw new Error(\"Not connected to SMB server\");\n if (!this._currentShare) throw new Error(\"No share connected\");\n\n await ReactNativeKookitModule.smbClientCreateDirectory(\n this.clientId,\n remotePath\n );\n }\n\n /**\n * Get the current connection status\n */\n async getStatus(): Promise<{\n clientId: string;\n exists: boolean;\n connected: boolean;\n currentShare: string | null;\n }> {\n const status = await ReactNativeKookitModule.getSmbClientStatus(\n this.clientId\n );\n return {\n clientId: this.clientId,\n currentShare: this._currentShare,\n ...status,\n };\n }\n\n /**\n * Get the client ID\n */\n getClientId(): string {\n return this.clientId;\n }\n\n /**\n * Get the current share name\n */\n getCurrentShare(): string | null {\n return this._currentShare;\n }\n\n /**\n * Check if connected to SMB server\n */\n async isConnected(): Promise<boolean> {\n if (this.isDisposed) return false;\n try {\n const status = await this.getStatus();\n return status.exists && status.connected;\n } catch {\n return false;\n }\n }\n\n /**\n * Check if connected to SMB server (synchronous)\n */\n isConnectedSync(): boolean {\n return this._isConnected;\n }\n\n /**\n * Check if connected to a share\n */\n hasShareConnected(): boolean {\n return this._isConnected && this._currentShare !== null;\n }\n\n /**\n * Dispose the SMB client and clean up resources\n */\n async dispose(): Promise<void> {\n if (this.isDisposed) return;\n try {\n await ReactNativeKookitModule.disposeSmbClient(this.clientId);\n } catch {}\n this.eventSubscriptions.forEach((s) => s.remove());\n this.eventSubscriptions = [];\n this.isDisposed = true;\n this._isConnected = false;\n this._currentShare = null;\n\n // 从静态实例管理器中移除\n SmbClient.instances.delete(this.clientId);\n }\n\n /**\n * List all SMB clients\n */\n static async listClients(): Promise<{\n clients: Record<string, { connected: boolean }>;\n count: number;\n }> {\n return ReactNativeKookitModule.listSmbClients();\n }\n\n /**\n * Create a new SMB client instance\n * @param clientId Optional client ID\n * @returns New SMB client instance\n */\n static async create(clientId?: string): Promise<SmbClient> {\n const client = new SmbClient(clientId);\n await client.initialize();\n return client;\n }\n\n /**\n * Dispose a specific SMB client by client ID\n * @param clientId Client ID to dispose\n * @returns true if client was found and disposed, false otherwise\n */\n static async disposeClient(clientId: string): Promise<boolean> {\n const client = SmbClient.instances.get(clientId);\n if (client) {\n await client.dispose();\n return true;\n }\n\n // Try to dispose on native side even if not in our instances map\n try {\n await ReactNativeKookitModule.disposeSmbClient(clientId);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get the status of a specific SMB client by client ID\n * @param clientId Client ID to check\n * @returns Client status or null if not found\n */\n static getClientStatus(clientId: string): SmbClientStatus {\n const client = SmbClient.instances.get(clientId);\n if (client) {\n return {\n exists: true,\n isConnected: client._isConnected,\n currentShare: client._currentShare,\n isDisposed: client.isDisposed,\n };\n }\n return {\n exists: false,\n isConnected: false,\n currentShare: null,\n isDisposed: true,\n };\n }\n\n /**\n * Get all active client IDs and their status\n * @returns Map of client IDs to their status\n */\n static getAllClientsStatus(): Map<string, SmbClientInfo> {\n const statusMap = new Map();\n SmbClient.instances.forEach((client, clientId) => {\n statusMap.set(clientId, {\n isConnected: client._isConnected,\n currentShare: client._currentShare,\n isDisposed: client.isDisposed,\n });\n });\n return statusMap;\n }\n\n /**\n * Get a specific SMB client instance by client ID\n * @param clientId Client ID to retrieve\n * @returns SMB client instance or null if not found\n */\n static getInstance(clientId: string): SmbClient | null {\n return SmbClient.instances.get(clientId) || null;\n }\n\n /**\n * Dispose all SMB clients\n * @returns Number of clients disposed\n */\n static async disposeAllClients(): Promise<number> {\n const clientIds = Array.from(SmbClient.instances.keys());\n let disposedCount = 0;\n\n for (const clientId of clientIds) {\n try {\n await SmbClient.disposeClient(clientId);\n disposedCount++;\n } catch {\n // Continue with next client even if disposal fails\n }\n }\n\n // Clear the instances map\n SmbClient.instances.clear();\n\n return disposedCount;\n }\n}\n\nexport default SmbClient;\n"]}
|
|
@@ -165,36 +165,36 @@ private class FtpConnectionBox: @unchecked Sendable {
|
|
|
165
165
|
do {
|
|
166
166
|
try await self.ftpClient.performAuthentication()
|
|
167
167
|
self.ftpClient.isConnected = true
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
// Resume on our serial queue to synchronize state, avoid sync deadlocks
|
|
169
|
+
self.queue.async {
|
|
170
|
+
if !self.hasResumed {
|
|
171
|
+
self.hasResumed = true
|
|
172
|
+
self.continuation.resume()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
174
175
|
} catch {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
// Resume on our serial queue to synchronize state, avoid sync deadlocks
|
|
177
|
+
self.queue.async {
|
|
178
|
+
if !self.hasResumed {
|
|
179
|
+
self.hasResumed = true
|
|
180
|
+
self.continuation.resume(throwing: error)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
case .failed(let error):
|
|
184
186
|
self.timeoutTask?.cancel()
|
|
185
|
-
self.queue
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
187
|
+
// We're already on self.queue due to the outer async; update inline
|
|
188
|
+
if !self.hasResumed {
|
|
189
|
+
self.hasResumed = true
|
|
190
|
+
self.continuation.resume(throwing: error)
|
|
190
191
|
}
|
|
191
192
|
case .cancelled:
|
|
192
193
|
self.timeoutTask?.cancel()
|
|
193
|
-
self.queue
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
194
|
+
// We're already on self.queue due to the outer async; update inline
|
|
195
|
+
if !self.hasResumed {
|
|
196
|
+
self.hasResumed = true
|
|
197
|
+
self.continuation.resume(throwing: FtpError.connectionCancelled)
|
|
198
198
|
}
|
|
199
199
|
default:
|
|
200
200
|
break
|
|
@@ -203,12 +203,13 @@ private class FtpConnectionBox: @unchecked Sendable {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
func handleTimeout() {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
// Schedule asynchronously to avoid any potential self-queue sync deadlocks
|
|
207
|
+
queue.async {
|
|
208
|
+
if !self.hasResumed {
|
|
209
|
+
self.hasResumed = true
|
|
210
|
+
self.continuation.resume(throwing: FtpError.connectionTimeout)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
212
213
|
}
|
|
213
214
|
}
|
|
214
215
|
|
|
@@ -263,8 +264,38 @@ class FtpClient: @unchecked Sendable {
|
|
|
263
264
|
isConnected = false
|
|
264
265
|
}
|
|
265
266
|
|
|
267
|
+
private func ensureConnected() async throws {
|
|
268
|
+
if !isConnected {
|
|
269
|
+
throw FtpError.notConnected
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Verify connection is alive by sending a NOOP command
|
|
273
|
+
do {
|
|
274
|
+
let response = try await sendCommand("NOOP")
|
|
275
|
+
if !response.hasPrefix("200") && !response.hasPrefix("250") {
|
|
276
|
+
// Connection might be dead, try to reconnect
|
|
277
|
+
try await reconnect()
|
|
278
|
+
}
|
|
279
|
+
} catch {
|
|
280
|
+
// If NOOP fails, try to reconnect
|
|
281
|
+
try await reconnect()
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private func reconnect() async throws {
|
|
286
|
+
guard let config = config else {
|
|
287
|
+
throw FtpError.notConnected
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Clean up dead connection
|
|
291
|
+
await disconnect()
|
|
292
|
+
|
|
293
|
+
// Reconnect with the same config
|
|
294
|
+
try await connect(config: config)
|
|
295
|
+
}
|
|
296
|
+
|
|
266
297
|
func listFiles(path: String? = nil) async throws -> [FtpFileInfo] {
|
|
267
|
-
|
|
298
|
+
try await ensureConnected()
|
|
268
299
|
|
|
269
300
|
// Set ASCII mode for directory listings
|
|
270
301
|
print("FTP DEBUG: Setting ASCII mode for directory listing")
|
|
@@ -317,7 +348,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
317
348
|
}
|
|
318
349
|
|
|
319
350
|
func downloadFile(remotePath: String, localPath: String) async throws {
|
|
320
|
-
|
|
351
|
+
try await ensureConnected()
|
|
321
352
|
|
|
322
353
|
print("FTP DEBUG: Starting download - Remote: \(remotePath), Local: \(localPath)")
|
|
323
354
|
|
|
@@ -370,7 +401,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
370
401
|
}
|
|
371
402
|
|
|
372
403
|
func uploadFile(localPath: String, remotePath: String) async throws {
|
|
373
|
-
|
|
404
|
+
try await ensureConnected()
|
|
374
405
|
|
|
375
406
|
let localURL = URL(fileURLWithPath: localPath)
|
|
376
407
|
guard FileManager.default.fileExists(atPath: localPath) else {
|
|
@@ -398,7 +429,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
398
429
|
}
|
|
399
430
|
|
|
400
431
|
func deleteFile(remotePath: String, isDirectory: Bool = false) async throws {
|
|
401
|
-
|
|
432
|
+
try await ensureConnected()
|
|
402
433
|
|
|
403
434
|
let command = isDirectory ? "RMD \(remotePath)" : "DELE \(remotePath)"
|
|
404
435
|
let response = try await sendCommand(command)
|
|
@@ -409,7 +440,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
409
440
|
}
|
|
410
441
|
|
|
411
442
|
func createDirectory(remotePath: String) async throws {
|
|
412
|
-
|
|
443
|
+
try await ensureConnected()
|
|
413
444
|
|
|
414
445
|
let response = try await sendCommand("MKD \(remotePath)")
|
|
415
446
|
guard response.hasPrefix("257") else {
|
|
@@ -418,7 +449,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
418
449
|
}
|
|
419
450
|
|
|
420
451
|
func changeDirectory(remotePath: String) async throws {
|
|
421
|
-
|
|
452
|
+
try await ensureConnected()
|
|
422
453
|
|
|
423
454
|
let response = try await sendCommand("CWD \(remotePath)")
|
|
424
455
|
guard response.hasPrefix("250") else {
|
|
@@ -427,7 +458,7 @@ class FtpClient: @unchecked Sendable {
|
|
|
427
458
|
}
|
|
428
459
|
|
|
429
460
|
func getCurrentDirectory() async throws -> String {
|
|
430
|
-
|
|
461
|
+
try await ensureConnected()
|
|
431
462
|
|
|
432
463
|
let response = try await sendCommand("PWD")
|
|
433
464
|
guard response.hasPrefix("257") else {
|
|
@@ -1677,4 +1708,4 @@ private class SmbProgressDelegateImpl: SmbProgressDelegate {
|
|
|
1677
1708
|
"error": error
|
|
1678
1709
|
])
|
|
1679
1710
|
}
|
|
1680
|
-
}
|
|
1711
|
+
}
|
package/package.json
CHANGED