Skip to content

Commit 8e58fab

Browse files
improve error handling, user specific worker limit
1 parent 299e7b6 commit 8e58fab

File tree

5 files changed

+43
-8
lines changed

5 files changed

+43
-8
lines changed

src/backend/src/api/APIError.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ module.exports = class APIError {
300300
// Subdomains
301301
'subdomain_limit_reached': {
302302
status: 400,
303-
message: ({ limit }) => `You have exceeded the number of subdomains under your current plan (${limit}).`,
303+
message: ({ limit, isWorker }) => isWorker ? `You have exceeded the maximum number of workers for your plan! (${limit})`:`You have exceeded the number of subdomains under your current plan (${limit}).`,
304304
},
305305
'subdomain_reserved': {
306306
status: 400,

src/backend/src/om/entitystorage/SQLES.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const { BaseES } = require("./BaseES");
2222
const APIError = require("../../api/APIError");
2323
const { Entity } = require("./Entity");
2424
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
25-
const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull } = require("../query/query");
25+
const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull, StartsWith } = require("../query/query");
2626
const { DB_WRITE } = require("../../services/database/consts");
2727

2828
class RawCondition extends AdvancedBase {
@@ -400,6 +400,25 @@ class SQLES extends BaseES {
400400

401401
return new RawCondition({ sql, values });
402402
}
403+
404+
if (om_query instanceof StartsWith) {
405+
const key = om_query.key;
406+
let value = om_query.value;
407+
const prop = this.om.properties[key];
408+
409+
value = await prop.sql_reference(value);
410+
411+
const options = prop.descriptor.sql ?? {};
412+
const col_name = options.column_name ?? prop.name;
413+
414+
const sql = `${col_name} LIKE ${this.db.case({
415+
sqlite: `? || '%'`,
416+
otherwise: `CONCAT(?, '%')`
417+
})}`;
418+
const values = value === null ? [] : [value];
419+
420+
return new RawCondition({ sql, values });
421+
}
403422

404423
if ( om_query instanceof IsNotNull ) {
405424
const key = om_query.key;

src/backend/src/om/query/query.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ class Eq extends Predicate {
5050
}
5151
}
5252

53+
class StartsWith extends Predicate {
54+
async check(entity) {
55+
return (await entity.get(this.key)).startsWith(this.value);
56+
}
57+
}
58+
5359
class IsNotNull extends Predicate {
5460
async check (entity) {
5561
return (await entity.get(this.key)) !== null;
@@ -122,4 +128,5 @@ module.exports = {
122128
Eq,
123129
IsNotNull,
124130
Like,
131+
StartsWith
125132
};

src/backend/src/services/worker/WorkerService.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ const { NodePathSelector } = require("../../filesystem/node/selectors");
3030
const { calculateWorkerNameNew } = require("./workerUtils/nameUtils");
3131
const { Entity } = require("../../om/entitystorage/Entity");
3232
const { SKIP_ES_VALIDATION } = require("../../om/entitystorage/consts");
33-
const { Eq } = require("../../om/query/query");
33+
const { Eq, StartsWith } = require("../../om/query/query");
3434
const { get_app } = require("../../helpers");
3535
const { UsernameNotifSelector } = require("../NotificationService");
3636
const APIError = require("../../api/APIError");
3737
const FSNodeParam = require("../../api/filesystem/FSNodeParam");
38+
const { UserActorType } = require("../auth/Actor");
3839

3940
async function readPuterFile(actor, filePath) {
4041
try {
@@ -191,9 +192,18 @@ class WorkerService extends BaseService {
191192
async create({ filePath, workerName, authorization }) {
192193
try {
193194
workerName = workerName.toLocaleLowerCase(); // just incase
195+
const svc_su = this.services.get("su");
196+
const es_subdomain = this.services.get('es:subdomain');
197+
198+
const currentDomains = await svc_su.sudo(Context.get("actor").get_related_actor(UserActorType), async () => {
199+
return (await es_subdomain.select({ predicate: new StartsWith({ key: "subdomain", value: "workers.puter." }) }));
200+
});
201+
if (currentDomains.length >= 10) {
202+
throw APIError.create('subdomain_limit_reached', null, {isWorker: true, limit: 10});
203+
}
194204

195205
if (this.global_config.reserved_words.includes(workerName)) {
196-
return APIError.create('subdomain_reserved', null, {
206+
throw APIError.create('subdomain_reserved', null, {
197207
subdomain: workerName,
198208
});
199209
}
@@ -204,7 +214,6 @@ class WorkerService extends BaseService {
204214
req: { user: Context.get("actor").type.user },
205215
getParam: () => filePath,
206216
})).get("path");
207-
const es_subdomain = this.services.get('es:subdomain');
208217

209218
const userData = await getUserInfo(authorization, this.global_config.api_base_url);
210219
const actor = Context.get("actor");

src/puter-js/src/modules/Workers.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class WorkersHandler {
2626
const driverCall = await puter.drivers.call("workers", "worker-service", "create", { authorization: puter.authToken, filePath, workerName });
2727
const driverResult = driverCall.result;
2828
if (!driverCall.success || !driverResult.success) {
29-
throw new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
29+
throw driverCall.error || new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
3030
}
3131
currentWorkers[workerName] = { filePath, url: driverResult["url"], deployTime: Date.now() };
3232
await puter.kv.set("user-workers", currentWorkers);
@@ -97,9 +97,9 @@ export class WorkersHandler {
9797

9898
if (!driverCall.success || !driverCall.result.result) {
9999
if (!driverCall.result.result) {
100-
throw new Error("Worker doesn't exist");
100+
new Error("Worker doesn't exist");
101101
}
102-
throw new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
102+
throw driverCall.error || new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
103103
} else {
104104
let currentWorkers = await puter.kv.get("user-workers");
105105

0 commit comments

Comments
 (0)