Skip to content

Commit

Permalink
support for local pointer transforms, cookie fixes, datex_wasm update
Browse files Browse the repository at this point in the history
  • Loading branch information
benStre committed Dec 8, 2023
1 parent 6b75de5 commit 069074a
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 92 deletions.
180 changes: 122 additions & 58 deletions compiler/compiler.ts

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions docs/manual/10 The DATEX API.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@ Inside function bodies, the [`datex.meta` object](https://github.com/unyt-org/da
type:ProtocolDataType
}
```

Example:

```ts
@endpoint class MyInterface {
@property myMethod(a: number) {
console.log("myMethod called by endpoint " + datex.meta.sender)
}
}
```
7 changes: 7 additions & 0 deletions init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import { IndexedDBStorageLocation } from "./runtime/storage-locations/indexed-db
import { LocalStorageLocation } from "./runtime/storage-locations/local-storage.ts";
import { DenoKVStorageLocation } from "./runtime/storage-locations/deno-kv.ts";
import { loadEternalValues } from "./utils/eternals.ts";
import { DX_BOUND_LOCAL_SLOT } from "./runtime/constants.ts";
import { verboseArg } from "./utils/logger.ts";
import { MessageLogger } from "./utils/message_logger.ts";


/**
Expand Down Expand Up @@ -67,6 +70,7 @@ export async function init() {

// set Runtime ENV (not persistent if globalThis.NO_INIT)
Runtime.ENV = globalThis.NO_INIT ? getDefaultEnv() : await Storage.loadOrCreate("Datex.Runtime.ENV", getDefaultEnv);
Runtime.ENV[DX_BOUND_LOCAL_SLOT] = "env"

// workaround, should never happen
if (!Runtime.ENV) {
Expand Down Expand Up @@ -133,4 +137,7 @@ export async function init() {

// @ts-ignore NO_INIT
if (!globalThis.NO_INIT) await loadEternalValues();

// enables message logger when running with -v
if (verboseArg) MessageLogger.enable()
}
3 changes: 1 addition & 2 deletions runtime/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ export const DX_IGNORE: unique symbol = Symbol("DX_IGNORE"); // ignore in DX (wh
export const DX_PREEMPTIVE: unique symbol = Symbol("DX_PREEMPTIVE"); // used to override the default loading behaviour for a pointer (fetching by id). Can be an arbitrary DATEX Script that can be resolved with datex.get. Currently only used by the interface generator for JS modules.

export const DX_REACTIVE_METHODS: unique symbol = Symbol("DX_REACTIVE_METHODS"); // object containing reactive methods for this obj, used e.g. for x.$.map, x.$.filter, ...

export const INIT_PROPS: unique symbol = Symbol("INIT_PROPS"); // key for init props function passed to constructor to initialize properties of pointer immediately

export const DX_BOUND_LOCAL_SLOT: unique symbol = Symbol("DX_BOUND_SLOT"); // local slot (e.g. #env) to which this value always gets serialized, instead of the value/pointer
// -------------------------------------
export const DX_SLOTS: unique symbol = Symbol("DX_SLOTS");

Expand Down
66 changes: 43 additions & 23 deletions runtime/pointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1505,8 +1505,10 @@ export class Pointer<T = any> extends Ref<T> {


// create a new pointer with a transform value
static createTransform<const T, const V extends TransformFunctionInputs>(observe_values:V, transform:TransformFunction<V,T>, persistent_datex_transform?:string) {
return Pointer.create(undefined, NOT_EXISTING).handleTransform(observe_values, transform, persistent_datex_transform);
static createTransform<const T, const V extends TransformFunctionInputs>(observe_values:V, transform:TransformFunction<V,T>, persistent_datex_transform?:string, force_transform = false) {
const ptr = Pointer.create(undefined, NOT_EXISTING).handleTransform(observe_values, transform, persistent_datex_transform);
ptr.force_local_transform = force_transform;
return ptr;
}

/**
Expand Down Expand Up @@ -1978,6 +1980,12 @@ export class Pointer<T = any> extends Ref<T> {
*/

public async subscribeForPointerUpdates(override_endpoint?:Endpoint, get_value = !this.#loaded, keep_pointer_origin = false):Promise<Pointer> {

// never subscribe if pointer is bound to a transform function
if (this.transform_scope) {
return this;
}

if (this.#subscribed) {
// logger.debug("already subscribed to " + this.idString());
return this;
Expand Down Expand Up @@ -2437,8 +2445,8 @@ export class Pointer<T = any> extends Ref<T> {
}

// propagate updates via datex
if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, '#0=?;? = #0', [this.current_val, this], this.origin, true)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(null, '#0=?;? = #0', [this.current_val, this], this.origin, true)
}
if (this.update_endpoints.size) {
logger.debug("forwarding update to subscribers", this.update_endpoints);
Expand All @@ -2463,6 +2471,9 @@ export class Pointer<T = any> extends Ref<T> {
#transform_scope?:Scope;
get transform_scope() {return this.#transform_scope}

#force_transform = false; // if true, the pointer transform function is always sent via DATEX
set force_local_transform(force_transform: boolean) {this.#force_transform = force_transform}
get force_local_transform() {return this.#force_transform}

/**
* transform observed values to update pointer value (using a transform function or DATEX transform scope)
Expand Down Expand Up @@ -2707,7 +2718,12 @@ export class Pointer<T = any> extends Ref<T> {
// TODO: JUST A WORKAROUND - if transform is a JS function, a DATEX Script can be provided to be stored as a transform method
async setDatexTransform(datex_transform:string) {
// TODO: fix and reenable
// this.#transform_scope = (await Runtime.executeDatexLocally(datex_transform)).transform_scope;
try {
this.#transform_scope = (await Runtime.executeDatexLocally(datex_transform)).transform_scope;
}
catch (e) {
console.log("transform error", e);
}
}

#registeredForGC = false;
Expand Down Expand Up @@ -2910,7 +2926,13 @@ export class Pointer<T = any> extends Ref<T> {
// updates are from datex (external) and should not be distributed again or local update -> should be distributed to subscribers
#update_endpoints: Disjunction<Endpoint>; // endpoint to update

#exclude_origin_from_updates:boolean;
get send_updates_to_origin() {
// assumes origin is not current endpoint
// don't send if exclude_origin_from_updates set or has a local transform_scope
return this.origin && !this.is_origin && !(this.#exclude_origin_from_updates || this.transform_scope)
}

#exclude_origin_from_updates?:boolean;
public excludeEndpointFromUpdates(endpoint:Endpoint) {
// TODO origin equals id also for remote endpoints!
if (this.origin.equals(endpoint)) this.#exclude_origin_from_updates = true;
Expand Down Expand Up @@ -3399,8 +3421,8 @@ export class Pointer<T = any> extends Ref<T> {
// get current value
value = value ?? this.getProperty(key);

if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(key, Runtime.PRECOMPILED_DXB.SET_PROPERTY, [this, key, value], this.origin)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(key, Runtime.PRECOMPILED_DXB.SET_PROPERTY, [this, key, value], this.origin)
}
if (this.update_endpoints.size) {
this.handleDatexUpdate(key, Runtime.PRECOMPILED_DXB.SET_PROPERTY, [this, key, value], this.update_endpoints)
Expand Down Expand Up @@ -3451,8 +3473,8 @@ export class Pointer<T = any> extends Ref<T> {


// propagate updates via datex
if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, '? += ?', [this, value], this.origin)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(null, '? += ?', [this, value], this.origin)
}
if (this.update_endpoints.size) {
this.handleDatexUpdate(null, '? += ?', [this, value], this.update_endpoints)
Expand Down Expand Up @@ -3482,9 +3504,9 @@ export class Pointer<T = any> extends Ref<T> {

this.streaming.push(true); // also stream for all future subscribers

if (this.origin && !this.is_origin) {
if (this.send_updates_to_origin) {
logger.info("streaming to parent " + this.origin);
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, '? << ?'/*DatexRuntime.PRECOMPILED_DXB.STREAM*/, [this, obj], this.origin)
this.handleDatexUpdate(null, '? << ?'/*DatexRuntime.PRECOMPILED_DXB.STREAM*/, [this, obj], this.origin)
}
if (this.update_endpoints.size) {
logger.info("streaming to subscribers " + this.update_endpoints);
Expand Down Expand Up @@ -3516,8 +3538,8 @@ export class Pointer<T = any> extends Ref<T> {


// propagate updates via datex?
if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, Runtime.PRECOMPILED_DXB.CLEAR_WILDCARD, [this], this.origin)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(null, Runtime.PRECOMPILED_DXB.CLEAR_WILDCARD, [this], this.origin)
}
if (this.update_endpoints.size) {
this.handleDatexUpdate(null, Runtime.PRECOMPILED_DXB.CLEAR_WILDCARD, [this], this.update_endpoints)
Expand Down Expand Up @@ -3572,11 +3594,9 @@ export class Pointer<T = any> extends Ref<T> {
const ret = Array.prototype.splice.call(this.shadow_object, start_index, deleteCount, ...replace);

// propagate updates via datex?
if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) {
if (!replace?.length) this.handleDatexUpdate(null, '#0 = ?0; #1 = count #0;#0.(?1..?2) = void;#0.(?1..#1) = #0.(?3..#1);', [this, start, end, start+size], this.origin) // no insert
else this.handleDatexUpdate(null, '#0=?0;#0.(?4..?1) = void; #0.(?2..((count #0) + ?3)) = #0.(?4..(count #0));#0.(?4..?5) = ?6;', [this, end, start-size+replace_length, replace_length, start, start+replace_length, replace], this.origin) // insert
}
if (this.send_updates_to_origin) {
if (!replace?.length) this.handleDatexUpdate(null, '#0 = ?0; #1 = count #0;#0.(?1..?2) = void;#0.(?1..#1) = #0.(?3..#1);', [this, start, end, start+size], this.origin) // no insert
else this.handleDatexUpdate(null, '#0=?0;#0.(?4..?1) = void; #0.(?2..((count #0) + ?3)) = #0.(?4..(count #0));#0.(?4..?5) = ?6;', [this, end, start-size+replace_length, replace_length, start, start+replace_length, replace], this.origin) // insert
}
if (this.update_endpoints.size) {
if (!replace?.length) this.handleDatexUpdate(null, '#0 = ?0; #1 = count #0;#0.(?1..?2) = void;#0.(?1..#1) = #0.(?3..#1);', [this, start, end, start+size], this.update_endpoints) // no insert
Expand Down Expand Up @@ -3638,8 +3658,8 @@ export class Pointer<T = any> extends Ref<T> {

if ((res == INVALID || res == NOT_EXISTING) && this.shadow_object instanceof Array) key = BigInt(key); // change to <Int> for DATEX if <Array>

if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, '?.? = void', [this, key], this.origin)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(null, '?.? = void', [this, key], this.origin)
}
if (this.update_endpoints.size) {
this.handleDatexUpdate(null, '?.? = void', [this, key], this.update_endpoints)
Expand Down Expand Up @@ -3677,8 +3697,8 @@ export class Pointer<T = any> extends Ref<T> {


// propagate updates via datex
if (this.origin && !this.is_origin) {
if (!this.#exclude_origin_from_updates) this.handleDatexUpdate(null, '? -= ?', [this, value], this.origin)
if (this.send_updates_to_origin) {
this.handleDatexUpdate(null, '? -= ?', [this, value], this.origin)
}
if (this.update_endpoints.size) {
logger.debug("forwarding delete to subscribers " + this.update_endpoints);
Expand Down
32 changes: 24 additions & 8 deletions runtime/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,15 @@ export class Runtime {
always (
if (local_map.(lang)) (local_map.(lang))
else (
'Could not translate to (lang)'
local_map.'en' default '?'
/*
val text = local_map.'en';
val language = lang;
@example.translate (text, language);
*/
)
)
` // used for persistent DATEX storage
`, true // used for persistent DATEX storage
);
}

Expand All @@ -308,14 +308,15 @@ export class Runtime {
always (
if (local_map.(lang)) (local_map.(lang).(key))
else (
'Could not translate to (lang)'
local_map.'en' default '?'
/*
val text = local_map.'en'.(key);
val language = lang;
@example.translate (text, language);
*/
)
)` : '' // used for persistent DATEX storage
, true
);
// add to saved string
if(!saved_strings) this.#saved_local_strings.set(local_map, saved_strings = new Map());
Expand Down Expand Up @@ -3048,7 +3049,7 @@ export class Runtime {
// resolve
if (p[1]?.resolve) {
p[1].resolve(ptr)
Pointer.loading_pointers.delete(ptr.id); // TODO: only workaround, automaticall handle delete, but leads to promise rejection errors
Pointer.loading_pointers.delete(ptr.id); // TODO: only workaround, automatically handle delete, but leads to promise rejection errors
}
}
else await Runtime.runtime_actions.handleAssignAction(SCOPE, p[1], null, null, el, p[0]); // other action on pointer
Expand Down Expand Up @@ -5795,10 +5796,25 @@ export class Runtime {
// TRANSFORM (always)
if (INNER_SCOPE.scope_block_for == BinaryCode.TRANSFORM) {
INNER_SCOPE.scope_block_for = null;
await this.runtime_actions.insertToScope(
SCOPE,
Ref.collapseValue(await Pointer.createTransformAsync(INNER_SCOPE.scope_block_vars, code_block))
)
const waiting = [...SCOPE.inner_scope.waiting_ptrs??[]].at(-1);
// assign always() to init ($xxx := always(...))
if (waiting && typeof waiting[1] == "object") { // is init
const ptr = waiting[0]
ptr.handleTransformAsync(INNER_SCOPE.scope_block_vars, code_block);
// resolve
if (waiting[1]?.resolve) {
waiting[1].resolve(ptr)
Pointer.loading_pointers.delete(ptr.id); // TODO: only workaround, automatically handle delete, but leads to promise rejection errors
}
SCOPE.inner_scope.waiting_ptrs!.delete(waiting)
}
else {
await this.runtime_actions.insertToScope(
SCOPE,
Ref.collapseValue(await Pointer.createTransformAsync(INNER_SCOPE.scope_block_vars, code_block))
)
}

}

// ASSERT
Expand Down
3 changes: 2 additions & 1 deletion utils/cookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { client_type } from "./constants.ts";

const port = globalThis.location?.port;
const isSafari = (/^((?!chrome|android).)*safari/i.test(navigator.userAgent));


export function deleteCookie(name: string) {
Expand All @@ -28,7 +29,7 @@ export function setCookie(name: string, value: string, expDays?: number) {
expiryDate.setTime(expiryDate.getTime() + (expDays * 24 * 60 * 60 * 1000));
}
const expires = expDays == 0 ? "" : "expires=" + expiryDate.toUTCString() + ";";
document.cookie = name + "=" + value + "; " + expires + " path=/;"
document.cookie = name + "=" + value + "; " + expires + " path=/; SameSite=None;" + (isSafari ? "" :" Secure;")
}

export function getCookie(name: string) {
Expand Down
1 change: 1 addition & 0 deletions utils/message_logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Logger } from "./logger.ts";

// WASM
import {decompile as wasm_decompile} from "../wasm/adapter/pkg/datex_wasm.js";
import { console } from "./ansi_compat.ts";

export class MessageLogger {

Expand Down
Binary file modified wasm/adapter/pkg/datex_wasm_bg.wasm
Binary file not shown.

0 comments on commit 069074a

Please sign in to comment.