browser wasm
This commit is contained in:
parent
28fab2509b
commit
e8630528af
24 changed files with 2490 additions and 100 deletions
152
implementations/Crafter.Network-WebTransport.cpp
Normal file
152
implementations/Crafter.Network-WebTransport.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Crafter®.Network
|
||||
Copyright (C) 2026 Catcrafts®
|
||||
Catcrafts.net
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3.0 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
module;
|
||||
module Crafter.Network:WebTransport_impl;
|
||||
import :WebTransport;
|
||||
import :ClientQUIC;
|
||||
import :HTTP3;
|
||||
import Crafter.Thread;
|
||||
import std;
|
||||
|
||||
using namespace Crafter;
|
||||
|
||||
struct WebTransportSession::Impl {
|
||||
// Non-owning. The session is constructed and owned by ListenerHTTP, and
|
||||
// ListenerHTTP keeps the underlying ClientQUIC alive in its PeerState
|
||||
// for the duration of the connection — so this pointer is valid as
|
||||
// long as the session is.
|
||||
ClientQUIC* connection = nullptr;
|
||||
|
||||
// The HTTP/3 extended-CONNECT bidi stream the session was upgraded on.
|
||||
// Stays open for the session's lifetime. Phase 1 closes it with a bare
|
||||
// FIN; later phases will emit a CLOSE_WEBTRANSPORT_SESSION capsule.
|
||||
QUICStream connectStream;
|
||||
|
||||
std::mutex mtx;
|
||||
std::function<void(QUICStream)> onStream;
|
||||
std::deque<QUICStream> pendingStreams;
|
||||
std::function<void(std::vector<char>)> onDatagram; // Phase 2
|
||||
|
||||
bool closed = false;
|
||||
};
|
||||
|
||||
WebTransportSession::WebTransportSession()
|
||||
: impl(std::make_unique<Impl>())
|
||||
{}
|
||||
|
||||
WebTransportSession::WebTransportSession(WebTransportSession&&) noexcept = default;
|
||||
WebTransportSession& WebTransportSession::operator=(WebTransportSession&&) noexcept = default;
|
||||
|
||||
WebTransportSession::~WebTransportSession() {
|
||||
if (impl) Close();
|
||||
}
|
||||
|
||||
QUICStream WebTransportSession::OpenStream(bool unidirectional) {
|
||||
if (!impl || impl->closed || !impl->connection) {
|
||||
throw QUICClosedException();
|
||||
}
|
||||
QUICStream stream = impl->connection->OpenStream(unidirectional);
|
||||
auto prefix = unidirectional
|
||||
? HTTP3::BuildWtUnidiPrefix(sessionId)
|
||||
: HTTP3::BuildWtBidiPrefix(sessionId);
|
||||
// Write the WT_STREAM (bidi) or stream-type (unidi) prefix as the
|
||||
// first send on the stream. The peer reads it to associate this
|
||||
// stream with our session before treating the rest as opaque payload.
|
||||
stream.SendSync(prefix.data(), static_cast<std::uint32_t>(prefix.size()), /*finish=*/false);
|
||||
return stream;
|
||||
}
|
||||
|
||||
void WebTransportSession::OnStream(std::function<void(QUICStream)> callback) {
|
||||
std::deque<QUICStream> drained;
|
||||
{
|
||||
std::lock_guard lk(impl->mtx);
|
||||
impl->onStream = callback;
|
||||
drained.swap(impl->pendingStreams);
|
||||
}
|
||||
// Dispatch any streams that arrived before the handler was installed.
|
||||
// Each goes to the ThreadPool so user code runs off the demuxer thread.
|
||||
for (auto& s : drained) {
|
||||
auto* shared = new QUICStream(std::move(s));
|
||||
ThreadPool::Enqueue([callback, shared]{
|
||||
callback(std::move(*shared));
|
||||
delete shared;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void WebTransportSession::OnDatagram(std::function<void(std::vector<char>)> callback) {
|
||||
// Phase 1 stub. Phase 2 will plumb QUIC datagrams through here after
|
||||
// demuxing on quarter_session_id.
|
||||
if (impl) impl->onDatagram = std::move(callback);
|
||||
}
|
||||
|
||||
void WebTransportSession::SendDatagram(const void*, std::uint32_t) {
|
||||
// Phase 1 stub — would prepend quarter_session_id varint and call
|
||||
// connection->SendDatagram. Drops silently for now.
|
||||
}
|
||||
|
||||
void WebTransportSession::Close() {
|
||||
if (!impl || impl->closed) return;
|
||||
impl->closed = true;
|
||||
try {
|
||||
// Empty FIN on the CONNECT stream. Chrome / Firefox both treat
|
||||
// peer-FIN of the CONNECT stream as session-close.
|
||||
impl->connectStream.SendSync(nullptr, 0, /*finish=*/true);
|
||||
} catch (...) {
|
||||
// Connection may already be gone — that's fine.
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Internal ListenerHTTP-facing helpers ───────────────────────────────
|
||||
//
|
||||
// Declared (not exported) in the interface partition so ListenerHTTP_impl
|
||||
// can call them; defined here. Friendship in WebTransportSession gives
|
||||
// them access to the private Impl.
|
||||
|
||||
namespace Crafter {
|
||||
void WebTransportInitialise(WebTransportSession& session,
|
||||
ClientQUIC* connection,
|
||||
QUICStream connectStream,
|
||||
std::uint64_t sessionId,
|
||||
std::string path) {
|
||||
session.impl->connection = connection;
|
||||
session.impl->connectStream = std::move(connectStream);
|
||||
session.sessionId = sessionId;
|
||||
session.path = std::move(path);
|
||||
}
|
||||
|
||||
void WebTransportDeliverStream(WebTransportSession& session, QUICStream stream) {
|
||||
std::function<void(QUICStream)> cb;
|
||||
{
|
||||
std::lock_guard lk(session.impl->mtx);
|
||||
cb = session.impl->onStream;
|
||||
if (!cb) {
|
||||
session.impl->pendingStreams.push_back(std::move(stream));
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto* shared = new QUICStream(std::move(stream));
|
||||
ThreadPool::Enqueue([cb, shared]{
|
||||
cb(std::move(*shared));
|
||||
delete shared;
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue