Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/backend/src/api/APIError.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ module.exports = class APIError {
// Subdomains
'subdomain_limit_reached': {
status: 400,
message: ({ limit }) => `You have exceeded the number of subdomains under your current plan (${limit}).`,
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}).`,
},
'subdomain_reserved': {
status: 400,
Expand Down
21 changes: 20 additions & 1 deletion src/backend/src/om/entitystorage/SQLES.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const { BaseES } = require("./BaseES");
const APIError = require("../../api/APIError");
const { Entity } = require("./Entity");
const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature");
const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull } = require("../query/query");
const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull, StartsWith } = require("../query/query");
const { DB_WRITE } = require("../../services/database/consts");

class RawCondition extends AdvancedBase {
Expand Down Expand Up @@ -400,6 +400,25 @@ class SQLES extends BaseES {

return new RawCondition({ sql, values });
}

if (om_query instanceof StartsWith) {
const key = om_query.key;
let value = om_query.value;
const prop = this.om.properties[key];

value = await prop.sql_reference(value);

const options = prop.descriptor.sql ?? {};
const col_name = options.column_name ?? prop.name;

const sql = `${col_name} LIKE ${this.db.case({
sqlite: `? || '%'`,
otherwise: `CONCAT(?, '%')`
})}`;
const values = value === null ? [] : [value];

return new RawCondition({ sql, values });
}

if ( om_query instanceof IsNotNull ) {
const key = om_query.key;
Expand Down
7 changes: 7 additions & 0 deletions src/backend/src/om/query/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class Eq extends Predicate {
}
}

class StartsWith extends Predicate {
async check(entity) {
return (await entity.get(this.key)).startsWith(this.value);
}
}

class IsNotNull extends Predicate {
async check (entity) {
return (await entity.get(this.key)) !== null;
Expand Down Expand Up @@ -122,4 +128,5 @@ module.exports = {
Eq,
IsNotNull,
Like,
StartsWith
};
15 changes: 12 additions & 3 deletions src/backend/src/services/worker/WorkerService.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ const { NodePathSelector } = require("../../filesystem/node/selectors");
const { calculateWorkerNameNew } = require("./workerUtils/nameUtils");
const { Entity } = require("../../om/entitystorage/Entity");
const { SKIP_ES_VALIDATION } = require("../../om/entitystorage/consts");
const { Eq } = require("../../om/query/query");
const { Eq, StartsWith } = require("../../om/query/query");
const { get_app } = require("../../helpers");
const { UsernameNotifSelector } = require("../NotificationService");
const APIError = require("../../api/APIError");
const FSNodeParam = require("../../api/filesystem/FSNodeParam");
const { UserActorType } = require("../auth/Actor");

async function readPuterFile(actor, filePath) {
try {
Expand Down Expand Up @@ -191,9 +192,18 @@ class WorkerService extends BaseService {
async create({ filePath, workerName, authorization }) {
try {
workerName = workerName.toLocaleLowerCase(); // just incase
const svc_su = this.services.get("su");
const es_subdomain = this.services.get('es:subdomain');

const currentDomains = await svc_su.sudo(Context.get("actor").get_related_actor(UserActorType), async () => {
return (await es_subdomain.select({ predicate: new StartsWith({ key: "subdomain", value: "workers.puter." }) }));
});
if (currentDomains.length >= 10) {
throw APIError.create('subdomain_limit_reached', null, {isWorker: true, limit: 10});
}

if (this.global_config.reserved_words.includes(workerName)) {
return APIError.create('subdomain_reserved', null, {
throw APIError.create('subdomain_reserved', null, {
subdomain: workerName,
});
}
Expand All @@ -204,7 +214,6 @@ class WorkerService extends BaseService {
req: { user: Context.get("actor").type.user },
getParam: () => filePath,
})).get("path");
const es_subdomain = this.services.get('es:subdomain');

const userData = await getUserInfo(authorization, this.global_config.api_base_url);
const actor = Context.get("actor");
Expand Down
6 changes: 3 additions & 3 deletions src/puter-js/src/modules/Workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class WorkersHandler {
const driverCall = await puter.drivers.call("workers", "worker-service", "create", { authorization: puter.authToken, filePath, workerName });
const driverResult = driverCall.result;
if (!driverCall.success || !driverResult.success) {
throw new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
throw driverCall.error || new Error(driverResult?.errors || "Driver failed to execute, do you have the necessary permissions?");
}
currentWorkers[workerName] = { filePath, url: driverResult["url"], deployTime: Date.now() };
await puter.kv.set("user-workers", currentWorkers);
Expand Down Expand Up @@ -97,9 +97,9 @@ export class WorkersHandler {

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

Expand Down