File
Blob: src/workerd/api/events.c++
| 1 | #include "events.h" |
| 2 | |
| 3 | #include "blob.h" |
| 4 | #include "messagechannel.h" |
| 5 | |
| 6 | namespace workerd::api { |
| 7 | |
| 8 | MessageEvent::MessageEvent(jsg::Lock& js, |
| 9 | const jsg::JsValue& data, |
| 10 | kj::String lastEventId, |
| 11 | kj::Maybe<jsg::Ref<MessagePort>> source, |
| 12 | kj::Maybe<jsg::Url&> urlForOrigin) |
| 13 | : Event("message"), |
| 14 | data(jsg::JsRef(js, data)), |
| 15 | lastEventId(kj::mv(lastEventId)), |
| 16 | maybeSource(kj::mv(source)), |
| 17 | maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} |
| 18 | MessageEvent::MessageEvent(jsg::Lock& js, |
| 19 | jsg::JsRef<jsg::JsValue> data, |
| 20 | kj::String lastEventId, |
| 21 | kj::Maybe<jsg::Ref<MessagePort>> source, |
| 22 | kj::Maybe<jsg::Url&> urlForOrigin) |
| 23 | : Event("message"), |
| 24 | data(kj::mv(data)), |
| 25 | lastEventId(kj::mv(lastEventId)), |
| 26 | maybeSource(kj::mv(source)), |
| 27 | maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} |
| 28 | MessageEvent::MessageEvent(jsg::Lock& js, |
| 29 | kj::String type, |
| 30 | const jsg::JsValue& data, |
| 31 | kj::String lastEventId, |
| 32 | kj::Maybe<jsg::Ref<MessagePort>> source, |
| 33 | kj::Maybe<jsg::Url&> urlForOrigin) |
| 34 | : Event(kj::mv(type)), |
| 35 | data(jsg::JsRef(js, kj::mv(data))), |
| 36 | lastEventId(kj::mv(lastEventId)), |
| 37 | maybeSource(kj::mv(source)), |
| 38 | maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} |
| 39 | MessageEvent::MessageEvent(jsg::Lock& js, |
| 40 | kj::String type, |
| 41 | kj::OneOf<jsg::JsRef<jsg::JsValue>, jsg::Ref<Blob>> data, |
| 42 | kj::String lastEventId, |
| 43 | kj::Maybe<jsg::Ref<MessagePort>> source, |
| 44 | kj::Maybe<jsg::Url&> urlForOrigin) |
| 45 | : Event(kj::mv(type)), |
| 46 | data(kj::mv(data)), |
| 47 | lastEventId(kj::mv(lastEventId)), |
| 48 | maybeSource(kj::mv(source)), |
| 49 | maybeOrigin(urlForOrigin.map([](auto& url) { return url.getOrigin(); })) {} |
| 50 | |
| 51 | jsg::Ref<MessageEvent> MessageEvent::constructor( |
| 52 | jsg::Lock& js, kj::String type, Initializer initializer) { |
| 53 | return js.alloc<MessageEvent>(js, kj::mv(type), kj::mv(initializer.data)); |
| 54 | } |
| 55 | |
| 56 | kj::OneOf<jsg::JsValue, jsg::Ref<Blob>> MessageEvent::getData(jsg::Lock& js) { |
| 57 | KJ_SWITCH_ONEOF(data) { |
| 58 | KJ_CASE_ONEOF(jsValue, jsg::JsRef<jsg::JsValue>) { |
| 59 | return jsValue.getHandle(js); |
| 60 | } |
| 61 | KJ_CASE_ONEOF(blob, jsg::Ref<Blob>) { |
| 62 | return blob.addRef(); |
| 63 | } |
| 64 | } |
| 65 | KJ_UNREACHABLE; |
| 66 | } |
| 67 | |
| 68 | kj::Maybe<kj::ArrayPtr<const char>> MessageEvent::getOrigin() { |
| 69 | return maybeOrigin.map([](auto& a) -> kj::ArrayPtr<const char> { return a.asPtr(); }); |
| 70 | } |
| 71 | |
| 72 | kj::StringPtr MessageEvent::getLastEventId() { |
| 73 | return lastEventId; |
| 74 | } |
| 75 | |
| 76 | // Per the spec, the source of a MessageEvent is one of a MessagePort, |
| 77 | // ServiceWorker, WindowProxy, etc. The only one of these we actually |
| 78 | // support is MessagePort, return that if its set or null if not. |
| 79 | kj::Maybe<jsg::Ref<MessagePort>> MessageEvent::getSource() { |
| 80 | return maybeSource.map([](auto& port) mutable -> jsg::Ref<MessagePort> { return port.addRef(); }); |
| 81 | } |
| 82 | kj::ArrayPtr<jsg::Ref<MessagePort>> MessageEvent::getPorts() { |
| 83 | // We don't support transferring MessagePorts in MessageEvent |
| 84 | // for now, so we return an empty array. Later we might support |
| 85 | // this. |
| 86 | return nullptr; |
| 87 | } |
| 88 | |
| 89 | void MessageEvent::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { |
| 90 | KJ_SWITCH_ONEOF(data) { |
| 91 | KJ_CASE_ONEOF(jsValue, jsg::JsRef<jsg::JsValue>) { |
| 92 | tracker.trackField("data", jsValue); |
| 93 | } |
| 94 | KJ_CASE_ONEOF(blob, jsg::Ref<Blob>) { |
| 95 | tracker.trackField("data", blob); |
| 96 | } |
| 97 | } |
| 98 | tracker.trackField("source", maybeSource); |
| 99 | } |
| 100 | |
| 101 | void MessageEvent::visitForGc(jsg::GcVisitor& visitor) { |
| 102 | KJ_SWITCH_ONEOF(data) { |
| 103 | KJ_CASE_ONEOF(jsValue, jsg::JsRef<jsg::JsValue>) { |
| 104 | visitor.visit(jsValue); |
| 105 | } |
| 106 | KJ_CASE_ONEOF(blob, jsg::Ref<Blob>) { |
| 107 | visitor.visit(blob); |
| 108 | } |
| 109 | } |
| 110 | visitor.visit(maybeSource); |
| 111 | } |
| 112 | |
| 113 | // ====================================================================================== |
| 114 | namespace { |
| 115 | const kj::StringPtr kDefaultErrorEventName = "error"_kj; |
| 116 | } // namespace |
| 117 | |
| 118 | ErrorEvent::ErrorEvent(ErrorEventInit init): Event(kDefaultErrorEventName), init(kj::mv(init)) {} |
| 119 | |
| 120 | ErrorEvent::ErrorEvent(kj::String type, ErrorEventInit init) |
| 121 | : Event(kj::mv(type)), |
| 122 | init(kj::mv(init)) {} |
| 123 | |
| 124 | ErrorEvent::ErrorEvent(jsg::Lock& js, jsg::JsValue error) |
| 125 | : ErrorEvent(ErrorEventInit{.error = jsg::JsRef(js, error)}) {} |
| 126 | |
| 127 | jsg::Ref<ErrorEvent> ErrorEvent::constructor( |
| 128 | jsg::Lock& js, kj::String type, jsg::Optional<ErrorEventInit> init) { |
| 129 | return js.alloc<ErrorEvent>(kj::mv(type), kj::mv(init).orDefault({})); |
| 130 | } |
| 131 | |
| 132 | kj::StringPtr ErrorEvent::getFilename() { |
| 133 | return init.filename.orDefault(nullptr); |
| 134 | } |
| 135 | |
| 136 | kj::StringPtr ErrorEvent::getMessage() { |
| 137 | return init.message.orDefault(nullptr); |
| 138 | } |
| 139 | |
| 140 | int ErrorEvent::getLineno() { |
| 141 | return init.lineno.orDefault(0); |
| 142 | } |
| 143 | |
| 144 | int ErrorEvent::getColno() { |
| 145 | return init.colno.orDefault(0); |
| 146 | } |
| 147 | |
| 148 | jsg::JsValue ErrorEvent::getError(jsg::Lock& js) { |
| 149 | KJ_IF_SOME(error, init.error) { |
| 150 | return error.getHandle(js); |
| 151 | } else { |
| 152 | return js.undefined(); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | void ErrorEvent::visitForMemoryInfo(jsg::MemoryTracker& tracker) const { |
| 157 | tracker.trackField("message", init.message); |
| 158 | tracker.trackField("filename", init.filename); |
| 159 | tracker.trackField("error", init.error); |
| 160 | } |
| 161 | |
| 162 | void ErrorEvent::visitForGc(jsg::GcVisitor& visitor) { |
| 163 | visitor.visit(init.error); |
| 164 | } |
| 165 | |
| 166 | // ====================================================================================== |
| 167 | namespace { |
| 168 | constexpr kj::StringPtr kUnhandledRejectionEventName = "unhandledrejection"_kj; |
| 169 | constexpr kj::StringPtr kRejectionHandledEventName = "rejectionhandled"_kj; |
| 170 | |
| 171 | constexpr kj::StringPtr getPromiseRejectionEventName(v8::PromiseRejectEvent type) { |
| 172 | switch (type) { |
| 173 | case v8::PromiseRejectEvent::kPromiseRejectWithNoHandler: |
| 174 | return kUnhandledRejectionEventName; |
| 175 | case v8::PromiseRejectEvent::kPromiseHandlerAddedAfterReject: |
| 176 | return kRejectionHandledEventName; |
| 177 | default: |
| 178 | // Events are not emitted for the other reject types. |
| 179 | KJ_UNREACHABLE; |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | } // namespace |
| 184 | |
| 185 | PromiseRejectionEvent::PromiseRejectionEvent( |
| 186 | v8::PromiseRejectEvent type, jsg::V8Ref<v8::Promise> promise, jsg::Value reason) |
| 187 | : Event(getPromiseRejectionEventName(type)), |
| 188 | promise(kj::mv(promise)), |
| 189 | reason(kj::mv(reason)) {} |
| 190 | |
| 191 | } // namespace workerd::api |