-
Notifications
You must be signed in to change notification settings - Fork 328
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
440 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...ava/polyglot-ydoc-server/src/main/java/org/enso/polyfill/web/AbortControllerPolyfill.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.enso.polyfill.web; | ||
|
||
import java.util.Arrays; | ||
import java.util.UUID; | ||
import org.enso.polyfill.Polyfill; | ||
import org.graalvm.polyglot.Context; | ||
import org.graalvm.polyglot.Source; | ||
import org.graalvm.polyglot.Value; | ||
import org.graalvm.polyglot.proxy.ProxyExecutable; | ||
|
||
public final class AbortControllerPolyfill implements ProxyExecutable, Polyfill { | ||
|
||
private static final String RANDOM_UUID = "random-uuid"; | ||
|
||
private static final String ABORT_CONTROLLER_POLYFILL_JS = "abort-controller-polyfill.js"; | ||
|
||
public AbortControllerPolyfill() { | ||
} | ||
|
||
@Override | ||
public void initialize(Context ctx) { | ||
Source abortControllerPolyfillJs = Source | ||
.newBuilder("js", AbortControllerPolyfill.class.getResource(ABORT_CONTROLLER_POLYFILL_JS)) | ||
.buildLiteral(); | ||
|
||
ctx.eval(abortControllerPolyfillJs).execute(this); | ||
} | ||
|
||
@Override | ||
public Object execute(Value... arguments) { | ||
var command = arguments[0].asString(); | ||
System.err.println(command + " " + Arrays.toString(arguments)); | ||
|
||
return switch (command) { | ||
case RANDOM_UUID -> | ||
UUID.randomUUID().toString(); | ||
|
||
default -> | ||
throw new IllegalStateException(command); | ||
}; | ||
} | ||
} |
120 changes: 120 additions & 0 deletions
120
lib/java/polyglot-ydoc-server/src/main/java/org/enso/polyfill/web/EventTargetPolyfill.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package org.enso.polyfill.web; | ||
|
||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.concurrent.ExecutorService; | ||
|
||
import org.enso.polyfill.Polyfill; | ||
import org.graalvm.polyglot.Context; | ||
import org.graalvm.polyglot.Source; | ||
import org.graalvm.polyglot.Value; | ||
import org.graalvm.polyglot.proxy.ProxyExecutable; | ||
|
||
public final class EventTargetPolyfill implements ProxyExecutable, Polyfill { | ||
|
||
private static final String NEW_EVENT_TARGET = "new-event-target"; | ||
private static final String ADD_EVENT_LISTENER = "add-event-listener"; | ||
private static final String REMOVE_EVENT_LISTENER = "remove-event-listener"; | ||
private static final String DISPATCH_EVENT = "dispatch-event"; | ||
|
||
private static final String EVENT_TARGET_POLYFILL_JS = "event-target-polyfill.js"; | ||
|
||
private final ExecutorService executor; | ||
|
||
public EventTargetPolyfill(ExecutorService executor) { | ||
this.executor = executor; | ||
} | ||
|
||
@Override | ||
public void initialize(Context ctx) { | ||
Source eventTargetPolyfillJs = Source | ||
.newBuilder("js", EventTargetPolyfill.class.getResource(EVENT_TARGET_POLYFILL_JS)) | ||
.buildLiteral(); | ||
|
||
ctx.eval(eventTargetPolyfillJs).execute(this); | ||
} | ||
|
||
@Override | ||
public Object execute(Value... arguments) { | ||
var command = arguments[0].asString(); | ||
System.err.println(command + " " + Arrays.toString(arguments)); | ||
|
||
return switch (command) { | ||
case NEW_EVENT_TARGET -> | ||
new EventStore(executor, new HashMap<>()); | ||
|
||
case ADD_EVENT_LISTENER -> { | ||
var store = arguments[1].as(EventStore.class); | ||
var type = arguments[2].asString(); | ||
var listener = arguments[3]; | ||
|
||
store.addEventListener(type, listener); | ||
yield null; | ||
} | ||
|
||
case REMOVE_EVENT_LISTENER -> { | ||
var store = arguments[1].as(EventStore.class); | ||
var type = arguments[2].asString(); | ||
var listener = arguments[3]; | ||
|
||
store.removeEventListener(type, listener); | ||
yield null; | ||
} | ||
|
||
case DISPATCH_EVENT -> { | ||
var store = arguments[1].as(EventStore.class); | ||
var type = arguments[2].asString(); | ||
var event = arguments[3]; | ||
|
||
store.dispatchEvent(type, event); | ||
yield null; | ||
} | ||
|
||
default -> | ||
throw new IllegalStateException(command); | ||
}; | ||
} | ||
|
||
private static final class EventStore { | ||
|
||
private final ExecutorService executor; | ||
private final Map<String, Set<Value>> listeners; | ||
|
||
EventStore(ExecutorService executor, Map<String, Set<Value>> listeners) { | ||
this.executor = executor; | ||
this.listeners = listeners; | ||
} | ||
|
||
public void addEventListener(String type, Value listener) { | ||
listeners.compute(type, (k, v) -> { | ||
var set = v == null ? new HashSet<Value>() : v; | ||
set.add(listener); | ||
return set; | ||
}); | ||
} | ||
|
||
public void removeEventListener(String type, Value listener) { | ||
listeners.compute(type, (k, v) -> { | ||
if (v == null) { | ||
return v; | ||
} else { | ||
v.remove(listener); | ||
return v.isEmpty() ? null : v; | ||
} | ||
}); | ||
} | ||
|
||
public void dispatchEvent(String type, Value event) { | ||
listeners.getOrDefault(type, Set.of()).forEach(listener -> { | ||
try { | ||
listener.executeVoid(event); | ||
} catch (Exception e) { | ||
System.err.println("Error dispatching event [" + type + "] " + listener + " " + event + " " + e); | ||
} | ||
}); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
...olyglot-ydoc-server/src/main/resources/org/enso/polyfill/web/abort-controller-polyfill.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
(function (jvm) { | ||
|
||
const ABORT_ERR = { code: 20, name: "AbortError" }; | ||
|
||
class AbortSignal extends EventTarget { | ||
|
||
#aborted; | ||
#reason; | ||
|
||
constructor(aborted, reason) { | ||
super(); | ||
this.#aborted = aborted === undefined ? false : aborted; | ||
this.#reason = reason === undefined ? ABORT_ERR : reason; | ||
} | ||
|
||
get aborted() { | ||
return this.#aborted; | ||
} | ||
|
||
set aborted(value) { | ||
this.#aborted = value === undefined ? false : value; | ||
} | ||
|
||
get reason() { | ||
return this.#reason; | ||
} | ||
|
||
set reason(value) { | ||
const reasonValue = value === undefined ? ABORT_ERR : value; | ||
this.#reason = reasonValue; | ||
} | ||
|
||
set onabort(callback) { | ||
this.addEventListener('abort', callback); | ||
} | ||
|
||
static abort(reason) { | ||
return new AbortSignal(true, reason); | ||
} | ||
|
||
throwIfAborted() { | ||
if (this.#aborted) { | ||
throw this.#reason; | ||
} | ||
} | ||
} | ||
|
||
class AbortController { | ||
|
||
#signal; | ||
|
||
constructor() { | ||
const signal = new AbortSignal(); | ||
signal.addEventListener('abort', (event) => { | ||
signal.aborted = true; | ||
signal.reason = event.reason; | ||
}) | ||
this.#signal = signal; | ||
} | ||
|
||
get signal() { | ||
return this.#signal; | ||
} | ||
|
||
abort(reason) { | ||
this.#signal.dispatchEvent({type: 'abort', reason: reason}); | ||
} | ||
} | ||
|
||
globalThis.AbortController = AbortController; | ||
|
||
}) |
Oops, something went wrong.