/// Dart Mix Payloads Sender Test /// Tests the smartsend function with mixed payload types /// /// This test mirrors test_julia_mix_payloads_sender.jl and test_js_mix_payloads_sender.js /// and demonstrates that any combination and any number of mixed content can be sent correctly. import 'dart:io'; import 'dart:typed_data'; import 'package:http/http.dart' as http; import 'package:uuid/uuid.dart'; // Add parent directory to path import 'package:natsbridge/natsbridge.dart' as natsbridge; const TEST_SUBJECT = '/natsbridge'; const TEST_BROKER_URL = String.fromEnvironment( 'NATS_URL', defaultValue: 'nats.yiem.cc', ); const TEST_FILESERVER_URL = String.fromEnvironment( 'FILESERVER_URL', defaultValue: 'http://192.168.88.104:8080', ); const SIZE_THRESHOLD = 1000000; // 1MB threshold void logTrace(String message) { final timestamp = DateTime.now().toUtc().toIsoString(); print('[$timestamp] [Correlation: $correlationId] $message'); } Future runTest() async { print('=== Dart Mix Payloads Sender Test ===\n'); final uuid = const Uuid(); final correlationId = uuid.v4(); print('Correlation ID: $correlationId'); print('Subject: $TEST_SUBJECT'); print('Broker URL: $TEST_BROKER_URL'); print('Fileserver URL: $TEST_FILESERVER_URL'); print('Size Threshold: $SIZE_THRESHOLD bytes (1MB)\n'); // Create sample data for each type (mirroring Julia test) final textData = 'Hello! This is a test chat message. šŸŽ‰\nHow are you doing today? 😊'; final dictData = { 'type': 'chat', 'sender': 'serviceA', 'receiver': 'serviceB', 'metadata': { 'timestamp': DateTime.now().toUtc().toIsoString(), 'priority': 'high', 'tags': ['urgent', 'chat', 'test'] }, 'content': { 'text': 'This is a JSON-formatted chat message with nested structure.', 'format': 'markdown', 'mentions': ['user1', 'user2'] } }; // Arrow table data (small - direct transport) final arrowTableSmall = [ {'id': 1, 'name': 'Alice', 'score': 95, 'active': true}, {'id': 2, 'name': 'Bob', 'score': 88, 'active': false}, {'id': 3, 'name': 'Charlie', 'score': 92, 'active': true}, {'id': 4, 'name': 'Diana', 'score': 78, 'active': true}, {'id': 5, 'name': 'Eve', 'score': 85, 'active': false}, {'id': 6, 'name': 'Frank', 'score': 91, 'active': true}, {'id': 7, 'name': 'Grace', 'score': 89, 'active': true}, {'id': 8, 'name': 'Henry', 'score': 76, 'active': false}, {'id': 9, 'name': 'Ivy', 'score': 94, 'active': true}, {'id': 10, 'name': 'Jack', 'score': 82, 'active': true} ]; // Json table data (small - direct transport) final jsonTableSmall = [ {'id': 1, 'name': 'Alice', 'score': 95, 'active': true}, {'id': 2, 'name': 'Bob', 'score': 88, 'active': false}, {'id': 3, 'name': 'Charlie', 'score': 92, 'active': true}, {'id': 4, 'name': 'Diana', 'score': 78, 'active': true}, {'id': 5, 'name': 'Eve', 'score': 85, 'active': false}, {'id': 6, 'name': 'Frank', 'score': 91, 'active': true}, {'id': 7, 'name': 'Grace', 'score': 89, 'active': true}, {'id': 8, 'name': 'Henry', 'score': 76, 'active': false}, {'id': 9, 'name': 'Ivy', 'score': 94, 'active': true}, {'id': 10, 'name': 'Jack', 'score': 82, 'active': true} ]; // Audio data (small binary - direct transport) final audioData = Uint8List(100); for (int i = 0; i < 100; i++) { audioData[i] = (Random().nextRange(1, 255)).toInt(); } // Video data (small binary - direct transport) final videoData = Uint8List(150); for (int i = 0; i < 150; i++) { videoData[i] = (Random().nextRange(1, 255)).toInt(); } // Binary data (small - direct transport) final binaryData = Uint8List(200); for (int i = 0; i < 200; i++) { binaryData[i] = (Random().nextRange(1, 255)).toInt(); } // Large data for link transport testing final largeArrowTable = List.generate(20000, (i) => { 'id': i + 1, 'name': 'user_${i + 1}', 'score': (Random().nextRange(50, 100)).toInt(), 'active': Random().nextBool(), 'timestamp': DateTime.now().toUtc().toIsoString() }); final largeJsonTable = List.generate(50000, (i) => { 'id': i + 1, 'name': 'user_${i + 1}', 'score': (Random().nextRange(50, 100)).toInt(), 'active': Random().nextBool() }); final largeAudioData = Uint8List(1500000); for (int i = 0; i < 1500000; i++) { largeAudioData[i] = (Random().nextRange(1, 255)).toInt(); } final largeVideoData = Uint8List(1500000); for (int i = 0; i < 1500000; i++) { largeVideoData[i] = (Random().nextRange(1, 255)).toInt(); } final largeBinaryData = Uint8List(1500000); for (int i = 0; i < 1500000; i++) { largeBinaryData[i] = (Random().nextRange(1, 255)).toInt(); } // Read image files from disk (following Julia test pattern) final filePathSmallImage = './test/small_image.jpg'; final fileDataSmallImage = File(filePathSmallImage).readAsBytesSync(); final filenameSmallImage = filePathSmallImage.split('/').last; final filePathLargeImage = './test/large_image.png'; final fileDataLargeImage = File(filePathLargeImage).readAsBytesSync(); final filenameLargeImage = filePathLargeImage.split('/').last; logTrace('Creating payloads list with mixed content'); // Create payloads list - mixed content with both small and large data // Small data uses direct transport, large data uses link transport final payloads = [ // Small data (direct transport) - text, dictionary, arrowtable, jsontable, small image ['chat_text', textData, 'text'], ['chat_json', dictData, 'dictionary'], // ['arrow_table_small', arrowTableSmall, 'arrowtable'], ['json_table_small', jsonTableSmall, 'jsontable'], [filenameSmallImage, fileDataSmallImage, 'binary'], // Large data (link transport) - large arrowtable, large jsontable, large image, large audio, large video, large binary // ['arrow_table_large', largeArrowTable, 'arrowtable'], ['json_table_large', largeJsonTable, 'jsontable'], [filenameLargeImage, fileDataLargeImage, 'binary'], // ['audio_clip_large', largeAudioData, 'audio'], // ['video_clip_large', largeVideoData, 'video'], // ['binary_file_large', largeBinaryData, 'binary'] ]; logTrace('Total payloads: ${payloads.length}'); try { // Send the message print('Sending mixed payloads...\n'); final (env, envJsonStr) = await natsbridge.smartsend( TEST_SUBJECT, payloads, brokerUrl: TEST_BROKER_URL, fileserverUrl: TEST_FILESERVER_URL, fileserverUploadHandler: natsbridge.plikOneshotUpload, sizeThreshold: SIZE_THRESHOLD, correlationId: correlationId, msgPurpose: 'chat', senderName: 'dart-mix-test', receiverName: '', receiverId: '', replyTo: '', replyToMsgId: '', isPublish: true, ); print('\n=== Envelope Created ==='); print('Correlation ID: ${env['correlation_id']}'); print('Message ID: ${env['msg_id']}'); print('Timestamp: ${env['timestamp']}'); print('Subject: ${env['send_to']}'); print('Purpose: ${env['msg_purpose']}'); print('Sender: ${env['sender_name']}'); print('Payloads: ${env['payloads'].length}\n'); // Log transport type for each payload for (int i = 0; i < env['payloads'].length; i++) { final payload = env['payloads'][i]; logTrace('Payload ${i + 1} (${payload['dataname']}):'); logTrace(' Transport: ${payload['transport']}'); logTrace(' Type: ${payload['payload_type']}'); logTrace(' Size: ${payload['size']} bytes'); logTrace(' Encoding: ${payload['encoding']}'); if (payload['transport'] == 'link') { logTrace(' URL: ${payload['data']}'); } } // Summary print('\n--- Transport Summary ---'); final directCount = env['payloads'].where((p) => p['transport'] == 'direct').length; final linkCount = env['payloads'].where((p) => p['transport'] == 'link').length; logTrace('Direct transport: $directCount payloads'); logTrace('Link transport: $linkCount payloads'); print('\nTest completed.'); } catch (error) { print('\nāŒ Test failed with error: $error'); print('$error'); exit(1); } } void main() { runTest(); }