pycfdp 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. cfdp/__init__.py +106 -0
  2. cfdp/checksum.py +94 -0
  3. cfdp/constants.py +153 -0
  4. cfdp/core.py +895 -0
  5. cfdp/event.py +55 -0
  6. cfdp/filestore/__init__.py +2 -0
  7. cfdp/filestore/base.py +99 -0
  8. cfdp/filestore/native.py +162 -0
  9. cfdp/meta/__init__.py +3 -0
  10. cfdp/meta/datafield.py +11 -0
  11. cfdp/meta/filestore.py +127 -0
  12. cfdp/meta/message.py +659 -0
  13. cfdp/pdu/__init__.py +8 -0
  14. cfdp/pdu/ack.py +90 -0
  15. cfdp/pdu/eof.py +123 -0
  16. cfdp/pdu/filedata.py +90 -0
  17. cfdp/pdu/finished.py +99 -0
  18. cfdp/pdu/header.py +159 -0
  19. cfdp/pdu/keep_alive.py +108 -0
  20. cfdp/pdu/metadata.py +211 -0
  21. cfdp/pdu/nak.py +220 -0
  22. cfdp/pdu/prompt.py +75 -0
  23. cfdp/pure/__init__.py +68 -0
  24. cfdp/pure/config.py +141 -0
  25. cfdp/pure/indications.py +130 -0
  26. cfdp/pure/machines/__init__.py +25 -0
  27. cfdp/pure/machines/receiver1.py +433 -0
  28. cfdp/pure/machines/receiver2.py +893 -0
  29. cfdp/pure/machines/sender1.py +400 -0
  30. cfdp/pure/machines/sender2.py +774 -0
  31. cfdp/pure/outputs.py +203 -0
  32. cfdp/pure/query_port.py +48 -0
  33. cfdp/pure/transaction.py +43 -0
  34. cfdp/py.typed +0 -0
  35. cfdp/remote_entity_config.py +12 -0
  36. cfdp/shell/__init__.py +44 -0
  37. cfdp/shell/checksum_service.py +136 -0
  38. cfdp/shell/dispatcher.py +185 -0
  39. cfdp/shell/effect_executor.py +285 -0
  40. cfdp/shell/machine_registry.py +165 -0
  41. cfdp/shell/query_port.py +70 -0
  42. cfdp/shell/timer_service.py +252 -0
  43. cfdp/transaction_handle.py +50 -0
  44. cfdp/transport/__init__.py +0 -0
  45. cfdp/transport/base.py +12 -0
  46. cfdp/transport/spacepacket.py +47 -0
  47. cfdp/transport/udp.py +90 -0
  48. cfdp/transport/zmq.py +54 -0
  49. pycfdp-0.2.2.dist-info/METADATA +76 -0
  50. pycfdp-0.2.2.dist-info/RECORD +53 -0
  51. pycfdp-0.2.2.dist-info/WHEEL +5 -0
  52. pycfdp-0.2.2.dist-info/licenses/LICENSE.txt +19 -0
  53. pycfdp-0.2.2.dist-info/top_level.txt +1 -0
