EdgeAIG's picture
download
raw
4.33 kB
/**
* Client-side worker primitives shared by browser, Node, and Bun adapters.
*
* This module defines the platform-neutral `Worker` client, the `WorkerPlatform`
* service that creates workers by numeric id, and the `Spawner` service used to
* find platform-specific worker instances. `makePlatform` wraps platform setup
* and listen hooks into a `WorkerPlatform`, buffers outgoing messages until the
* worker is ready, runs incoming messages with Effect handlers, and ties worker
* cleanup to scope lifetime.
*
* @since 4.0.0
*/
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as FiberSet from "../../FiberSet.js";
import * as Latch from "../../Latch.js";
import * as Layer from "../../Layer.js";
import * as Scope from "../../Scope.js";
import { WorkerError, WorkerSendError } from "./WorkerError.js";
/**
* Service that spawns effect `Worker` instances for numeric worker ids using
* the configured `Spawner`.
*
* @category models
* @since 4.0.0
*/
export class WorkerPlatform extends /*#__PURE__*/Context.Service()("effect/workers/Worker/WorkerPlatform") {}
/**
* Wraps platform-specific send and run functions into a `Worker`, translating
* platform ready/data messages and running the optional `onSpawn` effect when
* the worker reports readiness.
*
* @category models
* @since 4.0.0
*/
export const makeUnsafe = options => ({
send: options.send,
run(handler, options_) {
const onSpawn = options_?.onSpawn ?? Effect.void;
return options.run(msg => {
if (msg[0] === 0) return onSpawn;
return handler(msg[1]);
});
}
});
/**
* Service tag for the worker `SpawnerFn`.
*
* @category services
* @since 4.0.0
*/
export const Spawner = /*#__PURE__*/Context.Service("effect/workers/Worker/Spawner");
/**
* Creates a layer that provides a worker `Spawner` service from a `SpawnerFn`.
*
* @category layers
* @since 4.0.0
*/
export const layerSpawner = /*#__PURE__*/Layer.succeed(Spawner);
/**
* Creates a `WorkerPlatform` from platform-specific setup and listen hooks,
* buffering sent messages until the worker is ready and scoping port cleanup to
* the worker run.
*
* @category constructors
* @since 4.0.0
*/
export const makePlatform = () => options => WorkerPlatform.of({
spawn(id) {
return Effect.gen(function* () {
const spawn = yield* Spawner;
let currentPort;
const buffer = [];
const run = (handler, opts) => Effect.uninterruptibleMask(restore => Effect.scopedWith(Effect.fnUntraced(function* (scope) {
const port = yield* options.setup({
worker: spawn(id),
scope
});
yield* Scope.addFinalizer(scope, Effect.sync(() => {
currentPort = undefined;
}));
const fiberSet = yield* FiberSet.make().pipe(Scope.provide(scope));
const run = yield* FiberSet.runtime(fiberSet)();
const ready = Latch.makeUnsafe();
yield* options.listen({
port,
scope,
emit(data) {
if (data[0] === 0) {
if (opts?.onSpawn) {
run(Effect.ensuring(opts.onSpawn, ready.open));
} else {
ready.openUnsafe();
}
return;
}
run(handler(data[1]));
},
deferred: fiberSet.deferred
});
yield* ready.await;
currentPort = port;
if (buffer.length > 0) {
for (const [message, transfers] of buffer) {
port.postMessage([0, message], transfers);
}
buffer.length = 0;
}
return yield* restore(FiberSet.join(fiberSet));
})));
const send = (message, transfers) => Effect.suspend(() => {
if (currentPort === undefined) {
buffer.push([message, transfers]);
return Effect.void;
}
try {
currentPort.postMessage([0, message], transfers);
return Effect.void;
} catch (cause) {
return Effect.fail(new WorkerError({
reason: new WorkerSendError({
message: "Failed to send message to worker",
cause
})
}));
}
});
return {
run,
send
};
});
}
});
//# sourceMappingURL=Worker.js.map

Xet Storage Details

Size:
4.33 kB
·
Xet hash:
0fb56397f990c4cc4f7b05d9ab1e3ff9018ed0c51bf85b61ac43f15db27748d5

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.