@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.
- package/LICENSE +20 -0
- package/README.md +72 -0
- package/ReactNativeSmb.podspec +59 -0
- package/cpp/ios/OnLoad.mm +24 -0
- package/cpp/shared/HybridSMB.cpp +324 -0
- package/cpp/shared/HybridSMB.hpp +102 -0
- package/cpp/shared/ReactNativeSmb.hpp +428 -0
- package/cpp/shared/connection/ContextRequest.hpp +27 -0
- package/cpp/shared/connection/ContextRequestQueue.cpp +85 -0
- package/cpp/shared/connection/ContextRequestQueue.hpp +28 -0
- package/cpp/shared/connection/MetadataContextLease.hpp +33 -0
- package/cpp/shared/connection/PoolContextHandle.cpp +35 -0
- package/cpp/shared/connection/PoolContextHandle.hpp +44 -0
- package/cpp/shared/connection/PoolSlot.cpp +73 -0
- package/cpp/shared/connection/PoolSlot.hpp +46 -0
- package/cpp/shared/connection/PoolTypes.hpp +41 -0
- package/cpp/shared/connection/SmbConnection.cpp +385 -0
- package/cpp/shared/connection/SmbConnection.hpp +93 -0
- package/cpp/shared/connection/SmbConnectionPool.cpp +316 -0
- package/cpp/shared/connection/SmbConnectionPool.hpp +84 -0
- package/cpp/shared/core/CancellationToken.hpp +22 -0
- package/cpp/shared/core/OperatorContext.hpp +24 -0
- package/cpp/shared/core/SmbEnums.hpp +126 -0
- package/cpp/shared/core/SmbTask.cpp +131 -0
- package/cpp/shared/core/SmbTask.hpp +52 -0
- package/cpp/shared/core/SmbTaskCore.cpp +222 -0
- package/cpp/shared/core/SmbTaskCore.hpp +107 -0
- package/cpp/shared/core/SmbTypes.hpp +35 -0
- package/cpp/shared/core/TaskObserverHub.cpp +166 -0
- package/cpp/shared/core/TaskObserverHub.hpp +66 -0
- package/cpp/shared/core/TaskSnapshotCodec.cpp +32 -0
- package/cpp/shared/core/TaskSnapshotCodec.hpp +41 -0
- package/cpp/shared/io/SmbCopyTree.hpp +114 -0
- package/cpp/shared/io/SmbDirScan.hpp +80 -0
- package/cpp/shared/io/SmbFileIO.cpp +1355 -0
- package/cpp/shared/io/SmbFileIO.hpp +45 -0
- package/cpp/shared/io/SmbPathUtil.hpp +75 -0
- package/cpp/shared/io/SmbSecurity.cpp +308 -0
- package/cpp/shared/io/SmbSecurity.hpp +32 -0
- package/cpp/shared/io/SmbTreeOps.hpp +112 -0
- package/cpp/shared/operators/Operator.hpp +35 -0
- package/cpp/shared/operators/OperatorBase.cpp +57 -0
- package/cpp/shared/operators/OperatorBase.hpp +57 -0
- package/cpp/shared/operators/connection/ConnectOperator.cpp +19 -0
- package/cpp/shared/operators/connection/ConnectOperator.hpp +22 -0
- package/cpp/shared/operators/connection/ConnectShareOperator.cpp +19 -0
- package/cpp/shared/operators/connection/ConnectShareOperator.hpp +21 -0
- package/cpp/shared/operators/connection/DisconnectOperator.cpp +12 -0
- package/cpp/shared/operators/connection/DisconnectOperator.hpp +15 -0
- package/cpp/shared/operators/connection/InitializeOperator.cpp +12 -0
- package/cpp/shared/operators/connection/InitializeOperator.hpp +22 -0
- package/cpp/shared/operators/connection/ListSharesOperator.cpp +13 -0
- package/cpp/shared/operators/connection/ListSharesOperator.hpp +18 -0
- package/cpp/shared/operators/listing/GetPathInfoOperator.cpp +43 -0
- package/cpp/shared/operators/listing/GetPathInfoOperator.hpp +21 -0
- package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.cpp +202 -0
- package/cpp/shared/operators/listing/GetSecurityDescriptorOperator.hpp +22 -0
- package/cpp/shared/operators/listing/ListDirectoryOperator.cpp +20 -0
- package/cpp/shared/operators/listing/ListDirectoryOperator.hpp +24 -0
- package/cpp/shared/operators/mutate/CopyItemOperator.cpp +19 -0
- package/cpp/shared/operators/mutate/CopyItemOperator.hpp +25 -0
- package/cpp/shared/operators/mutate/CreateDirectoryOperator.cpp +28 -0
- package/cpp/shared/operators/mutate/CreateDirectoryOperator.hpp +20 -0
- package/cpp/shared/operators/mutate/DeleteItemOperator.cpp +96 -0
- package/cpp/shared/operators/mutate/DeleteItemOperator.hpp +23 -0
- package/cpp/shared/operators/mutate/DuplicateItemOperator.cpp +48 -0
- package/cpp/shared/operators/mutate/DuplicateItemOperator.hpp +23 -0
- package/cpp/shared/operators/mutate/MoveItemOperator.cpp +32 -0
- package/cpp/shared/operators/mutate/MoveItemOperator.hpp +21 -0
- package/cpp/shared/operators/mutate/RenameItemOperator.cpp +37 -0
- package/cpp/shared/operators/mutate/RenameItemOperator.hpp +21 -0
- package/cpp/shared/operators/transfer/DownloadFileOperator.cpp +31 -0
- package/cpp/shared/operators/transfer/DownloadFileOperator.hpp +21 -0
- package/cpp/shared/operators/transfer/UploadFileOperator.cpp +27 -0
- package/cpp/shared/operators/transfer/UploadFileOperator.hpp +21 -0
- package/cpp/shared/util/SmbErrorMapper.hpp +229 -0
- package/cpp/shared/util/SmbLog.hpp +20 -0
- package/docs/API.md +105 -0
- package/docs/ARCHITECTURE.md +70 -0
- package/docs/TASK_MODEL.md +149 -0
- package/ios/include/smb2/libsmb2-dcerpc-lsa.h +172 -0
- package/ios/include/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
- package/ios/include/smb2/libsmb2-dcerpc.h +155 -0
- package/ios/include/smb2/libsmb2-raw.h +497 -0
- package/ios/include/smb2/libsmb2.h +1384 -0
- package/ios/include/smb2/smb2-errors.h +549 -0
- package/ios/include/smb2/smb2.h +1251 -0
- package/ios/libs/device/libsmb2-device.a +0 -0
- package/ios/libs/libsmb2.xcframework/Info.plist +48 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-dcerpc.h +155 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2-raw.h +497 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/libsmb2.h +1384 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2-errors.h +549 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/Headers/smb2/smb2.h +1251 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64/libsmb2.a +0 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-lsa.h +172 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc-srvsvc.h +180 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-dcerpc.h +155 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2-raw.h +497 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/libsmb2.h +1384 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2-errors.h +549 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/Headers/smb2/smb2.h +1251 -0
- package/ios/libs/libsmb2.xcframework/ios-arm64_x86_64-simulator/libsmb2.a +0 -0
- package/ios/libs/simulator/libsmb2-simulator.a +0 -0
- package/lib/ReactNativeSmb.d.ts +200 -0
- package/lib/ReactNativeSmb.js +1 -0
- package/lib/bridge/decode.d.ts +4 -0
- package/lib/bridge/decode.js +92 -0
- package/lib/core/SMB.d.ts +3 -0
- package/lib/core/SMB.js +4 -0
- package/lib/core/SmbClient.d.ts +35 -0
- package/lib/core/SmbClient.js +99 -0
- package/lib/core/SmbTask.d.ts +41 -0
- package/lib/core/SmbTask.js +74 -0
- package/lib/core/TransferStore.d.ts +22 -0
- package/lib/core/TransferStore.js +88 -0
- package/lib/core/ids.d.ts +1 -0
- package/lib/core/ids.js +3 -0
- package/lib/core/taskResult.d.ts +3 -0
- package/lib/core/taskResult.js +52 -0
- package/lib/hooks/useSubscribe.d.ts +20 -0
- package/lib/hooks/useSubscribe.js +36 -0
- package/lib/hooks/useTransfers.d.ts +7 -0
- package/lib/hooks/useTransfers.js +29 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +7 -0
- package/lib/labels.d.ts +6 -0
- package/lib/labels.js +71 -0
- package/lib/types.d.ts +141 -0
- package/lib/types.js +59 -0
- package/lib/utils.d.ts +79 -0
- package/lib/utils.js +153 -0
- package/package.json +63 -0
- package/scripts/build-libsmb2.sh +143 -0
- package/scripts/create-xcframework.sh +84 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#include "SmbConnectionPool.hpp"
|
|
2
|
+
|
|
3
|
+
#include <stdexcept>
|
|
4
|
+
#include <utility>
|
|
5
|
+
|
|
6
|
+
#include "../util/SmbLog.hpp"
|
|
7
|
+
|
|
8
|
+
namespace react_native_smb {
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
const char* acquireModeName(AcquireMode mode) {
|
|
12
|
+
return mode == AcquireMode::Interactive ? "interactive" : "metadata";
|
|
13
|
+
}
|
|
14
|
+
} // namespace
|
|
15
|
+
|
|
16
|
+
SmbConnectionPool::SmbConnectionPool(size_t maxConnections) : maxConnections_(maxConnections) {
|
|
17
|
+
slots_.reserve(maxConnections);
|
|
18
|
+
slots_.emplace_back(0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
SmbConnectionPool::~SmbConnectionPool() {
|
|
22
|
+
for (auto& slot : slots_) {
|
|
23
|
+
if (slot.manager()) slot.manager()->disconnect();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
PoolSlot& SmbConnectionPool::primarySlot() { return slots_[0]; }
|
|
28
|
+
|
|
29
|
+
const PoolSlot& SmbConnectionPool::primarySlot() const { return slots_[0]; }
|
|
30
|
+
|
|
31
|
+
bool SmbConnectionPool::slotNeedsActivate(const PoolSlot& slot) const {
|
|
32
|
+
const auto* mgr = slot.manager();
|
|
33
|
+
if (!mgr) return true;
|
|
34
|
+
return !mgr->isInitialized() && !serverUrl_.empty() && credentials_ != nullptr;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
size_t SmbConnectionPool::findIdleSlot(AcquireMode mode) const {
|
|
38
|
+
if (mode == AcquireMode::Interactive) {
|
|
39
|
+
if (slots_[0].isIdle()) return 0;
|
|
40
|
+
for (size_t i = 1; i < slots_.size(); ++i) {
|
|
41
|
+
if (slots_[i].isIdle()) return i;
|
|
42
|
+
}
|
|
43
|
+
return SIZE_MAX;
|
|
44
|
+
}
|
|
45
|
+
for (size_t i = 1; i < slots_.size(); ++i) {
|
|
46
|
+
if (slots_[i].isIdle()) return i;
|
|
47
|
+
}
|
|
48
|
+
return SIZE_MAX;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
size_t SmbConnectionPool::maybeGrowSlot() {
|
|
52
|
+
if (slots_.size() >= maxConnections_) return SIZE_MAX;
|
|
53
|
+
const size_t idx = slots_.size();
|
|
54
|
+
slots_.emplace_back(idx);
|
|
55
|
+
return idx;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void SmbConnectionPool::tryAssignNext() {
|
|
59
|
+
std::vector<PoolSlotInfo> snap;
|
|
60
|
+
bool assigned = false;
|
|
61
|
+
for (;;) {
|
|
62
|
+
ContextRequestPtr req;
|
|
63
|
+
size_t slotIdx = SIZE_MAX;
|
|
64
|
+
bool needsActivate = false;
|
|
65
|
+
PoolConnectParams params;
|
|
66
|
+
std::string taskId;
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
std::unique_lock<std::mutex> lock(mutex_);
|
|
70
|
+
queue_.removeCancelledFromHead();
|
|
71
|
+
req = queue_.takeNext();
|
|
72
|
+
if (!req) break;
|
|
73
|
+
|
|
74
|
+
slotIdx = findIdleSlot(req->mode);
|
|
75
|
+
if (slotIdx == SIZE_MAX && req->mode == AcquireMode::Metadata) slotIdx = maybeGrowSlot();
|
|
76
|
+
if (slotIdx == SIZE_MAX) {
|
|
77
|
+
queue_.requeueFront(std::move(req));
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
PoolSlot& slot = slots_[slotIdx];
|
|
82
|
+
if (!slot.accepts(req->mode)) {
|
|
83
|
+
queue_.requeueFront(std::move(req));
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
slot.markActivating();
|
|
88
|
+
params.serverUrl = serverUrl_;
|
|
89
|
+
params.shareName = shareName_;
|
|
90
|
+
params.credentials = credentials_;
|
|
91
|
+
needsActivate = slotNeedsActivate(slot);
|
|
92
|
+
taskId = req->taskId;
|
|
93
|
+
|
|
94
|
+
lock.unlock();
|
|
95
|
+
|
|
96
|
+
bool ok = true;
|
|
97
|
+
try {
|
|
98
|
+
if (needsActivate)
|
|
99
|
+
slot.activate(params, taskId);
|
|
100
|
+
else
|
|
101
|
+
slot.ensureShare(shareName_, taskId);
|
|
102
|
+
} catch (...) {
|
|
103
|
+
ok = false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
lock.lock();
|
|
107
|
+
|
|
108
|
+
if (!ok) {
|
|
109
|
+
SMB_LOG("Pool assign failed slot=%zu kind=%s taskId=%s", slotIdx, operationName(req->kind), req->taskId.c_str());
|
|
110
|
+
slot.resetBroken();
|
|
111
|
+
req->fulfilled.store(true, std::memory_order_release);
|
|
112
|
+
try {
|
|
113
|
+
req->promise.set_value(PoolContextHandle{});
|
|
114
|
+
} catch (...) {
|
|
115
|
+
}
|
|
116
|
+
assignCv_.notify_all();
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
slot.assign(req->id, req->taskId, req->kind);
|
|
121
|
+
SMB_LOG("Pool assign slot=%zu kind=%s taskId=%s mode=%s", slotIdx, operationName(req->kind), req->taskId.c_str(),
|
|
122
|
+
acquireModeName(req->mode));
|
|
123
|
+
PoolContextHandle handle(this, slotIdx, slot.manager());
|
|
124
|
+
req->fulfilled.store(true, std::memory_order_release);
|
|
125
|
+
try {
|
|
126
|
+
req->promise.set_value(std::move(handle));
|
|
127
|
+
} catch (...) {
|
|
128
|
+
slot.release();
|
|
129
|
+
req->fulfilled.store(false, std::memory_order_release);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
assigned = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
{
|
|
136
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
137
|
+
if (assigned) {
|
|
138
|
+
snap.reserve(slots_.size());
|
|
139
|
+
for (const auto& slot : slots_) snap.push_back(slot.snapshot(slots_.size()));
|
|
140
|
+
}
|
|
141
|
+
assignCv_.notify_all();
|
|
142
|
+
}
|
|
143
|
+
if (assigned) {
|
|
144
|
+
for (auto& [id, fn] : observers_) {
|
|
145
|
+
try {
|
|
146
|
+
if (fn) fn(snap);
|
|
147
|
+
} catch (...) {
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
PoolContextHandle SmbConnectionPool::requestContext(AcquireMode mode, SmbOperatorKind kind, const std::string& taskId) {
|
|
154
|
+
ContextRequestPtr req;
|
|
155
|
+
std::future<PoolContextHandle> fut;
|
|
156
|
+
{
|
|
157
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
158
|
+
req = queue_.enqueue(mode, kind, taskId);
|
|
159
|
+
fut = req->promise.get_future();
|
|
160
|
+
}
|
|
161
|
+
tryAssignNext();
|
|
162
|
+
|
|
163
|
+
std::unique_lock<std::mutex> lock(mutex_);
|
|
164
|
+
assignCv_.wait(lock, [&] {
|
|
165
|
+
return req->fulfilled.load(std::memory_order_acquire) || req->cancelled.load(std::memory_order_acquire);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (req->cancelled.load(std::memory_order_acquire)) {
|
|
169
|
+
SMB_LOG("Pool requestContext cancelled kind=%s taskId=%s", operationName(kind), taskId.c_str());
|
|
170
|
+
throw std::runtime_error("context request cancelled");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
PoolContextHandle handle = fut.get();
|
|
174
|
+
if (!handle.valid()) {
|
|
175
|
+
SMB_LOG("Pool requestContext failed kind=%s taskId=%s", operationName(kind), taskId.c_str());
|
|
176
|
+
throw std::runtime_error("context request failed");
|
|
177
|
+
}
|
|
178
|
+
return handle;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
void SmbConnectionPool::releaseContext(const PoolContextHandle& handle) {
|
|
182
|
+
{
|
|
183
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
184
|
+
if (handle.valid()) {
|
|
185
|
+
SMB_LOG("Pool release slot=%zu", handle.slotIndex());
|
|
186
|
+
slots_[handle.slotIndex()].release();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
tryAssignNext();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
void SmbConnectionPool::cancelRequestsForTask(const std::string& taskId) {
|
|
193
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
194
|
+
queue_.cancelForTask(taskId);
|
|
195
|
+
assignCv_.notify_all();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
size_t SmbConnectionPool::addObserver(const PoolObserver& observer) {
|
|
199
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
200
|
+
const size_t id = nextObserverId_++;
|
|
201
|
+
observers_.emplace(id, observer);
|
|
202
|
+
return id;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
void SmbConnectionPool::removeObserver(size_t id) {
|
|
206
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
207
|
+
observers_.erase(id);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
std::vector<PoolSlotInfo> SmbConnectionPool::getPoolStatus() const {
|
|
211
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
212
|
+
std::vector<PoolSlotInfo> out;
|
|
213
|
+
out.reserve(slots_.size());
|
|
214
|
+
for (const auto& slot : slots_) out.push_back(slot.snapshot(slots_.size()));
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
void SmbConnectionPool::initialize(const std::string& url, const SmbCredentials& credentials, const std::string& taskId) {
|
|
219
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
220
|
+
serverUrl_ = url;
|
|
221
|
+
credentials_ = std::make_shared<SmbCredentials>(credentials);
|
|
222
|
+
shareName_.clear();
|
|
223
|
+
primarySlot().manager()->initialize(url, credentials, taskId);
|
|
224
|
+
for (size_t i = 1; i < slots_.size(); ++i) {
|
|
225
|
+
if (slots_[i].isIdle() && slots_[i].manager()) slots_[i].manager()->disconnect();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void SmbConnectionPool::connect(const std::string& url, const SmbCredentials& credentials, const std::string& taskId) {
|
|
230
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
231
|
+
serverUrl_ = url;
|
|
232
|
+
credentials_ = std::make_shared<SmbCredentials>(credentials);
|
|
233
|
+
shareName_.clear();
|
|
234
|
+
if (url.size() > 6 && url.substr(0, 6) == "smb://") {
|
|
235
|
+
std::string remaining = url.substr(6);
|
|
236
|
+
const size_t slash = remaining.find('/');
|
|
237
|
+
if (slash != std::string::npos) shareName_ = remaining.substr(slash + 1);
|
|
238
|
+
}
|
|
239
|
+
primarySlot().manager()->connect(url, credentials, taskId);
|
|
240
|
+
for (size_t i = 1; i < slots_.size(); ++i) {
|
|
241
|
+
if (slots_[i].isIdle() && slots_[i].manager()) slots_[i].manager()->disconnect();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
void SmbConnectionPool::connectShare(const std::string& share, const std::string& taskId) {
|
|
246
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
247
|
+
shareName_ = share;
|
|
248
|
+
primarySlot().manager()->connectShare(share, taskId);
|
|
249
|
+
for (size_t i = 1; i < slots_.size(); ++i) {
|
|
250
|
+
if (slots_[i].isIdle() && slots_[i].manager()) slots_[i].manager()->disconnect();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
void SmbConnectionPool::disconnect(const std::string& taskId) {
|
|
255
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
256
|
+
serverUrl_.clear();
|
|
257
|
+
shareName_.clear();
|
|
258
|
+
credentials_.reset();
|
|
259
|
+
for (auto& slot : slots_) {
|
|
260
|
+
if (slot.isIdle() && slot.manager()) slot.manager()->disconnect(taskId);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
void SmbConnectionPool::resetPool() {
|
|
265
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
266
|
+
for (auto& slot : slots_) {
|
|
267
|
+
if (slot.manager()) {
|
|
268
|
+
try {
|
|
269
|
+
slot.manager()->disconnect();
|
|
270
|
+
} catch (...) {
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (slots_.size() > 1) slots_.erase(slots_.begin() + 1, slots_.end());
|
|
275
|
+
slots_[0].resetBroken();
|
|
276
|
+
serverUrl_.clear();
|
|
277
|
+
shareName_.clear();
|
|
278
|
+
credentials_.reset();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
std::vector<SmbShareList> SmbConnectionPool::listShares(const std::string& taskId) {
|
|
282
|
+
auto handle = requestContext(AcquireMode::Interactive, SmbOperatorKind::ListShares, taskId);
|
|
283
|
+
return handle.manager().listShares(taskId);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
bool SmbConnectionPool::isConnected() const {
|
|
287
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
288
|
+
return primarySlot().manager() && primarySlot().manager()->isConnected();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
bool SmbConnectionPool::isInitialized() const {
|
|
292
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
293
|
+
return primarySlot().manager() && primarySlot().manager()->isInitialized();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
std::string SmbConnectionPool::getCurrentUrl() const {
|
|
297
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
298
|
+
return primarySlot().manager() ? primarySlot().manager()->getCurrentUrl() : std::string();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
std::string SmbConnectionPool::getServerName() const {
|
|
302
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
303
|
+
return primarySlot().manager() ? primarySlot().manager()->getServerName() : std::string();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
std::string SmbConnectionPool::getShareName() const {
|
|
307
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
308
|
+
return shareName_;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
std::shared_ptr<SmbCredentials> SmbConnectionPool::getCredentials() const {
|
|
312
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
313
|
+
return credentials_;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
} // namespace react_native_smb
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <condition_variable>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <mutex>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
#include "../core/SmbEnums.hpp"
|
|
12
|
+
#include "ContextRequestQueue.hpp"
|
|
13
|
+
#include "PoolContextHandle.hpp"
|
|
14
|
+
#include "PoolSlot.hpp"
|
|
15
|
+
#include "PoolTypes.hpp"
|
|
16
|
+
#include "SmbConnection.hpp"
|
|
17
|
+
|
|
18
|
+
namespace react_native_smb {
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pool layout (maxConnections = N):
|
|
22
|
+
*
|
|
23
|
+
* slot[0] — Interactive-only
|
|
24
|
+
* slot[1..N-1] — General (any AcquireMode; Interactive may overflow here)
|
|
25
|
+
*
|
|
26
|
+
* Op::requestContext → Interactive-first FIFO queue → exclusive slot assignment
|
|
27
|
+
*/
|
|
28
|
+
class SmbConnectionPool {
|
|
29
|
+
public:
|
|
30
|
+
using PoolObserver = std::function<void(const std::vector<PoolSlotInfo>&)>;
|
|
31
|
+
|
|
32
|
+
explicit SmbConnectionPool(size_t maxConnections = 4);
|
|
33
|
+
~SmbConnectionPool();
|
|
34
|
+
|
|
35
|
+
// [connection control]
|
|
36
|
+
void initialize(const std::string& url, const SmbCredentials& credentials, const std::string& taskId = "");
|
|
37
|
+
void connect(const std::string& url, const SmbCredentials& credentials, const std::string& taskId = "");
|
|
38
|
+
void connectShare(const std::string& share, const std::string& taskId = "");
|
|
39
|
+
void disconnect(const std::string& taskId = "");
|
|
40
|
+
void resetPool();
|
|
41
|
+
std::vector<SmbShareList> listShares(const std::string& taskId = "");
|
|
42
|
+
|
|
43
|
+
// [context]
|
|
44
|
+
PoolContextHandle requestContext(AcquireMode mode, SmbOperatorKind kind, const std::string& taskId = "");
|
|
45
|
+
void releaseContext(const PoolContextHandle& handle);
|
|
46
|
+
void cancelRequestsForTask(const std::string& taskId);
|
|
47
|
+
|
|
48
|
+
// [getter]
|
|
49
|
+
std::string getCurrentUrl() const;
|
|
50
|
+
std::string getServerName() const;
|
|
51
|
+
std::string getShareName() const;
|
|
52
|
+
std::shared_ptr<SmbCredentials> getCredentials() const;
|
|
53
|
+
std::vector<PoolSlotInfo> getPoolStatus() const;
|
|
54
|
+
|
|
55
|
+
// [is…]
|
|
56
|
+
bool isConnected() const;
|
|
57
|
+
bool isInitialized() const;
|
|
58
|
+
|
|
59
|
+
// [observer]
|
|
60
|
+
size_t addObserver(const PoolObserver& observer);
|
|
61
|
+
void removeObserver(size_t id);
|
|
62
|
+
|
|
63
|
+
private:
|
|
64
|
+
void tryAssignNext();
|
|
65
|
+
size_t findIdleSlot(AcquireMode mode) const;
|
|
66
|
+
size_t maybeGrowSlot();
|
|
67
|
+
bool slotNeedsActivate(const PoolSlot& slot) const;
|
|
68
|
+
PoolSlot& primarySlot();
|
|
69
|
+
const PoolSlot& primarySlot() const;
|
|
70
|
+
mutable std::mutex mutex_;
|
|
71
|
+
std::condition_variable assignCv_;
|
|
72
|
+
std::vector<PoolSlot> slots_;
|
|
73
|
+
size_t maxConnections_{4};
|
|
74
|
+
ContextRequestQueue queue_;
|
|
75
|
+
|
|
76
|
+
std::string serverUrl_;
|
|
77
|
+
std::string shareName_;
|
|
78
|
+
std::shared_ptr<SmbCredentials> credentials_;
|
|
79
|
+
|
|
80
|
+
std::map<size_t, PoolObserver> observers_;
|
|
81
|
+
size_t nextObserverId_{1};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
} // namespace react_native_smb
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <atomic>
|
|
4
|
+
#include <memory>
|
|
5
|
+
|
|
6
|
+
namespace react_native_smb {
|
|
7
|
+
|
|
8
|
+
// A cheap, copyable cancellation flag shared by a task and all its operators.
|
|
9
|
+
// The task owns the root token; cancel() trips it; operators poll cancelled()
|
|
10
|
+
// inside their work loops. Copying shares the same underlying atomic<bool>.
|
|
11
|
+
class CancellationToken {
|
|
12
|
+
public:
|
|
13
|
+
CancellationToken() = default;
|
|
14
|
+
|
|
15
|
+
void cancel() { flag_->store(true, std::memory_order_relaxed); }
|
|
16
|
+
bool cancelled() const { return flag_->load(std::memory_order_relaxed); }
|
|
17
|
+
|
|
18
|
+
private:
|
|
19
|
+
std::shared_ptr<std::atomic<bool>> flag_ = std::make_shared<std::atomic<bool>>(false);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
} // namespace react_native_smb
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstddef>
|
|
4
|
+
|
|
5
|
+
#include "CancellationToken.hpp"
|
|
6
|
+
|
|
7
|
+
namespace react_native_smb {
|
|
8
|
+
|
|
9
|
+
class SmbTask;
|
|
10
|
+
class SmbConnectionPool;
|
|
11
|
+
|
|
12
|
+
// Everything an operator needs, injected by OperatorBase::start() before run().
|
|
13
|
+
// - task : back-pointer to report status/progress and spawn() more work
|
|
14
|
+
// - pool : connection pool; op calls requestContext() when it needs a slot
|
|
15
|
+
// - cancel : shared token the operator polls in its loop
|
|
16
|
+
// - opIndex : this operator's stable index for per-op aggregation
|
|
17
|
+
struct OperatorContext {
|
|
18
|
+
SmbTask* task{nullptr}; // non-owning
|
|
19
|
+
SmbConnectionPool* pool{nullptr}; // non-owning
|
|
20
|
+
CancellationToken cancel; // shared with the task
|
|
21
|
+
size_t opIndex{0};
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
} // namespace react_native_smb
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
namespace react_native_smb {
|
|
4
|
+
|
|
5
|
+
// One operator class per kind. The enum is the single source of truth for the
|
|
6
|
+
// human-readable operation name (operationName) and whether byte-progress is
|
|
7
|
+
// meaningful (isDeterminate).
|
|
8
|
+
enum class SmbOperatorKind {
|
|
9
|
+
// Connection Management
|
|
10
|
+
Initialize,
|
|
11
|
+
Connect,
|
|
12
|
+
ConnectShare,
|
|
13
|
+
Disconnect,
|
|
14
|
+
ListShares,
|
|
15
|
+
// Listing & Info
|
|
16
|
+
ListDirectory,
|
|
17
|
+
GetPathInfo,
|
|
18
|
+
GetSecurityDescriptor,
|
|
19
|
+
// File Transfers
|
|
20
|
+
DownloadFile,
|
|
21
|
+
UploadFile,
|
|
22
|
+
// Mutating File Operations
|
|
23
|
+
CreateDirectory,
|
|
24
|
+
DeleteItem,
|
|
25
|
+
MoveItem,
|
|
26
|
+
RenameItem,
|
|
27
|
+
CopyItem,
|
|
28
|
+
DuplicateItem,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Task lifecycle status. Index order matters: statusName[] mirrors it.
|
|
32
|
+
enum class SmbTaskStatus {
|
|
33
|
+
Idle,
|
|
34
|
+
Pending,
|
|
35
|
+
Running,
|
|
36
|
+
Success,
|
|
37
|
+
Error,
|
|
38
|
+
Cancelled,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Single source of truth: operation string is derived from the enum, never
|
|
42
|
+
// typed by hand. HybridSMB passes no literal operation string.
|
|
43
|
+
constexpr const char* operationName(SmbOperatorKind k) {
|
|
44
|
+
switch (k) {
|
|
45
|
+
case SmbOperatorKind::Initialize:
|
|
46
|
+
return "initialize";
|
|
47
|
+
case SmbOperatorKind::Connect:
|
|
48
|
+
return "connect";
|
|
49
|
+
case SmbOperatorKind::ConnectShare:
|
|
50
|
+
return "connectShare";
|
|
51
|
+
case SmbOperatorKind::Disconnect:
|
|
52
|
+
return "disconnect";
|
|
53
|
+
case SmbOperatorKind::ListShares:
|
|
54
|
+
return "listShares";
|
|
55
|
+
case SmbOperatorKind::ListDirectory:
|
|
56
|
+
return "listDirectory";
|
|
57
|
+
case SmbOperatorKind::GetPathInfo:
|
|
58
|
+
return "getPathInfo";
|
|
59
|
+
case SmbOperatorKind::GetSecurityDescriptor:
|
|
60
|
+
return "getSecurityDescriptor";
|
|
61
|
+
case SmbOperatorKind::DownloadFile:
|
|
62
|
+
return "downloadFile";
|
|
63
|
+
case SmbOperatorKind::UploadFile:
|
|
64
|
+
return "uploadFile";
|
|
65
|
+
case SmbOperatorKind::CreateDirectory:
|
|
66
|
+
return "createDirectory";
|
|
67
|
+
case SmbOperatorKind::DeleteItem:
|
|
68
|
+
return "deleteItem";
|
|
69
|
+
case SmbOperatorKind::MoveItem:
|
|
70
|
+
return "moveItem";
|
|
71
|
+
case SmbOperatorKind::RenameItem:
|
|
72
|
+
return "renameItem";
|
|
73
|
+
case SmbOperatorKind::CopyItem:
|
|
74
|
+
return "copyItem";
|
|
75
|
+
case SmbOperatorKind::DuplicateItem:
|
|
76
|
+
return "duplicateItem";
|
|
77
|
+
}
|
|
78
|
+
return "unknown";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Transfers carry meaningful byte progress; metadata ops do not. The UI uses
|
|
82
|
+
// this to choose a determinate bar vs. an indeterminate spinner.
|
|
83
|
+
constexpr bool isDeterminate(SmbOperatorKind k) {
|
|
84
|
+
switch (k) {
|
|
85
|
+
case SmbOperatorKind::DownloadFile:
|
|
86
|
+
case SmbOperatorKind::UploadFile:
|
|
87
|
+
case SmbOperatorKind::CopyItem:
|
|
88
|
+
case SmbOperatorKind::DuplicateItem:
|
|
89
|
+
return true;
|
|
90
|
+
default:
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
constexpr bool isTransferKind(SmbOperatorKind k) {
|
|
96
|
+
switch (k) {
|
|
97
|
+
case SmbOperatorKind::DownloadFile:
|
|
98
|
+
case SmbOperatorKind::UploadFile:
|
|
99
|
+
case SmbOperatorKind::CopyItem:
|
|
100
|
+
case SmbOperatorKind::DuplicateItem:
|
|
101
|
+
return true;
|
|
102
|
+
default:
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Lowercase status name for the JS bridge. Index mirrors SmbTaskStatus.
|
|
108
|
+
constexpr const char* statusName(SmbTaskStatus s) {
|
|
109
|
+
switch (s) {
|
|
110
|
+
case SmbTaskStatus::Idle:
|
|
111
|
+
return "idle";
|
|
112
|
+
case SmbTaskStatus::Pending:
|
|
113
|
+
return "pending";
|
|
114
|
+
case SmbTaskStatus::Running:
|
|
115
|
+
return "running";
|
|
116
|
+
case SmbTaskStatus::Success:
|
|
117
|
+
return "success";
|
|
118
|
+
case SmbTaskStatus::Error:
|
|
119
|
+
return "error";
|
|
120
|
+
case SmbTaskStatus::Cancelled:
|
|
121
|
+
return "cancelled";
|
|
122
|
+
}
|
|
123
|
+
return "unknown";
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace react_native_smb
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#include "SmbTask.hpp"
|
|
2
|
+
|
|
3
|
+
#include <NitroModules/Promise.hpp>
|
|
4
|
+
#include <thread>
|
|
5
|
+
|
|
6
|
+
#include "../connection/SmbConnectionPool.hpp"
|
|
7
|
+
#include "../operators/OperatorBase.hpp"
|
|
8
|
+
#include "../util/SmbErrorMapper.hpp"
|
|
9
|
+
#include "TaskSnapshotCodec.hpp"
|
|
10
|
+
#include "../util/SmbLog.hpp"
|
|
11
|
+
|
|
12
|
+
namespace react_native_smb {
|
|
13
|
+
|
|
14
|
+
namespace jsi = facebook::jsi;
|
|
15
|
+
using namespace margelo::nitro;
|
|
16
|
+
|
|
17
|
+
SmbTask::SmbTask(std::string id, std::unique_ptr<OperatorBase> seedOp, SmbConnectionPool* pool)
|
|
18
|
+
: HybridObject("SmbTask"),
|
|
19
|
+
SmbTaskCore(std::move(id), seedOp->kind()),
|
|
20
|
+
pool_(pool) {
|
|
21
|
+
ops_.push_back(std::move(seedOp));
|
|
22
|
+
opProgress_.resize(1);
|
|
23
|
+
loadHybridMethods();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
SmbTask::~SmbTask() = default;
|
|
27
|
+
|
|
28
|
+
void SmbTask::cancel() {
|
|
29
|
+
SMB_LOG("Task cancel id=%s", getId().c_str());
|
|
30
|
+
if (pool_) pool_->cancelRequestsForTask(getId());
|
|
31
|
+
SmbTaskCore::cancel();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void SmbTask::start() {
|
|
35
|
+
markRunning();
|
|
36
|
+
auto fut = completionFuture();
|
|
37
|
+
{
|
|
38
|
+
std::lock_guard<std::mutex> lk(stateMutex_);
|
|
39
|
+
pending_ = 1;
|
|
40
|
+
launchOp(0);
|
|
41
|
+
}
|
|
42
|
+
fut.wait();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void SmbTask::launchOp(size_t opIndex) {
|
|
46
|
+
auto self = std::static_pointer_cast<SmbTask>(shared());
|
|
47
|
+
std::thread([self, opIndex] {
|
|
48
|
+
if (self->cancel_.cancelled()) {
|
|
49
|
+
self->onOpFinished();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
OperatorBase* op = nullptr;
|
|
53
|
+
{
|
|
54
|
+
std::lock_guard<std::mutex> lk(self->stateMutex_);
|
|
55
|
+
if (opIndex < self->ops_.size()) op = self->ops_[opIndex].get();
|
|
56
|
+
}
|
|
57
|
+
if (!op) {
|
|
58
|
+
self->onOpFinished();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
op->start(self.get(), self->pool_, self->cancel_, opIndex);
|
|
63
|
+
} catch (const std::exception& e) {
|
|
64
|
+
if (!self->cancel_.cancelled()) {
|
|
65
|
+
const int code = SmbErrorMapper::fromErrnoOrMessage(0, e.what());
|
|
66
|
+
self->settle(SmbTaskStatus::Error, e.what(), code);
|
|
67
|
+
}
|
|
68
|
+
} catch (...) {
|
|
69
|
+
if (!self->cancel_.cancelled()) {
|
|
70
|
+
self->settle(SmbTaskStatus::Error, "unknown error", static_cast<int>(SmbErrorCode::Unknown));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
self->onOpFinished();
|
|
74
|
+
}).detach();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
size_t SmbTask::appendOps(std::vector<std::unique_ptr<OperatorBase>>& more) {
|
|
78
|
+
const size_t first = ops_.size();
|
|
79
|
+
for (auto& op : more) {
|
|
80
|
+
ops_.push_back(std::move(op));
|
|
81
|
+
}
|
|
82
|
+
opProgress_.resize(ops_.size());
|
|
83
|
+
return first;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
size_t SmbTask::spawn(std::vector<std::unique_ptr<OperatorBase>> moreOps) {
|
|
87
|
+
if (moreOps.empty()) return ops_.size();
|
|
88
|
+
const size_t count = moreOps.size();
|
|
89
|
+
size_t first;
|
|
90
|
+
{
|
|
91
|
+
std::lock_guard<std::mutex> lk(stateMutex_);
|
|
92
|
+
first = appendOps(moreOps);
|
|
93
|
+
pending_ += count;
|
|
94
|
+
for (size_t i = 0; i < count; ++i) launchOp(first + i);
|
|
95
|
+
}
|
|
96
|
+
return first;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
std::unordered_map<std::string, std::string> SmbTask::get() {
|
|
100
|
+
return TaskSnapshotCodec::encode(getState());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
jsi::Value SmbTask::getResultValueRaw(jsi::Runtime& runtime, const jsi::Value& /*thisValue*/, const jsi::Value* /*args*/,
|
|
104
|
+
size_t /*count*/) {
|
|
105
|
+
return SmbTaskCore::getResultValue(runtime);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
std::string SmbTask::subscribeMap(const std::function<void(const std::unordered_map<std::string, std::string>&)>& listener) {
|
|
109
|
+
return SmbTaskCore::subscribe([listener](const SmbTaskState& s) {
|
|
110
|
+
if (listener) {
|
|
111
|
+
try {
|
|
112
|
+
listener(TaskSnapshotCodec::encode(s));
|
|
113
|
+
} catch (...) {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void SmbTask::loadHybridMethods() {
|
|
120
|
+
HybridObject::loadHybridMethods();
|
|
121
|
+
registerHybrids(this, [](Prototype& prototype) {
|
|
122
|
+
prototype.registerHybridMethod("id", &SmbTask::getId);
|
|
123
|
+
prototype.registerHybridMethod("cancel", &SmbTask::cancel);
|
|
124
|
+
prototype.registerHybridMethod("get", &SmbTask::get);
|
|
125
|
+
prototype.registerHybridMethod("subscribe", &SmbTask::subscribeMap);
|
|
126
|
+
prototype.registerHybridMethod("unsubscribe", &SmbTask::unsubscribe);
|
|
127
|
+
prototype.registerRawHybridMethod("getResultValue", 0, &SmbTask::getResultValueRaw);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
} // namespace react_native_smb
|