Skip to content

Commit

Permalink
refactor initial setters
Browse files Browse the repository at this point in the history
  • Loading branch information
adamdbradley committed Sep 22, 2021
1 parent dfd30c8 commit 69a8c84
Show file tree
Hide file tree
Showing 25 changed files with 418 additions and 229 deletions.
3 changes: 2 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ function managlePropsPlugin() {
$documentReferrer$: '',
$documentTitle$: '',
$errors$: '',
$extraInstructions$: '',
$firstScriptId$: '',
$immediateSetters$: '',
$importScripts$: '',
$instanceId$: '',
$instanceIdByInstance$: '',
Expand All @@ -405,6 +405,7 @@ function managlePropsPlugin() {
$location$: '',
$memberPath$: '',
$msgId$: '',
$newInstanceId$: '',
$nextId$: '',
$nodeName$: '',
$parentWinId$: '',
Expand Down
36 changes: 18 additions & 18 deletions src/lib/sandbox/main-access-handler.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import {
AccessType,
ExtraInstruction,
MainAccessRequest,
MainAccessResponse,
MainWindowContext,
} from '../types';
import { AccessType, MainAccessRequest, MainAccessResponse, MainWindowContext } from '../types';
import { deserializeFromWorker, serializeForWorker } from './main-serialization';
import { EMPTY_ARRAY, isPromise, len, PT_SCRIPT_TYPE } from '../utils';
import { EMPTY_ARRAY, isPromise, len } from '../utils';
import { forwardToWinAccessHandler } from './messenger';
import { getInstance } from './main-instances';
import { getInstance, setInstanceId } from './main-instances';

export const mainAccessHandler = async (
winCtx: MainWindowContext,
Expand All @@ -30,13 +24,14 @@ export const mainAccessHandler = async (
let memberPath = accessReqTask.$memberPath$;
let memberPathLength = len(memberPath);
let lastMemberName = memberPath[memberPathLength - 1];
let extraInstructions = accessReqTask.$extraInstructions$ || EMPTY_ARRAY;
let immediateSetters = accessReqTask.$immediateSetters$ || EMPTY_ARRAY;
let instance: any;
let rtnValue: any;
let data: any;
let i: number;
let count: number;
let tmr: any;
let immediateSetterName: string;

try {
instance = getInstance(winCtx, instanceId);
Expand All @@ -49,7 +44,7 @@ export const mainAccessHandler = async (
data = deserializeFromWorker(winCtx, instanceId, accessReqTask.$data$);

if (accessType === AccessType.Get) {
if (extraInstructions.includes(ExtraInstruction.WAIT_FOR_INSTANCE_MEMBER)) {
if (lastMemberName === 'partyWinId') {
await new Promise<void>((resolve) => {
count = 0;
tmr = setInterval(() => {
Expand All @@ -66,14 +61,19 @@ export const mainAccessHandler = async (
instance[lastMemberName] = data;
} else if (accessType === AccessType.CallMethod) {
rtnValue = instance[lastMemberName].apply(instance, data);
extraInstructions.forEach((extra, i) => {
if (extra === ExtraInstruction.SET_INERT_SCRIPT) {
(rtnValue as HTMLScriptElement).type = PT_SCRIPT_TYPE;
}
if (extra === ExtraInstruction.SET_IFRAME_SRCDOC) {
(rtnValue as HTMLIFrameElement).srcdoc = extraInstructions[i + 1] as any;
}

immediateSetters.map((immediateSetter) => {
immediateSetterName = immediateSetter[0][0];
rtnValue[immediateSetterName] = deserializeFromWorker(
winCtx,
instanceId,
immediateSetter[1]
);
});

if (accessReqTask.$newInstanceId$) {
setInstanceId(winCtx, rtnValue, accessReqTask.$newInstanceId$);
}
}

if (isPromise(rtnValue)) {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/sandbox/messenger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const onMessageFromWebWorker = (
forwardMsgResolve(accessRsp);
readNextScript(winCtx);
}
} else if (msgType === WorkerMessageType.RunStateProp) {
} else if (msgType === WorkerMessageType.RunStateHandlers) {
// run this state prop on all web workers (only one of them actually has it)
// this is used for script onload, when the function was created in another window
winCtxs.forEach((winCtx) => winCtx.$worker$!.postMessage(msg));
Expand Down
17 changes: 8 additions & 9 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type MessageFromWorkerToSandbox =
| [WorkerMessageType.InitializedWorkerScript, number, string]
| [WorkerMessageType.InitializeNextWorkerScript]
| [WorkerMessageType.ForwardMainDataResponse, MainAccessResponse]
| [WorkerMessageType.RunStateProp, RunStatePropData];
| [WorkerMessageType.RunStateHandlers, RunStatePropData];

export type MessageFromSandboxToWorker =
| [WorkerMessageType.MainDataResponseToWorker, InitWebWorkerData]
Expand All @@ -20,7 +20,7 @@ export type MessageFromSandboxToWorker =
]
| [WorkerMessageType.ForwardMainDataRequest, MainAccessRequest]
| [WorkerMessageType.ForwardEvent, string, any[] | undefined]
| [WorkerMessageType.RunStateProp, RunStatePropData];
| [WorkerMessageType.RunStateHandlers, RunStatePropData];

export const enum WorkerMessageType {
MainDataRequestFromWorker,
Expand All @@ -31,7 +31,7 @@ export const enum WorkerMessageType {
ForwardMainDataRequest,
ForwardMainDataResponse,
ForwardEvent,
RunStateProp,
RunStateHandlers,
}

export type RunStatePropData = {
Expand All @@ -43,6 +43,7 @@ export type RunStatePropData = {
export const enum StateProp {
errorHandlers,
loadHandlers,
isSuccessfulLoad,
url,
partyWinId,
}
Expand Down Expand Up @@ -157,14 +158,11 @@ export interface MainAccessRequestTask {
$accessType$: AccessType;
$memberPath$: string[];
$data$?: SerializedTransfer;
$extraInstructions$?: ExtraInstruction[];
$immediateSetters$?: ImmediateSetter[];
$newInstanceId$?: number;
}

export const enum ExtraInstruction {
SET_INERT_SCRIPT,
SET_IFRAME_SRCDOC,
WAIT_FOR_INSTANCE_MEMBER,
}
export type ImmediateSetter = [string[], SerializedTransfer | undefined];

export interface MainAccessResponse {
$msgId$: number;
Expand Down Expand Up @@ -300,6 +298,7 @@ export const enum NodeName {
Document = '#document',
DocumentElement = 'HTML',
DocumentFragment = '#document-fragment',
IFrame = 'IFRAME',
Head = 'HEAD',
Script = 'SCRIPT',
Text = '#text',
Expand Down
2 changes: 2 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,5 @@ export const PT_SCRIPT = `<script src="/~partytown/partytown${
}.js" async defer></script>`;

export const TOP_WIN_ID = 1;

export const randomId = () => Math.round(Math.random() * 999999999);
6 changes: 3 additions & 3 deletions src/lib/web-worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
RunStatePropData,
WorkerMessageType,
} from '../types';
import { runStateHandlers } from './worker-instance';
import { webWorkerCtx } from './worker-constants';
import { workerAccessHandler } from './worker-access-handler';
import { workerEventForwarding } from './worker-event-forwarding';
import { runStateProp } from './worker-instance';

const queuedEvents: MessageEvent<MessageFromSandboxToWorker>[] = [];

Expand All @@ -34,9 +34,9 @@ const onMessage = (ev: MessageEvent<MessageFromSandboxToWorker>) => {
workerAccessHandler(msgData as MainAccessRequest);
} else if (msgType === WorkerMessageType.ForwardEvent) {
workerEventForwarding(msgData as any, msg[2] as any);
} else if (msgType === WorkerMessageType.RunStateProp) {
} else if (msgType === WorkerMessageType.RunStateHandlers) {
const data: RunStatePropData = msgData as any;
runStateProp(data.$winId$, data.$instanceId$, data.$stateProp$);
runStateHandlers(data.$winId$, data.$instanceId$, data.$stateProp$);
}
} else if (msgType === WorkerMessageType.MainDataResponseToWorker) {
// initialize the web worker with the received the main data
Expand Down
26 changes: 23 additions & 3 deletions src/lib/web-worker/worker-access-handler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { AccessType, MainAccessRequest, MainAccessResponse, WorkerMessageType } from '../types';
import {
AccessType,
MainAccessRequest,
MainAccessResponse,
PlatformInstanceId,
WorkerMessageType,
} from '../types';
import { callMethod } from './worker-proxy';
import {
constructSerializedInstance,
deserializeFromMain,
Expand Down Expand Up @@ -39,10 +46,23 @@ export const workerAccessHandler = (accessReq: MainAccessRequest) => {
} else if (accessType === AccessType.Set) {
instance[lastMemberName] = data;
} else if (accessType === AccessType.CallMethod) {
rtnValue = instance[lastMemberName].apply(instance, data);
if (
accessReqTask.$instanceId$ === PlatformInstanceId.document &&
lastMemberName === 'createElement'
) {
rtnValue = callMethod(
instance,
memberPath,
data,
accessReqTask.$immediateSetters$,
accessReqTask.$newInstanceId$
);
} else {
rtnValue = instance[lastMemberName].apply(instance, data);
}
}

accessRsp.$rtnValue$ = serializeForMain(rtnValue, new Set());
accessRsp.$rtnValue$ = serializeForMain(rtnValue);
} catch (e: any) {
accessRsp.$errors$.push(String(e.stack || e));
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/web-worker/worker-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export const InstanceIdKey = Symbol();
export const InterfaceTypeKey = Symbol();
export const NodeNameKey = Symbol();
export const ProxyKey = Symbol();
export const ImmediateSettersKey = Symbol();
export const webWorkerCtx: WebWorkerContext = {} as any;
47 changes: 47 additions & 0 deletions src/lib/web-worker/worker-constructors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { InterfaceType, NodeName } from '../types';
import { WorkerAnchorElement, WorkerDocumentElementChild, WorkerElement } from './worker-element';
import { WorkerContentWindow, WorkerIFrameElement } from './worker-iframe';
import { WorkerDocument } from './worker-document';
import { WorkerInstance } from './worker-instance';
import { WorkerNode } from './worker-node';
import { WorkerScriptElement } from './worker-script';

export const constructInstance = (
interfaceType: InterfaceType,
instanceId: number,
winId?: number,
nodeName?: string
) => {
nodeName =
interfaceType === InterfaceType.Document
? NodeName.Document
: interfaceType === InterfaceType.TextNode
? NodeName.Text
: nodeName;

const Cstr = getConstructor(interfaceType, nodeName);
return new Cstr(interfaceType, instanceId, winId, nodeName);
};

const getConstructor = (interfaceType: InterfaceType, nodeName?: string): typeof WorkerInstance => {
if (interfaceType === InterfaceType.Element) {
return getElementConstructor(nodeName!);
} else if (interfaceType === InterfaceType.Document) {
return WorkerDocument;
} else if (interfaceType === InterfaceType.Window) {
return WorkerContentWindow;
} else if (interfaceType === InterfaceType.TextNode) {
return WorkerNode;
} else {
return WorkerInstance;
}
};

export const getElementConstructor = (nodeName: string): typeof WorkerElement =>
({
A: WorkerAnchorElement,
BODY: WorkerDocumentElementChild,
HEAD: WorkerDocumentElementChild,
IFRAME: WorkerIFrameElement,
SCRIPT: WorkerScriptElement,
}[nodeName] || WorkerElement);
50 changes: 32 additions & 18 deletions src/lib/web-worker/worker-document.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { callMethod, getter, setter } from './worker-proxy';
import { constructInstance } from './worker-serialization';
import { ExtraInstruction, InterfaceType, NodeName, PlatformInstanceId } from '../types';
import { logWorkerGetter, logWorkerSetter, PT_SCRIPT, toLower } from '../utils';
import { webWorkerCtx, WinIdKey } from './worker-constants';
import { constructInstance, getElementConstructor } from './worker-constructors';
import { ImmediateSettersKey, webWorkerCtx, WinIdKey } from './worker-constants';
import { InterfaceType, NodeName, PlatformInstanceId } from '../types';
import {
logWorkerGetter,
logWorkerSetter,
PT_SCRIPT,
PT_SCRIPT_TYPE,
randomId,
toUpper,
} from '../utils';
import { serializeForMain } from './worker-serialization';
import { WorkerElement } from './worker-element';

export class WorkerDocument extends WorkerElement {
Expand All @@ -27,16 +35,23 @@ export class WorkerDocument extends WorkerElement {
setter(this, ['cookie'], (webWorkerCtx.$documentCookie$ = cookie));
}

createElement(tagName: string, $extraInstructions$?: ExtraInstruction[]) {
tagName = toLower(tagName);
createElement(tagName: string) {
tagName = toUpper(tagName);

if (tagName === 'script') {
$extraInstructions$ = [ExtraInstruction.SET_INERT_SCRIPT];
} else if (tagName === 'iframe') {
$extraInstructions$ = [ExtraInstruction.SET_IFRAME_SRCDOC, PT_SCRIPT as any];
const winId = this[WinIdKey];
const instanceId = randomId();
const ElementCstr = getElementConstructor(tagName);
const elm = new ElementCstr(InterfaceType.Element, instanceId, winId, tagName);

if (tagName === NodeName.Script) {
elm[ImmediateSettersKey] = [[['type'], serializeForMain(PT_SCRIPT_TYPE)]];
} else if (tagName === NodeName.IFrame) {
elm[ImmediateSettersKey] = [[['srcdoc'], serializeForMain(PT_SCRIPT)]];
} else {
elm[ImmediateSettersKey] = [];
}

return callMethod(this, ['createElement'], [tagName], $extraInstructions$);
return elm;
}

get createEventObject() {
Expand Down Expand Up @@ -70,14 +85,12 @@ export class WorkerDocument extends WorkerElement {
}

getElementsByTagName(tagName: string) {
tagName = toLower(tagName);
if (tagName === 'body') {
tagName = toUpper(tagName);
if (tagName === NodeName.Body) {
return [this.body];
}
if (tagName === 'head') {
} else if (tagName === NodeName.Head) {
return [this.head];
}
if (tagName === 'script') {
} else if (tagName === NodeName.Script) {
return [
constructInstance(
InterfaceType.Element,
Expand All @@ -86,8 +99,9 @@ export class WorkerDocument extends WorkerElement {
NodeName.Script
),
];
} else {
return callMethod(this, ['getElementsByTagName'], [tagName]);
}
return callMethod(this, ['getElementsByTagName'], [tagName]);
}

get head() {
Expand Down
1 change: 0 additions & 1 deletion src/lib/web-worker/worker-element.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { EventHandler, StateProp } from '../types';
import { getInstanceStateValue, setInstanceStateValue } from './worker-instance';
import { InstanceIdKey, WinIdKey } from './worker-constants';
import { resolveUrl } from './worker-exec';
import { toLower } from '../utils';
import { WorkerNode } from './worker-node';
Expand Down
Loading

1 comment on commit 69a8c84

@vercel
Copy link

@vercel vercel bot commented on 69a8c84 Sep 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.