client-web/src/xmpp.ts
import xmpp, { xml } from "@xmpp/client";
import { Client } from "@xmpp/client";
import { CONFERENCEDOMAIN, DOMAIN, SERVICE } from "./constants";
import { useStoreState } from "./store";
import { walletToUsername } from "./utils/walletManipulation";
import { XmppHandler } from "./xmppHandler";
const xmppMessagesHandler = new XmppHandler();
export class XmppClass {
public client!: Client;
init(walletAddress: string, password: string) {
if (!password) {
return;
}
if (this.client) {
return;
}
this.client = xmpp.client({
service: SERVICE,
username: walletToUsername(walletAddress),
password,
});
this.client.start();
this.client.on("online", (jid) => xmppMessagesHandler.getListOfRooms(this));
this.client.on("stanza", xmppMessagesHandler.onMessageHistory);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onRealtimeMessage(stanza)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onGetLastMessageArchive(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.connectToUserRooms(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onLastMessageArchive(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onComposing(stanza)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onInvite(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onBlackList(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onGetRoomInfo(stanza)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onGetRoomMemberInfo(stanza)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onChangeDescription(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onChangeRoomName(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onPresenceInRoom(stanza)
);
this.client.on("stanza", (stanza) => xmppMessagesHandler.onBan(stanza));
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onRemoveFromBlackList(stanza, this)
);
this.client.on("stanza", (stanza) => xmppMessagesHandler.onBan(stanza));
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onNewSubscription(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onRoomDesignChange(stanza, this)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onSendReplaceMessageStanza(stanza)
);
this.client.on("stanza", (stanza) =>
xmppMessagesHandler.onDeleteMessageStanza(stanza)
);
this.client.on("offline", () => console.log("offline"));
this.client.on("error", (error) => {
console.log("xmmpp on error ", error);
this.stop();
console.log("xmmpp error, terminating collection");
});
}
stop() {
if (this.client) {
this.client.stop();
return;
}
}
setRoomImage = (
roomAddress: string,
roomThumbnail: string,
roomBackground: string,
type: string
) => {
const message = xml(
"iq",
{
from: this.client.jid?.toString(),
id: type === "icon" ? "setRoomImage" : "setRoomBackground",
type: "set",
},
xml("query", {
xmlns: "ns:getrooms:setprofile",
room_thumbnail: roomThumbnail,
room_background: roomBackground,
room: roomAddress + CONFERENCEDOMAIN,
})
);
this.client.send(message);
};
subsribe(address: string) {
const message = xml(
"iq",
{
from: this.client?.jid?.toString(),
to: address,
type: "set",
id: "newSubscription",
},
xml(
"subscribe",
{ xmlns: "urn:xmpp:mucsub:0", nick: this.client?.jid?.getLocal() },
xml("event", { node: "urn:xmpp:mucsub:nodes:messages" }),
xml("event", { node: "urn:xmpp:mucsub:nodes:presence" }),
xml("event", { node: "urn:xmpp:mucsub:nodes:subscribers" }),
xml("event", { node: "urn:xmpp:mucsub:nodes:subject" })
)
);
this.client.send(message);
}
discoInfo() {
const message = xml(
"iq",
{
from: this.client?.jid?.toString(),
to: this.client?.jid?.getDomain(),
type: "get",
id: "discover",
},
xml("query", { xmlns: "http://jabber.org/protocol/disco#info" })
);
this.client.send(message);
}
unsubscribe(address: string) {
const message = xml(
"iq",
{
from: this.client?.jid?.toString(),
to: address,
type: "set",
id: "unsubscribe",
},
xml("unsubscribe", { xmlns: "urn:xmpp:mucsub:0" })
);
this.client.send(message);
}
getRooms() {
const message = xml(
"iq",
{
type: "get",
from: this.client.jid?.toString(),
id: "getUserRooms",
},
xml("query", { xmlns: "ns:getrooms" })
);
this.client.send(message);
}
getVcard(username: string) {
if (username !== this.client.jid?.getLocal()) {
// get other vcard
const message = xml(
"iq",
{
from: this.client.jid?.toString(),
id: "vCardOther",
to: username + "@" + this.client.jid?.getDomain(),
type: "get",
},
xml("vCard", { xmlns: "vcard-temp" })
);
this.client.send(message);
} else {
const message = xml(
"iq",
{
from: username + "@" + this.client.jid?.getDomain(),
id: "vCardMy",
type: "get",
},
xml("vCard", {
xmlns: "vcard-temp",
})
);
this.client.send(message);
}
}
presence() {
this.client.send(xml("presence"));
}
botPresence(room: string) {
const xmlMsg = xml(
"presence",
{
from: this.client.jid?.toString(),
to: `${room}/${this.client.jid?.getLocal()}`,
},
xml("x", "http://jabber.org/protocol/muc")
);
this.client.send(xmlMsg);
}
roomPresence(room: string) {
const presence = xml(
"presence",
{
from: this.client.jid?.toString(),
to: `${room}/${this.client.jid?.getLocal()}`,
},
xml("x", "http://jabber.org/protocol/muc")
);
this.client.send(presence);
}
leaveTheRoom(room: string) {
const presence = xml("presence", {
from: this.client.jid?.toString(),
to: room + "/" + this.client.jid?.getLocal(),
type: "unavailable",
});
this.client.send(presence);
}
presenceInRoom(room: string) {
const presence = xml(
"presence",
{
from: this.client.jid?.toString(),
to: room + "/" + this.client.jid?.getLocal(),
id: "presenceInRoom",
},
xml("x", "http://jabber.org/protocol/muc")
);
this.client.send(presence);
}
getRoomArchiveStanza(chatJID: string, amount: number) {
let message = xml(
"iq",
{
type: "set",
to: chatJID,
id: "GetArchive",
},
xml(
"query",
{ xmlns: "urn:xmpp:mam:2" },
xml(
"set",
{ xmlns: "http://jabber.org/protocol/rsm" },
xml("max", {}, String(amount)),
xml("before")
)
)
);
this.client.send(message);
}
getPaginatedArchive = (
chatJID: string,
firstUserMessageID: string,
amount: number
) => {
if (xmppMessagesHandler.lastMsgId === firstUserMessageID) {
return;
}
xmppMessagesHandler.isGettingMessages = true;
xmppMessagesHandler.isGettingFirstMessages = true;
useStoreState.getState().setLoaderArchive(true);
const message = xml(
"iq",
{
type: "set",
to: chatJID,
id: "paginatedArchive",
},
xml(
"query",
{ xmlns: "urn:xmpp:mam:2" },
xml(
"set",
{ xmlns: "http://jabber.org/protocol/rsm" },
xml("max", {}, String(amount)),
xml("before", {}, firstUserMessageID)
)
)
);
this.client.send(message);
};
getLastMessageArchive(chat_jid: string) {
xmppMessagesHandler.isGettingMessages = true;
let message = xml(
"iq",
{
type: "set",
to: chat_jid,
id: "GetArchive",
},
xml(
"query",
{ xmlns: "urn:xmpp:mam:2" },
xml(
"set",
{ xmlns: "http://jabber.org/protocol/rsm" },
xml("max", {}, "1"),
xml("before")
)
)
);
this.client.send(message);
}
sendMessage(
roomJID: string,
firstName: string,
lastName: string,
photo: string,
walletAddress: string,
userMessage: string,
notDisplayedValue?: string
) {
const message = xml(
"message",
{
to: roomJID,
type: "groupchat",
id: "sendMessage",
},
xml("data", {
xmlns: SERVICE,
senderFirstName: firstName,
senderLastName: lastName,
photoURL: photo,
senderJID: this.client.jid?.toString(),
senderWalletAddress: walletAddress,
roomJid: roomJID,
isSystemMessage: false,
tokenAmount: 0,
quickReplies: [],
notDisplayedValue: notDisplayedValue ? notDisplayedValue : "",
}),
xml("body", {}, userMessage)
);
this.client.send(message);
}
sendMessageStanza = (roomJID: string, messageText: string, data: any) => {
const message = xml(
"message",
{
id: "sendMessage",
type: "groupchat",
from: this.client.jid?.toString(),
to: roomJID,
},
xml("body", {}, messageText),
xml("data", {
xmlns: SERVICE,
senderJID: this.client.jid?.toString(),
...data,
})
);
this.client.send(message);
};
sendSystemMessage(
roomJID: string,
firstName: string,
lastName: string,
walletAddress: string,
userMessage: string,
amount: number,
receiverMessageId: number,
transactionId: string
) {
const message = xml(
"message",
{
to: roomJID,
type: "groupchat",
id: "sendMessage",
},
xml("data", {
xmlns: SERVICE,
senderFirstName: firstName,
senderLastName: lastName,
senderJID: this.client.jid?.toString(),
senderWalletAddress: walletAddress,
roomJid: roomJID,
isSystemMessage: true,
tokenAmount: amount,
receiverMessageId: receiverMessageId,
transactionId,
}),
xml("body", {}, userMessage)
);
this.client.send(message);
}
sendMediaMessageStanza(roomJID: string, data: any) {
const message = xml(
"message",
{
id: "sendMessage",
type: "groupchat",
from: this.client.jid?.toString(),
to: roomJID,
},
xml("body", {}, "media"),
xml("store", { xmlns: "urn:xmpp:hints" }),
xml("data", {
xmlns: SERVICE,
senderJID: this.client.jid?.toString(),
senderFirstName: data.firstName,
senderLastName: data.lastName,
senderWalletAddress: data.walletAddress,
isSystemMessage: false,
tokenAmount: "0",
receiverMessageId: "0",
mucname: data.chatName,
photoURL: data.userAvatar ? data.userAvatar : "",
isMediafile: true,
createdAt: data.createdAt,
expiresAt: data.expiresAt,
fileName: data.fileName,
isVisible: data.isVisible,
location: data.location,
locationPreview: data.locationPreview,
mimetype: data.mimetype,
originalName: data.originalName,
ownerKey: data.ownerKey,
size: data.size,
duration: data?.duration,
updatedAt: data.updatedAt,
userId: data.userId,
waveForm: data.waveForm,
attachmentId: data?.attachmentId,
wrappable: data?.wrappable,
nftId: data?.nftId,
isReply: data?.isReply,
mainMessage: data?.mainMessage,
roomJid: data?.roomJid,
})
);
this.client.send(message);
}
createNewRoom(to: string) {
let message = xml(
"presence",
{
id: "createRoom",
from: this.client.jid?.toString(),
to:
to +
CONFERENCEDOMAIN +
"/" +
this.client.jid?.toString().split("@")[0],
},
xml("x", "http://jabber.org/protocol/muc")
);
// console.log(message.toString());
this.client.send(message);
}
roomConfig(to: string, data: { roomName: string; roomDescription?: string }) {
const message = xml(
"iq",
{
from: this.client.jid?.toString(),
id: "roomConfig",
to: to + CONFERENCEDOMAIN,
type: "set",
},
xml(
"query",
{ xmlns: "http://jabber.org/protocol/muc#owner" },
xml(
"x",
{ xmlns: "jabber:x:data", type: "submit" },
xml(
"field",
{ var: "FORM_TYPE" },
xml("value", {}, "http://jabber.org/protocol/muc#roomconfig")
),
xml(
"field",
{ var: "muc#roomconfig_roomname" },
xml("value", {}, data.roomName)
),
xml(
"field",
{ var: "muc#roomconfig_roomdesc" },
xml("value", {}, data.roomDescription)
)
)
)
);
this.client.send(message);
}
getArchive = (userJID: string) => {
let message = xml(
"iq",
{ type: "set", id: userJID },
xml(
"query",
{ xmlns: "urn:xmpp:mam:2", queryid: "userArchive" },
xml("set", { xmlns: "http://jabber.org/protocol/rsm" }, xml("before"))
)
);
this.client.send(message);
};
sendInvite(from: string, to: string, otherUserId: string) {
const stanza = xml(
"message",
{
from: this.client.jid?.toString().split("/")[0],
to: to,
},
xml(
"x",
"http://jabber.org/protocol/muc#user",
xml(
"invite",
{ to: otherUserId + DOMAIN },
xml("reason", {}, "Hey, this is the place with amazing cookies!")
)
)
);
this.client.send(stanza);
}
setOwner(to: string) {
const message = xml(
"iq",
{
to: to + CONFERENCEDOMAIN,
from: this.client.jid?.toString(),
id: "setOwner",
type: "get",
},
xml("query", { xmlns: "http://jabber.org/protocol/muc#owner" })
);
this.client.send(message);
}
getRoomInfo = (roomJID: string) => {
const message = xml(
"iq",
{
from: this.client.jid?.toString(),
id: "roomInfo",
to: roomJID,
type: "get",
},
xml("query", { xmlns: "http://jabber.org/protocol/disco#info" })
);
this.client.send(message);
};
isComposing = (walletAddress: string, chatJID: string, fullName: string) => {
const message = xml(
"message",
{
from: this.client.jid?.toString(),
to: chatJID,
id: "isComposing",
type: "groupchat",
},
xml("composing", {
xmlns: "http://jabber.org/protocol/chatstates",
}),
xml("data", {
xmlns: SERVICE,
fullName: fullName,
manipulatedWalletAddress: walletAddress,
})
);
this.client.send(message);
};
pausedComposing = (walletAddress: string, chatJID: string) => {
const message = xml(
"message",
{
from: this.client.jid?.toString(),
to: chatJID,
id: "pausedComposing",
type: "groupchat",
},
xml("paused", {
xmlns: "http://jabber.org/protocol/chatstates",
}),
xml("data", {
xmlns: SERVICE,
manipulatedWalletAddress: walletAddress,
})
);
this.client.send(message);
};
blacklistUser = (userJIDToBlacklist: string) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "set",
id: "addToBlackList",
},
xml("query", {
xmlns: "ns:deepx:muc:user:block",
user: userJIDToBlacklist,
})
);
this.client.send(stanza);
};
getBlackList = () => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "get",
id: "blackList",
},
xml("query", {
xmlns: "ns:deepx:muc:user:blocklist",
})
);
this.client.send(stanza);
};
getRoomMemberInfo = (roomJID) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "get",
id: "roomMemberInfo",
},
xml("query", {
xmlns: "ns:room:last",
room: roomJID,
})
);
this.client.send(stanza);
};
changeRoomDescription = (roomJID: string, newDescription: string) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
id: "changeRoomDescription",
to: roomJID,
type: "set",
},
xml(
"query",
{ xmlns: "http://jabber.org/protocol/muc#owner" },
xml(
"x",
{ xmlns: "jabber:x:data", type: "submit" },
xml(
"field",
{ var: "FORM_TYPE" },
xml("value", {}, "http://jabber.org/protocol/muc#roomconfig")
),
xml(
"field",
{ var: "muc#roomconfig_roomdesc" },
xml("value", {}, newDescription)
)
)
)
);
this.client.send(stanza);
};
changeRoomName = (roomJID: string, newRoomName: string) => {
console.log(roomJID, newRoomName);
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
id: "changeRoomName",
to: roomJID,
type: "set",
},
xml(
"query",
{ xmlns: "http://jabber.org/protocol/muc#owner" },
xml(
"x",
{ xmlns: "jabber:x:data", type: "submit" },
xml(
"field",
{ var: "FORM_TYPE" },
xml("value", {}, "http://jabber.org/protocol/muc#roomconfig")
),
xml(
"field",
{ var: "muc#roomconfig_roomname" },
xml("value", {}, newRoomName)
)
)
)
);
this.client.send(stanza);
};
banUserStanza = (banUserId: string, roomJID: string) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "set",
id: "ban",
},
xml("query", {
xmlns: "ns:deepx:muc:user:ban",
action: "ban",
user: banUserId,
type: "room",
room: roomJID,
time: "2592000",
comment: "Ban",
})
);
this.client.send(stanza);
};
unbanUserStanza = (unbanUserId: string, roomJID: string) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "set",
id: "unBan",
},
xml("query", {
xmlns: "ns:deepx:muc:user:ban",
action: "unban",
user: unbanUserId,
type: "room",
room: roomJID,
})
);
this.client.send(stanza);
};
removeUserFromBlackList = (userAddressToRemoveFromBlacklist: string) => {
const stanza = xml(
"iq",
{
from: this.client.jid?.toString(),
type: "set",
id: "removeFromBlackList",
},
xml("query", {
xmlns: "ns:deepx:muc:user:unblock",
user: userAddressToRemoveFromBlacklist,
})
);
this.client.send(stanza);
};
//stanza to edit/replace message.
sendReplaceMessageStanza = (
roomJID: string,
replaceText: string,
messageId: string,
data: any
) => {
const stanza = xml(
"message",
{
from: this.client.jid?.toString(),
id: "replaceMessage",
type: "groupchat",
to: roomJID,
},
xml("body", {}, replaceText),
xml("replace", {
id: messageId,
xmlns: "urn:xmpp:message-correct:0",
}),
xml("data", {
xmlns: "http://dev.dxmpp.com",
senderJID: this.client.jid?.toString(),
...data,
})
);
this.client.send(stanza);
};
//stanza to delete message
deleteMessageStanza = (roomJid: string, messageId: string) => {
// <message
// from="olek@localhost"
// id="1635229272917013"
// to="test_olek@conference.localhost"
// type="groupchat">
// <body>Wow</body>
// <delete id="1635229272917013" />
// </message>;
const stanza = xml(
"message",
{
from: this.client.jid?.toString(),
to: roomJid,
id: "deleteMessageStanza",
type: "groupchat",
},
xml("body", "wow"),
xml("delete", {
id: messageId,
})
);
this.client.send(stanza);
};
}
export default new XmppClass();