@trap_stevo/filetide 0.0.85 → 0.0.86
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/SCL-1.0-Universal.md +228 -0
- package/dist/cjs/FileMessagerClient.js +134 -70
- package/dist/cjs/FileTide.js +163 -82
- package/dist/cjs/{FileMessager.js → FileTideAnchor.js} +444 -264
- package/dist/cjs/HUDManagers/EndpointManager.js +157 -0
- package/dist/cjs/HUDManagers/{FileNetClientManager.js → FileTideAnchorClientManager.js} +3 -2
- package/dist/cjs/HUDManagers/{FileNetUtilityManager.js → FileTideAnchorUtilityManager.js} +2 -2
- package/dist/cjs/HUDManagers/FileTideDebugUtilityManager.js +6 -0
- package/dist/cjs/HUDManagers/FileTideNetworkTrafficManager.js +419 -0
- package/dist/cjs/HUDManagers/FileTransferManager.js +90 -157
- package/dist/cjs/HUDManagers/FileTransferReceiverManager.js +169 -9
- package/dist/cjs/HUDManagers/FileTransferStatsManager.js +138 -0
- package/dist/cjs/HUDManagers/FileTransferTrackingManager.js +22 -0
- package/package.json +4 -5
- package/LICENSE.md +0 -79
- package/dist/cjs/HUDComponents/ConsoleProgressBarManager.js +0 -288
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# SCL-1.0-Universal — Steven Compton Universal License v1.0
|
|
2
|
+
(Source-Available, No Redistribution, No Reverse Engineering)
|
|
3
|
+
|
|
4
|
+
**Effective Date:** September 10, 2024
|
|
5
|
+
**Licensor:** Hassan Steven Compton (Steven Compton) (“Licensor”)
|
|
6
|
+
**Package:** @trap_stevo/filetide (“Package”)
|
|
7
|
+
**Licensee:** Any individual or entity installing, using, referencing, or integrating the “Package”
|
|
8
|
+
|
|
9
|
+
**SPDX Identifier:** SCL-1.0-Universal
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Definitions
|
|
14
|
+
|
|
15
|
+
### **1.1 “Package”**
|
|
16
|
+
Refers to the software identified as @trap_stevo/filetide, including its source code, object code, binaries, compiled outputs, metadata, and documentation.
|
|
17
|
+
|
|
18
|
+
### **1.2 “Source Code”**
|
|
19
|
+
Human-readable implementation of the “Package”, whether distributed or not.
|
|
20
|
+
|
|
21
|
+
### **1.3 “Dependent System”**
|
|
22
|
+
Means any system, software, hardware, firmware, service, device, environment, runtime, application, platform, embedded implementation, virtual machine, cloud service, or any other construct that uses, integrates, links to, or depends upon the “Package”, directly or indirectly, without including or exposing the “Package’s” code or internal structure.
|
|
23
|
+
|
|
24
|
+
### **1.4 “Derivative Work”**
|
|
25
|
+
Any software, product, service, system, or implementation based on or derived from the “Package’s” source code, object code, architecture, structure, behavior, or design, in part or in whole.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. Ownership
|
|
30
|
+
|
|
31
|
+
The “Licensor” retains exclusive ownership of all rights, title, and interest in and to the “Package”, including all associated intellectual property.
|
|
32
|
+
|
|
33
|
+
This Agreement transfers no ownership rights to the “Licensee”.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 3. Grant of License
|
|
38
|
+
|
|
39
|
+
Subject to all terms of this Agreement, the “Licensor” grants the “Licensee” a limited, non-exclusive, revocable, non-transferable, and non-sublicensable license to:
|
|
40
|
+
|
|
41
|
+
1. Use the “Package” as a dependency in “Dependent Systems” created by the “Licensee”.
|
|
42
|
+
2. Distribute “Dependent Systems”, provided the “Package” is **never** included, exposed, modified, redistributed, or replicated in any form.
|
|
43
|
+
|
|
44
|
+
Nothing in this Agreement grants the “Licensee” permission to:
|
|
45
|
+
|
|
46
|
+
- modify the “Package”
|
|
47
|
+
- redistribute the “Package”
|
|
48
|
+
- fork the “Package”
|
|
49
|
+
- repackage the “Package”
|
|
50
|
+
- host the “Package”
|
|
51
|
+
- analyze the “Package”
|
|
52
|
+
- expose internal behavior of the “Package”
|
|
53
|
+
- create derivative or competing software based on the “Package”
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 4. Prohibited Uses
|
|
58
|
+
|
|
59
|
+
Without the express written permission of the “Licensor”, the “Licensee” shall not:
|
|
60
|
+
|
|
61
|
+
1. Modify, decompile, reverse-engineer, or disassemble the “Package” in any way.
|
|
62
|
+
2. Include the “Package’s” source code or object code in any distributed software, service, or application.
|
|
63
|
+
3. Use the “Package” to create a competing product or service that replicates the functionality of the “Package”.
|
|
64
|
+
4. Make the “Package” publicly available, including uploading it to public repositories or including it in distributed software bundles.
|
|
65
|
+
5. Attempt to extract or analyze the functionality, structure, or behavior of the “Package” through runtime inspection, instrumentation, reflection, or behavioral analysis.
|
|
66
|
+
6. Privately share, sublicense, or distribute the “Package” or any portion thereof, whether internally within an organization or externally to any third party, without written authorization.
|
|
67
|
+
7. Remove, obscure, obfuscate, or alter any attribution, copyright notices, proprietary labels, or identifiers included in the “Package”.
|
|
68
|
+
8. Re-upload, rename, fork, or redistribute the “Package” or any portion thereof on any registry, platform, or namespace other than that explicitly maintained or authorized by the “Licensor”.
|
|
69
|
+
9. Use the “Package” in any way that violates applicable laws, infringes on third-party rights, or breaches this Agreement.
|
|
70
|
+
|
|
71
|
+
Any attempt to bypass or circumvent these restrictions constitutes a material breach.
|
|
72
|
+
|
|
73
|
+
### 4.A. No Competitive Re-implementation
|
|
74
|
+
|
|
75
|
+
“Licensee” shall not create, develop, train, test, benchmark, or distribute any software, system, service, model, or method that uses, incorporates, is derived from, or is based upon the “Package’s” source code, object code, algorithms, data structures, interfaces, protocols, internal behavior, design, architecture, or execution characteristics for the purpose of creating a product or service that provides substantially similar functionality to the “Package”, competes with the “Package”, or reproduces its core operations.
|
|
76
|
+
|
|
77
|
+
“Licensee” shall not directly or indirectly analyze, observe, measure, study, or evaluate the behavior, performance, outputs, or internal characteristics of the “Package” for the purpose of creating, validating, training, improving, or assisting any competing or functionally similar software, system, service, or model.
|
|
78
|
+
|
|
79
|
+
Any such activity shall constitute creation of an unauthorized derivative work and is strictly prohibited.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 5. Dependent System Requirements
|
|
84
|
+
|
|
85
|
+
The “Licensee” may create and distribute “Dependent Systems” only if all of the following conditions are met:
|
|
86
|
+
|
|
87
|
+
1. The “Dependent System” does **not** include or expose any portion of the “Package’s” source code or object code.
|
|
88
|
+
2. The “Dependent System” identifies the “Package” as a dependency in its documentation.
|
|
89
|
+
3. The “Dependent System” provides substantial original functionality.
|
|
90
|
+
4. The “Dependent System” does not replicate, emulate, reimplement, or mimic any significant part of the “Package’s” behavior or design.
|
|
91
|
+
5. The “Dependent System” complies fully with this Agreement.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 6. Request for Additional Permissions
|
|
96
|
+
|
|
97
|
+
The “Licensee” may request additional rights by contacting:
|
|
98
|
+
|
|
99
|
+
**h.steven.compton13@gmail.com**
|
|
100
|
+
|
|
101
|
+
Requests must:
|
|
102
|
+
|
|
103
|
+
1. Be submitted in writing
|
|
104
|
+
2. Describe purpose, scope, and distribution method
|
|
105
|
+
|
|
106
|
+
The “Licensor” may:
|
|
107
|
+
|
|
108
|
+
- approve or deny at sole discretion
|
|
109
|
+
- impose additional terms
|
|
110
|
+
- revoke previously granted permissions with written notice
|
|
111
|
+
|
|
112
|
+
All permissions must be explicit and in writing.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 7. Violation of Terms (Termination)
|
|
117
|
+
|
|
118
|
+
1. Any violation of this Agreement results in immediate termination of all licensed rights.
|
|
119
|
+
2. Upon termination, the “Licensee” must:
|
|
120
|
+
- cease all use of the “Package”
|
|
121
|
+
- remove the “Package” from all systems and environments
|
|
122
|
+
- destroy all copies, including caches and build artifacts
|
|
123
|
+
- confirm destruction in writing if requested
|
|
124
|
+
3. The “Licensor” may pursue damages, injunctive relief, or any other legal remedy.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 8. No Warranty
|
|
129
|
+
|
|
130
|
+
The “Package” is provided **“AS IS”**, without any warranty, express or implied, including but not limited to merchantability, fitness for a particular purpose, or non-infringement.
|
|
131
|
+
|
|
132
|
+
The “Licensee” assumes all risk associated with use.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 9. Intellectual Property Limitations
|
|
137
|
+
|
|
138
|
+
Nothing in this Agreement grants the “Licensee” any rights under any patent, whether by implication, estoppel, exhaustion, or otherwise. Any use of the “Package” that would require a patent license must receive separate written permission from the “Licensor”.
|
|
139
|
+
|
|
140
|
+
This Agreement also grants no rights to use the “Licensor’s” trademarks, service marks, branding, logos, product names, or organizational names. Any such use requires separate written permission.
|
|
141
|
+
|
|
142
|
+
No patent rights, trademark rights, or branding rights are provided or implied by this license.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 10. Patent Rights and Restrictions
|
|
147
|
+
|
|
148
|
+
### 10.1 No Implied Patent License
|
|
149
|
+
|
|
150
|
+
Except as expressly stated in this Section, the “Licensor” grants no license, covenant, immunity, or right under any patent or patent application owned, controlled, or licensable by the “Licensor”. All such rights are expressly reserved.
|
|
151
|
+
|
|
152
|
+
### 10.2 Patent Grant for Non-Competitive Use
|
|
153
|
+
|
|
154
|
+
Subject to full compliance with this Agreement, the “Licensor” grants the “Licensee” a limited, non-exclusive, non-transferable, revocable, royalty-free patent license to use any patent claims embodied in the “Package” solely to the extent necessary to use the unmodified “Package” as permitted under Section 3.
|
|
155
|
+
|
|
156
|
+
This grant does not extend to:
|
|
157
|
+
|
|
158
|
+
- derivative works
|
|
159
|
+
|
|
160
|
+
- competing software
|
|
161
|
+
|
|
162
|
+
- re-implementations
|
|
163
|
+
|
|
164
|
+
- architectural replications
|
|
165
|
+
|
|
166
|
+
- alternative implementations of patented methods
|
|
167
|
+
|
|
168
|
+
- any use not directly involving the unmodified “Package”
|
|
169
|
+
|
|
170
|
+
### 10.3 Patent Restriction for Competing Systems
|
|
171
|
+
|
|
172
|
+
No patent license is granted for any software, system, service, or model that:
|
|
173
|
+
|
|
174
|
+
- competes with the “Package”,
|
|
175
|
+
|
|
176
|
+
- provides substantially similar core functionality,
|
|
177
|
+
|
|
178
|
+
- implements any patented algorithm, method, design, architecture, or process used by the Package, or
|
|
179
|
+
|
|
180
|
+
- is a re-implementation or functional substitute of the “Package”.
|
|
181
|
+
|
|
182
|
+
Any such use constitutes patent infringement and is prohibited.
|
|
183
|
+
|
|
184
|
+
### 10.4 Termination of Patent Rights
|
|
185
|
+
|
|
186
|
+
Any violation of this Agreement immediately terminates all patent licenses granted herein. Upon termination, Licensee must cease all uses of the patented subject matter and destroy any implementations utilizing such technology.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 11. Indemnification
|
|
191
|
+
|
|
192
|
+
The “Licensee” agrees to indemnify and hold harmless the “Licensor” from any claims, damages, liabilities, losses, or expenses arising from:
|
|
193
|
+
|
|
194
|
+
- violation of this Agreement
|
|
195
|
+
- misuse of the “Package”
|
|
196
|
+
- unlawful or infringing use
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 12. Governing Law & Dispute Resolution
|
|
201
|
+
|
|
202
|
+
This Agreement is governed by the laws of **Georgia, United States**, without regard to conflict-of-law principles.
|
|
203
|
+
|
|
204
|
+
All disputes shall be resolved exclusively through binding arbitration in **Georgia, United States**.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 13. Amendments
|
|
209
|
+
|
|
210
|
+
The “Licensor” may modify this Agreement at any time.
|
|
211
|
+
|
|
212
|
+
Changes take effect 30 days after posting at:
|
|
213
|
+
|
|
214
|
+
**https://www.npmjs.com/package/@trap_stevo/filetide**
|
|
215
|
+
|
|
216
|
+
Continued use of the “Package” constitutes acceptance of the updated terms.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 14. Applicability to All Versions
|
|
221
|
+
|
|
222
|
+
This Agreement applies to **all versions** of the “Package” downloaded, installed, or used on or after the Effective Date.
|
|
223
|
+
|
|
224
|
+
Use of any version after this date constitutes acceptance of this License unless explicitly overridden by the “Licensor”.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
**SPDX-License-Identifier: SCL-1.0-Universal**
|
|
@@ -15,6 +15,9 @@ const {
|
|
|
15
15
|
significantMessageColors,
|
|
16
16
|
errorMessageColors
|
|
17
17
|
} = require("./HUDManagers/FileTideDebugUtilityManager");
|
|
18
|
+
const {
|
|
19
|
+
STATES: NETWORK_TRAFFIC_STATES
|
|
20
|
+
} = require("./HUDManagers/FileTideNetworkTrafficManager.js");
|
|
18
21
|
const {
|
|
19
22
|
FileTransferTrackingManager
|
|
20
23
|
} = require("./HUDManagers/FileTransferTrackingManager.js");
|
|
@@ -42,10 +45,16 @@ class FileMessagerClient {
|
|
|
42
45
|
maxReconnectionAttempts = 15,
|
|
43
46
|
reconnectionAttempts = 15,
|
|
44
47
|
maxReconnectionDelay = 10000,
|
|
48
|
+
tideDurationMs: _tideDurationMs = 125,
|
|
49
|
+
minTideBytes = 512 * 1024,
|
|
50
|
+
maxTideBytes = 8 * 1024 * 1024,
|
|
45
51
|
...messagerConfigurations
|
|
46
52
|
} = messagerSettings;
|
|
47
53
|
this.clientOptions = FileMessagerConfigManager.getClientOptions(_options);
|
|
48
54
|
this.transporter = new FileTransferManager(transportOptions);
|
|
55
|
+
this.tideDurationMs = Math.max(25, _tideDurationMs);
|
|
56
|
+
this.minTideBytes = Math.max(512 * 1024, minTideBytes);
|
|
57
|
+
this.maxTideBytes = Math.max(this.minTideBytes, maxTideBytes);
|
|
49
58
|
this.activeTransferTypes = new Map();
|
|
50
59
|
this.clientTide = new HUDIoTide(maxReconnectionAttempts, reconnectionAttempts, maxReconnectionDelay, {
|
|
51
60
|
persistentTideIDs: true,
|
|
@@ -56,13 +65,19 @@ class FileMessagerClient {
|
|
|
56
65
|
});
|
|
57
66
|
this.clients = new Map();
|
|
58
67
|
}
|
|
68
|
+
recordNetworkThroughput(throughputBps) {
|
|
69
|
+
return this.transporter.recordNetworkThroughput(throughputBps);
|
|
70
|
+
}
|
|
71
|
+
getNetworkTrafficStatus() {
|
|
72
|
+
return this.transporter.getNetworkTrafficStatus();
|
|
73
|
+
}
|
|
59
74
|
joinRoom(userID, roomName, options = {}, headers = {}, onConnect = null, onDisconnect = null, authURL = "", authHeaders = {}, useAuthentication = false, queryAuthToken = false) {
|
|
60
75
|
const socketName = _assertClassBrand(_FileMessagerClient_brand, this, _createClientInstance).call(this, userID, {
|
|
61
76
|
url: this.clientOptions.url
|
|
62
77
|
}, options, headers, onConnect, onDisconnect, authURL, authHeaders, useAuthentication, queryAuthToken);
|
|
63
78
|
return () => {
|
|
64
79
|
this.clientTide.joinChannel(socketName, roomName, userID, () => {
|
|
65
|
-
FileTideDebugUtilityManager.outputGradient(`\n[FileTide ~
|
|
80
|
+
FileTideDebugUtilityManager.outputGradient(`\n[FileTide ~ Tider] ~ Client ~ ${userID} joined room ${roomName} successfully!`, significantMessageColors);
|
|
66
81
|
this.clients.set(userID, {
|
|
67
82
|
roomName
|
|
68
83
|
});
|
|
@@ -111,18 +126,18 @@ class FileMessagerClient {
|
|
|
111
126
|
transferType
|
|
112
127
|
}, transferExpirationTime);
|
|
113
128
|
if (!transferAccepted) {
|
|
114
|
-
FileTideDebugUtilityManager.outputGradient(`[FileTide ~
|
|
129
|
+
FileTideDebugUtilityManager.outputGradient(`[FileTide ~ Tider] ${recipientID} denied your transfer.`, errorMessageColors);
|
|
115
130
|
return false;
|
|
116
131
|
} else if (transferAccepted) {
|
|
117
|
-
FileTideDebugUtilityManager.outputGradient(`[FileTide ~
|
|
132
|
+
FileTideDebugUtilityManager.outputGradient(`[FileTide ~ Tider] ${recipientID} accepted your transfer!`, significantMessageColors);
|
|
118
133
|
return true;
|
|
119
134
|
}
|
|
120
135
|
} catch (error) {
|
|
121
136
|
if (error.message.startsWith("Timeout: No response")) {
|
|
122
|
-
FileTideDebugUtilityManager.outputGradient("[FileTide ~
|
|
137
|
+
FileTideDebugUtilityManager.outputGradient("[FileTide ~ Tider] Transfer approval timed out.", errorMessageColors);
|
|
123
138
|
return false;
|
|
124
139
|
}
|
|
125
|
-
FileTideDebugUtilityManager.outputGradient(`[FileTide ~
|
|
140
|
+
FileTideDebugUtilityManager.outputGradient(`[FileTide ~ Tider] Transfer approval refused.\n${error}`, errorMessageColors);
|
|
126
141
|
return false;
|
|
127
142
|
}
|
|
128
143
|
}
|
|
@@ -166,7 +181,7 @@ class FileMessagerClient {
|
|
|
166
181
|
});
|
|
167
182
|
Promise.all(sendFilePromises).then(() => console.log("\nAll files in directory transferred successfully!")).catch(error => console.error("Did not transfer directory: ", error));
|
|
168
183
|
} catch (error) {
|
|
169
|
-
FileTideDebugUtilityManager.outputGradient(`[FileTide ~
|
|
184
|
+
FileTideDebugUtilityManager.outputGradient(`[FileTide ~ Tider] ~ Refused directory transfer: ${error}`, errorMessageColors);
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
187
|
async sendDirectoryLargeFile(clientID, recipientId, fileName, filePath = process.cwd(), destinationPath = null, fileSize, index = 0, tideSize = 500, minTideSize = 10, maxTideSize = 2000, transferRequestExpirationTime = 30000, metadata = {}) {
|
|
@@ -196,7 +211,7 @@ class FileMessagerClient {
|
|
|
196
211
|
}
|
|
197
212
|
async sendFile(clientID, recipientId, fileName, filePath = process.cwd(), destination = process.cwd(), fileSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000, initiatingTransfer = true, inDirectory = false, largeFile = false, transferRequestExpirationTime = 30000, metadata = {}) {
|
|
198
213
|
const destinationPath = FileUtilityManager.normalizePath(path.join(destination, fileName));
|
|
199
|
-
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~
|
|
214
|
+
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~ Tider] ~ Requesting to transfer large file ~ ${destinationPath} to ${recipientId}!` : `[FileTide ~ Tider] ~ Requesting to transfer ~ ${destinationPath} to ${recipientId}!`, significantMessageColors);
|
|
200
215
|
const incomingType = this.activeTransferTypes.get(filePath);
|
|
201
216
|
if (!inDirectory && initiatingTransfer) {
|
|
202
217
|
const transferAllowed = incomingType && incomingType === "requestedTransfer" ? true : await this.allowedTransfer(clientID, recipientId, destinationPath, filePath, fileSize, 1, "file", "send", transferRequestExpirationTime);
|
|
@@ -227,12 +242,39 @@ class FileMessagerClient {
|
|
|
227
242
|
size: fileSize
|
|
228
243
|
};
|
|
229
244
|
try {
|
|
230
|
-
let lastSendTime = Date.now();
|
|
231
|
-
const maxBatchSize = maxTideSize;
|
|
232
|
-
const minBatchSize = minTideSize;
|
|
233
|
-
let batchSize = tideSize > maxBatchSize || tideSize > minBatchSize ? tideSize : tideSize <= minBatchSize ? minBatchSize : 10;
|
|
234
245
|
let transferInitiated = false;
|
|
235
|
-
const
|
|
246
|
+
const currentTide = [];
|
|
247
|
+
const flushTide = () => {
|
|
248
|
+
if (currentTide.length <= 0) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const outgoingChunks = currentTide.splice(0, currentTide.length);
|
|
252
|
+
const firstChunk = outgoingChunks[0];
|
|
253
|
+
const lastChunk = outgoingChunks[outgoingChunks.length - 1];
|
|
254
|
+
const tideBytes = outgoingChunks.reduce((total, chunk) => total + chunk.chunkSize, 0);
|
|
255
|
+
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
256
|
+
tide: {
|
|
257
|
+
transferId: firstChunk.transferId,
|
|
258
|
+
senderID: firstChunk.senderID,
|
|
259
|
+
recipientId: firstChunk.recipientId,
|
|
260
|
+
fileName: firstChunk.fileName,
|
|
261
|
+
filePath: firstChunk.filePath,
|
|
262
|
+
fileSize: firstChunk.fileSize,
|
|
263
|
+
totalChunks: firstChunk.totalChunks,
|
|
264
|
+
firstChunkIndex: firstChunk.chunkIndex,
|
|
265
|
+
lastChunkIndex: lastChunk.chunkIndex,
|
|
266
|
+
completedChunks: lastChunk.completedChunks,
|
|
267
|
+
tideChunkCount: outgoingChunks.length,
|
|
268
|
+
tideBytes,
|
|
269
|
+
chunks: outgoingChunks.map(chunk => ({
|
|
270
|
+
chunkIndex: chunk.chunkIndex,
|
|
271
|
+
chunkSize: chunk.chunkSize,
|
|
272
|
+
fileChunk: chunk.fileChunk
|
|
273
|
+
})),
|
|
274
|
+
metadata: firstChunk.metadata
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
};
|
|
236
278
|
await this.transporter.sendLargeFile(fileHandle, {
|
|
237
279
|
recipientID: recipientId,
|
|
238
280
|
originDetails: {
|
|
@@ -240,61 +282,48 @@ class FileMessagerClient {
|
|
|
240
282
|
senderID: clientID
|
|
241
283
|
},
|
|
242
284
|
fileDetails,
|
|
243
|
-
onSendChunk: (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
});
|
|
258
|
-
if (!transferInitiated) {
|
|
259
|
-
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
260
|
-
chunkBatch
|
|
261
|
-
});
|
|
262
|
-
transferInitiated = true;
|
|
263
|
-
chunkBatch.length = 0;
|
|
264
|
-
}
|
|
265
|
-
if (chunkBatch.length >= batchSize) {
|
|
266
|
-
const now = Date.now();
|
|
267
|
-
const rtt = now - lastSendTime;
|
|
268
|
-
lastSendTime = now;
|
|
269
|
-
this.clientTide.emitEvent(clientID, "client-to-client-transfer", {
|
|
270
|
-
chunkBatch
|
|
271
|
-
});
|
|
272
|
-
chunkBatch.length = 0;
|
|
273
|
-
if (rtt >= 200 && batchSize < maxBatchSize) {
|
|
274
|
-
batchSize = Math.min(batchSize + 50, maxBatchSize);
|
|
275
|
-
} else if (rtt < 200 && batchSize > minBatchSize) {
|
|
276
|
-
batchSize = Math.max(batchSize - 50, minBatchSize);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
resolve();
|
|
285
|
+
onSendChunk: async (transferId, chunkIndex, chunkSize, chunkData, totalChunks, completedChunks) => {
|
|
286
|
+
currentTide.push({
|
|
287
|
+
transferId,
|
|
288
|
+
senderID: clientID,
|
|
289
|
+
recipientId,
|
|
290
|
+
fileName,
|
|
291
|
+
fileChunk: chunkData,
|
|
292
|
+
completedChunks,
|
|
293
|
+
totalChunks,
|
|
294
|
+
chunkIndex,
|
|
295
|
+
chunkSize,
|
|
296
|
+
filePath: destination,
|
|
297
|
+
fileSize,
|
|
298
|
+
metadata
|
|
280
299
|
});
|
|
300
|
+
if (!transferInitiated) {
|
|
301
|
+
flushTide();
|
|
302
|
+
transferInitiated = true;
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const adaptiveTideSize = _assertClassBrand(_FileMessagerClient_brand, this, _getAdaptiveTideSize).call(this, chunkSize, tideSize, minTideSize, maxTideSize);
|
|
306
|
+
if (currentTide.length >= adaptiveTideSize) {
|
|
307
|
+
flushTide();
|
|
308
|
+
}
|
|
281
309
|
},
|
|
282
|
-
onComplete:
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
310
|
+
onComplete: async () => {
|
|
311
|
+
flushTide();
|
|
312
|
+
},
|
|
313
|
+
onFailure: async (transferId, error) => {
|
|
314
|
+
/*
|
|
315
|
+
* Do not flush an unfinished Tide after
|
|
316
|
+
* the transfer has already failed.
|
|
317
|
+
*/
|
|
318
|
+
currentTide.length = 0;
|
|
319
|
+
this.clientTide.emitEvent(clientID, "transfer-failed", {
|
|
320
|
+
transferId,
|
|
321
|
+
senderID: clientID,
|
|
322
|
+
recipientId,
|
|
323
|
+
fileName,
|
|
324
|
+
filePath: destination,
|
|
325
|
+
reason: error.message,
|
|
326
|
+
metadata
|
|
298
327
|
});
|
|
299
328
|
},
|
|
300
329
|
onTiding: () => {
|
|
@@ -304,9 +333,10 @@ class FileMessagerClient {
|
|
|
304
333
|
});
|
|
305
334
|
}
|
|
306
335
|
}, this.clientTide);
|
|
307
|
-
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~
|
|
336
|
+
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~ Tider] ~ Large file ~ ${fileName} transfer complete!` : `[FileTide ~ Tider] ~ File ~ ${fileName} transfer complete!`, significantMessageColors);
|
|
308
337
|
} catch (error) {
|
|
309
|
-
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~
|
|
338
|
+
FileTideDebugUtilityManager.outputGradient(largeFile ? `[FileTide ~ Tider] ~ Error transferring large file: ${error.message}` : `[FileTide ~ Tider] ~ Error transferring file ~ ${error.message}`, errorMessageColors);
|
|
339
|
+
throw error;
|
|
310
340
|
} finally {
|
|
311
341
|
await fileHandle.close();
|
|
312
342
|
}
|
|
@@ -316,14 +346,48 @@ function _createClientInstance(clientID, clientOptions, options = {}, headers =
|
|
|
316
346
|
this.clientTide.createIO(clientID, clientOptions.url, {
|
|
317
347
|
transports: ["websocket"],
|
|
318
348
|
...options
|
|
319
|
-
}, headers, authURL, authHeaders, useAuthentication, queryAuthToken,
|
|
349
|
+
}, headers, authURL, authHeaders, useAuthentication, queryAuthToken, (...connectionArguments) => {
|
|
350
|
+
this.transporter.updateNetworkTraffic({
|
|
351
|
+
online: true,
|
|
352
|
+
success: true
|
|
353
|
+
});
|
|
354
|
+
if (onConnect) {
|
|
355
|
+
return onConnect(...connectionArguments);
|
|
356
|
+
}
|
|
357
|
+
}, async (...disconnectArguments) => {
|
|
358
|
+
this.transporter.updateNetworkTraffic({
|
|
359
|
+
online: false
|
|
360
|
+
});
|
|
320
361
|
FileTransferTrackingManager.outputCurrentTransfers();
|
|
321
362
|
if (onDisconnect) {
|
|
322
|
-
await onDisconnect();
|
|
363
|
+
await onDisconnect(...disconnectArguments);
|
|
323
364
|
}
|
|
324
365
|
});
|
|
325
|
-
FileTideDebugUtilityManager.outputGradient(`\n[FileTide ~
|
|
366
|
+
FileTideDebugUtilityManager.outputGradient(`\n[FileTide ~ Tider] ~ Created client with ID ${clientID} and socket ${clientID}!`, significantMessageColors);
|
|
326
367
|
return clientID;
|
|
327
368
|
}
|
|
369
|
+
function _getAdaptiveTideSize(chunkSize, tideSize = 500, minTideSize = 10, maxTideSize = 2000) {
|
|
370
|
+
const networkStatus = this.transporter.getNetworkTrafficStatus();
|
|
371
|
+
const sendRateBps = Math.max(networkStatus.sendRateBps || chunkSize, chunkSize);
|
|
372
|
+
let tideDurationMs = this.tideDurationMs;
|
|
373
|
+
if (networkStatus.state === NETWORK_TRAFFIC_STATES.CONGESTED) {
|
|
374
|
+
tideDurationMs *= 0.50;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/*
|
|
378
|
+
* Determine how many chunks current network conditions
|
|
379
|
+
* can reasonably support during one Tide duration.
|
|
380
|
+
*/
|
|
381
|
+
const networkTideBytes = Math.max(sendRateBps * (tideDurationMs / 1000), chunkSize);
|
|
382
|
+
const networkTideSize = Math.max(1, Math.floor(networkTideBytes / chunkSize));
|
|
383
|
+
const normalizedMinTideSize = Math.max(1, minTideSize);
|
|
384
|
+
const normalizedMaxTideSize = Math.max(normalizedMinTideSize, maxTideSize);
|
|
385
|
+
const preferredTideSize = Math.min(Math.max(tideSize, normalizedMinTideSize), normalizedMaxTideSize);
|
|
386
|
+
const adaptiveTideSize = Math.min(networkTideSize, preferredTideSize);
|
|
387
|
+
const minTideChunkSize = Math.max(1, Math.floor(this.minTideBytes / chunkSize));
|
|
388
|
+
const maxTideChunkSize = Math.max(1, Math.floor(this.maxTideBytes / chunkSize));
|
|
389
|
+
const optimizedTideSize = adaptiveTideSize >= minTideChunkSize ? adaptiveTideSize : Math.min(networkTideSize, preferredTideSize);
|
|
390
|
+
return Math.max(1, Math.min(optimizedTideSize, maxTideChunkSize, normalizedMaxTideSize));
|
|
391
|
+
}
|
|
328
392
|
;
|
|
329
393
|
module.exports = FileMessagerClient;
|