Skip to content
File

Blob: src/workerd/api/hibernatable-web-socket.h

cpp105 lines
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 
17namespace workerd::api {
18 
19using HibernationReader =
20 rpc::HibernatableWebSocketEventDispatcher::HibernatableWebSocketEventParams::Reader;
21class 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 
58class 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