Rewrite for extensibility & compactness

-This is a break from previous versions unfortunately
-Connecting is now a promise
-Chats, contacts & previously unread messages are supplied on connection
-Groups!
-Message confirmations are more reliable
-Timeout queries & connections
This commit is contained in:
Adhiraj
2020-05-14 20:13:32 +05:30
parent 512d45c5bd
commit b60bd03d21
10 changed files with 1216 additions and 778 deletions

View File

@@ -1,45 +1,83 @@
/*
Contains the code for sending queries to WhatsApp
*/
module.exports = function(WhatsAppWeb) {
// check if given number is registered on WhatsApp
WhatsAppWeb.prototype.isOnWhatsApp = function (jid) {
return this.query(["query", "exist", jid]).then (([m, q]) => [m.status === 200, q[2]])
}
// check the presence status of a given jid
WhatsAppWeb.prototype.requestPresenceUpdate = function (jid) {
module.exports = {
/**
* Query whether a given number is registered on WhatsApp
* @param {string} jid the number you want to query, format as [number]@s.whatsapp.net
* @return {Promise<[boolean, string]>} Promise with an array [exists, jid]
*/
isOnWhatsApp: function (jid) {
return this.query(["query", "exist", jid]).then (([m, _]) => [m.status === 200, jid])
},
/**
* @param {string} jid the whatsapp ID of the person
* @return {Promise<[object, object]>}
*/
requestPresenceUpdate: function (jid) {
return this.query(["action","presence","subscribe",jid])
}
// check the presence status of a given jid
WhatsAppWeb.prototype.getStatus = function (jid) {
},
/**
* Query the status of the person
* @param {string} [jid] the whatsapp ID of the person
* @return {Promise<[object, object]>}
*/
getStatus: function (jid) {
jid = jid ?? this.userMetaData.id
return this.query(["query","Status",jid])
}
// check the presence status of a given jid
WhatsAppWeb.prototype.getProfilePicture = function (jid) {
if (!jid) {
jid = this.userMetaData.id
}
},
/**
* Get the URL to download the profile picture of a person/group
* @param {string} [jid] the whatsapp ID of the person/group (will get your own picture if not specified)
* @return {Promise<[object, object]>}
*/
getProfilePicture: function (jid) {
jid = jid ?? this.userMetaData.id
return this.query(["query","ProfilePicThumb",jid])
}
// query all the contacts
WhatsAppWeb.prototype.getContactList = function () {
const json = [
"query",
{epoch: this.msgCount.toString(), type: "contacts"},
null
]
return this.query(json, [10, 64]) // this has to be an encrypted query
}
// load messages from a group or sender
WhatsAppWeb.prototype.getMessages = function (jid, count, indexMessage=null, mode="before") {
},
/**
* @return {Promise<[object, object]>}
*/
getContacts: function () {
const json = ["query", {epoch: this.msgCount.toString(), type: "contacts"}, null]
return this.query(json, [10, 128]) // this has to be an encrypted query
},
/**
* @return {Promise<[object, object]>}
*/
getChats: function () {
const json = ["query", {epoch: this.msgCount.toString(), type: "chat"}, null]
return this.query(json, [10, 128]) // this has to be an encrypted query
},
/**
* Check if your phone is connected
* @param {number} timeoutMs max time for the phone to respond
* @return {Promise<[object, object]>}
*/
isPhoneConnected: function (timeoutMs=5000) {
return this.query (["admin", "test"], null, timeoutMs)
.then (([json, q]) => json[1])
.catch (err => false)
},
/**
* Load the conversation with a group or person
* @param {string} jid the id of the group or person
* @param {number} count the number of messages to load
* @param {object} [indexMessage] the data for which message to offset the query by
* @param {string} [indexMessage.id] the id of the message
* @param {object} [indexMessage.fromMe] whether the message was sent by yours truly
* @param {boolean} [mostRecentFirst] retreive the most recent message first or retreive from the converation start
* @return {Promise} Promise of the messages loaded
*/
loadConveration: function (jid, count, indexMessage=null, mostRecentFirst=true) {
// construct JSON
let json = [
"query",
{
{
epoch: this.msgCount.toString(),
type: "message",
jid: jid,
kind: mode,
kind: mostRecentFirst ? "before" : "after",
owner: "true",
count: count.toString()
},
@@ -50,20 +88,25 @@ module.exports = function(WhatsAppWeb) {
json[1].index = indexMessage.id
json[1].owner = indexMessage.fromMe ? "true" : "false"
}
return this.query(json, [10, 128])
}
// loads all the conversation you've had with given ID
WhatsAppWeb.prototype.getAllMessages = function (jid, onMessage, chunkSize=25, mode="before") {
},
/**
* Load the entire friggin conversation with a group or person
* @param {string} jid the id of the group or person
* @param {function} onMessage callback for every message retreived
* @param {number} [chunkSize] the number of messages to load in a single request
* @param {boolean} [mostRecentFirst] retreive the most recent message first or retreive from the converation start
*/
loadEntireConversation: function (jid, onMessage, chunkSize=25, mostRecentFirst=true) {
var offsetID = null
const loadMessage = () => {
return this.getMessages(jid, chunkSize, offsetID, mode)
return this.getMessages(jid, chunkSize, offsetID, mostRecentFirst)
.then (json => {
if (json[2]) {
// callback with most recent message first (descending order of date)
let lastMessage
if (mode === "before") {
if (mostRecentFirst) {
for (var i = json[2].length-1; i >= 0;i--) {
onMessage(json[2][i][2])
lastMessage = json[2][i][2]
@@ -87,5 +130,67 @@ module.exports = function(WhatsAppWeb) {
}
return loadMessage()
}
},
/**
* Create a group
* @param {string} title like, the title of the group
* @param {string[]} participants people to include in the group
* @return {Promise<[object, object]>}
*/
groupCreate: function (title, participants) {
return this.groupQuery ("create", null, title, participants)
},
/**
* Leave a group
* @param {string} jid the ID of the group
* @return {Promise<[object, object]>}
*/
groupLeave: function (jid) {
return this.groupQuery ("leave", jid)
},
/**
* Update the title of the group
* @param {string} jid the ID of the group
* @param {string} title the new title of the group
* @return {Promise<[object, object]>}
*/
groupUpdateTitle: function (jid, title) {
return this.groupQuery ("subject", jid, title)
},
/**
* Add somebody to the group
* @param {string} jid the ID of the group
* @param {string[]} participants the people to add
* @return {Promise<[object, object]>}
*/
groupAdd: function (jid, participants) {
return this.groupQuery ("add", jid, null, participants)
},
/**
* Remove somebody from the group
* @param {string} jid the ID of the group
* @param {string[]} participants the people to remove
* @return {Promise<[object, object]>}
*/
groupRemove: function (jid, participants) {
return this.groupQuery ("remove", jid, null, participants)
},
/**
* Make someone admin on the group
* @param {string} jid the ID of the group
* @param {string[]} participants the people to make admin
* @return {Promise<[object, object]>}
*/
groupMakeAdmin: function (jid, participants) {
return this.groupQuery ("promote", jid, null, participants)
},
/**
* Get the invite link of the group
* @param {string} jid the ID of the group
* @return {Promise<string>}
*/
groupInviteCode: function (jid) {
const json = ["query", "inviteCode", jid]
return this.query (json).then (([json, _]) => json.code)
}
}