I use socket.io and socket.io-client to create chat user - operator. I've made connections, all works good, but message sending has weird behavior.
Like I send message from first client to room in socket and don't see it, but other client can
When I send second message, the first sent msg just changes for the second one
I see this all messages in my Map on backend(I don't use DB yet) but can't see it on client side.
server
app.get("/rooms/:id", (req, res) => {
const roomId = req.params.id;
const obj = rooms.has(roomId)
? { messages: [...rooms.get(roomId).get("messages").values()] }
: { messages: [] };
res.send(obj);
});
app.post("/rooms", (req, res) => {
const { roomId, name } = req.body;
if (!rooms.has(roomId)) {
rooms.set(
roomId,
new Map([
["users", new Map()],
["messages", []],
])
);
}
res.json([...rooms.values()]);
});
io.on("connection", (socket) => {
socket.on("ROOM:JOIN", ({ roomId, name }) => {
socket.join(roomId);
rooms.get(roomId).get("users").set(socket.id, name);
const users = rooms && [...rooms.get(roomId).get("users").values()];
socket.to(roomId).emit("ROOM:JOINED", users);
});
socket.on("ROOM:NEW_MESSAGE", ({ roomId, name, text }) => {
const obj = { name, text };
console.log(rooms.get(roomId).get("messages"));
rooms.get(roomId).get("messages").push(obj);
socket.to(roomId).emit("ROOM:NEW_MESSAGE", obj);
});
socket.on("disconnect", () => {
rooms.forEach((value, roomId) => {
if (value.get("users").delete(socket.id)) {
const users = [...value.get("users").values()];
socket.to(roomId).emit("ROOM:JOINED", users);
}
});
});
});
client side
const [messageValue, setMessageValue] = useState<string>("");
const [freshData, setFreshData] = useState<Message[]>([]);
console.log(freshData);
const onSendMessage = () => {
socket.emit("ROOM:NEW_MESSAGE", {
roomId: socketData.roomId,
text: messageValue,
name: socketData.name,
});
setMessageValue("");
};
const getFreshData = async () => {
const { data } = await axios.get(
`http://localhost:4444/rooms/${socketData.roomId}`
);
setFreshData(data.messages);
};
useEffect(() => {
if (join) {
socket.emit("ROOM:JOIN", socketData);
getFreshData();
socket.on("ROOM:JOINED", (users) => {
console.log("new user", users);
});
}
}, [join]);
useEffect(() => {
socket.on("ROOM:NEW_MESSAGE", (message) =>
setFreshData([...freshData, message])
);
socket.on("ROOM:JOINED", (users) => {
console.log("new user", users);
});
}, []);
and just map through all messages, that I should get from server
Where I could make a mistake ? Thank you
So I had a mistake on client, I need to call socket function in other useEffect with dependency onSendMessage like this:
useEffect(() => {
socket.on("ROOM:NEW_MESSAGE", (message) =>
setFreshData([...freshData, message])
);
}, [onSendMessage]);
and to show your sent messages I need to make onSendMessage update state with messages like this:
const onSendMessage = () => {
socket.emit("ROOM:NEW_MESSAGE", {
roomId: socketData.roomId,
text: messageValue,
name: socketData.name,
});
setFreshData([...freshData, { text: messageValue, name: socketData.name }]);
setMessageValue("");
};
And it works !
Related
I am trying to build a simple peer to peer connection, 1 to 1, where a user shares his video peer to peer and we end up watching our localStream and the remoteOne on both sides.
I started building the webrtc connection with agoraRTM (for the signaling part) and it worked fine. I tried to change the signaling to use socket.io instead of agoraRTM.
In the end the app has a weird behaviour (probably related to socketIO) where if I run the first time it works (first time after websocket server relaunch), then it just stops working.
Here is my code:
main.js (webRTC and client socket.io)
let token = null;
let uid = String(Math.floor(Math.random() * 10000));
let queryString = window.location.search;
const urlSearch = new URLSearchParams(queryString);
const room = urlSearch.get("room");
if (!room) {
window.location = "lobby.html";
}
let client;
let channel;
let socket;
const constraints = {
video: {
width: { min: 640, ideal: 1920, max: 1920 },
height: { min: 480, ideal: 1080, max: 1920 },
aspectRatio: 1.777777778,
},
audio: false,
};
const servers = {
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
"stun:stun3.l.google.com:19302",
"stun:stun4.l.google.com:19302",
],
},
],
};
const localVideoRef = document.getElementById("localVideo");
const remoteVideoRef = document.getElementById("remoteVideo");
let localStream;
let remoteStream;
let peerConnection;
const configureSignaling = async () => {
socket = await io.connect("http://localhost:4000");
socket.emit("join", { room, uid });
socket.on("MemberJoined", handleMemberJoined);
socket.on("MessageFromPeer", handleMessageFromPeer);
socket.on("MemberLeft", handleMemberLeft)
};
const handleMemberLeft = async () => {
remoteVideoRef.style.display = "none";
};
const handleMessageFromPeer = (m, uid) => {
const message = JSON.parse(m.text);
if(message.type !== "candidate") {
console.log('handleMessageFromPeer: ', message, uid)
}
if (message.type === "offer") {
createAnswer(uid, message.offer);
}
if (message.type === "answer") {
addAnswer(message.answer);
}
if (message.type === "candidate") {
if (peerConnection && peerConnection.currentRemoteDescription) {
peerConnection.addIceCandidate(message.candidate);
}
}
};
const createLocalStream = async () => {
localStream = await navigator.mediaDevices.getUserMedia(constraints);
localVideoRef.srcObject = localStream;
};
const init = async () => {
await configureSignaling();
await createLocalStream();
};
const handleMemberJoined = async (uid) => {
createOffer(uid);
};
let createOffer = async (uid) => {
await createPeerConnection(uid);
let offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
socket.emit(
"sendMessageToPeer",
{ text: JSON.stringify({ type: "offer", offer: offer }) },
uid
);
};
let createPeerConnection = async (uid) => {
peerConnection = new RTCPeerConnection(servers);
remoteStream = new MediaStream();
remoteVideoRef.srcObject = remoteStream;
remoteVideoRef.style.display = "block";
remoteVideoRef.classList.add("remoteFrame");
if (!localStream) {
await createLocalStream();
}
localStream.getTracks().forEach((track) => {
peerConnection.addTrack(track, localStream);
});
peerConnection.ontrack = (event) => {
event.streams[0].getTracks().forEach((track) => {
remoteStream.addTrack(track);
});
};
peerConnection.onicecandidate = (event) => {
if (event.candidate) {
socket.emit(
"sendMessageToPeer",
{
text: JSON.stringify({
type: "candidate",
candidate: event.candidate,
}),
},
uid
);
}
};
};
let createAnswer = async (uid, offer) => {
await createPeerConnection(uid);
await peerConnection.setRemoteDescription(offer);
const answer = await peerConnection.createAnswer();
await peerConnection.setLocalDescription(answer);
socket.emit(
"sendMessageToPeer",
{ text: JSON.stringify({ type: "answer", answer: answer }) },
uid
);
};
let addAnswer = async (answer) => {
if (!peerConnection.currentRemoteDescription) {
peerConnection.setRemoteDescription(answer);
}
};
let onLogout = async () => {
remoteVideoRef.classList.remove("remoteFrame");
await socket.emit('onLeaveRoom', room)
};
let onToggleCamera = async () => {
const videoTrack = localStream
.getTracks()
.find((track) => track.kind === "video");
if (videoTrack.enabled) {
videoTrack.enabled = false;
document.getElementById("camera-btn").style.backgroundColor =
"rgb(255, 80, 80)";
} else {
videoTrack.enabled = true;
document.getElementById("camera-btn").style.backgroundColor =
"rgb(179, 102, 249, .9)";
}
};
let onToggleMic = async () => {
const audioTrack = localStream
.getTracks()
.find((track) => track.kind === "audio");
if (audioTrack.enabled) {
audioTrack.enabled = false;
document.getElementById("mic-btn").style.backgroundColor =
"rgb(255, 80, 80)";
} else {
audioTrack.enabled = true;
document.getElementById("mic-btn").style.backgroundColor =
"rgb(179, 102, 249, .9)";
}
};
window.addEventListener("beforeunload", onLogout);
init();
index.js (websocket server)
const express = require("express");
const app = express();
const PORT = 4000;
const http = require("http").Server(app);
const cors = require("cors");
app.use(cors());
const socketIO = require("socket.io")(http, {
cors: {
origin: "http://127.0.0.1:5501",
},
});
//Add this before the app.get() block
socketIO.on("connection", (socket) => {
console.log(`⚡: ${socket.id} user just connected!`);
console.log('CONNECTED')
socket.on('join', async ({room, uid}) => {
await socket.join(room);
const connectedUsers = await socket.in(room).fetchSockets()
console.log('room:', connectedUsers.length);
if(connectedUsers.length) {
console.log('PUMBA')
socket.broadcast.emit('MemberJoined', uid)
}
})
socket.on("onLeaveRoom", async (room) => {
await socket.leave(room)
socket.broadcast.emit('MemberLeft')
})
socket.on("disconnect", async (room) => {
socket.broadcast.emit('MemberLeft')
})
socket.on('sendMessageToPeer', (data, uid) => {
console.log('sendMessageTOPEER', uid)
socket.broadcast.emit('MessageFromPeer', data, uid )
});
});
app.get("/api", (req, res) => {
res.json({
message: "Hello world",
});
});
http.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
I tried a couple of different things, like checking how many users are in the room, the specific websocket ids, if the sdp offer and answer are being sent after I connect a new user (this is working correctly), not sure what is failling, any help? Thanks!
I am trying to create a bot in Slack called "Chochon", the problem is that when I receive the event "app_mention", chochon responds more than once several times in a row, instead of sending 1 message and stopping until they mention it again.
This is my code, chochon function:
socketModeClient.on('app_mention', async ({ event }) => {
try {
console.log(event);
let userBox = await Chochon.users.info({ user: event.user });
let userProfile = userBox.user.profile;
console.log(cli.green(`Event received : [ ${event.type} ] from [ ${userProfile.display_name} ]`));
// Respond to the event
Chochon.chat.postMessage({
channel: event.channel,
text: `Hello <#${event.user}>, I'm Chochon!, I'm a bot that can help you to manage your team.`
});
} catch (error) {
console.error(error);
}
});
The slack client:
Full code:
// Dependencies :
const dotenv = require('dotenv').config();
const path = require('path');
const cli = require('cli-color');
// Web client [CLI]
const { WebClient } = require('#slack/web-api');
const Chochon = new WebClient(process.env.SLACK_BOT_TOKEN.trim());
// Socket IO
const { SocketModeClient } = require('#slack/socket-mode');
const appToken = process.env.SLACK_APP_TOKEN;
const socketModeClient = new SocketModeClient({ appToken });
socketModeClient.start();
// Internal functions
//const eventManager = require(path.resolve(__dirname, './utils/events/manager'));
socketModeClient.on('app_mention', async ({ event }) => {
try {
console.log(event);
let userBox = await Chochon.users.info({ user: event.user });
let userProfile = userBox.user.profile;
console.log(cli.green(`Event received : [ ${event.type} ] from [ ${userProfile.display_name} ]`));
// Respond to the event
Chochon.chat.postMessage({
channel: event.channel,
text: `Hello <#${event.user}>, I'm Chochon!, I'm a bot that can help you to manage your team.`
});
} catch (error) {
console.error(error);
}
});
socketModeClient.on('slash_commands', async ({ body, ack }) => {
if (body.command === "/ping") {
console.log(cli.green(`Event received : [ ${body.command} ]`));
await ack({"text": "I got it, pong!"});
}
});
I am at a complete loss as to why this is not working, I am new to using Hooks in react however want to try.
This app basically connects sockets.io to the server using sockets-auth server emits the time every 1s <- this shows me that the connection is definitely live. It then uses sockets.emit to receive an array of data, this functions. The part that doesn't is a simple button press fails to achieve anything (see both 'Save Changes' buttons at bottom of React element). No error, no response, no acknowledgment at all. I have tried it inline, in its own function. The exact same server routes are functional simultaneously running a separate app with class components.
Help would be much appreciated. Anyway here is some code..
Client-Side (React.js)
import React, { Component,useState, useEffect } from "react";
import io from "socket.io-client";
import './Secret.css'
const Secret = () => {
const [time, setTime] = useState('');
const [userlist, setUserlist] = useState([]);
const socketUrl = 'http://localhost:3001';
let socket = io(socketUrl, {
autoConnect: false,
});
useEffect(() => {
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React POST Request Example' })
};
fetch('/api/connectsocket', requestOptions)
.then(async response => {
const data = await response.json();
if (!response.ok) {
const error = (data && data.message) || response.status;
return Promise.reject(error);
}
console.log(data)
connectSocket(data)
})
.catch(error => {
console.error('There was an error!', error);
});
}, [socketUrl]);
const connectSocket= (data)=>{
let dataUser = data
console.log(dataUser.email)
let error = null;
socket.on('connect', () => {
console.log('Connected');
socket.emit('authentication', {
token: dataUser.email,
i: dataUser.i
});
});
socket.on('unauthorized', (reason) => {
console.log('Unauthorized:', reason);
error = reason.message;
socket.disconnect();
});
socket.on('disconnect', (reason) => {
console.log(`Disconnected: ${error || reason}`);
error = null;
});
socket.on("admin connected", data => {
socket.emit('admin userlist', { get:'x',for:'who' }, (error) => {
if(error) {
alert(error);
}
});
console.log(data)
});
socket.on("admin user list", data => {
setUserlist(data)
console.log(data)
});
socket.on("FromAPI", data => {
setTime(data)
console.log(data)
});
socket.open();
}
const sendMessage = (x)=>{
console.log(x)
socket.emit('hello', 'JSON.stringify(x)');
}
const doSomething = ()=>{
socket.emit('chatmessage', {msg:"Hello"});
}
return (
<div>
<div className="outerContainer">
<div className="container">
{time}
<button onClick={sendMessage}>Save Changes</button>
<button onClick={doSomething}>Save Changes</button>
{userlist.map(user => (
<tr key={user.id} value={user.id}>
<td>{user.email}</td>
<td>{user.email}</td>
<td>{user.email}</td>
</tr>
))}
</div>
</div>
</div>
);
}
export default Secret
Server-side (Node.js)
const http = require('http');
const cors = require('cors');
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const io = require('socket.io')();
const socketAuth = require('socketio-auth');
//custom modules
const router = require('./modules/router');
const db = require('./modules/db.js');
const prettyDate = require('./modules/prettyDate.js');
const sortArray = require('./modules/sortArray.js');
const app = express();
const server = http.createServer(app);
io.attach(server);
app.use(cors()); ///delete for production
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload({
createParentPath: true
}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(router);
app.use(express.static('public'))
db.i12345.sessions.persistence.setAutocompactionInterval(400)
////Sessions Store; not important if you want to run the code without
function setUser(id,user,i){
console.log('setuser')
let institution = i
db[institution].sessions.find({ user:user }, function (err, docs) {
if(docs.length){
db[institution].sessions.update({user:user }, { $set: { id: id } }, { multi: true }, function (err, numReplaced) {
});
} else {
var d = new Date();
var n = d.getTime();
var doc = { user: user
, id: id
, t:n
};
db[institution].sessions.insert(doc, function (err, newDoc) {
});
}
});
}
///user verification; could easily mock; if wanting to actually run code
async function verifyUser (token,i) {
var institution =i
return new Promise((resolve, reject) => {
// setTimeout to mock a cache or database call
setTimeout(() => {
var user = new Promise((resolve,reject) =>{
db[institution].users.find({email:token}, function (err, docs) {
if(docs.length){
resolve(docs);
} else {
reject(false)
}
});
});
if (!user) {
return reject('USER_NOT_FOUND');
}
return resolve(user);
}, 200);
});
}
//// Sockets auth implementation
socketAuth(io, {
authenticate: async (socket, data, callback) => {
const { token, i } = data;
console.log(data)
try {
const user = await verifyUser(token, i);
socket.user = user;
socket.i = i
console.log(i)
return callback(null, true);
} catch (e) {
console.log(`Socket ${socket.id} unauthorized.`);
return callback({ message: 'UNAUTHORIZED' });
}
},
postAuthenticate: async (socket) => {
console.log(`Socket ${socket.id} authenticated.`);
console.log(socket.user)
setUser(socket.id,socket.user, socket.i)
socket.emit('empty list', {queryList:true});
io.emit('admin connected', {admin:true});
socket.conn.on('packet', async (packet) => {
if (socket.auth && packet.type === 'ping') {
}
});
socket.on('chatmessage', (msg) => {
io.emit('chatmessage', msg);
console.log(msg);
});
socket.on('hello', (msg) => {
io.emit('chatmessage', msg);
console.log(msg);
});
socket.on('get tasks', (get) => {
let i = socket.i
let user = socket.user
getTasksChunk(get,i,user)
});
socket.on('admin userlist', (get) => {
let i = socket.i
let user = socket.user
adminGetUserList(get,i,user)
});
socket.on('admin roles', (data) => {
let i = socket.i
let user = socket.user
console.log(data)
console.log('reaced')
});
interval = setInterval(() => getApiAndEmit(socket), 1000);
},
disconnect: async (socket) => {
console.log(`Socket ${socket.id} disconnected.`);
if (socket.user) {
}
},
})
function getTasksChunk(get,i, user){
console.log(get,i,user);
let institution = i
db[institution].tasks24.find({}, async function (err, docs) {
if(docs.length){
for(i=0;i<docs.length;i++){
docs[i].location = `Ward: ${docs[i].location.Ward} Bed: ${docs[i].location.Bed}`
docs[i].patient = docs[i].patient.join(' | ')
docs[i].timestamp = prettyDate(new Date(+docs[i].timestamp))
}
console.log(docs)
let sorted = await sortArray(docs,'timestamp')
let chunk = sorted.slice(0,10)
io.emit('tasks in', chunk);
} else {
}
});
}
const getApiAndEmit = socket => {
const response = new Date();
// Emitting a new message. Will be consumed by the client
socket.emit("FromAPI", response);
};
///////ADMIN????????
function adminGetUserList(get,i,user){
var institution = i
console.log('hello')
db[institution].users.find({}, async function (err, docs) {
if(docs.length){
console.log(docs)
let sorted = await sortArray(docs,'timestamp')
io.emit('admin user list', sorted);
} else {
}
});
}
server.listen(process.env.PORT || 3001, () => console.log(`Server has started.`));
You must store your socket instance in a ref otherwise you would loose the connected socket instance when your component re-renders.
In short you need the socket reference to be the same across renders
const socketUrl = 'http://localhost:3001';
let socket = useRef(null);
useEffect(() => {
socket.current = io(socketUrl, {
autoConnect: false,
});
...
}, [socketUrl]);
Now note that whereever you are using socket you would use socket.current.
Ex:
socket,.current.on('hello', (msg) => {
io.emit('chatmessage', msg);
console.log(msg);
});
I have a vue.js/node/socket.io chat application. I need to create a list of online users that will stay up to date when users connect or disconnect. I'm trying using this code, but I'm not able to update the users list when someone join the room. How I can fix this?
'use strict';
const express = require('express');
const socketIO = require('socket.io');
const PORT = process.env.PORT || 3000;
const INDEX = '/index.html';
// TODO: controllo query url
const server = express()
.use('/modules', express.static(__dirname + '/node_modules'))
.use('/assets', express.static(__dirname + '/assets'))
.use((req, res) => res.sendFile(INDEX, { root: __dirname }))
.listen(PORT, () => console.log(`Listening on ${PORT}`));
const io = socketIO(server);
let connectedUsers = [];
io.on('connection', (socket) => {
console.log('Connected peer: '+ socket.id);
socket.on('accessRoom', (username,room) => {
connectedUsers = { nickname: username, id: socket.id }
socket.join(room, (err) => {
socket.emit('accessStatus', 'done');
console.log(this)
})
updateUsersList()
})
socket.emit('channelStatus', socketData)
socket.emit('message', socket.id, 'connected')
socket.on('message', (id, msg) => {
socket.broadcast.emit('message', id, msg);
})
socket.on('disconnect', () => {
console.log('Disconnected')
})
function updateUsersList(){
socket.emit('usersList', connectedUsers)
}
});
io.on('ping', (socket) => {
console.log(socket);
io.emit('pong');
});
vuejs code
export default {
data () {
return {
isRegistered: false,
isConnected: false,
user: '',
message: '',
id: '',
channel: '',
usersList: []
}
},
mounted() {
this.pingServer()
this.updateUsersList()
io.on('pong', (data) => {
console.log(data);
})
io.on('channelStatus', (data) => {
if( data.status === 'connected' ){
this.id = data.IHMnumber;
this.isConnected = true;
console.log(data);
}
})
io.on('message', (from, msg) => {
console.log(from)
console.log(msg)
})
},
methods: {
pingServer(){
io.emit('ping')
},
connect(){
if( this.isRegistered === false){
this.user = this.user;
this.isRegistered = true;
console.log(this.isRegistered);
console.log(this.user);
io.open()
return this.user;
}
},
updateUsersList(){
io.on('usersList', (users) => {
console.log(users);
this.usersList.push(users);
})
},
sendMessage(){
console.log(this.message)
io.emit('message', this.id ,this.message)
}
}
}
Whit this code, the user that is creating the room will not recive the users list. For the users that will join the room instead, in the console I'm able to see that they are added to the array of users, but if someone joined the room, the event will not be logged in console with the updated info. Maybe I need to refactor the code, maybe I'm calling the updateUsersList in the wrong place?
First of all, if you divide users by rooms, send messages to their rooms https://socket.io/docs/server-api/#socket-to-room . Here I show you one of ways to solve your problem. Change type of 'connectedUsers', for example, to map, where keys will be room-name, value - array of users:
const connectedUsers = new Map();
To handle changes of user lists create method for join
joinToRoom(room, user) {
// create users array, if key not exists
if (!connectedUsers.has(room)) {
connectedUsers.set(room, []);
}
// add user to room array
connectedUsers.get(room).push(user);
// call update function
updateUsersList(room);
}
and leave room:
leaveRoom(room, user) {
let userList = connectedUsers.get(room);
// delete user
userList = userList.filter(u => u !== user);
// update user list
if (!userList.length) {
// delete key if no more users in room
connectedUsers.delete(room);
} else
{
connectedUsers.set(room, userList);
// call update function
updateUsersList(room);
}
}
ALso change your method updateUsersList:
function updateUsersList(room){
socket.to(room).emit('usersList', {
room: room,
users: connectedUsers.get(room)
});
}
Pay attention, that we emit to event 'usersList' an object with room field for clarify, what room you should update at frontend.
The last step is call our methods:
when user joins room:
socket.join(room, (err) => {
const user = resolve user from request;
socket.emit('accessStatus', 'done');
joinToRoom(room, user);
console.log(this);
})
when user leave room:
i don`t see the event for leave room, so you just call there leaveRoom(room, user)
Also you should create some map to compare socketId and user, to correctly handle disconnect event and call leaveRoom(room, user) method.
I'm working on a bot and I want to do a message that gets edited multiple times with a timeout function. What I'm trying to do is a loading thing. Here is my code:
const discord = require('discord.js');
const bot = new Discord.Client();
bot.on("message", message => {
if(message.content.startsWith("$load")){
const usere = message.mentions.users.first();
if(usere){
try{
message.channel.send(`Loading.`)
.then(message => { setTimeout(function() { message.edit(`Loading..`) }, 10000)})
.then(message => { setTimeout(function() { message.edit(`Loading...`) }, 10000)})
}catch(e){
}
}
}
})
bot.login('Token');
You tring to get promise message of set timeout function, and its will return undefined, you need use somethink like this:
bot.on("message", message => {
if (message.content.startsWith("$load")) {
const usere = message.mentions.users.first();
if (usere) {
message.channel.send(`Loading.`)
.then(msg => {
setTimeout(function() {
msg.edit(`Loading..`)
}, 10000);
setTimeout(function() {
msg.edit(`Loading...`)
}, 12000)
})
}
}
})
bot.login('Token');
Or you can use inteval, for edit every 10 second , just set Loading... as varivale and change it after every call.
bot.on("message", message => {
if (message.content.startsWith("$load")) {
const usere = message.mentions.users.first();
if (usere) {
message.channel.send(`Loading.`)
.then(msg => {
setInterval(function() {
msg.edit(`Loading..`)
}, 10000);
})
}
}
})