File
Blob: src/workerd/api/hibernatable-web-socket.h
| 1 | // Copyright (c) 2017-2022 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | |
| 5 | #pragma once |
| 6 | |
| 7 | #include <workerd/api/basics.h> |
| 8 | #include <workerd/api/hibernation-event-params.h> |
| 9 | #include <workerd/api/web-socket.h> |
| 10 | #include <workerd/io/trace.h> |
| 11 | #include <workerd/io/worker-interface.capnp.h> |
| 12 | #include <workerd/io/worker-interface.h> |
| 13 | #include <workerd/io/worker.h> |
| 14 | |
| 15 | #include <kj/debug.h> |
| 16 | |
| 17 | namespace workerd::api { |
| 18 | |
| 19 | using HibernationReader = |
| 20 | rpc::HibernatableWebSocketEventDispatcher::HibernatableWebSocketEventParams::Reader; |
| 21 | class HibernatableWebSocketEvent final: public ExtendableEvent { |
| 22 | public: |
| 23 | explicit HibernatableWebSocketEvent(); |
| 24 | |
| 25 | static jsg::Ref<HibernatableWebSocketEvent> constructor(kj::String type) = delete; |
| 26 | |
| 27 | // When we call a close or error event, we need to move the owned websocket and the tags back into |
| 28 | // the api::WebSocket to extend their lifetimes. This is because the HibernatableWebSocket, which |
| 29 | // has owned these things for the entire duration of the connection, is free to go away after we |
| 30 | // dispatch the final event. JS may still want to access the underlying kj::WebSocket or the tags, |
| 31 | // so we have to transfer ownership to JS-land. |
| 32 | struct ItemsForRelease { |
| 33 | jsg::Ref<WebSocket> webSocketRef; |
| 34 | kj::Own<kj::WebSocket> ownedWebSocket; |
| 35 | kj::Array<kj::String> tags; |
| 36 | |
| 37 | explicit ItemsForRelease( |
| 38 | jsg::Ref<WebSocket> ref, kj::Own<kj::WebSocket> owned, kj::Array<kj::String> tags); |
| 39 | }; |
| 40 | |
| 41 | // Call this when transferring ownership of the kj::WebSocket and tags to the api::WebSocket. |
| 42 | // |
| 43 | // Gets a reference to the api::WebSocket, and moves the owned kj::WebSocket out of the |
| 44 | // HibernatableWebSocket whose event we are currently delivering. |
| 45 | ItemsForRelease prepareForRelease(jsg::Lock& lock, kj::StringPtr websocketId); |
| 46 | |
| 47 | // Should only be called once per event, see definition for details. |
| 48 | jsg::Ref<WebSocket> claimWebSocket(jsg::Lock& lock, kj::StringPtr websocketId); |
| 49 | |
| 50 | JSG_RESOURCE_TYPE(HibernatableWebSocketEvent) { |
| 51 | JSG_INHERIT(ExtendableEvent); |
| 52 | } |
| 53 | |
| 54 | private: |
| 55 | Worker::Actor::HibernationManager& getHibernationManager(jsg::Lock& lock); |
| 56 | }; |
| 57 | |
| 58 | class HibernatableWebSocketCustomEvent final: public WorkerInterface::CustomEvent, |
| 59 | public kj::Refcounted { |
| 60 | public: |
| 61 | HibernatableWebSocketCustomEvent(uint16_t typeId, |
| 62 | kj::Own<HibernationReader> params, |
| 63 | kj::Maybe<Worker::Actor::HibernationManager&> manager = kj::none); |
| 64 | HibernatableWebSocketCustomEvent( |
| 65 | uint16_t typeId, HibernatableSocketParams params, Worker::Actor::HibernationManager& manager); |
| 66 | |
| 67 | kj::Promise<Result> run(kj::Own<IoContext_IncomingRequest> incomingRequest, |
| 68 | kj::Maybe<kj::StringPtr> entrypointName, |
| 69 | kj::Maybe<Worker::VersionInfo> versionInfo, |
| 70 | Frankenvalue props, |
| 71 | kj::TaskSet& waitUntilTasks, |
| 72 | bool isDynamicDispatch) override; |
| 73 | |
| 74 | kj::Promise<Result> sendRpc(capnp::HttpOverCapnpFactory& httpOverCapnpFactory, |
| 75 | capnp::ByteStreamFactory& byteStreamFactory, |
| 76 | rpc::EventDispatcher::Client dispatcher) override; |
| 77 | |
| 78 | uint16_t getType() override { |
| 79 | return typeId; |
| 80 | } |
| 81 | |
| 82 | tracing::EventInfo getEventInfo() const override; |
| 83 | |
| 84 | kj::Promise<Result> notSupported() override { |
| 85 | KJ_UNIMPLEMENTED("hibernatable web socket event not supported"); |
| 86 | } |
| 87 | |
| 88 | private: |
| 89 | // Returns `params`, but if we have a HibernationReader we convert it to a |
| 90 | // HibernatableSocketParams first. |
| 91 | HibernatableSocketParams consumeParams(); |
| 92 | |
| 93 | // Peeks at params to extract the event type for tracing, without consuming them. |
| 94 | tracing::HibernatableWebSocketEventInfo::Type getEventType() const; |
| 95 | |
| 96 | uint16_t typeId; |
| 97 | kj::OneOf<HibernatableSocketParams, kj::Own<HibernationReader>> params; |
| 98 | kj::Maybe<uint32_t> timeoutMs; |
| 99 | kj::Maybe<Worker::Actor::HibernationManager&> manager; |
| 100 | }; |
| 101 | |
| 102 | #define EW_WEB_SOCKET_MESSAGE_ISOLATE_TYPES \ |
| 103 | api::HibernatableWebSocketEvent, api::HibernatableWebSocketExportedHandler |
| 104 | } // namespace workerd::api |