Skip to content

Commit b741f98

Browse files
authored
Merge pull request #289 from Secreto31126/user-function
Implemented user_function to handle callbacks
2 parents 14d668d + f806581 commit b741f98

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "whatsapp-api-js",
3-
"version": "2.4.0",
3+
"version": "2.5.0",
44
"author": "Secreto31126",
55
"description": "A TypeScript server agnostic Whatsapp's Official API framework",
66
"license": "MIT",

src/index.ts

+31-8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ export default class WhatsAppAPI {
5959
* If true, API operations will return the fetch promise instead. Intended for low level debugging.
6060
*/
6161
private parsed: boolean;
62+
/**
63+
* If false, the user functions won't be offloaded from the main event loop.
64+
* Intended for Serverless Environments where the process might be killed after the main function finished.
65+
*/
66+
private offload_functions: boolean;
6267
/**
6368
* If false, the API will be used in a less secure way, reducing the need for appSecret. Defaults to true.
6469
*/
@@ -108,6 +113,7 @@ export default class WhatsAppAPI {
108113
webhookVerifyToken,
109114
v = "v18.0",
110115
parsed = true,
116+
offload_functions = true,
111117
secure = true,
112118
ponyfill = {}
113119
}: WhatsAppAPIConstructorArguments) {
@@ -152,6 +158,7 @@ export default class WhatsAppAPI {
152158
this.v = v;
153159

154160
this.parsed = !!parsed;
161+
this.offload_functions = !!offload_functions;
155162
}
156163

157164
//#region Message Operations
@@ -240,7 +247,7 @@ export default class WhatsAppAPI {
240247
response
241248
};
242249

243-
this.offload(this.on?.sent, args);
250+
this.user_function(this.on?.sent, args);
244251

245252
return response ?? promise;
246253
}
@@ -775,7 +782,7 @@ export default class WhatsAppAPI {
775782
Whatsapp: this
776783
};
777784

778-
this.offload(this.on?.message, args);
785+
this.user_function(this.on?.message, args);
779786
} else if ("statuses" in value) {
780787
const statuses = value.statuses[0];
781788

@@ -799,7 +806,7 @@ export default class WhatsAppAPI {
799806
raw: data
800807
};
801808

802-
this.offload(this.on?.status, args);
809+
this.user_function(this.on?.status, args);
803810
}
804811
// If unknown payload, just ignore it
805812
// Facebook doesn't care about your server's opinion
@@ -868,6 +875,7 @@ export default class WhatsAppAPI {
868875
/**
869876
* Get the body of a fetch response
870877
*
878+
* @internal
871879
* @param promise - The fetch response
872880
* @returns The json body parsed
873881
*/
@@ -878,19 +886,34 @@ export default class WhatsAppAPI {
878886
}
879887

880888
/**
881-
* Offload a function to the next tick of the event loop
889+
* Call a user function, offloading it from the main thread if needed
882890
*
883891
* @internal
884-
* @param f - The function to offload from the main thread
892+
* @param f - The user function to call
885893
* @param a - The arguments to pass to the function
886894
*/
887-
private offload<A, F extends ((...a: A[]) => unknown) | undefined>(
895+
private user_function<A, F extends ((...a: A[]) => unknown) | undefined>(
888896
f: F,
889897
...a: A[]
890898
) {
891899
if (f) {
892-
// Thanks @RahulLanjewar93
893-
Promise.resolve().then(() => f(...a));
900+
if (this.offload_functions) {
901+
this.offload(f, ...a);
902+
} else {
903+
f(...a);
904+
}
894905
}
895906
}
907+
908+
/**
909+
* Offload a function to the next tick of the event loop
910+
*
911+
* @internal
912+
* @param f - The function to offload from the main thread
913+
* @param a - The arguments to pass to the function
914+
*/
915+
private offload<A, F extends (...a: A[]) => unknown>(f: F, ...a: A[]) {
916+
// Thanks @RahulLanjewar93
917+
Promise.resolve().then(() => f(...a));
918+
}
896919
}

src/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export type TheBasicConstructorArguments = {
6868
* Intended for low level debugging.
6969
*/
7070
parsed?: boolean;
71+
/**
72+
* If false, the user functions won't be offloaded from the main event loop.
73+
* Intended for Serverless Environments where the process might be killed after the main function finished.
74+
*/
75+
offload_functions?: boolean;
7176
/**
7277
* If set to false, none of the API checks will be performed, and it will be used in a less secure way.
7378
*

test/index.test.cjs

+52
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,7 @@ describe("WhatsAppAPI", function () {
16811681
// This should improve the test speed
16821682
// Validation is already tested in the previous section
16831683
Whatsapp.secure = false;
1684+
Whatsapp.offload_functions = true;
16841685
});
16851686

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

1759+
it("should block the main thread with the user's callback if offload_functions is false", async function () {
1760+
// Emulates a blocking function
1761+
function block(delay) {
1762+
const start = Date.now();
1763+
while (Date.now() - start < delay);
1764+
}
1765+
1766+
const shorter_delay = 5;
1767+
const longer_delay = 10;
1768+
1769+
Whatsapp.offload_functions = false;
1770+
1771+
Whatsapp.on.message = () => {
1772+
block(longer_delay);
1773+
spy_on_message();
1774+
};
1775+
1776+
Whatsapp.post(valid_message_mock);
1777+
1778+
// Do critical operations for less time than the user's function
1779+
block(shorter_delay);
1780+
1781+
sinon_assert.calledOnce(spy_on_message);
1782+
});
1783+
17581784
it("should throw TypeError if the request is missing any data", function () {
17591785
let moddedMock;
17601786

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

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

1862+
it("should block the main thread with the user's callback if offload_functions is false", async function () {
1863+
// Emulates a blocking function
1864+
function block(delay) {
1865+
const start = Date.now();
1866+
while (Date.now() - start < delay);
1867+
}
1868+
1869+
const shorter_delay = 5;
1870+
const longer_delay = 10;
1871+
1872+
Whatsapp.offload_functions = false;
1873+
1874+
Whatsapp.on.status = () => {
1875+
block(longer_delay);
1876+
spy_on_status();
1877+
};
1878+
1879+
Whatsapp.post(valid_status_mock);
1880+
1881+
// Do critical operations for less time than the user's function
1882+
block(shorter_delay);
1883+
1884+
sinon_assert.calledOnce(spy_on_status);
1885+
});
1886+
18351887
it("should throw TypeError if the request is missing any data", function () {
18361888
let moddedMock;
18371889

0 commit comments

Comments
 (0)