Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented user_function to handle callbacks #289

Merged
merged 2 commits into from
Jan 16, 2024
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 package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "whatsapp-api-js",
"version": "2.4.0",
"version": "2.5.0",
"author": "Secreto31126",
"description": "A TypeScript server agnostic Whatsapp's Official API framework",
"license": "MIT",
Expand Down
39 changes: 31 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ export default class WhatsAppAPI {
* If true, API operations will return the fetch promise instead. Intended for low level debugging.
*/
private parsed: boolean;
/**
* If false, the user functions won't be offloaded from the main event loop.
* Intended for Serverless Environments where the process might be killed after the main function finished.
*/
private offload_functions: boolean;
/**
* If false, the API will be used in a less secure way, reducing the need for appSecret. Defaults to true.
*/
Expand Down Expand Up @@ -108,6 +113,7 @@ export default class WhatsAppAPI {
webhookVerifyToken,
v = "v18.0",
parsed = true,
offload_functions = true,
secure = true,
ponyfill = {}
}: WhatsAppAPIConstructorArguments) {
Expand Down Expand Up @@ -152,6 +158,7 @@ export default class WhatsAppAPI {
this.v = v;

this.parsed = !!parsed;
this.offload_functions = !!offload_functions;
}

//#region Message Operations
Expand Down Expand Up @@ -240,7 +247,7 @@ export default class WhatsAppAPI {
response
};

this.offload(this.on?.sent, args);
this.user_function(this.on?.sent, args);

return response ?? promise;
}
Expand Down Expand Up @@ -775,7 +782,7 @@ export default class WhatsAppAPI {
Whatsapp: this
};

this.offload(this.on?.message, args);
this.user_function(this.on?.message, args);
} else if ("statuses" in value) {
const statuses = value.statuses[0];

Expand All @@ -799,7 +806,7 @@ export default class WhatsAppAPI {
raw: data
};

this.offload(this.on?.status, args);
this.user_function(this.on?.status, args);
}
// If unknown payload, just ignore it
// Facebook doesn't care about your server's opinion
Expand Down Expand Up @@ -868,6 +875,7 @@ export default class WhatsAppAPI {
/**
* Get the body of a fetch response
*
* @internal
* @param promise - The fetch response
* @returns The json body parsed
*/
Expand All @@ -878,19 +886,34 @@ export default class WhatsAppAPI {
}

/**
* Offload a function to the next tick of the event loop
* Call a user function, offloading it from the main thread if needed
*
* @internal
* @param f - The function to offload from the main thread
* @param f - The user function to call
* @param a - The arguments to pass to the function
*/
private offload<A, F extends ((...a: A[]) => unknown) | undefined>(
private user_function<A, F extends ((...a: A[]) => unknown) | undefined>(
f: F,
...a: A[]
) {
if (f) {
// Thanks @RahulLanjewar93
Promise.resolve().then(() => f(...a));
if (this.offload_functions) {
this.offload(f, ...a);
} else {
f(...a);
}
}
}

/**
* Offload a function to the next tick of the event loop
*
* @internal
* @param f - The function to offload from the main thread
* @param a - The arguments to pass to the function
*/
private offload<A, F extends (...a: A[]) => unknown>(f: F, ...a: A[]) {
// Thanks @RahulLanjewar93
Promise.resolve().then(() => f(...a));
}
}
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ export type TheBasicConstructorArguments = {
* Intended for low level debugging.
*/
parsed?: boolean;
/**
* If false, the user functions won't be offloaded from the main event loop.
* Intended for Serverless Environments where the process might be killed after the main function finished.
*/
offload_functions?: boolean;
/**
* If set to false, none of the API checks will be performed, and it will be used in a less secure way.
*
Expand Down
52 changes: 52 additions & 0 deletions test/index.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,7 @@ describe("WhatsAppAPI", function () {
// This should improve the test speed
// Validation is already tested in the previous section
Whatsapp.secure = false;
Whatsapp.offload_functions = true;
});

it("should parse the post request and call back with the right parameters", async function () {
Expand Down Expand Up @@ -1755,6 +1756,31 @@ describe("WhatsAppAPI", function () {
sinon_assert.calledOnce(spy_on_message);
});

it("should block the main thread with the user's callback if offload_functions is false", async function () {
// Emulates a blocking function
function block(delay) {
const start = Date.now();
while (Date.now() - start < delay);
}

const shorter_delay = 5;
const longer_delay = 10;

Whatsapp.offload_functions = false;

Whatsapp.on.message = () => {
block(longer_delay);
spy_on_message();
};

Whatsapp.post(valid_message_mock);

// Do critical operations for less time than the user's function
block(shorter_delay);

sinon_assert.calledOnce(spy_on_message);
});

it("should throw TypeError if the request is missing any data", function () {
let moddedMock;

Expand Down Expand Up @@ -1782,6 +1808,7 @@ describe("WhatsAppAPI", function () {
// This should improve the test speed
// Validation is already tested in the previous section
Whatsapp.secure = false;
Whatsapp.offload_functions = true;
});

it("should parse the post request and call back with the right parameters", async function () {
Expand Down Expand Up @@ -1832,6 +1859,31 @@ describe("WhatsAppAPI", function () {
sinon_assert.calledOnce(spy_on_status);
});

it("should block the main thread with the user's callback if offload_functions is false", async function () {
// Emulates a blocking function
function block(delay) {
const start = Date.now();
while (Date.now() - start < delay);
}

const shorter_delay = 5;
const longer_delay = 10;

Whatsapp.offload_functions = false;

Whatsapp.on.status = () => {
block(longer_delay);
spy_on_status();
};

Whatsapp.post(valid_status_mock);

// Do critical operations for less time than the user's function
block(shorter_delay);

sinon_assert.calledOnce(spy_on_status);
});

it("should throw TypeError if the request is missing any data", function () {
let moddedMock;

Expand Down