37 Commits
v1.0.0 ... main

Author SHA1 Message Date
ton
a997d1d246 Merge pull request 'v1.2.0' (#4) from v1.2.0 into main
Reviewed-on: #4
2026-06-17 06:20:42 +00:00
ton
d257175cdb Merge pull request 'v1.2.0-HTTP2' (#3) from v1.2.0-HTTP2 into v1.2.0
Reviewed-on: #3
2026-06-17 06:19:51 +00:00
8de8e8b2f0 update http2.o 2026-06-17 13:12:17 +07:00
eeb67cebd3 HTTP2.0 2026-06-17 13:09:50 +07:00
b6e1ca95ac update comment 2026-06-13 19:00:30 +07:00
97821f83e5 update 2026-06-05 11:27:33 +07:00
0d1bf11b21 update 2026-05-29 11:30:23 +07:00
ton
8d3de4e50a Merge pull request 'v1.1.0-fix_JS_version' (#2) from v1.1.0-fix_JS_version into main
Reviewed-on: #2
2026-05-29 04:24:54 +00:00
5b70df7c9d update 2026-05-29 11:23:53 +07:00
da2085ad32 update 2026-05-25 10:32:12 +07:00
48fddb5cbc update doc 2026-05-25 07:36:17 +07:00
dff47a80f9 update readme 2026-05-25 06:46:19 +07:00
76c73aac03 update 2026-05-24 13:37:03 +07:00
0c981d943d update 2026-05-24 13:36:39 +07:00
481fef9f70 update readme 2026-05-24 13:35:08 +07:00
b11dd456c0 update 2026-05-24 13:11:25 +07:00
bc51f20e48 update 2026-05-24 13:05:39 +07:00
e7c78cf40d update 2026-05-24 13:03:28 +07:00
5d2b46eb38 update 2026-05-24 13:00:30 +07:00
a134bd44bd update 2026-05-24 12:57:45 +07:00
86224c1daf update docs 2026-05-24 12:52:00 +07:00
b8339897f3 update doc 2026-05-24 12:39:19 +07:00
42b68d5bee update 2026-05-24 11:40:27 +07:00
dcd88de1a5 update readme 2026-05-24 08:57:14 +07:00
6d327967b1 update readme 2026-05-23 20:37:01 +07:00
4e8b7faead update readme 2026-05-23 20:10:37 +07:00
efd77937a2 update readme 2026-05-23 14:29:10 +07:00
9c9493eaa0 update readme 2026-05-23 13:47:29 +07:00
f06fbce486 update 2026-05-23 13:07:37 +07:00
c919f9585d update readme 2026-05-23 12:29:18 +07:00
bfb7acd55b update readme 2026-05-23 12:20:17 +07:00
e74d0a3301 update readme 2026-05-23 12:15:27 +07:00
a4f450386c update 2026-05-23 12:02:18 +07:00
15a7f1c178 update readme 2026-05-23 10:57:01 +07:00
31727f3337 update 2026-05-23 06:17:13 +07:00
cc52ef1bda update 2026-05-23 06:16:16 +07:00
ton
a1fcd86a74 Merge pull request 'v1.0.0' (#1) from v1.0.0 into main
Reviewed-on: #1
2026-05-22 22:16:16 +00:00
12 changed files with 1576 additions and 1029 deletions

View File

@@ -267,6 +267,237 @@ What is the main interface of this package?
read the following files:
- ./src/msghandler.jl
- ./test/test_julia_mix_payloads_sender.jl
- ./src/msghandler-csr.js
- ./README.md
I want to add:
1) sending jsontable and arrowtable Julia example to README.md
2) sending image and jsontable Javascript(browser) example to README.md
read the following files:
- ./README.md
- ./src/msghandler.jl
- ./test/test_julia_mix_payloads_sender.jl
- ./src/msghandler-csr.js
I want to:
1) add sending jsontable and arrowtable julia example in README.md
2) add sending jsontable and image Javascript example in README.md
I execute test/test_julia_mix_payloads_sender.jl and I get this error:
ERROR: LoadError: HTTP.ConnectError for url = `https://fileserver.yiem.cc/upload`: IOError: SSL_ERROR_SSL
Stacktrace:
[1] macro expansion
@ ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:476 [inlined]
[2] macro expansion
@ ./lock.jl:376 [inlined]
[3] connect(ssl::OpenSSL.SSLStream; require_ssl_verification::Bool)
@ OpenSSL ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:443
[4] connect
@ ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:509 [inlined]
[5] #sslconnection#21
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:595 [inlined]
[6] sslconnection
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:585 [inlined]
[7] getconnection(::Type{OpenSSL.SSLStream}, host::SubString{String}, port::SubString{String}; kw::@Kwargs{require_ssl_verification::Bool, keepalive::Bool, readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.Connections ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:582
[8] getconnection
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:574 [inlined]
[9] #13
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:463 [inlined]
[10] macro expansion
@ ~/.julia/packages/ConcurrentUtilities/hQBsU/src/try_with_timeout.jl:92 [inlined]
[11] (::ConcurrentUtilities.var"#try_with_timeout##2#try_with_timeout##3"{Any, Channel{Any}, HTTP.Connections.var"#13#14"{OpenSSL.SSLStream, Bool, Bool, @Kwargs{readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool}, SubString{String}, SubString{String}}, Timer})()
@ ConcurrentUtilities ~/.julia/packages/ConcurrentUtilities/hQBsU/src/ConcurrentUtilities.jl:10
Stacktrace:
[1] (::HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}})(req::HTTP.Messages.Request; proxy::Nothing, socket_type::Type, socket_type_tls::Nothing, readtimeout::Int64, connect_timeout::Int64, logerrors::Bool, logtag::Nothing, closeimmediately::Bool, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.ConnectionRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/ConnectionRequest.jl:88
[2] connections
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/ConnectionRequest.jl:60 [inlined]
[3] (::Base.var"#46#47"{Base.var"#48#49"{ExponentialBackOff, HTTP.RetryRequest.var"#retrylayer##2#retrylayer##3"{Int64, typeof(HTTP.RetryRequest.FALSE), HTTP.Messages.Request, Base.RefValue{Int64}}, HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(args::HTTP.Messages.Request; kwargs::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ Base ./error.jl:309
[4] (::HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(req::HTTP.Messages.Request; retry::Bool, retries::Int64, retry_delays::ExponentialBackOff, retry_check::Function, retry_non_idempotent::Bool, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.RetryRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RetryRequest.jl:75
[5] manageretries
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RetryRequest.jl:30 [inlined]
[6] (::HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}})(req::HTTP.Messages.Request; cookies::Bool, cookiejar::HTTP.Cookies.CookieJar, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.CookieRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/CookieRequest.jl:42
[7] managecookies
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/CookieRequest.jl:19 [inlined]
[8] (::HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}})(req::HTTP.Messages.Request; iofunction::Nothing, decompress::Nothing, basicauth::Bool, detect_content_type::Bool, canonicalize_headers::Bool, kw::@Kwargs{verbose::Int64, body_is_form::Bool})
@ HTTP.HeadersRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/HeadersRequest.jl:71
[9] defaultheaders
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/HeadersRequest.jl:14 [inlined]
[10] (::HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}})(req::HTTP.Messages.Request; redirect::Bool, redirect_limit::Int64, redirect_method::Nothing, forwardheaders::Bool, response_stream::Nothing, kw::@Kwargs{verbose::Int64, body_is_form::Bool})
@ HTTP.RedirectRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RedirectRequest.jl:25
[11] redirects
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RedirectRequest.jl:14 [inlined]
[12] (::HTTP.MessageRequest.var"#makerequest#messagelayer##0"{HTTP.MessageRequest.var"#makerequest#1#messagelayer##1"{HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}})(method::String, url::URIs.URI, headers::Vector{Pair{String, String}}, body::String; copyheaders::Bool, response_stream::Nothing, http_version::HTTP.Strings.HTTPVersion, verbose::Int64, kw::@Kwargs{body_is_form::Bool})
@ HTTP.MessageRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/MessageRequest.jl:35
[13] makerequest
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/MessageRequest.jl:24 [inlined]
[14] request(stack::HTTP.MessageRequest.var"#makerequest#messagelayer##0"{HTTP.MessageRequest.var"#makerequest#1#messagelayer##1"{HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}}, method::String, url::String, h::Vector{Pair{String, String}}, b::String, q::Nothing; headers::Vector{Pair{String, String}}, body::String, query::Nothing, kw::@Kwargs{body_is_form::Bool})
@ HTTP ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:465
[15] #request#21
@ ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:323 [inlined]
[16] request
@ ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:321 [inlined]
[17] plik_upload_handler(fileserver_url::String, dataname::String, data::Vector{UInt8})
@ Main ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:48
[18] smartpack(subject::String, data::Vector{Tuple{String, Any, String}}; broker_url::String, fileserver_url::String, fileserver_upload_handler::typeof(plik_upload_handler), size_threshold::Int64, correlation_id::String, msg_purpose::String, sender_name::String, receiver_name::String, receiver_id::String, reply_to::String, reply_to_msg_id::String, msg_id::String, sender_id::String)
@ Main.msghandler ~/docker-apps/sommpanion/msghandler/src/msghandler.jl:493
[19] test_mix_send()
@ Main ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:208
[20] top-level scope
@ ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:256
[21] include(mod::Module, _path::String)
@ Base ./Base.jl:306
[22] exec_options(opts::Base.JLOptions)
@ Base ./client.jl:317
[23] _start()
@ Base ./client.jl:550
in expression starting at /home/ton/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:256
caused by: IOError: SSL_ERROR_SSL
Stacktrace:
[1] macro expansion
@ ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:476 [inlined]
[2] macro expansion
@ ./lock.jl:376 [inlined]
[3] connect(ssl::OpenSSL.SSLStream; require_ssl_verification::Bool)
@ OpenSSL ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:443
[4] connect
@ ~/.julia/packages/OpenSSL/2SUGA/src/ssl.jl:509 [inlined]
[5] #sslconnection#21
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:595 [inlined]
[6] sslconnection
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:585 [inlined]
[7] getconnection(::Type{OpenSSL.SSLStream}, host::SubString{String}, port::SubString{String}; kw::@Kwargs{require_ssl_verification::Bool, keepalive::Bool, readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.Connections ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:582
[8] getconnection
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:574 [inlined]
[9] #13
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:463 [inlined]
[10] macro expansion
@ ~/.julia/packages/ConcurrentUtilities/hQBsU/src/try_with_timeout.jl:92 [inlined]
[11] (::ConcurrentUtilities.var"#try_with_timeout##2#try_with_timeout##3"{Any, Channel{Any}, HTTP.Connections.var"#13#14"{OpenSSL.SSLStream, Bool, Bool, @Kwargs{readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool}, SubString{String}, SubString{String}}, Timer})()
@ ConcurrentUtilities ~/.julia/packages/ConcurrentUtilities/hQBsU/src/ConcurrentUtilities.jl:10
Stacktrace:
[1] try_yieldto(undo::typeof(Base.ensure_rescheduled))
@ Base ./task.jl:1157
[2] wait()
@ Base ./task.jl:1229
[3] wait(c::Base.GenericCondition{ReentrantLock}; first::Bool)
@ Base ./condition.jl:141
[4] wait
@ ./condition.jl:136 [inlined]
[5] take_unbuffered(c::Channel{Any})
@ Base ./channels.jl:549
[6] take!
@ ./channels.jl:526 [inlined]
[7] try_with_timeout(f::Function, timeout::Int64, ::Type{Any})
@ ConcurrentUtilities ~/.julia/packages/ConcurrentUtilities/hQBsU/src/try_with_timeout.jl:99
[8] try_with_timeout
@ ~/.julia/packages/ConcurrentUtilities/hQBsU/src/try_with_timeout.jl:77 [inlined]
[9] (::HTTP.Connections.var"#11#12"{OpenSSL.SSLStream, Int64, Int64, Bool, Bool, @Kwargs{readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool}, SubString{String}, SubString{String}})()
@ HTTP.Connections ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:460
[10] acquire(f::HTTP.Connections.var"#11#12"{OpenSSL.SSLStream, Int64, Int64, Bool, Bool, @Kwargs{readtimeout::Int64, iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool}, SubString{String}, SubString{String}}, pool::ConcurrentUtilities.Pools.Pool{Tuple{AbstractString, AbstractString, Bool, Bool, Bool}, HTTP.Connections.Connection{OpenSSL.SSLStream}}, key::Tuple{SubString{String}, SubString{String}, Bool, Bool, Bool}; forcenew::Bool, isvalid::HTTP.Connections.var"#15#16"{Int64})
@ ConcurrentUtilities.Pools ~/.julia/packages/ConcurrentUtilities/hQBsU/src/pools.jl:159
[11] acquire
@ ~/.julia/packages/ConcurrentUtilities/hQBsU/src/pools.jl:140 [inlined]
[12] #newconnection#7
@ ~/.julia/packages/HTTP/Y97L1/src/Connections.jl:455 [inlined]
[13] (::HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}})(req::HTTP.Messages.Request; proxy::Nothing, socket_type::Type, socket_type_tls::Nothing, readtimeout::Int64, connect_timeout::Int64, logerrors::Bool, logtag::Nothing, closeimmediately::Bool, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.ConnectionRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/ConnectionRequest.jl:82
[14] connections
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/ConnectionRequest.jl:60 [inlined]
[15] (::Base.var"#46#47"{Base.var"#48#49"{ExponentialBackOff, HTTP.RetryRequest.var"#retrylayer##2#retrylayer##3"{Int64, typeof(HTTP.RetryRequest.FALSE), HTTP.Messages.Request, Base.RefValue{Int64}}, HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(args::HTTP.Messages.Request; kwargs::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ Base ./error.jl:309
[16] (::HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(req::HTTP.Messages.Request; retry::Bool, retries::Int64, retry_delays::ExponentialBackOff, retry_check::Function, retry_non_idempotent::Bool, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.RetryRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RetryRequest.jl:75
[17] manageretries
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RetryRequest.jl:30 [inlined]
[18] (::HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}})(req::HTTP.Messages.Request; cookies::Bool, cookiejar::HTTP.Cookies.CookieJar, kw::@Kwargs{iofunction::Nothing, decompress::Nothing, verbose::Int64, body_is_form::Bool})
@ HTTP.CookieRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/CookieRequest.jl:42
[19] managecookies
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/CookieRequest.jl:19 [inlined]
[20] (::HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}})(req::HTTP.Messages.Request; iofunction::Nothing, decompress::Nothing, basicauth::Bool, detect_content_type::Bool, canonicalize_headers::Bool, kw::@Kwargs{verbose::Int64, body_is_form::Bool})
@ HTTP.HeadersRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/HeadersRequest.jl:71
[21] defaultheaders
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/HeadersRequest.jl:14 [inlined]
[22] (::HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}})(req::HTTP.Messages.Request; redirect::Bool, redirect_limit::Int64, redirect_method::Nothing, forwardheaders::Bool, response_stream::Nothing, kw::@Kwargs{verbose::Int64, body_is_form::Bool})
@ HTTP.RedirectRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RedirectRequest.jl:25
[23] redirects
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/RedirectRequest.jl:14 [inlined]
[24] (::HTTP.MessageRequest.var"#makerequest#messagelayer##0"{HTTP.MessageRequest.var"#makerequest#1#messagelayer##1"{HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}})(method::String, url::URIs.URI, headers::Vector{Pair{String, String}}, body::String; copyheaders::Bool, response_stream::Nothing, http_version::HTTP.Strings.HTTPVersion, verbose::Int64, kw::@Kwargs{body_is_form::Bool})
@ HTTP.MessageRequest ~/.julia/packages/HTTP/Y97L1/src/clientlayers/MessageRequest.jl:35
[25] makerequest
@ ~/.julia/packages/HTTP/Y97L1/src/clientlayers/MessageRequest.jl:24 [inlined]
[26] request(stack::HTTP.MessageRequest.var"#makerequest#messagelayer##0"{HTTP.MessageRequest.var"#makerequest#1#messagelayer##1"{HTTP.RedirectRequest.var"#redirects#redirectlayer##0"{HTTP.RedirectRequest.var"#redirects#1#redirectlayer##1"{HTTP.HeadersRequest.var"#defaultheaders#headerslayer##0"{HTTP.HeadersRequest.var"#defaultheaders#1#headerslayer##1"{HTTP.CookieRequest.var"#managecookies#cookielayer##0"{HTTP.CookieRequest.var"#managecookies#1#cookielayer##1"{HTTP.RetryRequest.var"#manageretries#retrylayer##0"{HTTP.RetryRequest.var"#manageretries#1#retrylayer##1"{HTTP.ConnectionRequest.var"#connections#connectionlayer##0"{HTTP.ConnectionRequest.var"#connections#1#connectionlayer##1"{HTTP.TimeoutRequest.var"#timeouts#timeoutlayer##0"{HTTP.TimeoutRequest.var"#timeouts#1#timeoutlayer##1"{HTTP.ExceptionRequest.var"#exceptions#exceptionlayer##0"{HTTP.ExceptionRequest.var"#exceptions#1#exceptionlayer##1"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}}, method::String, url::String, h::Vector{Pair{String, String}}, b::String, q::Nothing; headers::Vector{Pair{String, String}}, body::String, query::Nothing, kw::@Kwargs{body_is_form::Bool})
@ HTTP ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:465
[27] #request#21
@ ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:323 [inlined]
[28] request
@ ~/.julia/packages/HTTP/Y97L1/src/HTTP.jl:321 [inlined]
[29] plik_upload_handler(fileserver_url::String, dataname::String, data::Vector{UInt8})
@ Main ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:48
[30] smartpack(subject::String, data::Vector{Tuple{String, Any, String}}; broker_url::String, fileserver_url::String, fileserver_upload_handler::typeof(plik_upload_handler), size_threshold::Int64, correlation_id::String, msg_purpose::String, sender_name::String, receiver_name::String, receiver_id::String, reply_to::String, reply_to_msg_id::String, msg_id::String, sender_id::String)
@ Main.msghandler ~/docker-apps/sommpanion/msghandler/src/msghandler.jl:493
[31] test_mix_send()
@ Main ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:208
[32] top-level scope
@ ~/docker-apps/sommpanion/msghandler/test/test_julia_mix_payloads_sender.jl:256
[33] include(mod::Module, _path::String)
@ Base ./Base.jl:306
[34] exec_options(opts::Base.JLOptions)
@ Base ./client.jl:317
[35] _start()
@ Base ./client.jl:550
---
This is my Caddyfile:
fileserver.mydomain.cc {
# 1. Handle OPTIONS preflight requests specifically
@options {
method OPTIONS
}
respond @options 204
# 2. Add CORS headers to all responses (including those from the proxy)
header {
Access-Control-Allow-Origin "*"
Access-Control-Allow-Methods "GET, HEAD, OPTIONS, POST, PUT, DELETE"
Access-Control-Allow-Headers "*"
Access-Control-Max-Age "86400"
}
# 3. Proxy to your Plik server
reverse_proxy 192.168.88.104:8080 {
header_up Host {http.request.host}
header_up X-Forwarded-For {http.request.remote}
header_up X-Forwarded-Proto {http.request.scheme}
}
}
---
What do you think?

View File

@@ -2,7 +2,7 @@
julia_version = "1.12.6" julia_version = "1.12.6"
manifest_format = "2.0" manifest_format = "2.0"
project_hash = "6757ef801c2fba25b1829ffc7ce99f19563e7dc4" project_hash = "866f6d0804412d52eacd6423616500484f0060f0"
[[deps.AliasTables]] [[deps.AliasTables]]
deps = ["PtrArrays", "Random"] deps = ["PtrArrays", "Random"]
@@ -34,11 +34,6 @@ version = "1.11.0"
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
version = "1.11.0" version = "1.11.0"
[[deps.BitFlags]]
git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d"
uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
version = "0.1.9"
[[deps.BitIntegers]] [[deps.BitIntegers]]
deps = ["Random"] deps = ["Random"]
git-tree-sha1 = "091d591a060e43df1dd35faab3ca284925c48e46" git-tree-sha1 = "091d591a060e43df1dd35faab3ca284925c48e46"
@@ -50,6 +45,10 @@ git-tree-sha1 = "6863c5b7fc997eadcabdbaf6c5f201dc30032643"
uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d" uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d"
version = "1.2.2" version = "1.2.2"
[[deps.CRC32c]]
uuid = "8bf52ea8-c179-5cab-976a-9e18b702a9bc"
version = "1.11.0"
[[deps.CSV]] [[deps.CSV]]
deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"]
git-tree-sha1 = "8d8e0b0f350b8e1c91420b5e64e5de774c2f0f4d" git-tree-sha1 = "8d8e0b0f350b8e1c91420b5e64e5de774c2f0f4d"
@@ -130,9 +129,9 @@ version = "1.8.2"
[[deps.DataStructures]] [[deps.DataStructures]]
deps = ["OrderedCollections"] deps = ["OrderedCollections"]
git-tree-sha1 = "e86f4a2805f7f19bec5129bc9150c38208e5dc23" git-tree-sha1 = "6fb53a69613a0b2b68a0d12671717d307ab8b24e"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.19.4" version = "0.19.5"
[[deps.DataValueInterfaces]] [[deps.DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
@@ -146,9 +145,9 @@ version = "1.11.0"
[[deps.Distributions]] [[deps.Distributions]]
deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"]
git-tree-sha1 = "e421c1938fafab0165b04dc1a9dbe2a26272952c" git-tree-sha1 = "96f76dcd6cc75cf8eb49109123868499d413f526"
uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f"
version = "0.25.125" version = "0.25.126"
[deps.Distributions.extensions] [deps.Distributions.extensions]
DistributionsChainRulesCoreExt = "ChainRulesCore" DistributionsChainRulesCoreExt = "ChainRulesCore"
@@ -175,12 +174,6 @@ git-tree-sha1 = "c49898e8438c828577f04b92fc9368c388ac783c"
uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
version = "1.0.7" version = "1.0.7"
[[deps.ExceptionUnwrapping]]
deps = ["Test"]
git-tree-sha1 = "d36f682e590a83d63d1c7dbd287573764682d12a"
uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4"
version = "0.1.11"
[[deps.ExprTools]] [[deps.ExprTools]]
git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec" git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
@@ -191,12 +184,15 @@ deps = ["Compat", "Dates"]
git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2" git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2"
uuid = "48062228-2e41-5def-b9a4-89aafe57970f" uuid = "48062228-2e41-5def-b9a4-89aafe57970f"
version = "0.9.24" version = "0.9.24"
weakdeps = ["Mmap", "Test"]
[deps.FilePathsBase.extensions] [deps.FilePathsBase.extensions]
FilePathsBaseMmapExt = "Mmap" FilePathsBaseMmapExt = "Mmap"
FilePathsBaseTestExt = "Test" FilePathsBaseTestExt = "Test"
[deps.FilePathsBase.weakdeps]
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[[deps.FileWatching]] [[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
version = "1.11.0" version = "1.11.0"
@@ -226,17 +222,17 @@ version = "1.11.0"
[[deps.GeneralUtils]] [[deps.GeneralUtils]]
deps = ["CSV", "DataFrames", "DataStructures", "Dates", "Distributions", "JSON", "NATS", "PrettyPrinting", "Random", "Revise", "SHA", "UUIDs"] deps = ["CSV", "DataFrames", "DataStructures", "Dates", "Distributions", "JSON", "NATS", "PrettyPrinting", "Random", "Revise", "SHA", "UUIDs"]
git-tree-sha1 = "e28ca4df47d0c46d04716422bef6adb660f33dc3" git-tree-sha1 = "8720a31344bc85ad610ae12f7e1247de22070765"
repo-rev = "main" repo-rev = "main"
repo-url = "https://git.yiem.cc/ton/GeneralUtils" repo-url = "https://git.yiem.cc/ton/GeneralUtils"
uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe" uuid = "c6c72f09-b708-4ac8-ac7c-2084d70108fe"
version = "0.3.1" version = "0.3.2"
[[deps.HTTP]] [[deps.HTTP]]
deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] deps = ["Base64", "CodecZlib", "Dates", "EnumX", "PrecompileTools", "Random", "Reseau", "SHA", "URIs", "UUIDs", "Zlib_jll"]
git-tree-sha1 = "51059d23c8bb67911a2e6fd5130229113735fc7e" git-tree-sha1 = "196e75bcb0a53cbf80eebe6326d69a86605c34d6"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "1.11.0" version = "2.3.0"
[[deps.HashArrayMappedTries]] [[deps.HashArrayMappedTries]]
git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae" git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae"
@@ -287,9 +283,9 @@ version = "1.8.0"
[[deps.JSON]] [[deps.JSON]]
deps = ["Dates", "Logging", "Parsers", "PrecompileTools", "StructUtils", "UUIDs", "Unicode"] deps = ["Dates", "Logging", "Parsers", "PrecompileTools", "StructUtils", "UUIDs", "Unicode"]
git-tree-sha1 = "f76f7560267b840e492180f9899b472f30b88450" git-tree-sha1 = "c89d196f5ffb64bfbf80985b699ea913b0d2c211"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "1.6.0" version = "1.6.1"
weakdeps = ["ArrowTypes"] weakdeps = ["ArrowTypes"]
[deps.JSON.extensions] [deps.JSON.extensions]
@@ -357,9 +353,9 @@ version = "1.12.0"
[[deps.LogExpFunctions]] [[deps.LogExpFunctions]]
deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "13ca9e2586b89836fd20cccf56e57e2b9ae7f38f" git-tree-sha1 = "bba2d9aa057d8f126415de240573e86a8f39d2a1"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.29" version = "1.0.1"
[deps.LogExpFunctions.extensions] [deps.LogExpFunctions.extensions]
LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" LogExpFunctionsChainRulesCoreExt = "ChainRulesCore"
@@ -375,17 +371,11 @@ version = "0.3.29"
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
version = "1.11.0" version = "1.11.0"
[[deps.LoggingExtras]]
deps = ["Dates", "Logging"]
git-tree-sha1 = "f00544d95982ea270145636c181ceda21c4e2575"
uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36"
version = "1.2.0"
[[deps.LoweredCodeUtils]] [[deps.LoweredCodeUtils]]
deps = ["CodeTracking", "Compiler", "JuliaInterpreter"] deps = ["CodeTracking", "Compiler", "JuliaInterpreter"]
git-tree-sha1 = "5d4278f755440f70648d80cc6225f51e78e94094" git-tree-sha1 = "0aad96d7b987a5600e260eec50147b254d5ff7e6"
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
version = "3.5.1" version = "3.6.0"
[[deps.Lz4_jll]] [[deps.Lz4_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"] deps = ["Artifacts", "JLLWrappers", "Libdl"]
@@ -456,12 +446,6 @@ deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112" uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
version = "0.8.7+0" version = "0.8.7+0"
[[deps.OpenSSL]]
deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "NetworkOptions", "OpenSSL_jll", "Sockets"]
git-tree-sha1 = "1d1aaa7d449b58415f97d2839c318b70ffb525a0"
uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c"
version = "1.6.1"
[[deps.OpenSSL_jll]] [[deps.OpenSSL_jll]]
deps = ["Artifacts", "Libdl"] deps = ["Artifacts", "Libdl"]
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
@@ -474,9 +458,9 @@ uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.6+0" version = "0.5.6+0"
[[deps.OrderedCollections]] [[deps.OrderedCollections]]
git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" git-tree-sha1 = "94ba93778373a53bfd5a0caaf7d809c445292ff4"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.8.1" version = "1.8.2"
[[deps.PDMats]] [[deps.PDMats]]
deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
@@ -490,9 +474,9 @@ weakdeps = ["StatsBase"]
[[deps.Parsers]] [[deps.Parsers]]
deps = ["Dates", "PrecompileTools", "UUIDs"] deps = ["Dates", "PrecompileTools", "UUIDs"]
git-tree-sha1 = "5d5e0a78e971354b1c7bff0655d11fdc1b0e12c8" git-tree-sha1 = "32a4e09c5f29402573d673901778a0e03b0807b9"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.8.4" version = "2.8.6"
[[deps.PooledArrays]] [[deps.PooledArrays]]
deps = ["DataAPI", "Future"] deps = ["DataAPI", "Future"]
@@ -566,11 +550,17 @@ git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69" uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2" version = "1.2.2"
[[deps.Reseau]]
deps = ["NetworkOptions", "OpenSSL_jll", "PrecompileTools", "Random", "SHA"]
git-tree-sha1 = "0eab6d95ed40c2ef3992255c1c71e4f9748932b5"
uuid = "802f3686-a58f-41ce-bb0c-3c43c75bba36"
version = "1.3.1"
[[deps.Revise]] [[deps.Revise]]
deps = ["CodeTracking", "FileWatching", "InteractiveUtils", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Preferences", "REPL", "UUIDs"] deps = ["CRC32c", "CodeTracking", "FileWatching", "InteractiveUtils", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Preferences", "REPL", "UUIDs"]
git-tree-sha1 = "d9383b639663d8220ac9c523927e38bc21cad16a" git-tree-sha1 = "27e3ee13fc8739a59b380d6163d6a82f52c03bd7"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.14.3" version = "3.15.1"
[deps.Revise.extensions] [deps.Revise.extensions]
DistributedExt = "Distributed" DistributedExt = "Distributed"
@@ -616,11 +606,6 @@ version = "1.4.10"
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
version = "1.11.0" version = "1.11.0"
[[deps.SimpleBufferStream]]
git-tree-sha1 = "f305871d2f381d21527c770d4788c06c097c9bc1"
uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7"
version = "1.2.0"
[[deps.Sockets]] [[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc" uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
version = "1.11.0" version = "1.11.0"
@@ -644,9 +629,9 @@ version = "1.12.0"
[[deps.SpecialFunctions]] [[deps.SpecialFunctions]]
deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "2700b235561b0335d5bef7097a111dc513b8655e" git-tree-sha1 = "6547cbdd8ce32efba0d21c5a40fa96d1a3548f9f"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b" uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "2.7.2" version = "2.8.0"
[deps.SpecialFunctions.extensions] [deps.SpecialFunctions.extensions]
SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" SpecialFunctionsChainRulesCoreExt = "ChainRulesCore"
@@ -672,15 +657,15 @@ version = "1.8.0"
[[deps.StatsBase]] [[deps.StatsBase]]
deps = ["AliasTables", "DataAPI", "DataStructures", "IrrationalConstants", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] deps = ["AliasTables", "DataAPI", "DataStructures", "IrrationalConstants", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "aceda6f4e598d331548e04cc6b2124a6148138e3" git-tree-sha1 = "c6f18e5a52a176a383f6f6c635e0f81feed1d6d4"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.34.10" version = "0.34.11"
[[deps.StatsFuns]] [[deps.StatsFuns]]
deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
git-tree-sha1 = "91f091a8716a6bb38417a6e6f274602a19aaa685" git-tree-sha1 = "3f4e1d24289cd974e089c617b1472311a2b1feab"
uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c"
version = "1.5.2" version = "2.1.0"
[deps.StatsFuns.extensions] [deps.StatsFuns.extensions]
StatsFunsChainRulesCoreExt = "ChainRulesCore" StatsFunsChainRulesCoreExt = "ChainRulesCore"
@@ -759,11 +744,6 @@ git-tree-sha1 = "f2c1efbc8f3a609aadf318094f8fc5204bdaf344"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.12.1" version = "1.12.1"
[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
version = "1.11.0"
[[deps.TimeZones]] [[deps.TimeZones]]
deps = ["Artifacts", "Dates", "Downloads", "InlineStrings", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"] deps = ["Artifacts", "Dates", "Downloads", "InlineStrings", "Mocking", "Printf", "Scratch", "TZJData", "Unicode", "p7zip_jll"]
git-tree-sha1 = "d422301b2a1e294e3e4214061e44f338cafe18a2" git-tree-sha1 = "d422301b2a1e294e3e4214061e44f338cafe18a2"
@@ -829,7 +809,7 @@ uuid = "a9144af2-ca23-56d9-984f-0d03f7b5ccf8"
version = "1.0.21+0" version = "1.0.21+0"
[[deps.msghandler]] [[deps.msghandler]]
deps = ["Arrow", "Base64", "DataFrames", "Dates", "HTTP", "JSON", "NATS", "PrettyPrinting", "Revise", "UUIDs"] deps = ["Arrow", "Base64", "DataFrames", "Dates", "GeneralUtils", "HTTP", "JSON", "NATS", "PrettyPrinting", "Revise", "UUIDs"]
path = "." path = "."
uuid = "f2724d33-f338-4a57-b9f8-1be882570d10" uuid = "f2724d33-f338-4a57-b9f8-1be882570d10"
version = "0.5.6" version = "0.5.6"

View File

@@ -19,5 +19,5 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[compat] [compat]
Base64 = "1.11.0" Base64 = "1.11.0"
Dates = "1.11.0" Dates = "1.11.0"
GeneralUtils = "0.3.1" GeneralUtils = "0.3.2"
JSON = "1.4.0" JSON = "1.4.0"

1279
README.md

File diff suppressed because it is too large Load Diff

View File

@@ -526,36 +526,15 @@ async function smartunpack(msg, options = {}) {
max_delay = 5000 max_delay = 5000
} = options; } = options;
// Handle both raw JSON strings and transport message objects let envJsonObj;
let payload;
if (typeof msg === 'string') { // NATS's Javascript lib already return JSON object
payload = msg; if (msg !== null && typeof msg === 'object') {
} else if (msg !== null && typeof msg === 'object') { envJsonObj = msg;
if (msg.data !== undefined) {
payload = typeof msg.data === 'string' ? msg.data : new TextDecoder().decode(msg.data);
} else if (msg.payload !== undefined) {
payload = typeof msg.payload === 'string' ? msg.payload : new TextDecoder().decode(msg.payload);
} else {
throw new Error('Message has neither data nor payload property');
}
} else { } else {
throw new Error('Invalid message format: expected JSON string or message object'); throw new Error('Invalid message format: expected JSON string or message object');
} }
logTrace('smartunpack', `smartunpack: raw payload length=${payload.length}`);
// Debug: Show first 200 chars of payload
const payloadPreview = payload.substring(0, 200);
logTrace('smartunpack', `smartunpack: payload preview: ${payloadPreview}`);
let envJsonObj;
try {
envJsonObj = JSON.parse(payload);
} catch (e) {
logTrace('smartunpack', `smartunpack: JSON parse failed: ${e.message}`);
throw e;
}
logTrace(envJsonObj.correlation_id, 'Processing received message'); logTrace(envJsonObj.correlation_id, 'Processing received message');
logTrace(envJsonObj.correlation_id, `smartunpack: envelope has ${envJsonObj.payloads.length} payloads`); logTrace(envJsonObj.correlation_id, `smartunpack: envelope has ${envJsonObj.payloads.length} payloads`);

View File

@@ -421,7 +421,7 @@ env, msg_json = smartpack("chat.subject", [
""" """
function smartpack( function smartpack(
subject::String, # smartunpack's subject subject::String, # smartunpack's subject
data::AbstractArray{Tuple{String, T1, String}, 1}; # List of (dataname, data, type) tuples. Use Tuple{String, Any, String}[] for empty payloads data::AbstractArray{Tuple{String, T1, String}, 1}; # List of (dataname, data, type) tuples. Use data = Tuple{String, Any, String}[] for empty payloads
broker_url::String = DEFAULT_BROKER_URL, # Broker URL broker_url::String = DEFAULT_BROKER_URL, # Broker URL
fileserver_url = DEFAULT_FILESERVER_URL, fileserver_url = DEFAULT_FILESERVER_URL,
fileserver_upload_handler::Function = plik_oneshot_upload, # a function to handle uploading data to specific HTTP fileserver fileserver_upload_handler::Function = plik_oneshot_upload, # a function to handle uploading data to specific HTTP fileserver
@@ -451,9 +451,9 @@ function smartpack(
# Process each payload in the list # Process each payload in the list
payloads = msg_payload_v1[] payloads = msg_payload_v1[]
for (dataname, payload_data, payload_type) in data for (dataname, payload_data, payload_type) in data
@show dataname typeof(payload_data) # @show dataname typeof(payload_data)
# Serialize data based on type # Serialize data based on type. use bytes as medium for every datatype
payload_bytes = _serialize_data(payload_data, payload_type) payload_bytes = _serialize_data(payload_data, payload_type)
payload_size = length(payload_bytes) # Calculate payload size in bytes payload_size = length(payload_bytes) # Calculate payload size in bytes
@@ -811,7 +811,7 @@ function smartunpack(
max_retries::Int = 5, max_retries::Int = 5,
base_delay::Int = 100, base_delay::Int = 100,
max_delay::Int = 5000 max_delay::Int = 5000
)::JSON.Object{String, Any} )::JSON.Object{String, Any}
# Parse the JSON envelope # Parse the JSON envelope
env_json_obj = JSON.parse(msg_json_str) env_json_obj = JSON.parse(msg_json_str)
@@ -834,7 +834,7 @@ function smartunpack(
# Extract base64 payload from the payload # Extract base64 payload from the payload
payload_b64 = String(payload["data"]) payload_b64 = String(payload["data"])
# Decode Base64 payload # Decode Base64 payload back into bytes (smartpack use bytes as medium for every datatype)
payload_bytes = Base64.base64decode(payload_b64) # Decode base64 payload to bytes payload_bytes = Base64.base64decode(payload_b64) # Decode base64 payload to bytes
# Deserialize based on type # Deserialize based on type
@@ -1048,7 +1048,7 @@ function plik_oneshot_upload(file_server_url::String, dataname::String, data::Ve
url_getUploadID = "$file_server_url/upload" # URL to get upload ID url_getUploadID = "$file_server_url/upload" # URL to get upload ID
headers = ["Content-Type" => "application/json"] headers = ["Content-Type" => "application/json"]
body = """{ "OneShot" : true }""" body = """{ "OneShot" : true }"""
http_response = HTTP.request("POST", url_getUploadID, headers, body; body_is_form=false) http_response = HTTP.request("POST", url_getUploadID, headers, body)
response_json = JSON.parse(http_response.body) response_json = JSON.parse(http_response.body)
uploadid = response_json["id"] uploadid = response_json["id"]
uploadtoken = response_json["uploadToken"] uploadtoken = response_json["uploadToken"]
@@ -1125,7 +1125,7 @@ function plik_oneshot_upload(file_server_url::String, filepath::String)
url_getUploadID = "$file_server_url/upload" # URL to get upload ID url_getUploadID = "$file_server_url/upload" # URL to get upload ID
headers = ["Content-Type" => "application/json"] headers = ["Content-Type" => "application/json"]
body = """{ "OneShot" : true }""" body = """{ "OneShot" : true }"""
http_response = HTTP.request("POST", url_getUploadID, headers, body; body_is_form=false) http_response = HTTP.request("POST", url_getUploadID, headers, body)
response_json = JSON.parse(http_response.body) response_json = JSON.parse(http_response.body)
uploadid = response_json["id"] uploadid = response_json["id"]

66
test/runtest.jl Normal file
View File

@@ -0,0 +1,66 @@
function plik_oneshot_upload(file_server_url::String, dataname::String, data::Vector{UInt8})
# ----------------------------------------- get upload id ---------------------------------------- #
# Equivalent curl command: curl -X POST -d '{ "OneShot" : true }' http://localhost:8080/upload
url_getUploadID = "$file_server_url/upload" # URL to get upload ID
headers = ["Content-Type" => "application/json"]
body = """{ "OneShot" : true }"""
http_response = HTTP.request("POST", url_getUploadID, headers, body)
response_json = JSON.parse(http_response.body)
uploadid = response_json["id"]
uploadtoken = response_json["uploadToken"]
# ------------------------------------------ upload file ----------------------------------------- #
# Equivalent curl command: curl -X POST --header "X-UploadToken: UPLOAD_TOKEN" -F "file=@PATH_TO_FILE" http://localhost:8080/file/UPLOAD_ID
file_multipart = HTTP.Multipart(dataname, IOBuffer(data), "application/octet-stream") # Plik won't accept raw bytes upload
url_upload = "$file_server_url/file/$uploadid"
headers = ["X-UploadToken" => uploadtoken]
# Create the multipart form data
form = HTTP.Form(Dict(
"file" => file_multipart
))
# Execute the POST request
http_response = nothing
try
http_response = HTTP.post(url_upload, headers, form)
catch e
@error "Request failed" exception=e
end
response_json = JSON.parse(http_response.body)
fileid = response_json["id"]
# url of the uploaded data e.g. "http://192.168.1.20:8080/file/3F62E/4AgGT/test.zip"
url = "$file_server_url/file/$uploadid/$fileid/$dataname"
return Dict("status" => http_response.status, "uploadid" => uploadid, "fileid" => fileid, "url" => url)
end
using HTTP, JSON
file_server_url = "https://fileserver.yiem.cc"
dataname = "test.txt"
data = Vector{UInt8}("hello world")
# Upload to local plik server
result = plik_oneshot_upload(file_server_url, dataname, data)
println(result)

View File

@@ -6,7 +6,7 @@
* any combination and any number of mixed content can be received correctly. * any combination and any number of mixed content can be received correctly.
*/ */
const msghandler = require('../src/msghandler.js'); const msghandler = require('../src/msghandler-csr.js');
const nats = require('nats'); const nats = require('nats');
const crypto = require('crypto'); const crypto = require('crypto');

View File

@@ -6,7 +6,7 @@
* any combination and any number of mixed content can be sent correctly. * any combination and any number of mixed content can be sent correctly.
*/ */
const msghandler = require('../src/msghandler.js'); const msghandler = require('../src/msghandler-csr.js').default;
const crypto = require('crypto'); const crypto = require('crypto');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');

View File

@@ -9,7 +9,7 @@
using NATS, JSON, UUIDs, Dates, PrettyPrinting, DataFrames, Arrow, HTTP, Base64 using NATS, JSON, UUIDs, Dates, PrettyPrinting, DataFrames, Arrow, HTTP, Base64
# Include the bridge module # Include the bridge module
include("../src/msghandler.jl") include("/home/ton/docker-apps/sommpanion/msghandler/src/msghandler.jl")
using .msghandler using .msghandler
# Configuration # Configuration
@@ -39,7 +39,7 @@ function test_mix_receive()
# Use msghandler.smartunpack to handle the data # Use msghandler.smartunpack to handle the data
# API: smartunpack(msg, download_handler; max_retries, base_delay, max_delay) # API: smartunpack(msg, download_handler; max_retries, base_delay, max_delay)
result = msghandler.smartunpack( result = msghandler.smartunpack(
msg; env_json_str;
max_retries = 5, max_retries = 5,
base_delay = 100, base_delay = 100,
max_delay = 5000 max_delay = 5000

View File

@@ -1,258 +1,632 @@
#!/usr/bin/env julia /**
# Test script for mixed-content message testing * msghandler - Cross-Platform Bi-Directional Data Bridge
# Tests sending a mix of text, dictionary, arrowtable, jsontable, image, audio, video, and binary data * Browser-Compatible Implementation (Client-Side Rendering)
# from Julia serviceA to Julia serviceB using msghandler.jl smartpack *
# * This module provides functionality for sending and receiving data across network boundaries
# This test demonstrates that any combination and any number of mixed content * with support for both direct payload transport and URL-based transport for larger payloads.
# can be sent and received correctly. *
# * Supported payload types: "text", "dictionary", "jsontable", "image", "audio", "video", "binary"
# Key concept: DataFrames are the main table representation in Julia. * Note: Browser version does NOT support Apache Arrow IPC (arrowtable) due to browser compatibility constraints.
# The msghandler.jl library handles serialization: * Use "jsontable" for tabular data in browser applications.
# - For "arrowtable" type: DataFrame is serialized to Arrow IPC format *
# - For "jsontable" type: DataFrame is converted to Vector{Dict} and then to JSON * Browser requirements:
* - Modern browser with ES module support (or use module bundler)
* - Web Crypto API for UUID generation
* - Fetch API for HTTP requests
*
* Browser-compatible version uses:
* - Web Crypto API for UUID generation
* - Uint8Array instead of Buffer
* - fetch API for file server communication
*
* @module msghandlerCSR
*/
using NATS, JSON, UUIDs, Dates, PrettyPrinting, DataFrames, Arrow, HTTP, Base64 // Use native fetch available in browsers
# Include the bridge module // ---------------------------------------------- Constants ---------------------------------------------- //
include("../src/msghandler.jl")
using .msghandler
# Configuration /**
const SUBJECT = "/msghandler" * Default size threshold for switching from direct to link transport (0.5MB)
const NATS_URL = "nats.yiem.cc" */
const FILESERVER_URL = "http://192.168.88.104:8080" const DEFAULT_SIZE_THRESHOLD = 500_000;
# Create correlation ID for tracing /**
correlation_id = string(uuid4()) * Default broker URL
*/
const DEFAULT_BROKER_URL = 'localhost:4222';
/**
* Default HTTP file server URL for link transport
*/
const DEFAULT_FILESERVER_URL = 'http://localhost:8080';
# ------------------------------------------------------------------------------------------------ # // ---------------------------------------------- Utility Functions ---------------------------------------------- //
# test mixed content transfer #
# ------------------------------------------------------------------------------------------------ #
/**
* Convert Uint8Array to Base64 string
* @param {Uint8Array} data - Data to encode
* @returns {string} Base64 encoded string
*/
function bufferToBase64(data) {
const bytes = new Uint8Array(data);
const binary = String.fromCharCode(...bytes);
return btoa(binary);
}
# Helper: Log with correlation ID /**
function log_trace(message) * Convert Base64 string to Uint8Array
timestamp = Dates.now() * @param {string} base64 - Base64 encoded string
println("[$timestamp] [Correlation: $correlation_id] $message") * @returns {Uint8Array} Decoded binary data
end */
function base64ToBuffer(base64) {
const binary = atob(base64);
const len = binary.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
/**
* Generate UUID v4 using Web Crypto API
* @returns {string} UUID string
*/
function uuidv4() {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
array[6] = (array[6] & 0x0f) | 0x40;
array[8] = (array[8] & 0x3f) | 0x80;
return Array.from(array, (val) => val.toString(16).padStart(2, '0').toUpperCase()).join('');
}
# File upload handler for plik server /**
function plik_upload_handler(fileserver_url::String, dataname::String, data::Vector{UInt8})::Dict{String, Any} * Log a trace message with correlation ID and timestamp
# Get upload ID * @param {string} correlationId - Correlation ID for tracing
url_getUploadID = "$fileserver_url/upload" * @param {string} message - Message content to log
headers = ["Content-Type" => "application/json"] */
body = """{ "OneShot" : true }""" function logTrace(correlationId, message) {
httpResponse = HTTP.request("POST", url_getUploadID, headers, body; body_is_form=false) const timestamp = new Date().toISOString();
responseJson = JSON.parse(String(httpResponse.body)) console.log(`[${timestamp}] [Correlation: ${correlationId}] ${message}`);
uploadid = responseJson["id"] }
uploadtoken = responseJson["uploadToken"]
# Upload file // ---------------------------------------------- Serialization Functions ---------------------------------------------- //
file_multipart = HTTP.Multipart(dataname, IOBuffer(data), "application/octet-stream")
url_upload = "$fileserver_url/file/$uploadid"
headers = ["X-UploadToken" => uploadtoken]
form = HTTP.Form(Dict("file" => file_multipart)) /**
httpResponse = HTTP.post(url_upload, headers, form) * Serialize data according to specified format
responseJson = JSON.parse(String(httpResponse.body)) * @param {any} data - Data to serialize
* @param {string} payloadType - Target format: "text", "dictionary", "jsontable", "image", "audio", "video", "binary"
* @returns {Uint8Array} Binary representation of the serialized data
*/
async function serializeData(data, payloadType) {
if (payloadType === 'text') {
if (typeof data === 'string') {
return new Uint8Array(new TextEncoder().encode(data));
} else {
throw new Error('Text data must be a string');
}
} else if (payloadType === 'dictionary') {
const jsonStr = JSON.stringify(data);
return new Uint8Array(new TextEncoder().encode(jsonStr));
} else if (payloadType === 'jsontable') {
// Serialize array of objects to JSON format
if (!Array.isArray(data)) {
throw new Error('JSON table data must be an array');
}
const jsonStr = JSON.stringify(data);
return new Uint8Array(new TextEncoder().encode(jsonStr));
} else if (payloadType === 'image') {
if (data instanceof Uint8Array || data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
return new Uint8Array(data);
} else {
throw new Error('Image data must be Uint8Array, ArrayBuffer, or ArrayBuffer view');
}
} else if (payloadType === 'audio') {
if (data instanceof Uint8Array || data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
return new Uint8Array(data);
} else {
throw new Error('Audio data must be Uint8Array, ArrayBuffer, or ArrayBuffer view');
}
} else if (payloadType === 'video') {
if (data instanceof Uint8Array || data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
return new Uint8Array(data);
} else {
throw new Error('Video data must be Uint8Array, ArrayBuffer, or ArrayBuffer view');
}
} else if (payloadType === 'binary') {
if (data instanceof Uint8Array || data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
return new Uint8Array(data);
} else {
throw new Error('Binary data must be Uint8Array, ArrayBuffer, or ArrayBuffer view');
}
} else {
throw new Error(`Unknown payload_type: ${payloadType}`);
}
}
fileid = responseJson["id"] /**
url = "$fileserver_url/file/$uploadid/$fileid/$dataname" * Deserialize bytes to data based on type
* @param {Uint8Array|ArrayBuffer} data - Serialized data as bytes
* @param {string} payloadType - Data type
* @param {string} correlationId - Correlation ID for logging
* @returns {any} Deserialized data
*/
async function deserializeData(data, payloadType, correlationId) {
const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);
return Dict("status" => httpResponse.status, "uploadid" => uploadid, "fileid" => fileid, "url" => url) logTrace(correlationId, `deserializeData: type=${payloadType}, bufferLength=${buffer.length}`);
end
// Debug: Show first 20 bytes in hex for binary data
if (payloadType === 'jsontable' || payloadType === 'image' || payloadType === 'binary') {
const hexPreview = [];
for (let i = 0; i < Math.min(20, buffer.length); i++) {
hexPreview.push(buffer[i].toString(16).padStart(2, '0'));
}
logTrace(correlationId, `deserializeData: First 20 bytes (hex): ${hexPreview.join(' ')}`);
}
# Helper: Create sample data for each type if (payloadType === 'text') {
function create_sample_data() const result = new TextDecoder().decode(buffer);
# Text data (small - direct transport) logTrace(correlationId, `deserializeData: text result length=${result.length}`);
text_data = "Hello! This is a test chat message. 🎉\nHow are you doing today? 😊" return result;
} else if (payloadType === 'dictionary') {
const jsonStr = new TextDecoder().decode(buffer);
const result = JSON.parse(jsonStr);
logTrace(correlationId, `deserializeData: dictionary keys=${Object.keys(result).join(', ')}`);
return result;
} else if (payloadType === 'jsontable') {
const jsonStr = new TextDecoder().decode(buffer);
const result = JSON.parse(jsonStr);
logTrace(correlationId, `deserializeData: jsontable result length=${Array.isArray(result) ? result.length : 'N/A'}`);
return result;
} else if (payloadType === 'image') {
logTrace(correlationId, `deserializeData: image buffer length=${buffer.length}`);
return buffer;
} else if (payloadType === 'audio') {
logTrace(correlationId, `deserializeData: audio buffer length=${buffer.length}`);
return buffer;
} else if (payloadType === 'video') {
logTrace(correlationId, `deserializeData: video buffer length=${buffer.length}`);
return buffer;
} else if (payloadType === 'binary') {
logTrace(correlationId, `deserializeData: binary buffer length=${buffer.length}`);
return buffer;
} else {
throw new Error(`Unknown payload_type: ${payloadType}`);
}
}
# Dictionary/JSON data (medium - could be direct or link) // ---------------------------------------------- File Server Handlers ---------------------------------------------- //
dict_data = Dict(
"type" => "chat",
"sender" => "serviceA",
"receiver" => "serviceB",
"metadata" => Dict(
"timestamp" => string(Dates.now()),
"priority" => "high",
"tags" => ["urgent", "chat", "test"]
),
"content" => Dict(
"text" => "This is a JSON-formatted chat message with nested structure.",
"format" => "markdown",
"mentions" => ["user1", "user2"]
)
)
# Arrow table data (DataFrame - small - direct transport) /**
# Uses Arrow IPC format for efficient binary serialization * Upload data to plik server in one-shot mode
# msghandler.jl handles serialization: DataFrame -> Arrow IPC * @param {string} fileServerUrl - Base URL of the plik server
arrow_table_small = DataFrame( * @param {string} dataname - Name of the file being uploaded
id = 1:10, * @param {Uint8Array} data - Raw byte data of the file content
name = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack"], * @returns {Promise<{status: number, uploadid: string, fileid: string, url: string}>}
score = rand(50:100, 10), */
active = rand([true, false], 10) async function plikOneshotUpload(fileServerUrl, dataname, data) {
) const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);
# Arrow table data (DataFrame - large - link transport) // Get upload id
# ~1.5MB of Arrow data (200,000 rows) - should trigger link transport const urlGetUploadID = `${fileServerUrl}/upload`;
# msghandler.jl handles serialization: DataFrame -> Arrow IPC const headers = { 'Content-Type': 'application/json' };
arrow_table_large = DataFrame( const body = JSON.stringify({ OneShot: true });
id = 1:2_000_000,
name = ["user_$i" for i in 1:2_000_000],
score = rand(50:100, 2_000_000),
active = rand([true, false], 2_000_000),
timestamp = [string(Dates.now()) for _ in 1:2_000_000]
)
# Json table data (DataFrame - small - direct transport) const httpResponse = await fetch(urlGetUploadID, {
# Uses JSON format for human-readable tabular data method: 'POST',
# msghandler.jl handles serialization: DataFrame -> Vector{Dict} -> JSON headers,
json_table_small = DataFrame( body
id = 1:10, });
name = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Henry", "Ivy", "Jack"],
score = rand(50:100, 10),
active = rand([true, false], 10)
)
# Json table data (DataFrame - large - link transport) const responseJson = await httpResponse.json();
# ~1.5MB of JSON data (150,000 rows) - should trigger link transport const uploadid = responseJson.id;
# msghandler.jl handles serialization: DataFrame -> Vector{Dict} -> JSON const uploadtoken = responseJson.uploadToken;
json_table_large = DataFrame(
id = 1:2_000_000,
name = ["user_$i" for i in 1:2_000_000],
score = rand(50:100, 2_000_000),
active = rand([true, false], 2_000_000)
)
# Audio data (small binary - direct transport) // Upload file
audio_data = UInt8[rand(1:255) for _ in 1:100] const urlUpload = `${fileServerUrl}/file/${uploadid}`;
const form = new FormData();
const blob = new Blob([buffer], { type: 'application/octet-stream' });
form.append('file', blob, dataname);
# Audio data (large - link transport) const uploadHeaders = {
# ~1.5MB of audio-like data 'X-UploadToken': uploadtoken
large_audio_data = UInt8[rand(1:255) for _ in 1:1_500_000] };
# Video data (small binary - direct transport) const uploadResponse = await fetch(urlUpload, {
video_data = UInt8[rand(1:255) for _ in 1:150] method: 'POST',
headers: uploadHeaders,
body: form
});
# Video data (large - link transport) const uploadJson = await uploadResponse.json();
# ~1.5MB of video-like data const fileid = uploadJson.id;
large_video_data = UInt8[rand(1:255) for _ in 1:1_500_000]
# Binary data (small - direct transport) const url = `${fileServerUrl}/file/${uploadid}/${fileid}/${dataname}`;
binary_data = UInt8[rand(1:255) for _ in 1:200]
# Binary data (large - link transport) return {
# ~1.5MB of binary data status: uploadResponse.status,
large_binary_data = UInt8[rand(1:255) for _ in 1:1_500_000] uploadid,
fileid,
url
};
}
return ( /**
text_data, * Fetch data from URL with exponential backoff
dict_data, * @param {string} url - URL to fetch from
arrow_table_small, * @param {number} maxRetries - Maximum number of retry attempts
arrow_table_large, * @param {number} baseDelay - Initial delay in milliseconds
json_table_small, * @param {number} maxDelay - Maximum delay in milliseconds
json_table_large, * @param {string} correlationId - Correlation ID for logging
audio_data, * @returns {Promise<Uint8Array>} Fetched data as bytes
large_audio_data, */
video_data, async function fetchWithBackoff(url, maxRetries, baseDelay, maxDelay, correlationId) {
large_video_data, let delay = baseDelay;
binary_data,
large_binary_data
)
end
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url);
# Sender: Send mixed content via smartpack if (response.status === 200) {
function test_mix_send() logTrace(correlationId, `Successfully fetched data from ${url} on attempt ${attempt}`);
# Create sample data const arrayBuffer = await response.arrayBuffer();
(text_data, dict_data, arrow_table_small, arrow_table_large, json_table_small, json_table_large, audio_data, large_audio_data, video_data, large_video_data, binary_data, large_binary_data) = create_sample_data() return new Uint8Array(arrayBuffer);
} else {
throw new Error(`Failed to fetch: ${response.status}`);
}
} catch (e) {
logTrace(correlationId, `Attempt ${attempt} failed: ${e.constructor.name} - ${e.message}`);
# Read image files from disk (following test_julia_file_sender.jl pattern) if (attempt < maxRetries) {
# Small image - should use direct transport await new Promise(resolve => setTimeout(resolve, delay));
file_path_small_image = "./test/small_image.jpg" delay = Math.min(delay * 2, maxDelay);
file_data_small_image = read(file_path_small_image) }
filename_small_image = basename(file_path_small_image) }
}
# Large image - should use link transport throw new Error(`Failed to fetch data after ${maxRetries} attempts`);
file_path_large_image = "./test/large_image.png" }
file_data_large_image = read(file_path_large_image)
filename_large_image = basename(file_path_large_image)
# Create payloads list - mixed content with both small and large data // ---------------------------------------------- Core Functions ---------------------------------------------- //
# Small data uses direct transport, large data uses link transport
# Key: Pass DataFrame directly and specify type as "arrowtable" or "jsontable"
# msghandler.jl handles the serialization internally
payloads = [
# Small data (direct transport) - text, dictionary, arrowtable, jsontable, small image
("chat_text", text_data, "text"),
("chat_json", dict_data, "dictionary"),
# ("arrow_table_small", arrow_table_small, "arrowtable"),
("json_table_small", json_table_small, "jsontable"),
(filename_small_image, file_data_small_image, "binary"),
# Large data (link transport) - large arrowtable, large jsontable, large image, large audio, large video, large binary /**
# ("arrow_table_large", arrow_table_large, "arrowtable"), * Build message envelope from payloads and metadata
("json_table_large", json_table_large, "jsontable"), * @param {string} subject - Subject/topic
(filename_large_image, file_data_large_image, "binary"), * @param {Array} payloads - Array of payload objects
("audio_clip_large", large_audio_data, "audio"), * @param {Object} options - Envelope metadata options
("video_clip_large", large_video_data, "video"), * @returns {Object} Envelope object
("binary_file_large", large_binary_data, "binary") */
] function buildEnvelope(subject, payloads, options) {
return {
correlation_id: options.correlation_id,
msg_id: options.msg_id,
timestamp: new Date().toISOString(),
send_to: subject,
msg_purpose: options.msg_purpose,
sender_name: options.sender_name,
sender_id: options.sender_id,
receiver_name: options.receiver_name,
receiver_id: options.receiver_id,
reply_to: options.reply_to,
reply_to_msg_id: options.reply_to_msg_id,
broker_url: options.broker_url,
metadata: options.metadata || {},
payloads: payloads
};
}
# Use smartpack with mixed content /**
sendinfo = msghandler.smartpack( * Build payload object from serialized data
SUBJECT, * @param {string} dataname - Name of the payload
payloads; # List of (dataname, data, type) tuples * @param {string} payloadType - Type of the payload
broker_url = NATS_URL, * @param {Uint8Array} payloadBytes - Serialized payload bytes
fileserver_url = FILESERVER_URL, * @param {string} transport - Transport type ("direct" or "link")
fileserver_upload_handler = plik_upload_handler, * @param {string} data - Data (base64 for direct, URL for link)
size_threshold = 1_000_000, # 1MB threshold * @returns {Object} Payload object
correlation_id = correlation_id, */
msg_purpose = "chat", function buildPayload(dataname, payloadType, payloadBytes, transport, data) {
sender_name = "mix_sender", // Determine encoding based on payload type (matching Julia implementation)
receiver_name = "", let encoding = 'base64';
receiver_id = "", if (payloadType === 'jsontable') {
reply_to = "", encoding = 'json';
reply_to_msg_id = "", }
is_publish = true # Publish the message to NATS
)
env, env_json_str = sendinfo return {
log_trace("Sent message with $(length(env.payloads)) payloads") id: uuidv4(),
dataname,
payload_type: payloadType,
transport,
encoding,
size: payloadBytes.byteLength,
data,
metadata: transport === 'direct' ? { payload_bytes: payloadBytes.byteLength } : {}
};
}
# Log transport type for each payload /**
for (i, payload) in enumerate(env.payloads) * Send data with automatic transport selection
log_trace("Payload $i ('$payload.dataname'):") *
log_trace(" Transport: $(payload.transport)") * This function intelligently routes data delivery based on payload size.
log_trace(" Type: $(payload.payload_type)") * If the serialized payload is smaller than size_threshold, it encodes the data as Base64
log_trace(" Size: $(payload.size) bytes") * into a "direct" payload. Otherwise, it uploads the data to a fileserver
log_trace(" Encoding: $(payload.encoding)") * and creates a "link" payload with the URL.
*
* Transport publishing is the caller's responsibility. This function returns the
* envelope and its JSON string representation.
*
* @param {string} subject - Subject/topic to send the message to
* @param {Array} data - List of [dataname, data, type] tuples to send
* - type: "text", "dictionary", "jsontable", "image", "audio", "video", "binary"
* - Note: "arrowtable" is NOT supported in browser (use "jsontable" for tabular data)
* @param {Object} options - Optional configuration
* @param {string} [options.broker_url=DEFAULT_BROKER_URL] - Broker URL (for envelope metadata)
* @param {string} [options.fileserver_url=DEFAULT_FILESERVER_URL] - URL of the HTTP file server
* @param {Function} [options.fileserver_upload_handler=plikOneshotUpload] - Function to handle fileserver uploads
* @param {number} [options.size_threshold=DEFAULT_SIZE_THRESHOLD] - Threshold separating direct vs link transport
* @param {string} [options.correlation_id=uuidv4()] - Correlation ID for tracing
* @param {string} [options.msg_purpose="chat"] - Purpose of the message
* @param {string} [options.sender_name="msghandler"] - Name of the sender
* @param {string} [options.receiver_name=""] - Name of the receiver (empty means broadcast)
* @param {string} [options.receiver_id=""] - UUID of the receiver (empty means broadcast)
* @param {string} [options.reply_to=""] - Topic to reply to
* @param {string} [options.reply_to_msg_id=""] - Message ID this message is replying to
* @param {string} [options.msg_id=uuidv4()] - Message ID
* @param {string} [options.sender_id=uuidv4()] - Sender ID
* @returns {Promise<[Object, string]>} Tuple of [env, env_json_str]
*
* @example
* // Send a single payload
* const [env, envJsonStr] = await msghandlerCSR.smartpack(
* "/test",
* [["dataname1", data1, "dictionary"]]
* );
*
* // Send multiple payloads (use jsontable instead of arrowtable for browser)
* const [env, envJsonStr] = await msghandlerCSR.smartpack(
* "/test",
* [
* ["dataname1", data1, "dictionary"],
* ["dataname2", tableData, "jsontable"]
* ]
* );
*
* // Publish via your transport (NATS, MQTT, HTTP, etc.)
* // await myNatsClient.publish("/test", envJsonStr);
*/
async function smartpack(subject, data, options = {}) {
const {
broker_url = DEFAULT_BROKER_URL,
fileserver_url = DEFAULT_FILESERVER_URL,
fileserver_upload_handler = plikOneshotUpload,
size_threshold = DEFAULT_SIZE_THRESHOLD,
correlation_id = uuidv4(),
msg_purpose = 'chat',
sender_name = 'msghandler',
receiver_name = '',
receiver_id = '',
reply_to = '',
reply_to_msg_id = '',
msg_id = uuidv4(),
sender_id = uuidv4()
} = options;
if payload.transport == "link" logTrace(correlation_id, `Starting smartpack for subject: ${subject}`);
log_trace(" URL: $(payload.data)") logTrace(correlation_id, `smartpack: data array length=${data.length}`);
end
end
# Summary // Debug: Log input data structure
println("\n--- Transport Summary ---") for (let i = 0; i < data.length; i++) {
direct_count = count(p -> p.transport == "direct", env.payloads) const [dataname, payloadData, payloadType] = data[i];
link_count = count(p -> p.transport == "link", env.payloads) logTrace(correlation_id, `smartpack: payload[${i}] dataname=${dataname}, type=${payloadType}, data type=${typeof payloadData}, constructor=${payloadData?.constructor?.name}`);
log_trace("Direct transport: $direct_count payloads") }
log_trace("Link transport: $link_count payloads")
end
// Process payloads
const payloads = [];
for (const [dataname, payloadData, payloadType] of data) {
logTrace(correlation_id, `smartpack: Processing payload '${dataname}' type=${payloadType}`);
logTrace(correlation_id, `smartpack: payloadData type=${typeof payloadData}, constructor=${payloadData?.constructor?.name}`);
# Run the test const payloadBytes = await serializeData(payloadData, payloadType);
println("Starting mixed-content transport test...") const payloadSize = payloadBytes.byteLength;
println("Correlation ID: $correlation_id")
# Run sender logTrace(correlation_id, `Serialized payload '${dataname}' (type: ${payloadType}) size: ${payloadSize} bytes`);
println("start smartpack for mixed content")
test_mix_send()
println("\nTest completed.") // Debug: Show first 20 bytes of serialized data for table type
println("Note: Run test_julia_to_julia_mix_receiver.jl to receive the messages.") if (payloadType === 'table') {
const hexPreview = [];
for (let i = 0; i < Math.min(20, payloadBytes.length); i++) {
hexPreview.push(payloadBytes[i].toString(16).padStart(2, '0'));
}
logTrace(correlation_id, `Serialized table data first 20 bytes (hex): ${hexPreview.join(' ')}`);
}
if (payloadSize < size_threshold) {
// Direct path
const payloadB64 = bufferToBase64(payloadBytes);
logTrace(correlation_id, `Using direct transport for ${payloadSize} bytes, base64 length=${payloadB64.length}`);
const payload = buildPayload(dataname, payloadType, payloadBytes, 'direct', payloadB64);
payloads.push(payload);
} else {
// Link path
logTrace(correlation_id, `Using link transport, uploading to fileserver`);
const response = await fileserver_upload_handler(fileserver_url, dataname, payloadBytes);
if (response.status !== 200) {
throw new Error(`Failed to upload data to fileserver: ${response.status}`);
}
logTrace(correlation_id, `Uploaded to URL: ${response.url}`);
const payload = buildPayload(dataname, payloadType, payloadBytes, 'link', response.url);
payloads.push(payload);
}
}
// Build envelope
const env = buildEnvelope(subject, payloads, {
correlation_id,
msg_id,
msg_purpose,
sender_name,
sender_id,
receiver_name,
receiver_id,
reply_to,
reply_to_msg_id,
broker_url
});
const env_json_str = JSON.stringify(env);
return [env, env_json_str];
}
/**
* Receive and process messages
*
* This function processes incoming messages, handling both direct transport
* (base64 decoded payloads) and link transport (URL-based payloads).
* It deserializes the data based on the transport type and returns the result.
*
* @param {string|Object} msg - Message payload. Accepts either a JSON string directly,
* or an object with a `data` or `payload` property containing the JSON string.
* @param {Object} options - Optional configuration
* @param {Function} [options.fileserver_download_handler=fetchWithBackoff] - Function to handle fileserver downloads
* @param {number} [options.max_retries=5] - Maximum retry attempts for fetching URL
* @param {number} [options.base_delay=100] - Initial delay for exponential backoff in ms
* @param {number} [options.max_delay=5000] - Maximum delay for exponential backoff in ms
* @returns {Promise<Object>} Envelope object with processed payloads
*
* @example
* // Receive from JSON string directly
* const env = await msghandlerCSR.smartunpack(jsonString, {
* fileserver_download_handler: msghandlerCSR.fetchWithBackoff,
* max_retries: 5,
* base_delay: 100,
* max_delay: 5000
* });
*
* // Receive from transport message object (e.g., NATS, MQTT)
* const env = await msghandlerCSR.smartunpack(natsMsg, {
* fileserver_download_handler: msghandlerCSR.fetchWithBackoff
* });
* // env.payloads is an Array of [dataname, data, type] arrays
* for (const [dataname, data, type] of env.payloads) {
* console.log(`${dataname}: ${data} (type: ${type})`);
* }
*/
async function smartunpack(msg, options = {}) {
const {
fileserver_download_handler = fetchWithBackoff,
max_retries = 5,
base_delay = 100,
max_delay = 5000
} = options;
let envJsonObj;
// NATS's Javascript lib already return JSON object
if (msg !== null && typeof msg === 'object') {
envJsonObj = msg;
} else {
throw new Error('Invalid message format: expected JSON string or message object');
}
logTrace(envJsonObj.correlation_id, 'Processing received message');
logTrace(envJsonObj.correlation_id, `smartunpack: envelope has ${envJsonObj.payloads.length} payloads`);
// Process all payloads in the envelope
const payloadsList = [];
const numPayloads = envJsonObj.payloads.length;
logTrace(envJsonObj.correlation_id, `smartunpack: Processing ${numPayloads} payloads`);
for (let i = 0; i < numPayloads; i++) {
const payloadObj = envJsonObj.payloads[i];
const transport = payloadObj.transport;
const dataname = payloadObj.dataname;
const payloadType = payloadObj.payload_type;
logTrace(envJsonObj.correlation_id, `smartunpack: Processing payload ${i + 1}/${numPayloads}: dataname=${dataname}, type=${payloadType}, transport=${transport}`);
if (transport === 'direct') {
logTrace(envJsonObj.correlation_id, `Direct transport - decoding payload '${dataname}'`);
// Extract base64 payload from the payload
const payloadB64 = payloadObj.data;
logTrace(envJsonObj.correlation_id, `Direct transport: base64 length=${payloadB64?.length}`);
// Decode Base64 payload
const payloadBytes = base64ToBuffer(payloadB64);
logTrace(envJsonObj.correlation_id, `Direct transport: decoded bytes=${payloadBytes.length}`);
// Deserialize based on type
const dataType = payloadObj.payload_type;
const data = await deserializeData(payloadBytes, dataType, envJsonObj.correlation_id);
logTrace(envJsonObj.correlation_id, `Direct transport: deserialized data type=${typeof data}, constructor=${data?.constructor?.name}`);
payloadsList.push([dataname, data, dataType]);
} else if (transport === 'link') {
// Extract download URL from the payload
const url = payloadObj.data;
logTrace(envJsonObj.correlation_id, `Link transport - fetching '${dataname}' from URL: ${url}`);
// Fetch with exponential backoff using the download handler
const downloadedData = await fileserver_download_handler(
url,
max_retries,
base_delay,
max_delay,
envJsonObj.correlation_id
);
// Deserialize based on type
const dataType = payloadObj.payload_type;
const data = await deserializeData(downloadedData, dataType, envJsonObj.correlation_id);
payloadsList.push([dataname, data, dataType]);
} else {
throw new Error(`Unknown transport type for payload '${dataname}': ${transport}`);
}
}
logTrace(envJsonObj.correlation_id, `smartunpack: Successfully processed all ${payloadsList.length} payloads`);
envJsonObj.payloads = payloadsList;
return envJsonObj;
}
// ---------------------------------------------- Module Exports ---------------------------------------------- //
const msghandlerCSR = {
/**
* Send data with automatic transport selection
*/
smartpack,
/**
* Receive and process messages
*/
smartunpack,
/**
* Upload data to plik server in one-shot mode
*/
plikOneshotUpload,
/**
* Fetch data from URL with exponential backoff
*/
fetchWithBackoff,
/**
* Default constants
*/
DEFAULT_SIZE_THRESHOLD,
DEFAULT_BROKER_URL,
DEFAULT_FILESERVER_URL
};
export default msghandlerCSR;