@cetapod/react-native-smb 1.0.0

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.
Files changed (137) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +72 -0
  3. package/ReactNativeSmb.podspec +59 -0
  4. package/cpp/ios/OnLoad.mm +24 -0
  5. package/cpp/shared/HybridSMB.cpp +324 -0
  6. package/cpp/shared/HybridSMB.hpp +102 -0
  7. package/cpp/shared/ReactNativeSmb.hpp +428 -0
  8. package/cpp/shared/connection/ContextRequest.hpp +27 -0
  9. package/cpp/shared/connection/ContextRequestQueue.cpp +85 -0
  10. package/cpp/shared/connection/ContextRequestQueue.hpp +28 -0
  11. package/cpp/shared/connection/MetadataContextLease.hpp +33 -0
  12. package/cpp/shared/connection/PoolContextHandle.cpp +35 -0
  13. package/cpp/shared/connection/PoolContextHandle.hpp +44 -0
  14. package/cpp/shared/connection/PoolSlot.cpp +73 -0
  15. package/cpp/shared/connection/PoolSlot.hpp +46 -0
  16. package/cpp/shared/connection/PoolTypes.hpp +41 -0
  17. package/cpp/shared/connection/SmbConnection.cpp +385 -0
  18. package/cpp/shared/connection/SmbConnection.hpp +93 -0
  19. package/cpp/shared/connection/SmbConnectionPool.cpp +316 -0
  20. package/cpp/shared/connection/SmbConnectionPool.hpp +84 -0
  21. package/cpp/shared/core/CancellationToken.hpp +22 -0
  22. package/cpp/shared/core/OperatorContext.hpp +24 -0
  23. package/cpp/shared/core/SmbEnums.hpp +126 -0
  24. package/cpp/shared/core/SmbTask.cpp +131 -0
  25. package/cpp/shared/core/SmbTask.hpp +52 -0
  26. package/cpp/shared/core/SmbTaskCore.cpp +222 -0
  27. package/cpp/shared/core/SmbTaskCore.hpp +107 -0
  28. package/cpp/shared/core/SmbTypes.hpp +35 -0
  29. package/cpp/shared/core/TaskObserverHub.cpp +166 -0
  30. package/cpp/shared/core/TaskObserverHub.hpp +66 -0
  31. package/cpp/shared/core/TaskSnapshotCodec.cpp +32 -0
  32. package/cpp/shared/core/TaskSnapshotCodec.hpp +41 -0
  33. package/cpp/shared/io/SmbCopyTree.hpp +114 -0
  34. package/cpp/shared/io/SmbDirScan.hpp +80 -0
  35. package/cpp/shared/io/SmbFileIO.cpp +1355 -0
  36. package/cpp/shared/io/SmbFileIO.hpp +45 -0
  37. package/cpp/shared/io/SmbPathUtil.hpp +75 -0
  38. package/cpp/shared/io/SmbSecurity.cpp +308 -0
  39. package/cpp/shared/io/SmbSecurity.hpp +32 -0
  40. package/cpp/shared/io/SmbTreeOps.hpp +112 -0
  41. package/cpp/shared/operators/Operator.hpp +35 -0
  42. package/cpp/shared/operators/OperatorBase.cpp +57 -0
  43. package/cpp/shared/operators/OperatorBase.hpp +57 -0
  44. package/cpp/shared/operators/connection/ConnectOperator.cpp +19 -0
  45. package/cpp/shared/operators/connection/ConnectOperator.hpp +22 -0
  46. package/cpp/shared/operators/connection/ConnectShareOperator.cpp +19 -0
  47. package/cpp/shared/operators/connection/ConnectShareOperator.hpp +21 -0
  48. package/cpp/shared/operators/connection/DisconnectOperator.cpp +12 -0
  49. package/cpp/shared/operators/connection/DisconnectOperator.hpp +15 -0
  50. package/cpp/shared/operators/connection/InitializeOperator.cpp +12 -0
  51. package/cpp/shared/operators/connection/InitializeOperator.hpp +22 -0
  52. package/cpp/shared/operators/connection/ListSharesOperator.cpp +13 -0
  53. package/cpp/shared/operators/connection/ListSharesOperator.hpp +18 -0
  54. package/cpp/shared/operators/listing/GetPathInfoOperator.cpp +43 -0
  55. package/cpp/shared/operators/listing/GetPathInfoOperator.hpp +21 -0
  56. package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.cpp +202 -0
  57. package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.hpp +22 -0
  58. package/cpp/shared/operators/listing/ListDirectoryOperator.cpp +20 -0
  59. package/cpp/shared/operators/listing/ListDirectoryOperator.hpp +24 -0
  60. package/cpp/shared/operators/mutate/CopyItemOperator.cpp +19 -0
  61. package/cpp/shared/operators/mutate/CopyItemOperator.hpp +25 -0
  62. package/cpp/shared/operators/mutate/CreateDirectoryOperator.cpp +28 -0
  63. package/cpp/shared/operators/mutate/CreateDirectoryOperator.hpp +20 -0
  64. package/cpp/shared/operators/mutate/DeleteItemOperator.cpp +96 -0
  65. package/cpp/shared/operators/mutate/DeleteItemOperator.hpp +23 -0
  66. package/cpp/shared/operators/mutate/DuplicateItemOperator.cpp +48 -0
  67. package/cpp/shared/operators/mutate/DuplicateItemOperator.hpp +23 -0
  68. package/cpp/shared/operators/mutate/MoveItemOperator.cpp +32 -0
  69. package/cpp/shared/operators/mutate/MoveItemOperator.hpp +21 -0
  70. package/cpp/shared/operators/mutate/RenameItemOperator.cpp +37 -0
  71. package/cpp/shared/operators/mutate/RenameItemOperator.hpp +21 -0
  72. package/cpp/shared/operators/transfer/DownloadFileOperator.cpp +31 -0
  73. package/cpp/shared/operators/transfer/DownloadFileOperator.hpp +21 -0
  74. package/cpp/shared/operators/transfer/UploadFileOperator.cpp +27 -0
  75. package/cpp/shared/operators/transfer/UploadFileOperator.hpp +21 -0
  76. package/cpp/shared/util/SmbErrorMapper.hpp +229 -0
  77. package/cpp/shared/util/SmbLog.hpp +20 -0
  78. package/docs/API.md +105 -0
  79. package/docs/ARCHITECTURE.md +70 -0
  80. package/docs/TASK_MODEL.md +149 -0
  81. package/ios/include/smb2/libsmb2-dcerpc-lsa.h +172 -0
  82. package/ios/include/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  83. package/ios/include/smb2/libsmb2-dcerpc.h +155 -0
  84. package/ios/include/smb2/libsmb2-raw.h +497 -0
  85. package/ios/include/smb2/libsmb2.h +1384 -0
  86. package/ios/include/smb2/smb2-errors.h +549 -0
  87. package/ios/include/smb2/smb2.h +1251 -0
  88. package/ios/libs/device/libsmb2-device.a +0 -0
  89. package/ios/libs/libsmb2.xcframework/Info.plist +48 -0
  90. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
  91. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  92. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc.h +155 -0
  93. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-raw.h +497 -0
  94. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2.h +1384 -0
  95. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2-errors.h +549 -0
  96. package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2.h +1251 -0
  97. package/ios/libs/libsmb2.xcframework/ios-arm64/libsmb2.a +0 -0
  98. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
  99. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
  100. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc.h +155 -0
  101. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-raw.h +497 -0
  102. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2.h +1384 -0
  103. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2-errors.h +549 -0
  104. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2.h +1251 -0
  105. package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/libsmb2.a +0 -0
  106. package/ios/libs/simulator/libsmb2-simulator.a +0 -0
  107. package/lib/ReactNativeSmb.d.ts +200 -0
  108. package/lib/ReactNativeSmb.js +1 -0
  109. package/lib/bridge/decode.d.ts +4 -0
  110. package/lib/bridge/decode.js +92 -0
  111. package/lib/core/SMB.d.ts +3 -0
  112. package/lib/core/SMB.js +4 -0
  113. package/lib/core/SmbClient.d.ts +35 -0
  114. package/lib/core/SmbClient.js +99 -0
  115. package/lib/core/SmbTask.d.ts +41 -0
  116. package/lib/core/SmbTask.js +74 -0
  117. package/lib/core/TransferStore.d.ts +22 -0
  118. package/lib/core/TransferStore.js +88 -0
  119. package/lib/core/ids.d.ts +1 -0
  120. package/lib/core/ids.js +3 -0
  121. package/lib/core/taskResult.d.ts +3 -0
  122. package/lib/core/taskResult.js +52 -0
  123. package/lib/hooks/useSubscribe.d.ts +20 -0
  124. package/lib/hooks/useSubscribe.js +36 -0
  125. package/lib/hooks/useTransfers.d.ts +7 -0
  126. package/lib/hooks/useTransfers.js +29 -0
  127. package/lib/index.d.ts +7 -0
  128. package/lib/index.js +7 -0
  129. package/lib/labels.d.ts +6 -0
  130. package/lib/labels.js +71 -0
  131. package/lib/types.d.ts +141 -0
  132. package/lib/types.js +59 -0
  133. package/lib/utils.d.ts +79 -0
  134. package/lib/utils.js +153 -0
  135. package/package.json +63 -0
  136. package/scripts/build-libsmb2.sh +143 -0
  137. package/scripts/create-xcframework.sh +84 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 2.1, February 1999
