| /* | |
| * Copyright 2026 Rive | |
| */ | |
| #pragma once | |
| #include "rive/scriptnet/http.hpp" | |
| #include "rive/scriptnet/net_policy.hpp" | |
| #include "rive/refcnt.hpp" | |
| #include <cstdint> | |
| // Script networking. A script's fetch() becomes a request here; NetPolicy and | |
| // the per-VM limits run first, then the host's Provider sends it, and the | |
| // outcome is delivered by poll(), which rive_pollAsyncWork() drains each | |
| // frame. Promises therefore settle inside the advance window, never from a | |
| // transport callback. | |
| // | |
| // Outcomes are delivered only on the thread that started the request, so a | |
| // VM living on a worker thread is never touched by another thread's poll. | |
| // | |
| // Not rive::net: that namespace belongs to packages/rive_net (the backend | |
| // client), which hosts like rive-cli link alongside the runtime. | |
| namespace rive::scriptnet | |
| { | |
| using RequestId = uint32_t; | |
| /// Receives the outcome of one request. Exactly one of onResponse, onError or | |
| /// onCancel is called. | |
| class FetchListener : public RefCnt<FetchListener> | |
| { | |
| public: | |
| virtual ~FetchListener() = default; | |
| /// From poll(), on the thread that started the request. | |
| virtual void onResponse(HttpResponse&& response) = 0; | |
| /// From poll(), on the thread that started the request. | |
| virtual void onError(const NetError& error) = 0; | |
| /// From cancel() or cancelAllForOwner(), possibly while the owner's VM is | |
| /// closing, so it must not call into Lua. | |
| virtual void onCancel() {} | |
| }; | |
| /// A transport, chosen by the host, never by a file. start() runs on the | |
| /// thread that called fetch(); outcomes come back through complete() and | |
| /// fail() below, from any thread. | |
| class Provider : public RefCnt<Provider> | |
| { | |
| public: | |
| virtual ~Provider() = default; | |
| /// Begin sending `request`, which NetPolicy already checked. The outcome | |
| /// may be reported from inside this call. | |
| virtual void start(RequestId id, const HttpRequest& request) = 0; | |
| /// Best effort; later outcomes for `id` are dropped either way. | |
| virtual void abort(RequestId id) {} | |
| }; | |
| /// This platform's transport, or null where there is none yet. Apple builds | |
| /// get a cookie-less, credential-less NSURLSession; Windows builds the same | |
| /// over WinHTTP. Nothing is installed by default: a host opts in with | |
| /// setProvider(makePlatformProvider()). | |
| rcp<Provider> makePlatformProvider(); | |
| /// Replaces the transport. Null (the default) denies every request. | |
| void setProvider(rcp<Provider> provider); | |
| bool hasProvider(); | |
| void setLimits(const NetLimits& limits); | |
| NetLimits limits(); | |
| /// Runs the policy, then hands the request to the provider, or queues it | |
| /// behind `ownerId`'s others while its limits are reached; poll() starts it | |
| /// once they allow. Always returns a nonzero id: refusals settle through | |
| /// poll() like every other outcome, so a script never sees its promise | |
| /// settle during the fetch() call. | |
| RequestId fetch( | |
| uint64_t ownerId, | |
| HttpRequest request, | |
| rcp<FetchListener> listener); | |
| /// Forgets the request and aborts it at the provider. Returns true when the | |
| /// listener got onCancel(), false when it was or is being delivered instead. | |
| bool cancel(RequestId id); | |
| /// cancel() for everything `ownerId` started. Call before the owner's Lua | |
| /// state closes. | |
| void cancelAllForOwner(uint64_t ownerId); | |
| /// Times out overdue requests, starts queued ones this thread made as limits | |
| /// allow, then delivers up to `maxDeliveries` outcomes of requests this | |
| /// thread started. Returns how many it delivered. | |
| uint32_t poll(uint32_t maxDeliveries = 16); | |
| /// True while a request this thread started is outstanding or awaiting | |
| /// delivery. | |
| bool hasPendingWork(); | |
| /// hasPendingWork() for the requests `ownerId` started, on any thread. | |
| bool hasPendingWorkForOwner(uint64_t ownerId); | |
| /// Any thread. The provider's outcome for `id`; ignored once `id` has been | |
| /// cancelled, timed out or already completed. | |
| void complete(RequestId id, HttpResponse&& response); | |
| void fail(RequestId id, NetError&& error); | |
| } // namespace rive::scriptnet |