Skip to content

Commit 845d892

Browse files
committed
Basic procedure calling
1 parent 6e0a752 commit 845d892

File tree

12 files changed

+316
-25
lines changed

12 files changed

+316
-25
lines changed

Cargo.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ enum-map = "2.6.3"
175175
env_logger = "0.10"
176176
ethnum = { version = "1.5.0", features = ["serde"] }
177177
flate2 = "1.0.24"
178+
flume = { version = "0.11", default-features = false, features = ["async"] }
178179
foldhash = "0.1.4"
179180
fs-err = "2.9.0"
180181
fs_extra = "1.3.0"
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { AlgebraicType, ProductType } from '../lib/algebraic_type';
2+
import BinaryReader from '../lib/binary_reader';
3+
import BinaryWriter from '../lib/binary_writer';
4+
import type { ConnectionId } from '../lib/connection_id';
5+
import type { Identity } from '../lib/identity';
6+
import type { Timestamp } from '../lib/timestamp';
7+
import type { ParamsObj } from './reducers';
8+
import { MODULE_DEF, type UntypedSchemaDef } from './schema';
9+
import type { Infer, InferTypeOfRow, TypeBuilder } from './type_builders';
10+
import { bsatnBaseSize } from './util';
11+
12+
export type ProcedureFn<
13+
S extends UntypedSchemaDef,
14+
Params extends ParamsObj,
15+
Ret extends TypeBuilder<any, any>,
16+
> = (ctx: ProcedureCtx<S>, args: InferTypeOfRow<Params>) => Infer<Ret>;
17+
18+
export type ProcedureCtx<S extends UntypedSchemaDef> = Readonly<{
19+
sender: Identity;
20+
timestamp: Timestamp;
21+
connectionId: ConnectionId | null;
22+
}>;
23+
24+
export function procedure<
25+
S extends UntypedSchemaDef,
26+
Params extends ParamsObj,
27+
Ret extends TypeBuilder<any, any>,
28+
>(name: string, params: Params, ret: Ret, fn: ProcedureFn<S, Params, Ret>) {
29+
const paramsType: ProductType = {
30+
elements: Object.entries(params).map(([n, c]) => ({
31+
name: n,
32+
algebraicType: c.algebraicType,
33+
})),
34+
};
35+
const returnType = ret.algebraicType;
36+
37+
MODULE_DEF.miscExports.push({
38+
tag: 'Procedure',
39+
value: {
40+
name,
41+
params: paramsType,
42+
returnType,
43+
},
44+
});
45+
46+
PROCEDURES.push({
47+
fn,
48+
paramsType,
49+
returnType,
50+
returnTypeBaseSize: bsatnBaseSize(MODULE_DEF.typespace, returnType),
51+
});
52+
}
53+
54+
const PROCEDURES: Array<{
55+
fn: ProcedureFn<any, any, any>;
56+
paramsType: ProductType;
57+
returnType: AlgebraicType;
58+
returnTypeBaseSize: number;
59+
}> = [];
60+
61+
export function callProcedure(
62+
id: number,
63+
sender: Identity,
64+
connectionId: ConnectionId | null,
65+
timestamp: Timestamp,
66+
argsBuf: Uint8Array
67+
): Uint8Array {
68+
const { fn, paramsType, returnType, returnTypeBaseSize } = PROCEDURES[id];
69+
const args = ProductType.deserializeValue(
70+
new BinaryReader(argsBuf),
71+
paramsType,
72+
MODULE_DEF.typespace
73+
);
74+
const ret = fn(Object.freeze({ sender, connectionId, timestamp }), args);
75+
const retBuf = new BinaryWriter(returnTypeBaseSize);
76+
AlgebraicType.serializeValue(retBuf, returnType, ret, MODULE_DEF.typespace);
77+
return retBuf.getBuffer();
78+
}

crates/bindings-typescript/src/server/runtime.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AlgebraicType } from '../lib/algebraic_type';
1+
import { AlgebraicType, ProductType } from '../lib/algebraic_type';
22
import RawModuleDef from '../lib/autogen/raw_module_def_type';
33
import type RawModuleDefV9 from '../lib/autogen/raw_module_def_v_9_type';
44
import type RawTableDefV9 from '../lib/autogen/raw_table_def_v_9_type';
@@ -36,6 +36,7 @@ import {
3636
type ViewCtx,
3737
} from './views';
3838
import { bsatnBaseSize } from './util';
39+
import { callProcedure } from './procedures';
3940

4041
const { freeze } = Object;
4142

