Skip to content

Commit

Permalink
rework feature attributes and implement updateTrainee
Browse files Browse the repository at this point in the history
  • Loading branch information
fulpm committed Sep 27, 2024
1 parent 8dbc9b0 commit 01215b1
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 212 deletions.
314 changes: 157 additions & 157 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@eslint/js": "^9.10.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^11.1.6",
"@types/emscripten": "^1.39.10",
"@types/emscripten": "^1.39.13",
"@types/eslint__js": "^8.42.3",
"@types/node": "^20.16.5",
"@types/nunjucks": "^3.2.6",
Expand Down
3 changes: 2 additions & 1 deletion src/client/base.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Trainee } from "@/types";
import type { FeatureAttributesIndex, Trainee } from "@/types";
import { DEFAULT_ERROR_MESSAGE, HowsoError, HowsoValidationError } from "./errors";
import type { CacheMap } from "./utilities/cache";

export interface ClientCache {
trainee: Trainee;
feature_attributes?: FeatureAttributesIndex;
}

export interface ExecuteResponse<R = unknown> {
Expand Down
97 changes: 52 additions & 45 deletions src/client/worker/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface ClientOptions {
export class HowsoWorkerClient extends TraineeClient {
public readonly fs: FileSystemClient;
protected activeSession?: Session;
protected cache: CacheMap<ClientCache>;
protected cache: CacheMap<Required<ClientCache>>;

constructor(
protected readonly worker: Worker,
Expand Down Expand Up @@ -129,9 +129,7 @@ export class HowsoWorkerClient extends TraineeClient {
if (traineeId == null) {
throw new TypeError("A Trainee identifier is required.");
}
if (!this.cache.has(traineeId)) {
await this.acquireTraineeResources(traineeId);
}
await this.acquireTraineeResources(traineeId); // does nothing if already cached
const cached = this.cache.get(traineeId);
if (cached == null) {
throw new HowsoError(`Trainee "${traineeId}" not found.`, "not_found");
Expand All @@ -154,23 +152,25 @@ export class HowsoWorkerClient extends TraineeClient {
* Constructs Trainee object from it's Engine metadata.
*
* @param traineeId The Trainee identifier.
* @returns The Trainee object.
* @returns The Trainee object and its feature attributes.
*/
protected async getTraineeFromEngine(traineeId: string): Promise<Trainee> {
protected async getTraineeFromEngine(traineeId: string): Promise<[Trainee, FeatureAttributesIndex]> {
const [metadata, features] = await Promise.all([
this.execute<any>(traineeId, "get_metadata", {}),
this.execute<FeatureAttributesIndex>(traineeId, "get_feature_attributes", {}),
]);
if (!metadata?.payload) {
throw new HowsoError(`Trainee "${traineeId}" not found.`, "not_found");
}
return {
id: traineeId,
name: metadata?.payload?.name,
features: features?.payload,
persistence: metadata?.payload?.persistence ?? "allow",
metadata: metadata?.payload?.metadata,
};
return [
{
id: traineeId,
name: metadata?.payload?.name,
persistence: metadata?.payload?.persistence ?? "allow",
metadata: metadata?.payload?.metadata,
},
features?.payload,
];
}

/**
Expand Down Expand Up @@ -257,29 +257,35 @@ export class HowsoWorkerClient extends TraineeClient {
}

const filename = this.fs.traineeFilename(traineeId);
const filePath = this.fs.join(this.fs.traineeDir, filename);
if (url) {
// Prepare the file on the virtual file system
await this.fs.prepareFile(this.fs.traineeDir, filename, url);
}

const fileStat = await this.fs.analyzePath(filePath);
if (!fileStat?.exists) {
throw new HowsoError(`Trainee "${traineeId}" not found.`, "not_found");
}

// Load Trainee only if entity not already loaded
const loaded = await this.getEntities();
if (loaded.indexOf(traineeId) == -1) {
// Only call load if not already loaded
const status = await this.dispatch({
type: "request",
command: "loadEntity",
parameters: [traineeId, this.fs.join(this.fs.traineeDir, filename)],
parameters: [traineeId, filePath],
});
if (!status.loaded) {
throw new HowsoError(`Failed to acquire the Trainee "${traineeId}": ${status.message}`);
}
}

// Get Trainee details. Use the internal method to prevent auto resolution loops.
const trainee = await this.getTraineeFromEngine(traineeId);
const [trainee, feature_attributes] = await this.getTraineeFromEngine(traineeId);
// Cache the Trainee
this.cache.set(traineeId, { trainee });
this.cache.set(traineeId, { trainee, feature_attributes });
}

/**
Expand Down Expand Up @@ -339,35 +345,35 @@ export class HowsoWorkerClient extends TraineeClient {
// Set Trainee metadata
const metadata = {
name: trainee.name,
metadata: structuredClone(trainee.metadata || {}),
metadata: trainee.metadata || {},
persistence: trainee.persistence || "allow",
};
await this.execute(traineeId, "set_metadata", { metadata });

// Set the feature attributes
const { payload: feature_attributes } = await this.execute<FeatureAttributesIndex>(
traineeId,
"set_feature_attributes",
{
feature_attributes: trainee.features || {},
},
);

// Build, cache and return new trainee object
const newTrainee: Trainee = { id: traineeId, features: feature_attributes, ...metadata };
this.cache.set(traineeId, { trainee: newTrainee });
const newTrainee: Trainee = { id: traineeId, ...metadata };
this.cache.set(traineeId, { trainee: structuredClone(newTrainee), feature_attributes: {} });
return newTrainee;
}

/**
* Update a Trainee's properties.
* @param trainee The Trainee identifier.
*/
public async updateTrainee(
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
trainee: Trainee,
): Promise<Trainee> {
throw new Error("Method not implemented.");
public async updateTrainee(trainee: Trainee): Promise<Trainee> {
await this.autoResolveTrainee(trainee.id);

// Set Trainee metadata
const metadata = {
name: trainee.name,
metadata: trainee.metadata || {},
persistence: trainee.persistence || "allow",
};
await this.execute(trainee.id, "set_metadata", { metadata });

const [updatedTrainee, feature_attributes] = await this.getTraineeFromEngine(trainee.id);
this.cache.set(trainee.id, { trainee: structuredClone(updatedTrainee), feature_attributes });
return updatedTrainee;
}

/**
Expand All @@ -377,7 +383,8 @@ export class HowsoWorkerClient extends TraineeClient {
*/
public async getTrainee(traineeId: string): Promise<Trainee> {
await this.autoResolveTrainee(traineeId);
return await this.getTraineeFromEngine(traineeId); // Get latest Trainee from Engine
const [trainee] = await this.getTraineeFromEngine(traineeId); // Get latest Trainee from Engine
return trainee;
}

/**
Expand All @@ -404,8 +411,8 @@ export class HowsoWorkerClient extends TraineeClient {
await this.execute(newTraineeId, "set_metadata", { metadata });

// Get fresh copy of the trainee object
const newTrainee = await this.getTraineeFromEngine(newTraineeId);
this.cache.set(newTraineeId, { trainee: newTrainee });
const [newTrainee, feature_attributes] = await this.getTraineeFromEngine(newTraineeId);
this.cache.set(newTraineeId, { trainee: structuredClone(newTrainee), feature_attributes });
return newTrainee;
}

Expand Down Expand Up @@ -459,31 +466,31 @@ export class HowsoWorkerClient extends TraineeClient {
public async setFeatureAttributes(traineeId: string, request: schemas.SetFeatureAttributesRequest) {
const response = await super.setFeatureAttributes(traineeId, request);
// Also update cached Trainee
const trainee = this.cache.get(traineeId)?.trainee;
if (trainee) {
trainee.features = response.payload;
const cached = this.cache.get(traineeId);
if (cached) {
cached.feature_attributes = structuredClone(response.payload);
}
return response;
}

public async addFeature(traineeId: string, request: schemas.AddFeatureRequest) {
const response = await super.addFeature(traineeId, request);
// Also update cached Trainee
const trainee = this.cache.get(traineeId)?.trainee;
if (trainee) {
const cached = this.cache.get(traineeId);
if (cached) {
const { payload: features } = await this.getFeatureAttributes(traineeId);
trainee.features = features;
cached.feature_attributes = features;
}
return response;
}

public async removeFeature(traineeId: string, request: schemas.RemoveFeatureRequest) {
const response = await super.removeFeature(traineeId, request);
// Also update cached Trainee
const trainee = this.cache.get(traineeId)?.trainee;
if (trainee) {
const cached = this.cache.get(traineeId);
if (cached) {
const { payload: features } = await this.getFeatureAttributes(traineeId);
trainee.features = features;
cached.feature_attributes = features;
}
return response;
}
Expand Down
10 changes: 9 additions & 1 deletion src/client/worker/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ export class FileSystemClient implements IFileSystem {
}
}

public async analyzePath(path: string, dontResolveLastLink?: boolean): Promise<FS.Analyze> {
return await this.dispatch({
type: "request",
command: "analyzePath",
parameters: [path, dontResolveLastLink],
});
}

public async createLazyFile(
parent: string,
name: string,
Expand All @@ -89,7 +97,7 @@ export class FileSystemClient implements IFileSystem {

public async writeFile(
path: string,
data: string | DataView | ArrayBufferView,
data: string | ArrayBufferView,
opts?: { flags?: string | undefined },
): Promise<void> {
await this.dispatch({
Expand Down
7 changes: 0 additions & 7 deletions src/types/trainee.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { FeatureAttributes } from "./schemas";

export interface TraineeIdentity {
/**
* The unique identifier of the Trainee.
Expand All @@ -13,11 +11,6 @@ export interface TraineeIdentity {
}

export interface Trainee extends TraineeIdentity {
/**
* Feature attributes of the Trainee.
*/
features?: { [key: string]: FeatureAttributes };

/**
* The type of persistence schedule to use.
* If allow, the trainee may be manually persisted and will be persisted automatically only when unloaded.
Expand Down

0 comments on commit 01215b1

Please sign in to comment.