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
177 changes: 98 additions & 79 deletions src/backend/src/services/worker/WorkerService.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ async function readPuterFile(actor, filePath) {
stream.on("data", (data) => {
chunks.push(data)
bytes += data.byteLength
if (bytes > 10**7) {
if (bytes > 10 ** 7) {
const err = Error("Worker source code must not exceed 10MB");
stream.emit("error", err);
throw err;
Expand Down Expand Up @@ -82,7 +82,7 @@ const PREAMBLE_LENGTH = preamble.split("\n").length - 1
class WorkerService extends BaseService {
_init() {
setCloudflareKeys(this.config);

// Services used
const svc_event = this.services.get('event');
const svc_su = this.services.get("su");
Expand All @@ -95,87 +95,89 @@ class WorkerService extends BaseService {
if (meta.from_outside) return;

// Check if the file that was written correlates to a worker
const result = await svc_su.sudo(async ()=> {
const results = await svc_su.sudo(async () => {
return await es_subdomain.select({ predicate: new Eq({ key: "root_dir", value: data.node }) });
});
if (!result || result.length === 0)
if (!results || results.length === 0)
return;

// Person who just wrote file (not necessarily file owner)
const actor = Context.get("actor");

// Worker data
const fileData = (await readPuterFile(Context.get("actor"), data.node.path)).toString();
const workerName = (await result[0].get("subdomain")).split(".").pop();

// Get appropriate deploy time auth token to give to the worker
let authToken;
const appOwner = await result[0].get("app_owner");
if (appOwner) { // If the deployer is an app...
const appID = await appOwner.get("uid");
authToken = await svc_su.sudo(await data.node.get("owner"), async () => {
return await svc_auth.get_user_app_token(appID);
})
} else { // If the deployer is not attached to any application
authToken = (await svc_auth.create_session_token((await data.node.get("owner")).type.user)).token
}


svc_notification.notify(
UsernameNotifSelector(actor.type.user.username),
{
source: 'worker',
title: `Deploying CF worker ${workerName}`,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
},
for (const result of results) {
// Person who just wrote file (not necessarily file owner)
const actor = Context.get("actor");

// Worker data
const fileData = (await readPuterFile(Context.get("actor"), data.node.path)).toString();
const workerName = (await result.get("subdomain")).split(".").pop();

// Get appropriate deploy time auth token to give to the worker
let authToken;
const appOwner = await result.get("app_owner");
if (appOwner) { // If the deployer is an app...
const appID = await appOwner.get("uid");
authToken = await svc_su.sudo(await data.node.get("owner"), async () => {
return await svc_auth.get_user_app_token(appID);
})
} else { // If the deployer is not attached to any application
authToken = (await svc_auth.create_session_token((await data.node.get("owner")).type.user)).token
}
);
try {
// Create the worker
const cfData = await createWorker((await data.node.get("owner")).type.user, authToken, workerName, preamble + fileData, PREAMBLE_LENGTH);

// Send user the appropriate notification
if (cfData.success) {
svc_notification.notify(
UsernameNotifSelector(actor.type.user.username),
{
source: 'worker',
title: `Succesfully deployed ${cfData.url}`,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
},
}
);
} else {

// svc_notification.notify(
// UsernameNotifSelector(actor.type.user.username),
// {
// source: 'worker',
// title: `Deploying CF worker ${workerName}`,
// template: 'user-requesting-share',
// fields: {
// username: actor.type.user.username,
// },
// }
// );
try {
// Create the worker
const cfData = await createWorker((await data.node.get("owner")).type.user, authToken, workerName, preamble + fileData, PREAMBLE_LENGTH);

// Send user the appropriate notification
if (cfData.success) {
// svc_notification.notify(
// UsernameNotifSelector(actor.type.user.username),
// {
// source: 'worker',
// title: `Succesfully deployed ${cfData.url}`,
// template: 'user-requesting-share',
// fields: {
// username: actor.type.user.username,
// },
// }
// );
} else {
svc_notification.notify(
UsernameNotifSelector(actor.type.user.username),
{
source: 'worker',
title: `Failed to deploy ${workerName}! ${cfData.errors}`,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
},
}
);
}


} catch (e) {
svc_notification.notify(
UsernameNotifSelector(actor.type.user.username),
{
source: 'worker',
title: `Failed to deploy ${workerName}! ${cfData.errors}`,
title: `Failed to deploy ${workerName}!!\n ${e}`,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
},
}
);
}


} catch (e) {
svc_notification.notify(
UsernameNotifSelector(actor.type.user.username),
{
source: 'worker',
title: `Failed to deploy ${workerName}!!\n ${e}`,
template: 'user-requesting-share',
fields: {
username: actor.type.user.username,
},
}
);
}
});
}
Expand All @@ -189,28 +191,39 @@ class WorkerService extends BaseService {
async create({ filePath, workerName, authorization }) {
try {
workerName = workerName.toLocaleLowerCase(); // just incase
if(!(/^[a-zA-Z0-9_-]+$/.test(workerName))) return;

if (this.global_config.reserved_words.includes(workerName)) {
return APIError.create('subdomain_reserved', null, {
subdomain: workerName,
});
}

if (!(/^[a-zA-Z0-9_-]+$/.test(workerName))) return;

filePath = await (await (new FSNodeParam('path')).consolidate({
req: { user: Context.get("actor").type.user },
getParam: () => filePath,
})).get("path");
const userData = await getUserInfo(authorization, this.global_config.api_base_url);
const actor = Context.get("actor");
const es_subdomain = this.services.get('es:subdomain');
const fileData = (await readPuterFile(actor, filePath)).toString();
const cfData = await createWorker(userData, authorization, calculateWorkerNameNew(userData.uuid, workerName), preamble + fileData, PREAMBLE_LENGTH);

const userData = await getUserInfo(authorization, this.global_config.api_base_url);
const actor = Context.get("actor");
await Context.sub({ [SKIP_ES_VALIDATION]: true }).arun(async () => {
const entity = await Entity.create({ om: es_subdomain.om }, {
subdomain: "workers.puter." + calculateWorkerNameNew(userData.uuid, workerName),
subdomain: "workers.puter." + calculateWorkerNameNew(userData, workerName),
root_dir: filePath
});
await es_subdomain.upsert(entity);
});


const fileData = (await readPuterFile(actor, filePath)).toString();
const cfData = await createWorker(userData, authorization, calculateWorkerNameNew(userData.uuid, workerName), preamble + fileData, PREAMBLE_LENGTH);


return cfData;
} catch (e) {
if (e instanceof APIError)
throw e;
console.error(e)
return { success: false, errors: e }
}
Expand All @@ -219,20 +232,26 @@ class WorkerService extends BaseService {
try {
workerName = workerName.toLocaleLowerCase(); // just incase
const svc_su = this.services.get("su");
const es_subdomain = this.services.get('es:subdomain');

const userData = await getUserInfo(authorization, this.global_config.api_base_url);

const [result] = (await es_subdomain.select({ predicate: new Eq({ key: "subdomain", value: "workers.puter." + calculateWorkerNameNew(undefined, workerName) }) }));

if (result.values_.owner.uuid !== userData.uuid) {
throw new Error("This is not your worker!");
}

const cfData = await deleteWorker(userData, authorization, workerName);

const es_subdomain = this.services.get('es:subdomain');
const result = await svc_su.sudo(async () => {
const row = (await es_subdomain.select({ predicate: new Eq({ key: "subdomain", value: "workers.puter." + calculateWorkerNameNew(userData.uuid, workerName) }) }));
return row;
})

await es_subdomain.delete(await result[0].get("uid"));
await es_subdomain.delete(await result.get("uid"));
return cfData;


} catch (e) {
if (e instanceof APIError)
throw e;
console.error(e);
return { success: false, e }
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend/src/services/worker/workerUtils/nameUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function sha1(input) {

function calculateWorkerNameNew(uuid, workerId) {

return `${workerId}-${uuid.replaceAll("-", "")}`
return `${workerId}`; // Used to be ${workerId}-${uuid.replaceAll("-", "")}
}
module.exports = {
sha1,
Expand Down