3
+
4
+ Copyright (C) 2026 Cetapod
5
+
6
+ This library is free software; you can redistribute it and/or modify it under
7
+ the terms of the GNU Lesser General Public License as published by the Free
8
+ Software Foundation; either version 2.1 of the License, or (at your option)
9
+ any later version.
10
+
11
+ This library is distributed in the hope that it will be useful, but WITHOUT
12
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
+ FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
+ details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public License along
17
+ with this library. If not, see <https://www.gnu.org/licenses/>.
18
+
19
+ This project incorporates libsmb2 (https://github.com/sahlberg/libsmb2),
20
+ which is also licensed under LGPL-2.1.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @cetapod/react-native-smb
2
+
3
+ ![@cetapod/react-native-smb](./.github/og-image.svg)
4
+
5
+ [![Website](https://img.shields.io/badge/website-cetapod.github.io-blue)](https://cetapod.github.io/react-native-smb/)
6
+ [![Docs](https://img.shields.io/badge/docs-read%20now-blue)](https://cetapod.github.io/react-native-smb/docs/)
7
+
8
+ SMB client for React Native via [libsmb2](https://github.com/sahlberg/libsmb2) and [Nitro Modules](https://nitro.margelo.com).
9
+
10
+ ## Features
11
+
12
+ - SMBv2/v3
13
+ - `SmbTask` per operation — `result()`, `subscribe()`, `cancel()`
14
+ - 4-slot connection pool, interactive-priority slot 0
15
+ - 8-chunk pipelining per connection
16
+ - `SmbError` / `SmbTaskError`, React hooks
17
+
18
+ ## Compatibility
19
+
20
+ | | |
21
+ | -------------------------- | -------------- |
22
+ | React Native | >= 0.76 |
23
+ | React | >= 19 |
24
+ | react-native-nitro-modules | >= 0.22, < 1.0 |
25
+ | iOS | 12+ |
26
+ | Android | not yet |
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npm install @cetapod/react-native-smb react-native-nitro-modules
32
+ cd ios && pod install
33
+ ```
34
+
35
+ ## Quick start
36
+
37
+ ```typescript
38
+ import { SMB, type SmbCredentials } from '@cetapod/react-native-smb';
39
+
40
+ const smb = SMB();
41
+ const creds: SmbCredentials = { username: 'user', password: 'pass' };
42
+
43
+ await smb.connect('smb://192.168.1.100/Media', creds).result();
44
+ const entries = await smb.listDirectory('/', false).result();
45
+
46
+ const task = smb.downloadFile('/video.mp4', '/local/video.mp4');
47
+ task.subscribe((snap) => console.log(snap.progress));
48
+ await task.result();
49
+ ```
50
+
51
+ URL: `smb://[<domain;][<user>@]<host>[:<port>]/<share>/<path>`
52
+
53
+ ## Documentation
54
+
55
+ | | |
56
+ | ----------------------------------------- | ------------------------------------------------- |
57
+ | [Task model](./docs/TASK_MODEL.md) | Subscribe, fire-and-forget, transfer tray, errors |
58
+ | [API reference](./docs/API.md) | Methods, types, hooks, utilities |
59
+ | [Connection pool](./docs/ARCHITECTURE.md) | Slots, chunk pipeline, multichannel |
60
+ | [Example app](./example/README.md) | Running the Expo demo |
61
+
62
+ ## Example app
63
+
64
+ ```bash
65
+ npm run example
66
+ ```
67
+
68
+ See [example/README.md](./example/README.md).
69
+
70
+ ## License
71
+
72
+ LGPL-2.1 — same family as libsmb2. See [LICENSE](./LICENSE).
@@ -0,0 +1,59 @@
1
+ Pod::Spec.new do |s|
2
+ s.name = "ReactNativeSmb"
3
+ s.version = "1.0.0"
4
+ s.summary = "A React Native Nitro module for SMB client functionality using libsmb2"
5
+ s.description = <<-DESC
6
+ A SMB client library for React Native applications using the libsmb2 C library, built using Nitro modules.
7
+ DESC
8
+
9
+ s.homepage = "https://github.com/cetapod/react-native-smb"
10
+ s.author = { "Cetapod" => "open-source@cetapod.com" }
11
+ s.platform = :ios, "12.0"
12
+
13
+ s.source = { :git => "https://github.com/cetapod/react-native-smb.git", :tag => "#{s.version}" }
14
+
15
+ s.source_files = [
16
+ "cpp/shared/**/*.{cpp,hpp}",
17
+ "cpp/ios/**/*.{cpp,hpp,mm,m,h}"
18
+ ]
19
+
20
+ s.header_mappings_dir = "cpp"
21
+ s.public_header_files = "cpp/**/*.hpp"
22
+
23
+ # React Native dependencies
24
+ s.dependency "React"
25
+ s.dependency "React-Core"
26
+ s.dependency "NitroModules"
27
+
28
+ # Include paths for libsmb2 headers (XCFramework provides its own headers)
29
+ s.public_header_files = [
30
+ "cpp/**/*.hpp"
31
+ ]
32
+
33
+ # Compiler settings
34
+ s.requires_arc = true
35
+ s.pod_target_xcconfig = {
36
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FOLLY_NO_CONFIG FOLLY_MOBILE=1 FOLLY_USE_LIBCPP=1',
37
+ 'HEADER_SEARCH_PATHS' => [
38
+ '$(inherited)',
39
+ '$(PODS_TARGET_SRCROOT)/cpp',
40
+ '$(PODS_TARGET_SRCROOT)/libsmb2/include',
41
+ '$(PODS_ROOT)/NitroModules',
42
+ '$(PODS_ROOT)/Headers/Private/NitroModules'
43
+ ].join(' '),
44
+ 'OTHER_CPLUSPLUSFLAGS' => '$(inherited) -std=c++20 -Wall'
45
+ }
46
+
47
+ s.user_target_xcconfig = {
48
+ 'HEADER_SEARCH_PATHS' => [
49
+ '$(inherited)',
50
+ '$(PODS_ROOT)/ReactNativeSmb/cpp',
51
+ '$(PODS_TARGET_SRCROOT)/libsmb2/include',
52
+ '$(PODS_ROOT)/Headers/Private/NitroModules'
53
+ ].join(' ')
54
+ }
55
+
56
+ # Modern XCFramework approach - automatically selects correct library
57
+ s.vendored_frameworks = "ios/libs/libsmb2.xcframework"
58
+
59
+ end
@@ -0,0 +1,24 @@
1
+ #import <Foundation/Foundation.h>
2
+ #include <NitroModules/HybridObjectRegistry.hpp>
3
+ #include <ReactNativeSmb/shared/HybridSMB.hpp>
4
+
5
+ @interface ReactNativeSmbModuleLoader : NSObject
6
+ @end
7
+
8
+ @implementation ReactNativeSmbModuleLoader
9
+
10
+ + (void)load {
11
+ using namespace react_native_smb;
12
+ using namespace margelo::nitro;
13
+
14
+ HybridObjectRegistry::registerHybridObjectConstructor(
15
+ "ReactNativeSmb",
16
+ []() -> std::shared_ptr<HybridObject> {
17
+ return std::make_shared<HybridSMB>();
18
+ }
19
+ );
20
+
21
+ NSLog(@"ReactNativeSmb module registered");
22
+ }
23
+
24
+ @end
@@ -0,0 +1,324 @@
1
+ #include "HybridSMB.hpp"
2
+
3
+ #include <poll.h>
4
+ #include <smb2/libsmb2-dcerpc-srvsvc.h>
5
+ #include <smb2/libsmb2-raw.h>
6
+
7
+ #include <NitroModules/Promise.hpp>
8
+ #include <stdexcept>
9
+ #include <type_traits>
10
+ #include <unordered_map>
11
+ #include <utility>
12
+
13
+ #include "connection/PoolTypes.hpp"
14
+ #include "util/SmbErrorMapper.hpp"
15
+ #include "util/SmbLog.hpp"
16
+ #include "core/SmbEnums.hpp"
17
+ #include "core/TaskSnapshotCodec.hpp"
18
+ #include "operators/connection/ConnectOperator.hpp"
19
+ #include "operators/connection/ConnectShareOperator.hpp"
20
+ #include "operators/connection/DisconnectOperator.hpp"
21
+ #include "operators/connection/InitializeOperator.hpp"
22
+ #include "operators/connection/ListSharesOperator.hpp"
23
+ #include "operators/listing/GetPathInfoOperator.hpp"
24
+ #include "operators/listing/GetSecurityDescriptorOperator.hpp"
25
+ #include "operators/listing/ListDirectoryOperator.hpp"
26
+ #include "operators/mutate/CopyItemOperator.hpp"
27
+ #include "operators/mutate/CreateDirectoryOperator.hpp"
28
+ #include "operators/mutate/DeleteItemOperator.hpp"
29
+ #include "operators/mutate/DuplicateItemOperator.hpp"
30
+ #include "operators/mutate/MoveItemOperator.hpp"
31
+ #include "operators/mutate/RenameItemOperator.hpp"
32
+ #include "operators/transfer/DownloadFileOperator.hpp"
33
+ #include "operators/transfer/UploadFileOperator.hpp"
34
+
35
+ namespace react_native_smb {
36
+ using namespace margelo::nitro;
37
+
38
+ template <typename OpT, typename R>
39
+ std::shared_ptr<SmbTask> HybridSMB::createTask(const std::string& taskId, std::unique_ptr<OpT> seedOp) {
40
+ auto task = std::make_shared<SmbTask>(taskId, std::move(seedOp), pool_.get());
41
+
42
+ if (observer_) observer_->track(task);
43
+ {
44
+ std::lock_guard<std::mutex> lk(tasksMutex_);
45
+ tasks_[taskId] = task;
46
+ }
47
+
48
+ (void)Promise<void>::async([task]() {
49
+ task->start();
50
+ });
51
+
52
+ return task;
53
+ }
54
+
55
+ HybridSMB::HybridSMB() : HybridObject(NAME) {
56
+ // 4 parallel SMB connections — each slot is an independent TCP/SMB2 session
57
+ // to the same server/user/share. The pool reserves one slot for Interactive
58
+ // callers (UI ops) so long Metadata fan-outs (parallel copy/delete/list) cannot
59
+ // freeze the UI; see AcquireMode in PoolTypes.hpp.
60
+ pool_ = std::make_unique<SmbConnectionPool>(4);
61
+ observer_ = std::make_unique<TaskObserverHub>();
62
+ }
63
+
64
+ HybridSMB::~HybridSMB() { pool_->disconnect(); }
65
+
66
+ // --- State Checks ---
67
+
68
+ bool HybridSMB::isConnected() { return pool_ && pool_->isConnected(); }
69
+
70
+ bool HybridSMB::isInitialized() { return pool_ && pool_->isInitialized(); }
71
+
72
+ // --- Connection Management ---
73
+
74
+ std::shared_ptr<SmbTask> HybridSMB::initialize(const std::string& taskId, const std::string& url, const SmbCredentials& credentials) {
75
+ return createTask<InitializeOperator, void>(taskId, std::make_unique<InitializeOperator>(url, credentials));
76
+ }
77
+
78
+ std::shared_ptr<SmbTask> HybridSMB::connect(const std::string& taskId, const std::string& url, const SmbCredentials& credentials) {
79
+ return createTask<ConnectOperator, SmbConnectionInfo>(taskId, std::make_unique<ConnectOperator>(url, credentials));
80
+ }
81
+
82
+ std::shared_ptr<SmbTask> HybridSMB::disconnect(const std::string& taskId) {
83
+ return createTask<DisconnectOperator, void>(taskId, std::make_unique<DisconnectOperator>());
84
+ }
85
+
86
+ std::shared_ptr<SmbTask> HybridSMB::listShares(const std::string& taskId) {
87
+ return createTask<ListSharesOperator, std::vector<SmbShareList>>(taskId, std::make_unique<ListSharesOperator>());
88
+ }
89
+
90
+ std::shared_ptr<SmbTask> HybridSMB::connectShare(const std::string& taskId, const std::string& share) {
91
+ return createTask<ConnectShareOperator, SmbConnectionInfo>(taskId, std::make_unique<ConnectShareOperator>(share));
92
+ }
93
+
94
+ // --- Listing & Info ---
95
+
96
+ std::shared_ptr<SmbTask> HybridSMB::listDirectory(const std::string& taskId, const std::string& path, bool recursive, int maxDepth) {
97
+ return createTask<ListDirectoryOperator, std::vector<SmbFileInfo>>(taskId, std::make_unique<ListDirectoryOperator>(path, recursive, maxDepth));
98
+ }
99
+
100
+ std::shared_ptr<SmbTask> HybridSMB::getPathInfo(const std::string& taskId, const std::string& path) {
101
+ return createTask<GetPathInfoOperator, SmbFileInfo>(taskId, std::make_unique<GetPathInfoOperator>(path));
102
+ }
103
+
104
+ std::shared_ptr<SmbTask> HybridSMB::getSecurityDescriptor(const std::string& taskId, const std::string& path) {
105
+ return createTask<GetSecurityDescriptorOperator, SmbSecurityDescriptor>(taskId, std::make_unique<GetSecurityDescriptorOperator>(path));
106
+ }
107
+
108
+ // --- File Transfers ---
109
+
110
+ std::shared_ptr<SmbTask> HybridSMB::downloadFile(const std::string& taskId, const std::string& remotePath, const std::string& localPath) {
111
+ return createTask<DownloadFileOperator, void>(taskId, std::make_unique<DownloadFileOperator>(remotePath, localPath));
112
+ }
113
+
114
+ std::shared_ptr<SmbTask> HybridSMB::uploadFile(const std::string& taskId, const std::string& localPath, const std::string& remotePath) {
115
+ return createTask<UploadFileOperator, void>(taskId, std::make_unique<UploadFileOperator>(localPath, remotePath));
116
+ }
117
+
118
+ // --- Mutating File Operations ---
119
+
120
+ std::shared_ptr<SmbTask> HybridSMB::createDirectory(const std::string& taskId, const std::string& path) {
121
+ return createTask<CreateDirectoryOperator, void>(taskId, std::make_unique<CreateDirectoryOperator>(path));
122
+ }
123
+
124
+ std::shared_ptr<SmbTask> HybridSMB::deleteItem(const std::string& taskId, const std::string& path) {
125
+ return createTask<DeleteItemOperator, void>(taskId, std::make_unique<DeleteItemOperator>(path));
126
+ }
127
+
128
+ std::shared_ptr<SmbTask> HybridSMB::moveItem(const std::string& taskId, const std::string& fromPath, const std::string& toPath) {
129
+ return createTask<MoveItemOperator, void>(taskId, std::make_unique<MoveItemOperator>(fromPath, toPath));
130
+ }
131
+
132
+ std::shared_ptr<SmbTask> HybridSMB::renameItem(const std::string& taskId, const std::string& currentPath, const std::string& newName) {
133
+ return createTask<RenameItemOperator, void>(taskId, std::make_unique<RenameItemOperator>(currentPath, newName));
134
+ }
135
+
136
+ std::shared_ptr<SmbTask> HybridSMB::copyItem(const std::string& taskId, const std::string& fromPath, const std::string& toPath, bool recursive) {
137
+ return createTask<CopyItemOperator, void>(taskId, std::make_unique<CopyItemOperator>(fromPath, toPath, recursive));
138
+ }
139
+
140
+ std::shared_ptr<SmbTask> HybridSMB::duplicateItem(const std::string& taskId, const std::string& path) {
141
+ return createTask<DuplicateItemOperator, std::string>(taskId, std::make_unique<DuplicateItemOperator>(path));
142
+ }
143
+
144
+ void HybridSMB::cancelTask(const std::string& taskId) {
145
+ std::shared_ptr<SmbTask> task;
146
+ {
147
+ std::lock_guard<std::mutex> lk(tasksMutex_);
148
+ auto it = tasks_.find(taskId);
149
+ if (it != tasks_.end()) task = it->second;
150
+ }
151
+ if (task) task->cancel();
152
+ }
153
+
154
+ void HybridSMB::resetPool() {
155
+ if (pool_) pool_->resetPool();
156
+ }
157
+
158
+ namespace {
159
+
160
+ std::unordered_map<std::string, std::string> encodePoolSlot(const PoolSlotInfo& s) {
161
+ std::unordered_map<std::string, std::string> m;
162
+ m["poolSize"] = std::to_string(s.poolSize);
163
+ m["index"] = std::to_string(s.index);
164
+ m["interactiveOnly"] = s.interactiveOnly ? "1" : "0";
165
+ m["state"] = std::to_string(static_cast<int>(s.state));
166
+ m["kind"] = std::to_string(static_cast<int>(s.kind));
167
+ m["isConnected"] = s.isConnected ? "1" : "0";
168
+ m["shareName"] = s.shareName;
169
+ m["taskId"] = s.taskId;
170
+ return m;
171
+ }
172
+
173
+ } // namespace
174
+
175
+ std::vector<std::unordered_map<std::string, std::string>> HybridSMB::getPoolInfo() {
176
+ std::vector<std::unordered_map<std::string, std::string>> out;
177
+ if (!pool_) return out;
178
+ for (const auto& s : pool_->getPoolStatus()) out.push_back(encodePoolSlot(s));
179
+ return out;
180
+ }
181
+
182
+ std::string HybridSMB::subscribePoolInfo(const std::function<void(const std::vector<std::unordered_map<std::string, std::string>>&)>& listener) {
183
+ std::string key = std::to_string(poolListenerToken_.fetch_add(1));
184
+ {
185
+ std::lock_guard<std::mutex> lock(poolListenersMutex_);
186
+ poolListeners_.emplace(key, listener);
187
+ }
188
+ if (pool_) {
189
+ size_t obsId = pool_->addObserver([this, key](const std::vector<PoolSlotInfo>& status) {
190
+ std::vector<std::unordered_map<std::string, std::string>> out;
191
+ for (const auto& s : status) out.push_back(encodePoolSlot(s));
192
+ PoolListener cb;
193
+ {
194
+ std::lock_guard<std::mutex> lock(poolListenersMutex_);
195
+ auto it = poolListeners_.find(key);
196
+ if (it != poolListeners_.end()) cb = it->second;
197
+ }
198
+ if (cb) {
199
+ try {
200
+ cb(out);
201
+ } catch (...) {
202
+ }
203
+ }
204
+ });
205
+ std::lock_guard<std::mutex> lock(poolListenersMutex_);
206
+ poolObserverIds_[key] = obsId;
207
+ }
208
+ return key;
209
+ }
210
+
211
+ void HybridSMB::unsubscribePoolInfo(const std::string& subscriptionId) {
212
+ size_t obsId = 0;
213
+ {
214
+ std::lock_guard<std::mutex> lock(poolListenersMutex_);
215
+ auto it = poolObserverIds_.find(subscriptionId);
216
+ if (it != poolObserverIds_.end()) {
217
+ obsId = it->second;
218
+ poolObserverIds_.erase(it);
219
+ }
220
+ poolListeners_.erase(subscriptionId);
221
+ }
222
+ if (obsId && pool_) {
223
+ pool_->removeObserver(obsId);
224
+ }
225
+ }
226
+
227
+ // --- Task observer APIs ---
228
+
229
+ std::string HybridSMB::subscribeTaskEvents(const std::function<void(const std::unordered_map<std::string, std::string>&)>& listener) {
230
+ if (!observer_) return "";
231
+ // The hub forwards snapshots
232
+ auto eventId = std::make_shared<std::atomic<uint64_t>>(1);
233
+ return observer_->subscribeAll([listener, eventId](const SmbTaskState& s) {
234
+ std::unordered_map<std::string, std::string> m = TaskSnapshotCodec::encode(s);
235
+ m["eventId"] = std::to_string(eventId->fetch_add(1));
236
+ m["type"] = std::to_string(static_cast<int>(s.status)); // status drives event type
237
+ m["ts"] = std::to_string(s.updatedAt);
238
+ listener(m);
239
+ });
240
+ }
241
+
242
+ void HybridSMB::unsubscribeTaskEvents(const std::string& subscriptionId) {
243
+ if (observer_) observer_->unsubscribe(subscriptionId);
244
+ }
245
+
246
+ std::unordered_map<std::string, std::string> HybridSMB::getTask(const std::string& taskId) {
247
+ if (!observer_) return TaskSnapshotCodec::notFound();
248
+ auto snapshot = observer_->getTask(taskId);
249
+ if (!snapshot) return TaskSnapshotCodec::notFound();
250
+ return TaskSnapshotCodec::encode(*snapshot);
251
+ }
252
+
253
+ std::vector<std::unordered_map<std::string, std::string>> HybridSMB::getActiveTasks() {
254
+ std::vector<std::unordered_map<std::string, std::string>> out;
255
+ if (!observer_) return out;
256
+ for (const auto& snapshot : observer_->getActive()) out.push_back(TaskSnapshotCodec::encode(snapshot));
257
+ return out;
258
+ }
259
+
260
+ std::vector<std::unordered_map<std::string, std::string>> HybridSMB::getTaskHistory(int limit, int offset) {
261
+ std::vector<std::unordered_map<std::string, std::string>> out;
262
+ if (!observer_) return out;
263
+ const size_t safeLimit = limit < 0 ? 0 : static_cast<size_t>(limit);
264
+ const size_t safeOffset = offset < 0 ? 0 : static_cast<size_t>(offset);
265
+ for (const auto& snapshot : observer_->getHistory(safeLimit, safeOffset)) out.push_back(TaskSnapshotCodec::encode(snapshot));
266
+ return out;
267
+ }
268
+
269
+ void HybridSMB::clearTaskHistory(int64_t beforeTs) {
270
+ if (observer_) observer_->clearHistory(beforeTs);
271
+ }
272
+
273
+ void HybridSMB::loadHybridMethods() {
274
+ // Call parent implementation
275
+ HybridObject::loadHybridMethods();
276
+
277
+ // Register methods
278
+ registerHybrids(this, [](Prototype& prototype) {
279
+ // --- State Checks ---
280
+ prototype.registerHybridMethod("isConnected", &HybridSMB::isConnected);
281
+ prototype.registerHybridMethod("isInitialized", &HybridSMB::isInitialized);
282
+
283
+ // --- Connection Management ---
284
+ prototype.registerHybridMethod("initialize", &HybridSMB::initialize);
285
+ prototype.registerHybridMethod("connect", &HybridSMB::connect);
286
+ prototype.registerHybridMethod("connectShare", &HybridSMB::connectShare);
287
+ prototype.registerHybridMethod("disconnect", &HybridSMB::disconnect);
288
+ prototype.registerHybridMethod("listShares", &HybridSMB::listShares);
289
+
290
+ // --- Listing & Info ---
291
+ prototype.registerHybridMethod("listDirectory", &HybridSMB::listDirectory);
292
+ prototype.registerHybridMethod("getPathInfo", &HybridSMB::getPathInfo);
293
+ prototype.registerHybridMethod("getSecurityDescriptor", &HybridSMB::getSecurityDescriptor);
294
+
295
+ // --- File Transfers ---
296
+ prototype.registerHybridMethod("downloadFile", &HybridSMB::downloadFile);
297
+ prototype.registerHybridMethod("uploadFile", &HybridSMB::uploadFile);
298
+
299
+ // --- Mutating File Operations ---
300
+ prototype.registerHybridMethod("createDirectory", &HybridSMB::createDirectory);
301
+ prototype.registerHybridMethod("deleteItem", &HybridSMB::deleteItem);
302
+ prototype.registerHybridMethod("moveItem", &HybridSMB::moveItem);
303
+ prototype.registerHybridMethod("renameItem", &HybridSMB::renameItem);
304
+ prototype.registerHybridMethod("copyItem", &HybridSMB::copyItem);
305
+ prototype.registerHybridMethod("duplicateItem", &HybridSMB::duplicateItem);
306
+
307
+ // Task control
308
+ prototype.registerHybridMethod("subscribeTaskEvents", &HybridSMB::subscribeTaskEvents);
309
+ prototype.registerHybridMethod("unsubscribeTaskEvents", &HybridSMB::unsubscribeTaskEvents);
310
+ prototype.registerHybridMethod("getTask", &HybridSMB::getTask);
311
+ prototype.registerHybridMethod("getActiveTasks", &HybridSMB::getActiveTasks);
312
+ prototype.registerHybridMethod("getTaskHistory", &HybridSMB::getTaskHistory);
313
+ prototype.registerHybridMethod("cancelTask", &HybridSMB::cancelTask);
314
+ prototype.registerHybridMethod("clearTaskHistory", &HybridSMB::clearTaskHistory);
315
+
316
+ // Debug / instrumentation
317
+ prototype.registerHybridMethod("subscribePoolInfo", &HybridSMB::subscribePoolInfo);
318
+ prototype.registerHybridMethod("unsubscribePoolInfo", &HybridSMB::unsubscribePoolInfo);
319
+ prototype.registerHybridMethod("getPoolInfo", &HybridSMB::getPoolInfo);
320
+ prototype.registerHybridMethod("resetPool", &HybridSMB::resetPool);
321
+ });
322
+ }
323
+
324
+ } // namespace react_native_smb
@@ -0,0 +1,102 @@
1
+ #pragma once
2
+
3
+ #include "ReactNativeSmb.hpp"
4
+ #include "connection/SmbConnectionPool.hpp"
5
+ #include "core/SmbTask.hpp"
6
+ #include "core/TaskObserverHub.hpp"
7
+ #include "operators/OperatorBase.hpp"
8
+
9
+ #include <smb2/smb2.h>
10
+ #include <smb2/libsmb2.h>
11
+
12
+ #include <NitroModules/HybridObject.hpp>
13
+ #include <NitroModules/Promise.hpp>
14
+ #include <atomic>
15
+ #include <cstddef>
16
+ #include <cstdint>
17
+ #include <ctime>
18
+ #include <functional>
19
+ #include <map>
20
+ #include <memory>
21
+ #include <mutex>
22
+ #include <unordered_map>
23
+ #include <vector>
24
+
25
+ namespace react_native_smb {
26
+ using namespace margelo::nitro;
27
+
28
+ class HybridSMB : public ReactNativeSmb {
29
+ private:
30
+ std::unique_ptr<SmbConnectionPool> pool_;
31
+ // Optional observer; tracks every task this instance creates.
32
+ std::unique_ptr<TaskObserverHub> observer_;
33
+
34
+ // Live tasks, kept only so cancelTask/getTask can locate them.
35
+ std::map<std::string, std::shared_ptr<SmbTask>> tasks_;
36
+ std::mutex tasksMutex_;
37
+
38
+ using PoolListener = std::function<void(const std::vector<std::unordered_map<std::string, std::string>>&)>;
39
+ std::map<std::string, PoolListener> poolListeners_;
40
+ std::map<std::string, size_t> poolObserverIds_;
41
+ std::mutex poolListenersMutex_;
42
+ std::atomic<size_t> poolListenerToken_{1};
43
+
44
+ // SmbTask factory
45
+ template <typename OpT, typename R>
46
+ std::shared_ptr<SmbTask> createTask(const std::string& taskId, std::unique_ptr<OpT> seedOp);
47
+
48
+
49
+ public:
50
+ HybridSMB();
51
+ virtual ~HybridSMB();
52
+
53
+ // Implement ReactNativeSmb interface
54
+
55
+ // --- State Checks ---
56
+ bool isConnected() override;
57
+ bool isInitialized() override;
58
+
59
+ // --- Connection Management ---
60
+ std::shared_ptr<SmbTask> initialize(const std::string& taskId, const std::string& url, const SmbCredentials& credentials) override;
61
+ std::shared_ptr<SmbTask> connect(const std::string& taskId, const std::string& url, const SmbCredentials& credentials) override;
62
+ std::shared_ptr<SmbTask> connectShare(const std::string& taskId, const std::string& share) override;
63
+ std::shared_ptr<SmbTask> disconnect(const std::string& taskId) override;
64
+ std::shared_ptr<SmbTask> listShares(const std::string& taskId) override;
65
+
66
+ // --- Listing & Info ---
67
+ std::shared_ptr<SmbTask> listDirectory(const std::string& taskId, const std::string& path, bool recursive, int maxDepth) override;
68
+ std::shared_ptr<SmbTask> getPathInfo(const std::string& taskId, const std::string& path) override;
69
+ std::shared_ptr<SmbTask> getSecurityDescriptor(const std::string& taskId, const std::string& path) override;
70
+
71
+ // --- File Transfers ---
72
+ std::shared_ptr<SmbTask> downloadFile(const std::string& taskId, const std::string& remotePath, const std::string& localPath) override;
73
+ std::shared_ptr<SmbTask> uploadFile(const std::string& taskId, const std::string& localPath, const std::string& remotePath) override;
74
+
75
+ // --- Mutating File Operations ---
76
+ std::shared_ptr<SmbTask> createDirectory(const std::string& taskId, const std::string& path) override;
77
+ std::shared_ptr<SmbTask> deleteItem(const std::string& taskId, const std::string& path) override;
78
+ std::shared_ptr<SmbTask> moveItem(const std::string& taskId, const std::string& fromPath, const std::string& toPath) override;
79
+ std::shared_ptr<SmbTask> renameItem(const std::string& taskId, const std::string& currentPath, const std::string& newName) override;
80
+ std::shared_ptr<SmbTask> copyItem(const std::string& taskId, const std::string& fromPath, const std::string& toPath, bool recursive) override;
81
+ std::shared_ptr<SmbTask> duplicateItem(const std::string& taskId, const std::string& path) override;
82
+
83
+ // Task control
84
+ std::string subscribeTaskEvents(const std::function<void(const std::unordered_map<std::string, std::string>&)>& listener) override;
85
+ void unsubscribeTaskEvents(const std::string& subscriptionId) override;
86
+ std::unordered_map<std::string, std::string> getTask(const std::string& taskId) override;
87
+ std::vector<std::unordered_map<std::string, std::string>> getActiveTasks() override;
88
+ std::vector<std::unordered_map<std::string, std::string>> getTaskHistory(int limit, int offset) override;
89
+ void cancelTask(const std::string& taskId) override;
90
+ void clearTaskHistory(int64_t beforeTs) override;
91
+
92
+ // Debug / instrumentation
93
+ std::string subscribePoolInfo(const std::function<void(const std::vector<std::unordered_map<std::string, std::string>>&)>& listener) override;
94
+ void unsubscribePoolInfo(const std::string& subscriptionId) override;
95
+ std::vector<std::unordered_map<std::string, std::string>> getPoolInfo() override;
96
+ void resetPool() override;
97
+
98
+ protected:
99
+ void loadHybridMethods() override;
100
+ };
101
+
102
+ } // namespace react_native_smb