cfdp/meta/message.py ADDED
@@ -0,0 +1,659 @@
1
+ import math
2
+
3
+ from cfdp.constants import MessageType, TypeFieldCode
4
+
5
+ from .datafield import TypeLengthValue
6
+ from .filestore import extract_filestore_request
7
+
8
+
9
+ def get_required_octets(number):
10
+ return max(math.ceil(math.log(number + 1, 2) / 8), 1)
11
+
12
+
13
+ class UnrecognizedMessage:
14
+ """Wraps raw TLV value bytes for messages with an unrecognized type."""
15
+
16
+ def __init__(self, raw_bytes: bytes):
17
+ self.raw_bytes = raw_bytes
18
+
19
+
20
+ class MessageToUser(TypeLengthValue):
21
+ def __init__(self):
22
+ self.type = TypeFieldCode.MESSAGE_TO_USER
23
+
24
+
25
+ class ReservedMessageToUser(MessageToUser):
26
+ def __init__(self):
27
+ super().__init__()
28
+ self.message_identifier = "cfdp"
29
+
30
+
31
+ class OriginatingTransactionId(ReservedMessageToUser):
32
+ def __init__(self, source_entity_id, transaction_seq_number):
33
+ super().__init__()
34
+ self.message_type = MessageType.ORIGINATING_TRANSACTION_ID
35
+
36
+ self.source_entity_id = source_entity_id
37
+ self.transaction_seq_number = transaction_seq_number
38
+
39
+ def encode(self):
40
+ data = self.message_identifier.encode("utf-8")
41
+ data += bytes([self.message_type])
42
+
43
+ length_of_entity_id = get_required_octets(self.source_entity_id) - 1
44
+ length_of_seq_number = get_required_octets(self.transaction_seq_number) - 1
45
+ data += bytes(
46
+ [(0 << 7) + (length_of_entity_id << 4) + (0 << 3) + length_of_seq_number]
47
+ )
48
+
49
+ x = []
50
+
51
+ for i in range(length_of_entity_id + 1):
52
+ x.append((self.source_entity_id >> (8 * i)) & 0xFF)
53
+ x.reverse()
54
+ data += bytes(x)
55
+
56
+ x = []
57
+
58
+ for i in range(length_of_seq_number + 1):
59
+ x.append((self.transaction_seq_number >> (8 * i)) & 0xFF)
60
+
61
+ x.reverse()
62
+ data += bytes(x)
63
+
64
+ self.value = data
65
+ return super().encode()
66
+
67
+
68
+ class ProxyPutRequest(ReservedMessageToUser):
69
+ def __init__(
70
+ self, destination_entity_id, source_filename=None, destination_filename=None
71
+ ):
72
+ super().__init__()
73
+ self.message_type = MessageType.PROXY_PUT_REQUEST
74
+
75
+ self.destination_entity_id = destination_entity_id
76
+ self.source_filename = source_filename
77
+ self.destination_filename = destination_filename
78
+
79
+ def encode(self):
80
+ data = self.message_identifier.encode("utf-8")
81
+ data += bytes([self.message_type])
82
+
83
+ length_of_entity_id = get_required_octets(self.destination_entity_id)
84
+ data += bytes([length_of_entity_id])
85
+ x = []
86
+ for i in range(length_of_entity_id):
87
+ x.append((self.destination_entity_id >> (8 * i)) & 0xFF)
88
+ x.reverse()
89
+ data += bytes(x)
90
+
91
+ value = self.source_filename.encode("utf-8")
92
+ length = len(value)
93
+ data += bytes([length])
94
+ data += value
95
+
96
+ value = self.destination_filename.encode("utf-8")
97
+ length = len(value)
98
+ data += bytes([length])
99
+ data += value
100
+
101
+ self.value = data
102
+ return super().encode()
103
+
104
+
105
+ class ProxyPutCancel(ReservedMessageToUser):
106
+ def __init__(self, entity_id, seq_number):
107
+ super().__init__()
108
+ self.message_type = MessageType.PROXY_PUT_CANCEL
109
+
110
+ self.entity_id = entity_id
111
+ self.seq_number = seq_number
112
+
113
+ def encode(self):
114
+ data = self.message_identifier.encode("utf-8")
115
+ data += bytes([self.message_type])
116
+ self.value = data
117
+
118
+ length_of_entity_id = get_required_octets(self.entity_id)
119
+
120
+ data += bytes([length_of_entity_id])
121
+
122
+ x = []
123
+
124
+ for i in range(length_of_entity_id):
125
+ x.append((self.entity_id >> (8 * i)) & 0xFF)
126
+
127
+ x.reverse()
128
+ data += bytes(x)
129
+
130
+ length_of_seq_number = get_required_octets(self.seq_number)
131
+ data += bytes([length_of_seq_number])
132
+
133
+ x = []
134
+
135
+ for i in range(length_of_seq_number):
136
+ x.append((self.seq_number >> (8 * i)) & 0xFF)
137
+ x.reverse()
138
+ data += bytes(x)
139
+
140
+ self.value = data
141
+ return super().encode()
142
+
143
+
144
+ class DirectoryListingRequest(ReservedMessageToUser):
145
+ def __init__(self, remote_directory, local_file):
146
+ super().__init__()
147
+ self.message_type = MessageType.DIRECTORY_LISTING_REQUEST
148
+
149
+ self.directory_name = remote_directory
150
+ self.directory_file_name = local_file
151
+
152
+ def encode(self):
153
+ data = self.message_identifier.encode("utf-8")
154
+ data += bytes([self.message_type])
155
+
156
+ value = self.directory_name.encode("utf-8")
157
+ length = len(value)
158
+ data += bytes([length])
159
+ data += value
160
+
161
+ value = self.directory_file_name.encode("utf-8")
162
+ length = len(value)
163
+ data += bytes([length])
164
+ data += value
165
+
166
+ self.value = data
167
+ return super().encode()
168
+
169
+
170
+ class DirectoryListingResponse(ReservedMessageToUser):
171
+ def __init__(self, remote_directory, local_file, listing_response_code=0x00):
172
+ super().__init__()
173
+ self.message_type = MessageType.DIRECTORY_LISTING_RESPONSE
174
+
175
+ self.listing_response_code = listing_response_code
176
+ self.directory_name = remote_directory
177
+ self.directory_file_name = local_file
178
+
179
+ def encode(self):
180
+ data = self.message_identifier.encode("utf-8")
181
+ data += bytes([self.message_type])
182
+
183
+ data += bytes([self.listing_response_code])
184
+
185
+ value = self.directory_name.encode("utf-8")
186
+ length = len(value)
187
+ data += bytes([length])
188
+ data += value
189
+
190
+ value = self.directory_file_name.encode("utf-8")
191
+ length = len(value)
192
+ data += bytes([length])
193
+ data += value
194
+
195
+ self.value = data
196
+ return super().encode()
197
+
198
+
199
+ class RemoteSuspendRequest(ReservedMessageToUser):
200
+ def __init__(self, source_entity_id, transaction_seq_number):
201
+ super().__init__()
202
+ self.message_type = MessageType.REMOTE_SUSPEND_REQUEST
203
+
204
+ self.source_entity_id = source_entity_id
205
+ self.transaction_seq_number = transaction_seq_number
206
+
207
+ def encode(self):
208
+ data = self.message_identifier.encode("utf-8")
209
+ data += bytes([self.message_type])
210
+
211
+ length_of_entity_id = get_required_octets(self.source_entity_id) - 1
212
+ length_of_seq_number = get_required_octets(self.transaction_seq_number) - 1
213
+
214
+ data += bytes(
215
+ [(0 << 7) + (length_of_entity_id << 4) + (0 << 3) + length_of_seq_number]
216
+ )
217
+
218
+ x = []
219
+
220
+ for i in range(length_of_entity_id + 1):
221
+ x.append((self.source_entity_id >> (8 * i)) & 0xFF)
222
+ x.reverse()
223
+ data += bytes(x)
224
+
225
+ x = []
226
+
227
+ for i in range(length_of_seq_number + 1):
228
+ x.append((self.transaction_seq_number >> (8 * i)) & 0xFF)
229
+ x.reverse()
230
+ data += bytes(x)
231
+
232
+ self.value = data
233
+ return super().encode()
234
+
235
+
236
+ class RemoteSuspendResponse(ReservedMessageToUser):
237
+ def __init__(
238
+ self,
239
+ source_entity_id,
240
+ transaction_seq_number,
241
+ suspension_indicator=1,
242
+ transaction_status=0,
243
+ ):
244
+ super().__init__()
245
+ self.message_type = MessageType.REMOTE_SUSPEND_RESPONSE
246
+
247
+ self.suspension_indicator = suspension_indicator
248
+ self.transaction_status = transaction_status
249
+ self.source_entity_id = source_entity_id
250
+ self.transaction_seq_number = transaction_seq_number
251
+
252
+ def encode(self):
253
+ data = self.message_identifier.encode("utf-8")
254
+ data += bytes([self.message_type])
255
+
256
+ data += bytes(
257
+ [(self.suspension_indicator << 7) + (self.transaction_status << 5)]
258
+ )
259
+
260
+ length_of_entity_id = get_required_octets(self.source_entity_id) - 1
261
+ length_of_seq_number = get_required_octets(self.transaction_seq_number) - 1
262
+
263
+ data += bytes(
264
+ [(0 << 7) + (length_of_entity_id << 4) + (0 << 3) + length_of_seq_number]
265
+ )
266
+
267
+ x = []
268
+
269
+ for i in range(length_of_entity_id + 1):
270
+ x.append((self.source_entity_id >> (8 * i)) & 0xFF)
271
+ x.reverse()
272
+ data += bytes(x)
273
+
274
+ x = []
275
+
276
+ for i in range(length_of_seq_number + 1):
277
+ x.append((self.transaction_seq_number >> (8 * i)) & 0xFF)
278
+ x.reverse()
279
+ data += bytes(x)
280
+
281
+ self.value = data
282
+ return super().encode()
283
+
284
+
285
+ class RemoteResumeRequest(ReservedMessageToUser):
286
+ def __init__(self, source_entity_id, transaction_seq_number):
287
+ super().__init__()
288
+ self.message_type = MessageType.REMOTE_RESUME_REQUEST
289
+
290
+ self.source_entity_id = source_entity_id
291
+ self.transaction_seq_number = transaction_seq_number
292
+
293
+ def encode(self):
294
+ data = self.message_identifier.encode("utf-8")
295
+ data += bytes([self.message_type])
296
+
297
+ length_of_entity_id = get_required_octets(self.source_entity_id) - 1
298
+
299
+ length_of_seq_number = get_required_octets(self.transaction_seq_number) - 1
300
+ data += bytes(
301
+ [(0 << 7) + (length_of_entity_id << 4) + (0 << 3) + length_of_seq_number]
302
+ )
303
+
304
+ x = []
305
+
306
+ for i in range(length_of_entity_id + 1):
307
+ x.append((self.source_entity_id >> (8 * i)) & 0xFF)
308
+ x.reverse()
309
+ data += bytes(x)
310
+ x = []
311
+ for i in range(length_of_seq_number + 1):
312
+ x.append((self.transaction_seq_number >> (8 * i)) & 0xFF)
313
+ x.reverse()
314
+ data += bytes(x)
315
+
316
+ self.value = data
317
+ return super().encode()
318
+
319
+
320
+ class RemoteResumeResponse(ReservedMessageToUser):
321
+ def __init__(
322
+ self,
323
+ source_entity_id,
324
+ transaction_seq_number,
325
+ suspension_indicator=1,
326
+ transaction_status=0,
327
+ ):
328
+ super().__init__()
329
+ self.message_type = MessageType.REMOTE_RESUME_RESPONSE
330
+
331
+ self.suspension_indicator = suspension_indicator
332
+ self.transaction_status = transaction_status
333
+ self.source_entity_id = source_entity_id
334
+ self.transaction_seq_number = transaction_seq_number
335
+
336
+ def encode(self):
337
+ data = self.message_identifier.encode("utf-8")
338
+ data += bytes([self.message_type])
339
+
340
+ data += bytes(
341
+ [(self.suspension_indicator << 7) + (self.transaction_status << 5)]
342
+ )
343
+
344
+ length_of_entity_id = get_required_octets(self.source_entity_id) - 1
345
+ length_of_seq_number = get_required_octets(self.transaction_seq_number) - 1
346
+
347
+ data += bytes(
348
+ [(0 << 7) + (length_of_entity_id << 4) + (0 << 3) + length_of_seq_number]
349
+ )
350
+
351
+ x = []
352
+
353
+ for i in range(length_of_entity_id + 1):
354
+ x.append((self.source_entity_id >> (8 * i)) & 0xFF)
355
+ x.reverse()
356
+ data += bytes(x)
357
+
358
+ x = []
359
+
360
+ for i in range(length_of_seq_number + 1):
361
+ x.append((self.transaction_seq_number >> (8 * i)) & 0xFF)
362
+ x.reverse()
363
+ data += bytes(x)
364
+
365
+ self.value = data
366
+ return super().encode()
367
+
368
+
369
+ def extract_metadata_options(databytes):
370
+ filestore_requests = []
371
+ messages_to_user = []
372
+ fault_handler_overrides = []
373
+ flow_label = []
374
+
375
+ while databytes:
376
+ type = databytes[0]
377
+ length = databytes[1]
378
+ data = databytes[2 : 2 + length]
379
+ databytes = databytes[2 + length :]
380
+
381
+ if type == TypeFieldCode.FILESTORE_REQUEST:
382
+ filestore_request = extract_filestore_request(data)
383
+ filestore_requests.append(filestore_request)
384
+
385
+ if type == TypeFieldCode.MESSAGE_TO_USER:
386
+ message_to_user = extract_message_to_user(data)
387
+ messages_to_user.append(message_to_user)
388
+
389
+ return filestore_requests, messages_to_user, fault_handler_overrides, flow_label
390
+
391
+
392
+ def extract_message_to_user(data):
393
+ if not data.startswith(b"cfdp"):
394
+ return UnrecognizedMessage(data)
395
+
396
+ message_type = data[4]
397
+ data = data[5:]
398
+
399
+ if message_type == MessageType.ORIGINATING_TRANSACTION_ID:
400
+ length_of_entity_id = (data[0] >> 4) + 1
401
+ length_of_seq_number = (data[0] & 0x0F) + 1
402
+ source_entity_id = int.from_bytes(
403
+ data[2 : 2 + length_of_entity_id], byteorder="big", signed=False
404
+ )
405
+ transaction_seq_number = int.from_bytes(
406
+ data[2 + length_of_entity_id :], byteorder="big", signed=False
407
+ )
408
+ return OriginatingTransactionId(source_entity_id, transaction_seq_number)
409
+
410
+ elif message_type == MessageType.PROXY_PUT_REQUEST:
411
+ len_destination_entity_id = data[0]
412
+ offset = 1
413
+ destination_entity_id = int.from_bytes(
414
+ data[offset : offset + len_destination_entity_id],
415
+ byteorder="big",
416
+ signed=False,
417
+ )
418
+ offset += len_destination_entity_id
419
+ len_source_filename = data[offset]
420
+ offset += 1
421
+ source_filename = data[offset : offset + len_source_filename]
422
+ offset += len_source_filename
423
+ len_destination_filename = data[offset]
424
+ offset += 1
425
+ destination_filename = data[offset : offset + len_destination_filename]
426
+ return ProxyPutRequest(
427
+ destination_entity_id, source_filename, destination_filename
428
+ )
429
+
430
+ elif message_type == MessageType.PROXY_PUT_CANCEL:
431
+ len_entity_id = data[0]
432
+ offset = 1
433
+ entity_id = int.from_bytes(
434
+ data[offset : offset + len_entity_id], byteorder="big", signed=False
435
+ )
436
+ offset += len_entity_id
437
+ len_seq_number = data[offset]
438
+ offset += 1
439
+ seq_number = int.from_bytes(
440
+ data[offset : offset + len_seq_number], byteorder="big", signed=False
441
+ )
442
+ return ProxyPutCancel(entity_id, seq_number)
443
+
444
+ elif message_type == MessageType.DIRECTORY_LISTING_REQUEST:
445
+ length_of_first_filename = data[0]
446
+ directory_name = data[1 : 1 + length_of_first_filename]
447
+ directory_file_name = data[2 + length_of_first_filename :]
448
+ return DirectoryListingRequest(directory_name, directory_file_name)
449
+
450
+ elif message_type == MessageType.DIRECTORY_LISTING_RESPONSE:
451
+ listing_response_code = data[0]
452
+ length_of_directory_name = data[1]
453
+ directory_name = data[2 : 2 + length_of_directory_name]
454
+ directory_file_name = data[3 + length_of_directory_name :]
455
+ return DirectoryListingResponse(
456
+ directory_name, directory_file_name, listing_response_code
457
+ )
458
+
459
+ elif message_type == MessageType.REMOTE_SUSPEND_REQUEST:
460
+ length_of_entity_id = (data[0] >> 4) + 1
461
+ length_of_seq_number = (data[0] & 0x0F) + 1
462
+ source_entity_id = int.from_bytes(
463
+ data[1 : 1 + length_of_entity_id], byteorder="big", signed=False
464
+ )
465
+ transaction_seq_number = int.from_bytes(
466
+ data[1 + length_of_entity_id :], byteorder="big", signed=False
467
+ )
468
+ return RemoteSuspendRequest(source_entity_id, transaction_seq_number)
469
+
470
+ elif message_type == MessageType.REMOTE_SUSPEND_RESPONSE:
471
+ suspension_indicator = data[0] >> 7
472
+ transaction_status = (data[0] >> 7) & 0x03
473
+ length_of_entity_id = (data[1] >> 4) + 1
474
+ length_of_seq_number = (data[1] & 0x0F) + 1
475
+ source_entity_id = int.from_bytes(
476
+ data[2 : 2 + length_of_entity_id], byteorder="big", signed=False
477
+ )
478
+ transaction_seq_number = int.from_bytes(
479
+ data[2 + length_of_seq_number :], byteorder="big", signed=False
480
+ )
481
+ return RemoteSuspendResponse(
482
+ source_entity_id,
483
+ transaction_seq_number,
484
+ suspension_indicator,
485
+ transaction_status,
486
+ )
487
+
488
+ elif message_type == MessageType.REMOTE_RESUME_REQUEST:
489
+ length_of_entity_id = (data[0] >> 4) + 1
490
+ length_of_seq_number = (data[0] & 0x0F) + 1
491
+ source_entity_id = int.from_bytes(
492
+ data[1 : 1 + length_of_entity_id], byteorder="big", signed=False
493
+ )
494
+ transaction_seq_number = int.from_bytes(
495
+ data[1 + length_of_entity_id :], byteorder="big", signed=False
496
+ )
497
+ return RemoteResumeRequest(source_entity_id, transaction_seq_number)
498
+
499
+ elif message_type == MessageType.REMOTE_RESUME_RESPONSE:
500
+ suspension_indicator = data[0] >> 7
501
+ transaction_status = (data[0] >> 7) & 0x03
502
+ length_of_entity_id = (data[1] >> 4) + 1
503
+ length_of_seq_number = (data[1] & 0x0F) + 1
504
+ source_entity_id = int.from_bytes(
505
+ data[2 : 2 + length_of_entity_id], byteorder="big", signed=False
506
+ )
507
+ transaction_seq_number = int.from_bytes(
508
+ data[2 + length_of_seq_number :], byteorder="big", signed=False
509
+ )
510
+ return RemoteResumeResponse(
511
+ source_entity_id,
512
+ transaction_seq_number,
513
+ suspension_indicator,
514
+ transaction_status,
515
+ )
516
+
517
+ else:
518
+ return UnrecognizedMessage(data)
519
+
520
+
521
+ def process_user_message(kernel, message):
522
+ if isinstance(message, OriginatingTransactionId):
523
+ pass
524
+
525
+ elif isinstance(message, ProxyPutRequest):
526
+ destination_entity_id = message.destination_entity_id
527
+ source_filename = message.source_filename.decode()
528
+ destination_filename = message.destination_filename.decode()
529
+
530
+ transmission_mode = message.originating_transaction.transmission_mode
531
+ source_entity_id = message.originating_transaction.source_entity_id
532
+ transaction_seq_number = message.originating_transaction.seq_number
533
+ kernel.put(
534
+ destination_id=destination_entity_id,
535
+ source_filename=source_filename,
536
+ destination_filename=destination_filename,
537
+ transmission_mode=transmission_mode,
538
+ messages_to_user=[
539
+ OriginatingTransactionId(
540
+ source_entity_id=source_entity_id,
541
+ transaction_seq_number=transaction_seq_number,
542
+ )
543
+ ],
544
+ )
545
+
546
+ elif isinstance(message, ProxyPutCancel):
547
+ transaction_id = (message.entity_id, message.seq_number)
548
+ kernel.cancel(transaction_id)
549
+
550
+ elif isinstance(message, DirectoryListingRequest):
551
+ dirname = message.directory_name.decode()
552
+ listing = kernel.filestore.list_directory(dirname)
553
+
554
+ filename = kernel.filestore.join_path(dirname, ".listing")
555
+ fh = kernel.filestore.open(filename, "wt")
556
+ fh.write(listing)
557
+ fh.close()
558
+
559
+ # send file and directory response
560
+ destination_id = message.originating_transaction.source_entity_id
561
+ transmission_mode = message.originating_transaction.transmission_mode
562
+
563
+ destination_filename = message.directory_file_name.decode()
564
+ directory_name = message.directory_name.decode()
565
+ source_entity_id = message.originating_transaction.source_entity_id
566
+ transaction_seq_number = message.originating_transaction.seq_number
567
+ kernel.put(
568
+ destination_id=destination_id,
569
+ source_filename=filename,
570
+ destination_filename=destination_filename,
571
+ transmission_mode=transmission_mode,
572
+ messages_to_user=[
573
+ DirectoryListingResponse(directory_name, destination_filename),
574
+ OriginatingTransactionId(
575
+ source_entity_id=source_entity_id,
576
+ transaction_seq_number=transaction_seq_number,
577
+ ),
578
+ ],
579
+ )
580
+
581
+ elif isinstance(message, DirectoryListingResponse):
582
+ # TODO: let user add a callback to be triggered with directory listing
583
+ pass
584
+
585
+ elif isinstance(message, RemoteSuspendRequest):
586
+ transaction_id = (message.source_entity_id, message.transaction_seq_number)
587
+ kernel.suspend(transaction_id)
588
+ transmission_mode = message.originating_transaction.transmission_mode
589
+ source_entity_id = message.originating_transaction.source_entity_id
590
+ transaction_seq_number = message.originating_transaction.seq_number
591
+ kernel.put(
592
+ destination_id=source_entity_id,
593
+ transmission_mode=transmission_mode,
594
+ messages_to_user=[
595
+ RemoteSuspendResponse(
596
+ source_entity_id=message.source_entity_id,
597
+ transaction_seq_number=message.transaction_seq_number,
598
+ ),
599
+ OriginatingTransactionId(
600
+ source_entity_id=source_entity_id,
601
+ transaction_seq_number=transaction_seq_number,
602
+ ),
603
+ ],
604
+ )
605
+
606
+ elif isinstance(message, RemoteSuspendResponse):
607
+ kernel._indication_suspended(
608
+ (message.source_entity_id, message.transaction_seq_number),
609
+ message.transaction_status,
610
+ )
611
+
612
+ elif isinstance(message, RemoteResumeRequest):
613
+ transaction_id = (message.source_entity_id, message.transaction_seq_number)
614
+ kernel.resume(transaction_id)
615
+ transmission_mode = message.originating_transaction.transmission_mode
616
+ source_entity_id = message.originating_transaction.source_entity_id
617
+ transaction_seq_number = message.originating_transaction.seq_number
618
+ kernel.put(
619
+ destination_id=source_entity_id,
620
+ transmission_mode=transmission_mode,
621
+ messages_to_user=[
622
+ RemoteResumeResponse(
623
+ source_entity_id=message.source_entity_id,
624
+ transaction_seq_number=message.transaction_seq_number,
625
+ ),
626
+ OriginatingTransactionId(
627
+ source_entity_id=source_entity_id,
628
+ transaction_seq_number=transaction_seq_number,
629
+ ),
630
+ ],
631
+ )
632
+
633
+ elif isinstance(message, RemoteResumeResponse):
634
+ kernel._indication_resumed(
635
+ (message.source_entity_id, message.transaction_seq_number),
636
+ message.transaction_status,
637
+ )
638
+
639
+ elif isinstance(message, UnrecognizedMessage):
640
+ if kernel.on_unrecognized_message is not None:
641
+ try:
642
+ kernel.on_unrecognized_message(message.raw_bytes)
643
+ except Exception:
644
+ import logging
645
+
646
+ logging.getLogger(__name__).exception(
647
+ "Unhandled exception in on_unrecognized_message"
648
+ )
649
+
650
+ else:
651
+ if kernel.on_unrecognized_message is not None:
652
+ try:
653
+ kernel.on_unrecognized_message(bytes(message))
654
+ except Exception:
655
+ import logging
656
+
657
+ logging.getLogger(__name__).exception(
658
+ "Unhandled exception in on_unrecognized_message"
659
+ )
cfdp/pdu/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ from .ack import *
2
+ from .eof import *
3
+ from .filedata import *
4
+ from .finished import *
5
+ from .keep_alive import *
6
+ from .metadata import *
7
+ from .nak import *
8
+ from .prompt import *