1use super::*;
2
3pub(super) struct ResourceSendParams<'a> {
4 pub(super) data: &'a [u8],
5 pub(super) metadata: Option<&'a [u8]>,
6 pub(super) auto_compress: bool,
7 pub(super) is_response: bool,
8 pub(super) request_id: Option<Vec<u8>>,
9 pub(super) rng: &'a mut dyn Rng,
10 pub(super) now: f64,
11}
12
13impl LinkManager {
14 pub(super) fn request_response_deadline(link: &ManagedLink, now: f64) -> f64 {
15 now + link.engine.rtt().unwrap_or(1.0) * constants::LINK_TRAFFIC_TIMEOUT_FACTOR
16 + constants::RESOURCE_RESPONSE_MAX_GRACE_TIME * 1.125
17 }
18
19 pub(super) fn build_resource_senders(
20 link: &ManagedLink,
21 params: ResourceSendParams<'_>,
22 ) -> Result<Vec<ResourceSender>, rns_core::resource::ResourceError> {
23 let ResourceSendParams {
24 data,
25 metadata,
26 auto_compress,
27 is_response,
28 request_id,
29 rng,
30 now,
31 } = params;
32 let link_rtt = link.engine.rtt().unwrap_or(1.0);
33 let resource_sdu = Self::resource_sdu_for_link(link);
34 let metadata_overhead = metadata.map(|m| 3 + m.len()).unwrap_or(0);
35 let logical_size = metadata_overhead + data.len();
36
37 if logical_size <= constants::RESOURCE_MAX_EFFICIENT_SIZE {
38 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
39 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
40 link.engine
41 .encrypt(plaintext, &mut *enc_rng.borrow_mut())
42 .unwrap_or_else(|_| plaintext.to_vec())
43 };
44 return ResourceSender::new(
45 data,
46 metadata,
47 resource_sdu,
48 &encrypt_fn,
49 &Bzip2Compressor,
50 rng,
51 now,
52 auto_compress,
53 is_response,
54 request_id,
55 1,
56 1,
57 None,
58 link_rtt,
59 6.0,
60 )
61 .map(|sender| vec![sender]);
62 }
63
64 if metadata_overhead > constants::RESOURCE_MAX_EFFICIENT_SIZE {
65 return Err(rns_core::resource::ResourceError::TooLarge);
66 }
67
68 let first_payload_len = core::cmp::min(
69 data.len(),
70 constants::RESOURCE_MAX_EFFICIENT_SIZE - metadata_overhead,
71 );
72 let remaining = data.len().saturating_sub(first_payload_len);
73 let total_segments = 1 + remaining.div_ceil(constants::RESOURCE_MAX_EFFICIENT_SIZE) as u64;
74
75 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
76 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
77 link.engine
78 .encrypt(plaintext, &mut *enc_rng.borrow_mut())
79 .unwrap_or_else(|_| plaintext.to_vec())
80 };
81
82 let mut senders = Vec::new();
83 let mut first = ResourceSender::new(
84 &data[..first_payload_len],
85 metadata,
86 resource_sdu,
87 &encrypt_fn,
88 &Bzip2Compressor,
89 rng,
90 now,
91 auto_compress,
92 is_response,
93 request_id.clone(),
94 1,
95 total_segments,
96 None,
97 link_rtt,
98 6.0,
99 )?;
100 first.data_size = logical_size;
101 let original_hash = first.original_hash;
102 let has_metadata = metadata.is_some();
103 senders.push(first);
104
105 let mut offset = first_payload_len;
106 let mut segment_index = 2;
107 while offset < data.len() {
108 let end = core::cmp::min(offset + constants::RESOURCE_MAX_EFFICIENT_SIZE, data.len());
109 let mut sender = ResourceSender::new(
110 &data[offset..end],
111 None,
112 resource_sdu,
113 &encrypt_fn,
114 &Bzip2Compressor,
115 rng,
116 now,
117 auto_compress,
118 is_response,
119 request_id.clone(),
120 segment_index,
121 total_segments,
122 Some(original_hash),
123 link_rtt,
124 6.0,
125 )?;
126 sender.data_size = logical_size;
127 sender.flags.has_metadata = has_metadata;
128 senders.push(sender);
129 segment_index += 1;
130 offset = end;
131 }
132
133 Ok(senders)
134 }
135
136 fn read_stream_segment(
137 stream: &mut OutgoingStreamTransfer,
138 capacity: usize,
139 ) -> Result<Vec<u8>, ResourceTransferError> {
140 let length = stream.remaining.min(capacity as u64) as usize;
141 let mut data = vec![0; length];
142 stream
143 .reader
144 .read_exact(&mut data)
145 .map_err(|error| ResourceTransferError::Source(error.to_string()))?;
146 stream.remaining -= length as u64;
147 if stream.remaining == 0 {
148 let mut trailing = [0u8; 1];
149 if stream
150 .reader
151 .read(&mut trailing)
152 .map_err(|error| ResourceTransferError::Source(error.to_string()))?
153 != 0
154 {
155 return Err(ResourceTransferError::Source(
156 "resource source exceeds declared length".into(),
157 ));
158 }
159 }
160 Ok(data)
161 }
162
163 #[allow(clippy::too_many_arguments)]
164 fn build_stream_segment(
165 link: &ManagedLink,
166 stream: &mut OutgoingStreamTransfer,
167 metadata: Option<&[u8]>,
168 segment_index: u64,
169 total_segments: u64,
170 original_hash: Option<[u8; 32]>,
171 rng: &mut dyn Rng,
172 now: f64,
173 ) -> Result<ResourceSender, ResourceTransferError> {
174 let metadata_overhead = metadata.map(|value| 3 + value.len()).unwrap_or(0);
175 if metadata_overhead > constants::RESOURCE_MAX_EFFICIENT_SIZE {
176 return Err(ResourceTransferError::Protocol(
177 "resource metadata exceeds maximum segment size".into(),
178 ));
179 }
180 let data = Self::read_stream_segment(
181 stream,
182 constants::RESOURCE_MAX_EFFICIENT_SIZE - metadata_overhead,
183 )?;
184 let enc_rng = std::cell::RefCell::new(rns_crypto::OsRng);
185 let encrypt_fn = |plaintext: &[u8]| -> Vec<u8> {
186 link.engine
187 .encrypt(plaintext, &mut *enc_rng.borrow_mut())
188 .unwrap_or_else(|_| plaintext.to_vec())
189 };
190 let mut sender = ResourceSender::new(
191 &data,
192 metadata,
193 Self::resource_sdu_for_link(link),
194 &encrypt_fn,
195 &Bzip2Compressor,
196 rng,
197 now,
198 stream.auto_compress,
199 false,
200 None,
201 segment_index,
202 total_segments,
203 original_hash,
204 link.engine.rtt().unwrap_or(1.0),
205 6.0,
206 )
207 .map_err(|error| ResourceTransferError::Protocol(error.to_string()))?;
208 sender.data_size = (stream.declared_length + stream.metadata_overhead) as usize;
209 sender.flags.has_metadata = stream.metadata_overhead != 0;
210 Ok(sender)
211 }
212
213 pub(super) fn start_resource_senders(
214 link: &mut ManagedLink,
215 mut senders: Vec<ResourceSender>,
216 now: f64,
217 ) -> Vec<ResourceAction> {
218 if senders.is_empty() {
219 return Vec::new();
220 }
221
222 let mut first = senders.remove(0);
223 let adv_actions = first.advertise(now);
224
225 if first.total_segments > 1 {
226 let original_hash = first.original_hash;
227 let split = OutgoingSplitTransfer {
228 total_segments: first.total_segments,
229 completed_segments: 0,
230 current_segment_index: first.segment_index,
231 current_sent_parts: 0,
232 current_total_parts: first.total_parts(),
233 };
234 link.outgoing_splits.insert(original_hash, split);
235 }
236
237 link.outgoing_resources.push(first);
238 link.outgoing_resources.extend(senders);
239 adv_actions
240 }
241
242 pub(super) fn handle_resource_adv(
244 &mut self,
245 link_id: &LinkId,
246 adv_plaintext: &[u8],
247 rng: &mut dyn Rng,
248 ) -> Vec<LinkManagerAction> {
249 let has_request_handlers = !self.request_handlers.is_empty()
250 || !self.deferred_request_handlers.is_empty()
251 || !self.management_paths.is_empty();
252 let link = match self.links.get_mut(link_id) {
253 Some(l) => l,
254 None => return Vec::new(),
255 };
256
257 let link_rtt = link.engine.rtt().unwrap_or(1.0);
258 let resource_sdu = Self::resource_sdu_for_link(link);
259 let now = time::now();
260
261 let receiver = match ResourceReceiver::from_advertisement(
262 adv_plaintext,
263 resource_sdu,
264 link_rtt,
265 now,
266 None,
267 None,
268 ) {
269 Ok(r) => r,
270 Err(e) => {
271 log::debug!("Resource ADV rejected: {}", e);
272 let _ = link;
273 return self.teardown_link(link_id);
274 }
275 };
276
277 let strategy = link.resource_strategy;
278 let resource_hash = receiver.resource_hash.clone();
279 let transfer_size = receiver.transfer_size;
280 let has_metadata = receiver.has_metadata;
281 let is_request = receiver.flags.is_request;
282 let is_response = receiver.flags.is_response;
283 let is_split = receiver.flags.split;
284 let segment_index = receiver.segment_index;
285 let total_segments = receiver.total_segments;
286 let original_hash = match Self::resource_hash_key(&receiver.original_hash) {
287 Some(key) => key,
288 None => return Vec::new(),
289 };
290
291 if !is_request && !is_response {
292 let maximum = match &link.resource_receive_mode {
293 ResourceReceiveMode::Memory { max_bytes } => Some(*max_bytes),
294 ResourceReceiveMode::TemporaryFile { max_bytes, .. } => *max_bytes,
295 };
296 if maximum.is_some_and(|maximum| receiver.data_size > maximum) {
297 let reject_actions = {
298 let mut receiver = receiver;
299 receiver.reject()
300 };
301 let _ = link;
302 return self.process_resource_actions(link_id, reject_actions, rng);
303 }
304 }
305
306 if is_split && segment_index > 1 {
307 let should_accept = link
308 .incoming_splits
309 .get(&original_hash)
310 .is_some_and(|split| {
311 split.completed_segments + 1 == segment_index
312 && split.total_segments == total_segments
313 });
314
315 if !should_accept {
316 let reject_actions = {
317 let mut r = receiver;
318 r.reject()
319 };
320 let _ = link;
321 return self.process_resource_actions(link_id, reject_actions, rng);
322 }
323
324 let current_total_parts = receiver.total_parts;
325 link.incoming_resources.push(receiver);
326 let idx = link.incoming_resources.len() - 1;
327 if let Some(split) = link.incoming_splits.get_mut(&original_hash) {
328 split.current_segment_index = segment_index;
329 split.current_received_parts = 0;
330 split.current_total_parts = current_total_parts;
331 }
332 let resource_actions = link.incoming_resources[idx].accept(now);
333 let _ = link;
334 return self.process_resource_actions(link_id, resource_actions, rng);
335 }
336
337 if is_request {
338 if !has_request_handlers || Self::response_request_id(&receiver.request_id).is_none() {
341 return Vec::new();
342 }
343 if link
344 .max_request_size
345 .is_some_and(|limit| receiver.data_size > limit as u64)
346 {
347 log::debug!(
348 "ignored request with excessive size {} bytes on link {:02x?}",
349 receiver.data_size,
350 &link_id[..4]
351 );
352 let reject_actions = {
353 let mut receiver = receiver;
354 receiver.reject()
355 };
356 let _ = link;
357 return self.process_resource_actions(link_id, reject_actions, rng);
358 }
359 if is_split {
360 link.incoming_splits.insert(
361 original_hash,
362 IncomingSplitTransfer {
363 total_segments,
364 completed_segments: 0,
365 current_segment_index: segment_index,
366 current_received_parts: 0,
367 current_total_parts: receiver.total_parts,
368 storage: IncomingSplitStorage::Memory(Vec::new()),
369 metadata: None,
370 is_request: true,
371 is_response: false,
372 },
373 );
374 }
375 link.incoming_resources.push(receiver);
376 let idx = link.incoming_resources.len() - 1;
377 let resource_actions = link.incoming_resources[idx].accept(now);
378 let _ = link;
379 return self.process_resource_actions(link_id, resource_actions, rng);
380 }
381
382 if is_response {
383 let Some(request_id) = Self::response_request_id(&receiver.request_id) else {
386 return Vec::new();
387 };
388 let Some(pending) = link.pending_requests.get(&request_id) else {
389 return Vec::new();
390 };
391 if let Some(maximum) = pending.max_response_size {
392 if receiver.data_size > maximum as u64 {
393 let response_size = receiver.data_size;
394 link.pending_requests.remove(&request_id);
395 log::debug!(
396 "rejected response with excessive size {} bytes on link {:02x?}",
397 response_size,
398 &link_id[..4]
399 );
400 let reject_actions = {
401 let mut receiver = receiver;
402 receiver.reject()
403 };
404 let _ = link;
405 let mut actions = self.process_resource_actions(link_id, reject_actions, rng);
406 actions.push(LinkManagerAction::RequestFailed {
407 link_id: *link_id,
408 request_id,
409 reason: RequestFailure::ResponseTooLarge {
410 size: response_size,
411 maximum,
412 },
413 });
414 return actions;
415 }
416 }
417 if is_split {
418 link.incoming_splits.insert(
419 original_hash,
420 IncomingSplitTransfer {
421 total_segments,
422 completed_segments: 0,
423 current_segment_index: segment_index,
424 current_received_parts: 0,
425 current_total_parts: receiver.total_parts,
426 storage: IncomingSplitStorage::Memory(Vec::new()),
427 metadata: None,
428 is_request: false,
429 is_response,
430 },
431 );
432 }
433 link.incoming_resources.push(receiver);
434 let idx = link.incoming_resources.len() - 1;
435 let resource_actions = link.incoming_resources[idx].accept(now);
436 let _ = link;
437 return self.process_resource_actions(link_id, resource_actions, rng);
438 }
439
440 match strategy {
441 ResourceStrategy::AcceptNone => {
442 let reject_actions = {
444 let mut r = receiver;
445 r.reject()
446 };
447 self.process_resource_actions(link_id, reject_actions, rng)
448 }
449 ResourceStrategy::AcceptAll => {
450 if is_split {
451 let storage =
452 match Self::incoming_storage(&link.resource_receive_mode, &original_hash) {
453 Ok(storage) => storage,
454 Err(error) => {
455 let reject_actions = {
456 let mut receiver = receiver;
457 receiver.reject()
458 };
459 let _ = link;
460 let mut actions =
461 self.process_resource_actions(link_id, reject_actions, rng);
462 actions.push(LinkManagerAction::ResourceFailed {
463 link_id: *link_id,
464 error: format!("resource storage failed: {error}"),
465 });
466 return actions;
467 }
468 };
469 link.incoming_splits.insert(
470 original_hash,
471 IncomingSplitTransfer {
472 total_segments,
473 completed_segments: 0,
474 current_segment_index: segment_index,
475 current_received_parts: 0,
476 current_total_parts: receiver.total_parts,
477 storage,
478 metadata: None,
479 is_request: false,
480 is_response,
481 },
482 );
483 }
484 link.incoming_resources.push(receiver);
485 let idx = link.incoming_resources.len() - 1;
486 let resource_actions = link.incoming_resources[idx].accept(now);
487 let _ = link;
488 self.process_resource_actions(link_id, resource_actions, rng)
489 }
490 ResourceStrategy::AcceptApp => {
491 link.incoming_resources.push(receiver);
492 vec![LinkManagerAction::ResourceAcceptQuery {
494 link_id: *link_id,
495 resource_hash,
496 transfer_size,
497 has_metadata,
498 }]
499 }
500 }
501 }
502
503 pub fn accept_resource(
505 &mut self,
506 link_id: &LinkId,
507 resource_hash: &[u8],
508 accept: bool,
509 rng: &mut dyn Rng,
510 ) -> Vec<LinkManagerAction> {
511 let link = match self.links.get_mut(link_id) {
512 Some(l) => l,
513 None => return Vec::new(),
514 };
515
516 let now = time::now();
517 let idx = link
518 .incoming_resources
519 .iter()
520 .position(|r| r.resource_hash == resource_hash);
521 let idx = match idx {
522 Some(i) => i,
523 None => return Vec::new(),
524 };
525
526 if accept && link.incoming_resources[idx].flags.split {
527 if let Some(original_hash) =
528 Self::resource_hash_key(&link.incoming_resources[idx].original_hash)
529 {
530 if !link.incoming_splits.contains_key(&original_hash) {
531 let storage =
532 match Self::incoming_storage(&link.resource_receive_mode, &original_hash) {
533 Ok(storage) => storage,
534 Err(error) => {
535 let resource_actions = link.incoming_resources[idx].reject();
536 let _ = link;
537 let mut actions =
538 self.process_resource_actions(link_id, resource_actions, rng);
539 actions.push(LinkManagerAction::ResourceFailed {
540 link_id: *link_id,
541 error: format!("resource storage failed: {error}"),
542 });
543 return actions;
544 }
545 };
546 link.incoming_splits.insert(
547 original_hash,
548 IncomingSplitTransfer {
549 total_segments: link.incoming_resources[idx].total_segments,
550 completed_segments: 0,
551 current_segment_index: link.incoming_resources[idx].segment_index,
552 current_received_parts: 0,
553 current_total_parts: link.incoming_resources[idx].total_parts,
554 storage,
555 metadata: None,
556 is_request: link.incoming_resources[idx].flags.is_request,
557 is_response: link.incoming_resources[idx].flags.is_response,
558 },
559 );
560 }
561 }
562 }
563
564 let resource_actions = if accept {
565 link.incoming_resources[idx].accept(now)
566 } else {
567 link.incoming_resources[idx].reject()
568 };
569
570 let _ = link;
571 self.process_resource_actions(link_id, resource_actions, rng)
572 }
573
574 pub(super) fn handle_resource_req(
576 &mut self,
577 link_id: &LinkId,
578 plaintext: &[u8],
579 rng: &mut dyn Rng,
580 ) -> Vec<LinkManagerAction> {
581 let link = match self.links.get_mut(link_id) {
582 Some(l) => l,
583 None => return Vec::new(),
584 };
585
586 let now = time::now();
587 let mut all_actions = Vec::new();
588 let mut progress_update = None;
589 let mut progress_stream_hash = None;
590 for sender in &mut link.outgoing_resources {
591 if sender.flags.split && sender.status == rns_core::resource::ResourceStatus::Queued {
592 continue;
593 }
594 let before_sent = sender.sent_parts;
595 let resource_actions = sender.handle_request(plaintext, now);
596 if !resource_actions.is_empty() {
597 if sender.sent_parts != before_sent {
598 progress_stream_hash = Some(sender.original_hash);
599 if sender.flags.split {
600 if let Some(split) = link.outgoing_splits.get_mut(&sender.original_hash) {
601 split.current_segment_index = sender.segment_index;
602 split.current_sent_parts = sender.sent_parts;
603 split.current_total_parts = sender.total_parts();
604 progress_update =
605 Some(Self::outgoing_split_progress(split, sender.sdu));
606 }
607 } else {
608 progress_update = Some((sender.sent_parts, sender.total_parts()));
609 }
610 }
611 all_actions.extend(resource_actions);
612 break;
613 }
614 }
615
616 let _ = link;
617 let mut out = self.process_resource_actions(link_id, all_actions, rng);
618 if let Some((received, total)) = progress_update {
619 if let Some((stream, transferred)) = progress_stream_hash.and_then(|hash| {
620 self.links.get(link_id).and_then(|link| {
621 link.outgoing_streams.get(&hash).map(|stream| {
622 let transferred = if total == 0 {
623 0
624 } else {
625 stream.declared_length.saturating_mul(received as u64) / total as u64
626 };
627 (stream, transferred.min(stream.declared_length))
628 })
629 })
630 }) {
631 out.push(LinkManagerAction::ResourceStreamProgress {
632 link_id: *link_id,
633 transfer_id: stream.transfer_id,
634 transferred,
635 total: stream.declared_length,
636 });
637 } else {
638 out.push(LinkManagerAction::ResourceProgress {
639 link_id: *link_id,
640 received,
641 total,
642 });
643 }
644 }
645 out
646 }
647
648 pub(super) fn handle_resource_hmu(
650 &mut self,
651 link_id: &LinkId,
652 plaintext: &[u8],
653 rng: &mut dyn Rng,
654 ) -> Vec<LinkManagerAction> {
655 let link = match self.links.get_mut(link_id) {
656 Some(l) => l,
657 None => return Vec::new(),
658 };
659
660 let now = time::now();
661 let mut all_actions = Vec::new();
662 for receiver in &mut link.incoming_resources {
663 let resource_actions = receiver.handle_hashmap_update(plaintext, now);
664 if !resource_actions.is_empty() {
665 all_actions.extend(resource_actions);
666 break;
667 }
668 }
669
670 let _ = link;
671 self.process_resource_actions(link_id, all_actions, rng)
672 }
673
674 pub(super) fn handle_resource_part(
676 &mut self,
677 link_id: &LinkId,
678 raw_data: &[u8],
679 rng: &mut dyn Rng,
680 ) -> Vec<LinkManagerAction> {
681 let link = match self.links.get_mut(link_id) {
682 Some(l) => l,
683 None => return Vec::new(),
684 };
685
686 let now = time::now();
687 let resource_sdu = Self::resource_sdu_for_link(link);
688 let mut all_actions = Vec::new();
689 let mut assemble_idx = None;
690 let mut assembled_is_request = false;
691 let mut assembled_is_response = false;
692 let mut request_request_id = None;
693 let mut response_request_id = None;
694 let mut completed_file = None;
695 let mut storage_failure = None;
696
697 for (idx, receiver) in link.incoming_resources.iter_mut().enumerate() {
698 if receiver.status >= rns_core::resource::ResourceStatus::Complete {
699 continue;
700 }
701 let resource_actions = receiver.receive_part(raw_data, now);
702 if !resource_actions.is_empty() {
703 if receiver.received_count == receiver.total_parts {
704 assemble_idx = Some(idx);
705 }
706 if receiver.flags.split {
707 if let Some(key) = Self::resource_hash_key(&receiver.original_hash) {
708 if let Some(split) = link.incoming_splits.get_mut(&key) {
709 split.current_segment_index = receiver.segment_index;
710 split.current_received_parts = receiver.received_count;
711 split.current_total_parts = receiver.total_parts;
712 let (received, total) =
713 Self::incoming_split_progress(split, resource_sdu);
714 for action in resource_actions {
715 match action {
716 ResourceAction::ProgressUpdate { .. } => {
717 all_actions.push(ResourceAction::ProgressUpdate {
718 received,
719 total,
720 });
721 }
722 other => all_actions.push(other),
723 }
724 }
725 } else {
726 all_actions.extend(resource_actions);
727 }
728 } else {
729 all_actions.extend(resource_actions);
730 }
731 } else {
732 all_actions.extend(resource_actions);
733 }
734 break;
735 }
736 }
737
738 if let Some(idx) = assemble_idx {
739 let split_key = if link.incoming_resources[idx].flags.split {
740 Self::resource_hash_key(&link.incoming_resources[idx].original_hash)
741 } else {
742 None
743 };
744 let split_segment_index = link.incoming_resources[idx].segment_index;
745 let split_segment_total = link.incoming_resources[idx].total_segments;
746 let split_segment_parts = link.incoming_resources[idx].total_parts;
747 let split_is_request = link.incoming_resources[idx].flags.is_request;
748 let split_is_response = link.incoming_resources[idx].flags.is_response;
749 let resource_original_hash =
750 Self::resource_hash_key(&link.incoming_resources[idx].original_hash)
751 .unwrap_or([0; 32]);
752 let resource_request_id =
753 Self::response_request_id(&link.incoming_resources[idx].request_id);
754 if split_is_request {
755 request_request_id = resource_request_id;
756 } else if split_is_response {
757 response_request_id = resource_request_id;
758 }
759 let decrypt_fn = |ciphertext: &[u8]| -> Result<Vec<u8>, ()> {
760 link.engine.decrypt(ciphertext).map_err(|_| ())
761 };
762 let mut assemble_actions =
763 link.incoming_resources[idx].assemble(&decrypt_fn, &Bzip2Compressor);
764 assembled_is_request = split_is_request;
765 assembled_is_response = split_is_response;
766
767 if let Some(key) = split_key {
768 let mut converted_actions = Vec::new();
769 let mut segment_data = None;
770 let mut segment_metadata = None;
771 for action in assemble_actions {
772 match action {
773 ResourceAction::DataReceived { data, metadata } => {
774 segment_data = Some(data);
775 segment_metadata = metadata;
776 }
777 ResourceAction::Completed => {}
778 other => converted_actions.push(other),
779 }
780 }
781
782 if let Some(data) = segment_data {
783 if let Some(split) = link.incoming_splits.get_mut(&key) {
784 let write_result = match &mut split.storage {
785 IncomingSplitStorage::Memory(buffer) => {
786 buffer.extend_from_slice(&data);
787 Ok(())
788 }
789 IncomingSplitStorage::File { file, size, .. } => {
790 file.write_all(&data).map(|()| *size += data.len() as u64)
791 }
792 };
793 if let Err(error) = write_result {
794 storage_failure = Some(error.to_string());
795 }
796 if segment_metadata.is_some() {
797 split.metadata = segment_metadata;
798 }
799 split.completed_segments = split_segment_index;
800 split.current_segment_index = split_segment_index;
801 split.current_received_parts = split_segment_parts;
802 split.current_total_parts = split_segment_parts;
803 }
804
805 if storage_failure.is_none() && split_segment_index == split_segment_total {
806 if let Some(split) = link.incoming_splits.remove(&key) {
807 assembled_is_request = split.is_request;
808 assembled_is_response = split.is_response;
809 match split.storage {
810 IncomingSplitStorage::Memory(data) => {
811 converted_actions.push(ResourceAction::DataReceived {
812 data,
813 metadata: split.metadata,
814 });
815 }
816 IncomingSplitStorage::File { file, path, size } => {
817 match file.sync_all() {
818 Ok(()) => {
819 completed_file = Some(ReceivedResourceFile::new(
820 path,
821 key,
822 size,
823 split.metadata,
824 ));
825 }
826 Err(error) => storage_failure = Some(error.to_string()),
827 }
828 }
829 }
830 converted_actions.push(ResourceAction::Completed);
831 }
832 }
833 if storage_failure.is_some() {
834 link.incoming_splits.remove(&key);
835 converted_actions.clear();
836 converted_actions.push(ResourceAction::SendCancelReceiver(Vec::new()));
837 }
838 }
839
840 assemble_actions = converted_actions;
841 } else if !split_is_request
842 && !split_is_response
843 && matches!(
844 link.resource_receive_mode,
845 ResourceReceiveMode::TemporaryFile { .. }
846 )
847 {
848 let directory = match &link.resource_receive_mode {
849 ResourceReceiveMode::TemporaryFile { directory, .. } => directory.clone(),
850 ResourceReceiveMode::Memory { .. } => unreachable!(),
851 };
852 let mut converted_actions = Vec::new();
853 for action in assemble_actions {
854 match action {
855 ResourceAction::DataReceived { data, metadata } => {
856 match crate::resource::create_receive_file(
857 &directory,
858 &resource_original_hash,
859 )
860 .and_then(|(mut file, path)| {
861 file.write_all(&data)?;
862 file.sync_all()?;
863 Ok(ReceivedResourceFile::new(
864 path,
865 resource_original_hash,
866 data.len() as u64,
867 metadata,
868 ))
869 }) {
870 Ok(resource) => completed_file = Some(resource),
871 Err(error) => storage_failure = Some(error.to_string()),
872 }
873 }
874 other => converted_actions.push(other),
875 }
876 }
877 if storage_failure.is_some() {
878 converted_actions.retain(|action| {
879 !matches!(
880 action,
881 ResourceAction::SendProof(_) | ResourceAction::Completed
882 )
883 });
884 converted_actions.push(ResourceAction::SendCancelReceiver(Vec::new()));
885 }
886 assemble_actions = converted_actions;
887 }
888 all_actions.extend(assemble_actions);
889 }
890
891 let _ = link;
892 let mut out = self.process_resource_actions(link_id, all_actions, rng);
893 if let Some(resource) = completed_file {
894 out.push(LinkManagerAction::ResourceFileReceived {
895 link_id: *link_id,
896 resource,
897 });
898 }
899 if let Some(error) = storage_failure {
900 out.push(LinkManagerAction::ResourceFailed {
901 link_id: *link_id,
902 error: format!("resource storage failed: {error}"),
903 });
904 }
905
906 if assembled_is_request {
907 let mut converted = Vec::new();
908 for action in out {
909 match action {
910 LinkManagerAction::ResourceReceived { data, .. } => {
911 if let Some(request_id) = request_request_id {
912 converted.extend(self.handle_request(link_id, &data, request_id, rng));
913 }
914 }
915 LinkManagerAction::ResourceAcceptQuery { .. } => {
916 }
918 other => converted.push(other),
919 }
920 }
921 out = converted;
922 } else if assembled_is_response {
923 let mut converted = Vec::new();
924 for action in out {
925 match action {
926 LinkManagerAction::ResourceReceived { data, metadata, .. } => {
927 converted.extend(self.handle_response(
928 link_id,
929 &data,
930 metadata,
931 response_request_id,
932 ));
933 }
934 LinkManagerAction::ResourceAcceptQuery { .. } => {
935 }
937 other => converted.push(other),
938 }
939 }
940 out = converted;
941 }
942
943 out
944 }
945
946 pub(super) fn handle_resource_prf(
948 &mut self,
949 link_id: &LinkId,
950 plaintext: &[u8],
951 rng: &mut dyn Rng,
952 ) -> Vec<LinkManagerAction> {
953 let link = match self.links.get_mut(link_id) {
954 Some(l) => l,
955 None => return Vec::new(),
956 };
957
958 let now = time::now();
959 let mut result_actions = Vec::new();
960 let mut completed_sender = None;
961 let mut completed_request_id = None;
962 let mut failed_split = None;
963 let mut failed_request_id = None;
964 let proof_hash = plaintext.get(..32);
965 for sender in &mut link.outgoing_resources {
966 if proof_hash.is_some_and(|hash| hash != sender.resource_hash.as_slice()) {
967 continue;
968 }
969 let resource_actions = sender.handle_proof(plaintext, now);
970 if !resource_actions.is_empty() {
971 if resource_actions
972 .iter()
973 .any(|action| matches!(action, ResourceAction::Completed))
974 {
975 completed_sender = Some((
976 sender.original_hash,
977 sender.segment_index,
978 sender.total_segments,
979 sender.total_parts(),
980 ));
981 if sender.flags.is_request && sender.segment_index == sender.total_segments {
982 completed_request_id = Self::response_request_id(&sender.request_id);
983 }
984 }
985 if resource_actions
986 .iter()
987 .any(|action| matches!(action, ResourceAction::Failed(_)))
988 {
989 failed_split = Some(sender.original_hash);
990 }
991 if resource_actions
992 .iter()
993 .any(|action| matches!(action, ResourceAction::Failed(_)))
994 && sender.flags.is_request
995 {
996 failed_request_id = Self::response_request_id(&sender.request_id);
997 }
998 result_actions.extend(resource_actions);
999 break;
1000 }
1001 }
1002
1003 let mut actions = Vec::new();
1005 let mut advertise_next = None;
1006 let mut stream_failure = None;
1007 for ra in result_actions {
1008 match ra {
1009 ResourceAction::Completed => {
1010 if let Some((original_hash, segment_index, total_segments, total_parts)) =
1011 completed_sender
1012 {
1013 if total_segments > 1 && segment_index < total_segments {
1014 if let Some(split) = link.outgoing_splits.get_mut(&original_hash) {
1015 split.completed_segments = segment_index;
1016 split.current_segment_index = segment_index;
1017 split.current_sent_parts = total_parts;
1018 split.current_total_parts = total_parts;
1019 }
1020 if let Some(next) = link.outgoing_resources.iter_mut().find(|s| {
1021 s.flags.split
1022 && s.original_hash == original_hash
1023 && s.segment_index == segment_index + 1
1024 }) {
1025 if let Some(split) = link.outgoing_splits.get_mut(&original_hash) {
1026 split.current_segment_index = next.segment_index;
1027 split.current_sent_parts = 0;
1028 split.current_total_parts = next.total_parts();
1029 }
1030 advertise_next = Some(next.advertise(now));
1031 } else if let Some(mut stream) =
1032 link.outgoing_streams.remove(&original_hash)
1033 {
1034 match Self::build_stream_segment(
1035 link,
1036 &mut stream,
1037 None,
1038 segment_index + 1,
1039 total_segments,
1040 Some(original_hash),
1041 rng,
1042 now,
1043 ) {
1044 Ok(mut next) => {
1045 if let Some(split) =
1046 link.outgoing_splits.get_mut(&original_hash)
1047 {
1048 split.current_segment_index = next.segment_index;
1049 split.current_sent_parts = 0;
1050 split.current_total_parts = next.total_parts();
1051 }
1052 advertise_next = Some(next.advertise(now));
1053 link.outgoing_resources.push(next);
1054 link.outgoing_streams.insert(original_hash, stream);
1055 }
1056 Err(error) => {
1057 stream_failure = Some((stream.transfer_id, error));
1058 link.outgoing_splits.remove(&original_hash);
1059 }
1060 }
1061 }
1062 } else {
1063 link.outgoing_splits.remove(&original_hash);
1064 if let Some(stream) = link.outgoing_streams.remove(&original_hash) {
1065 actions.push(LinkManagerAction::ResourceStreamCompleted {
1066 link_id: *link_id,
1067 transfer_id: stream.transfer_id,
1068 });
1069 } else {
1070 actions.push(LinkManagerAction::ResourceCompleted {
1071 link_id: *link_id,
1072 });
1073 }
1074 }
1075 } else {
1076 actions.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1077 }
1078 }
1079 ResourceAction::Failed(e) => {
1080 if let Some(original_hash) = failed_split {
1081 link.outgoing_splits.remove(&original_hash);
1082 if let Some(stream) = link.outgoing_streams.remove(&original_hash) {
1083 actions.push(LinkManagerAction::ResourceStreamFailed {
1084 link_id: *link_id,
1085 transfer_id: stream.transfer_id,
1086 error: ResourceTransferError::Protocol(e.to_string()),
1087 });
1088 continue;
1089 }
1090 }
1091 actions.push(LinkManagerAction::ResourceFailed {
1092 link_id: *link_id,
1093 error: format!("{}", e),
1094 });
1095 }
1096 _ => {}
1097 }
1098 }
1099
1100 if let Some((transfer_id, error)) = stream_failure {
1101 actions.push(LinkManagerAction::ResourceStreamFailed {
1102 link_id: *link_id,
1103 transfer_id,
1104 error,
1105 });
1106 }
1107
1108 if let Some(request_id) = completed_request_id {
1109 let deadline = Self::request_response_deadline(link, now);
1110 if let Some(entry) = link.pending_requests.get_mut(&request_id) {
1111 entry.deadline = Some(deadline);
1112 }
1113 }
1114 if let Some(request_id) = failed_request_id {
1115 link.pending_requests.remove(&request_id);
1116 }
1117
1118 link.outgoing_resources
1120 .retain(|s| s.status < rns_core::resource::ResourceStatus::Complete);
1121
1122 let _ = link;
1123 if let Some(next_actions) = advertise_next {
1124 actions.extend(self.process_resource_actions(link_id, next_actions, rng));
1125 }
1126
1127 actions
1128 }
1129
1130 pub(super) fn handle_resource_icl(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1132 let link = match self.links.get_mut(link_id) {
1133 Some(l) => l,
1134 None => return Vec::new(),
1135 };
1136
1137 let mut actions = Vec::new();
1138 for receiver in &mut link.incoming_resources {
1139 let ra = receiver.handle_cancel();
1140 for a in ra {
1141 if let ResourceAction::Failed(ref e) = a {
1142 actions.push(LinkManagerAction::ResourceFailed {
1143 link_id: *link_id,
1144 error: format!("{}", e),
1145 });
1146 }
1147 }
1148 }
1149 link.incoming_resources
1150 .retain(|r| r.status < rns_core::resource::ResourceStatus::Complete);
1151 link.incoming_splits.clear();
1152 actions
1153 }
1154
1155 pub(super) fn handle_resource_rcl(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1157 let link = match self.links.get_mut(link_id) {
1158 Some(l) => l,
1159 None => return Vec::new(),
1160 };
1161
1162 let request_ids: Vec<[u8; 16]> = link
1163 .outgoing_resources
1164 .iter()
1165 .filter(|sender| sender.flags.is_request)
1166 .filter_map(|sender| Self::response_request_id(&sender.request_id))
1167 .collect();
1168 let mut actions = Vec::new();
1169 for sender in &mut link.outgoing_resources {
1170 let ra = sender.handle_reject();
1171 for a in ra {
1172 if let ResourceAction::Failed(ref e) = a {
1173 actions.push(LinkManagerAction::ResourceFailed {
1174 link_id: *link_id,
1175 error: format!("{}", e),
1176 });
1177 }
1178 }
1179 }
1180 link.outgoing_resources
1181 .retain(|s| s.status < rns_core::resource::ResourceStatus::Complete);
1182 link.outgoing_splits.clear();
1183 actions.extend(link.outgoing_streams.drain().map(|(_, stream)| {
1184 LinkManagerAction::ResourceStreamFailed {
1185 link_id: *link_id,
1186 transfer_id: stream.transfer_id,
1187 error: ResourceTransferError::Cancelled,
1188 }
1189 }));
1190 for request_id in request_ids {
1191 link.pending_requests.remove(&request_id);
1192 }
1193 actions
1194 }
1195
1196 fn resource_link_is_active(&self, link_id: &LinkId) -> bool {
1197 self.links
1198 .get(link_id)
1199 .is_some_and(|link| link.engine.state() == LinkState::Active)
1200 }
1201
1202 fn abort_resources_on_inactive_link(&mut self, link_id: &LinkId) -> Vec<LinkManagerAction> {
1203 let Some(link) = self.links.get_mut(link_id) else {
1204 return Vec::new();
1205 };
1206 for sender in &mut link.outgoing_resources {
1207 let _ = sender.cancel();
1208 }
1209 for receiver in &mut link.incoming_resources {
1210 let _ = receiver.cancel();
1211 }
1212 link.outgoing_resources.clear();
1213 link.incoming_resources.clear();
1214 link.outgoing_splits.clear();
1215 let actions = link
1216 .outgoing_streams
1217 .drain()
1218 .map(|(_, stream)| LinkManagerAction::ResourceStreamFailed {
1219 link_id: *link_id,
1220 transfer_id: stream.transfer_id,
1221 error: ResourceTransferError::Cancelled,
1222 })
1223 .collect();
1224 link.incoming_splits.clear();
1225 link.pending_requests.clear();
1226 actions
1227 }
1228
1229 pub(super) fn process_resource_actions(
1231 &mut self,
1232 link_id: &LinkId,
1233 actions: Vec<ResourceAction>,
1234 rng: &mut dyn Rng,
1235 ) -> Vec<LinkManagerAction> {
1236 let mut result = Vec::new();
1237 for action in actions {
1238 let requires_active_link = matches!(
1239 &action,
1240 ResourceAction::SendAdvertisement(_)
1241 | ResourceAction::SendPart(_)
1242 | ResourceAction::SendRequest(_)
1243 | ResourceAction::SendHmu(_)
1244 | ResourceAction::SendProof(_)
1245 );
1246 if requires_active_link && !self.resource_link_is_active(link_id) {
1247 result.extend(self.abort_resources_on_inactive_link(link_id));
1248 continue;
1249 }
1250
1251 match action {
1252 ResourceAction::SendAdvertisement(data) => {
1253 let encrypted = self
1255 .links
1256 .get(link_id)
1257 .and_then(|link| link.engine.encrypt(&data, rng).ok());
1258 if let Some(encrypted) = encrypted {
1259 result.extend(self.build_link_packet(
1260 link_id,
1261 constants::CONTEXT_RESOURCE_ADV,
1262 &encrypted,
1263 ));
1264 }
1265 }
1266 ResourceAction::SendPart(data) => {
1267 result.extend(self.build_link_packet(
1269 link_id,
1270 constants::CONTEXT_RESOURCE,
1271 &data,
1272 ));
1273 }
1274 ResourceAction::SendRequest(data) => {
1275 let encrypted = self
1276 .links
1277 .get(link_id)
1278 .and_then(|link| link.engine.encrypt(&data, rng).ok());
1279 if let Some(encrypted) = encrypted {
1280 result.extend(self.build_link_packet(
1281 link_id,
1282 constants::CONTEXT_RESOURCE_REQ,
1283 &encrypted,
1284 ));
1285 }
1286 }
1287 ResourceAction::SendHmu(data) => {
1288 let encrypted = self
1289 .links
1290 .get(link_id)
1291 .and_then(|link| link.engine.encrypt(&data, rng).ok());
1292 if let Some(encrypted) = encrypted {
1293 result.extend(self.build_link_packet(
1294 link_id,
1295 constants::CONTEXT_RESOURCE_HMU,
1296 &encrypted,
1297 ));
1298 }
1299 }
1300 ResourceAction::SendProof(data) => {
1301 let flags = PacketFlags {
1302 header_type: constants::HEADER_1,
1303 context_flag: constants::FLAG_UNSET,
1304 transport_type: constants::TRANSPORT_BROADCAST,
1305 destination_type: constants::DESTINATION_LINK,
1306 packet_type: constants::PACKET_TYPE_PROOF,
1307 };
1308 if let Ok((raw, _packet_hash)) = RawPacket::pack_raw_with_hash(
1309 flags,
1310 0,
1311 link_id,
1312 None,
1313 constants::CONTEXT_RESOURCE_PRF,
1314 &data,
1315 ) {
1316 result.push(LinkManagerAction::SendPacket {
1317 raw,
1318 dest_type: constants::DESTINATION_LINK,
1319 attached_interface: None,
1320 });
1321 }
1322 }
1323 ResourceAction::SendCancelInitiator(data) => {
1324 let encrypted = self
1325 .links
1326 .get(link_id)
1327 .filter(|link| link.engine.state() == LinkState::Active)
1328 .and_then(|link| link.engine.encrypt(&data, rng).ok());
1329 if let Some(encrypted) = encrypted {
1330 result.extend(self.build_link_packet(
1331 link_id,
1332 constants::CONTEXT_RESOURCE_ICL,
1333 &encrypted,
1334 ));
1335 }
1336 }
1337 ResourceAction::SendCancelReceiver(data) => {
1338 let encrypted = self
1339 .links
1340 .get(link_id)
1341 .filter(|link| link.engine.state() == LinkState::Active)
1342 .and_then(|link| link.engine.encrypt(&data, rng).ok());
1343 if let Some(encrypted) = encrypted {
1344 result.extend(self.build_link_packet(
1345 link_id,
1346 constants::CONTEXT_RESOURCE_RCL,
1347 &encrypted,
1348 ));
1349 }
1350 }
1351 ResourceAction::DataReceived { data, metadata } => {
1352 result.push(LinkManagerAction::ResourceReceived {
1353 link_id: *link_id,
1354 data,
1355 metadata,
1356 });
1357 }
1358 ResourceAction::Completed => {
1359 result.push(LinkManagerAction::ResourceCompleted { link_id: *link_id });
1360 }
1361 ResourceAction::Failed(e) => {
1362 result.push(LinkManagerAction::ResourceFailed {
1363 link_id: *link_id,
1364 error: format!("{}", e),
1365 });
1366 }
1367 ResourceAction::TeardownLink => {
1368 let teardown_actions = match self.links.get_mut(link_id) {
1369 Some(link) => link.engine.handle_teardown(),
1370 None => Vec::new(),
1371 };
1372 result.extend(self.process_link_actions(link_id, &teardown_actions));
1373 }
1374 ResourceAction::ProgressUpdate { received, total } => {
1375 result.push(LinkManagerAction::ResourceProgress {
1376 link_id: *link_id,
1377 received,
1378 total,
1379 });
1380 }
1381 }
1382 }
1383 result
1384 }
1385
1386 pub(super) fn build_link_packet(
1388 &self,
1389 link_id: &LinkId,
1390 context: u8,
1391 data: &[u8],
1392 ) -> Vec<LinkManagerAction> {
1393 let flags = PacketFlags {
1394 header_type: constants::HEADER_1,
1395 context_flag: constants::FLAG_UNSET,
1396 transport_type: constants::TRANSPORT_BROADCAST,
1397 destination_type: constants::DESTINATION_LINK,
1398 packet_type: constants::PACKET_TYPE_DATA,
1399 };
1400 let mut actions = Vec::new();
1401 let max_mtu = self
1402 .links
1403 .get(link_id)
1404 .map(|l| l.engine.mtu() as usize)
1405 .unwrap_or(constants::MTU);
1406 if let Ok((raw, _packet_hash)) = RawPacket::pack_raw_with_hash_with_max_mtu(
1407 flags, 0, link_id, None, context, data, max_mtu,
1408 ) {
1409 actions.push(LinkManagerAction::SendPacket {
1410 raw,
1411 dest_type: constants::DESTINATION_LINK,
1412 attached_interface: None,
1413 });
1414 }
1415 actions
1416 }
1417
1418 pub fn send_resource(
1420 &mut self,
1421 link_id: &LinkId,
1422 data: &[u8],
1423 metadata: Option<&[u8]>,
1424 rng: &mut dyn Rng,
1425 ) -> Vec<LinkManagerAction> {
1426 self.send_resource_with_auto_compress(link_id, data, metadata, true, rng)
1427 }
1428
1429 pub fn send_resource_with_auto_compress(
1431 &mut self,
1432 link_id: &LinkId,
1433 data: &[u8],
1434 metadata: Option<&[u8]>,
1435 auto_compress: bool,
1436 rng: &mut dyn Rng,
1437 ) -> Vec<LinkManagerAction> {
1438 let link = match self.links.get_mut(link_id) {
1439 Some(l) => l,
1440 None => return Vec::new(),
1441 };
1442
1443 if link.engine.state() != LinkState::Active {
1444 return Vec::new();
1445 }
1446
1447 let now = time::now();
1448
1449 let senders = match Self::build_resource_senders(
1450 link,
1451 ResourceSendParams {
1452 data,
1453 metadata,
1454 auto_compress,
1455 is_response: false,
1456 request_id: None,
1457 rng,
1458 now,
1459 },
1460 ) {
1461 Ok(s) => s,
1462 Err(e) => {
1463 log::debug!("Failed to create ResourceSender: {}", e);
1464 return Vec::new();
1465 }
1466 };
1467
1468 let adv_actions = Self::start_resource_senders(link, senders, now);
1469
1470 let _ = link;
1471 self.process_resource_actions(link_id, adv_actions, rng)
1472 }
1473
1474 #[allow(clippy::too_many_arguments)]
1480 pub fn send_resource_stream(
1481 &mut self,
1482 link_id: &LinkId,
1483 transfer_id: ResourceTransferId,
1484 reader: Box<dyn Read + Send>,
1485 declared_length: u64,
1486 metadata: Option<Vec<u8>>,
1487 auto_compress: bool,
1488 rng: &mut dyn Rng,
1489 ) -> Vec<LinkManagerAction> {
1490 let Some(link) = self.links.get_mut(link_id) else {
1491 return vec![LinkManagerAction::ResourceStreamFailed {
1492 link_id: *link_id,
1493 transfer_id,
1494 error: ResourceTransferError::Protocol("link does not exist".into()),
1495 }];
1496 };
1497 if link.engine.state() != LinkState::Active {
1498 return vec![LinkManagerAction::ResourceStreamFailed {
1499 link_id: *link_id,
1500 transfer_id,
1501 error: ResourceTransferError::Protocol("link is not active".into()),
1502 }];
1503 }
1504
1505 let metadata_overhead = metadata.as_ref().map(|value| 3 + value.len()).unwrap_or(0);
1506 let Some(logical_size) = declared_length.checked_add(metadata_overhead as u64) else {
1507 return vec![LinkManagerAction::ResourceStreamFailed {
1508 link_id: *link_id,
1509 transfer_id,
1510 error: ResourceTransferError::Protocol("resource length overflow".into()),
1511 }];
1512 };
1513 if usize::try_from(logical_size).is_err()
1514 || metadata_overhead > constants::RESOURCE_MAX_EFFICIENT_SIZE
1515 {
1516 return vec![LinkManagerAction::ResourceStreamFailed {
1517 link_id: *link_id,
1518 transfer_id,
1519 error: ResourceTransferError::Protocol(
1520 "resource length cannot be represented by this platform".into(),
1521 ),
1522 }];
1523 }
1524
1525 let first_capacity = constants::RESOURCE_MAX_EFFICIENT_SIZE - metadata_overhead;
1526 let first_length = declared_length.min(first_capacity as u64);
1527 let remaining_after_first = declared_length - first_length;
1528 let total_segments =
1529 1 + remaining_after_first.div_ceil(constants::RESOURCE_MAX_EFFICIENT_SIZE as u64);
1530 let now = time::now();
1531 let mut stream = OutgoingStreamTransfer {
1532 transfer_id,
1533 reader,
1534 remaining: declared_length,
1535 declared_length,
1536 metadata_overhead: metadata_overhead as u64,
1537 auto_compress,
1538 };
1539 let mut first = match Self::build_stream_segment(
1540 link,
1541 &mut stream,
1542 metadata.as_deref(),
1543 1,
1544 total_segments,
1545 None,
1546 rng,
1547 now,
1548 ) {
1549 Ok(sender) => sender,
1550 Err(error) => {
1551 return vec![LinkManagerAction::ResourceStreamFailed {
1552 link_id: *link_id,
1553 transfer_id,
1554 error,
1555 }]
1556 }
1557 };
1558 let original_hash = first.original_hash;
1559 let current_total_parts = first.total_parts();
1560 let adv_actions = first.advertise(now);
1561 if total_segments > 1 {
1562 link.outgoing_splits.insert(
1563 original_hash,
1564 OutgoingSplitTransfer {
1565 total_segments,
1566 completed_segments: 0,
1567 current_segment_index: 1,
1568 current_sent_parts: 0,
1569 current_total_parts,
1570 },
1571 );
1572 }
1573 link.outgoing_streams.insert(original_hash, stream);
1574 link.outgoing_resources.push(first);
1575 let _ = link;
1576 self.process_resource_actions(link_id, adv_actions, rng)
1577 }
1578
1579 pub fn set_resource_strategy(&mut self, link_id: &LinkId, strategy: ResourceStrategy) {
1581 if let Some(link) = self.links.get_mut(link_id) {
1582 link.resource_strategy = strategy;
1583 }
1584 }
1585
1586 pub fn set_resource_receive_mode(&mut self, link_id: &LinkId, mode: ResourceReceiveMode) {
1587 if let Some(link) = self.links.get_mut(link_id) {
1588 link.resource_receive_mode = mode;
1589 }
1590 }
1591}