@@ -229,9 +230,9 @@ export const hooks_v1_1: import('spacetime:[email protected]').ModuleHooks = {
229230
// at runtime
230231
db: getDbView(),
231232
});
232-
const args = AlgebraicType.deserializeValue(
233+
const args = ProductType.deserializeValue(
233234
new BinaryReader(argsBuf),
234-
AlgebraicType.Product(params),
235+
params,
235236
MODULE_DEF.typespace
236237
);
237238
const ret = fn(ctx, args);
@@ -247,9 +248,9 @@ export const hooks_v1_1: import('spacetime:[email protected]').ModuleHooks = {
247248
// at runtime
248249
db: getDbView(),
249250
});
250-
const args = AlgebraicType.deserializeValue(
251+
const args = ProductType.deserializeValue(
251252
new BinaryReader(argsBuf),
252-
AlgebraicType.Product(params),
253+
params,
253254
MODULE_DEF.typespace
254255
);
255256
const ret = fn(ctx, args);
@@ -259,6 +260,18 @@ export const hooks_v1_1: import('spacetime:[email protected]').ModuleHooks = {
259260
},
260261
};
261262

263+
export const hooks_v1_2: import('spacetime:[email protected]').ModuleHooks = {
264+
__call_procedure__(id, sender, connection_id, timestamp, args) {
265+
return callProcedure(
266+
id,
267+
new Identity(sender),
268+
ConnectionId.nullIfZero(new ConnectionId(connection_id)),
269+
new Timestamp(timestamp),
270+
args
271+
);
272+
},
273+
};
274+
262275
let DB_VIEW: DbView<any> | null = null;
263276
function getDbView() {
264277
DB_VIEW ??= makeDbView(MODULE_DEF);

crates/bindings-typescript/src/server/schema.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
type ViewOpts,
3030
type ViewReturnTypeBuilder,
3131
} from './views';
32+
import { procedure, type ProcedureFn } from './procedures';
3233

3334
/**
3435
* The global module definition that gets populated by calls to `reducer()` and lifecycle hooks.
@@ -348,6 +349,32 @@ class Schema<S extends UntypedSchemaDef> {
348349
// }
349350
// }
350351

352+
procedure<Params extends ParamsObj, Ret extends TypeBuilder<any, any>>(
353+
name: string,
354+
params: Params,
355+
ret: Ret,
356+
fn: ProcedureFn<S, Params, Ret>
357+
): ProcedureFn<S, Params, Ret>;
358+
procedure<Ret extends TypeBuilder<any, any>>(
359+
name: string,
360+
ret: Ret,
361+
fn: ProcedureFn<S, {}, Ret>
362+
): ProcedureFn<S, {}, Ret>;
363+
procedure<Params extends ParamsObj, Ret extends TypeBuilder<any, any>>(
364+
name: string,
365+
paramsOrRet: Ret | Params,
366+
retOrFn: ProcedureFn<S, {}, Ret> | Ret,
367+
maybeFn?: ProcedureFn<S, Params, Ret>
368+
): ProcedureFn<S, Params, Ret> {
369+
if (typeof retOrFn === 'function') {
370+
procedure(name, {}, paramsOrRet as Ret, retOrFn);
371+
return retOrFn;
372+
} else {
373+
procedure(name, paramsOrRet as Params, retOrFn, maybeFn!);
374+
return maybeFn!;
375+
}
376+
}
377+
351378
clientVisibilityFilter = {
352379
sql(filter: string): void {
353380
MODULE_DEF.rowLevelSecurity.push({ sql: filter });

crates/bindings-typescript/src/server/sys.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,17 @@ declare module 'spacetime:[email protected]' {
7575

7676
export function register_hooks(hooks: ModuleHooks);
7777
}
78+
79+
declare module 'spacetime:[email protected]' {
80+
export type ModuleHooks = {
81+
__call_procedure__(
82+
id: u32,
83+
sender: u256,
84+
connection_id: u128,
85+
timestamp: bigint,
86+
args: Uint8Array
87+
): Uint8Array;
88+
};
89+
90+
export function register_hooks(hooks: ModuleHooks);
91+
}

crates/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ jwks.workspace = true
120120
async_cache = "0.3.1"
121121
faststr = "0.2.23"
122122
core_affinity = "0.8"
123+
flume.workspace = true
123124

124125
[target.'cfg(not(target_env = "msvc"))'.dependencies]
125126
tikv-jemallocator = {workspace = true}

0 commit comments

Comments
 (0)