I'm having some trouble with automating my bots servercount in its status whenever it gets added to a server, but the member count updates as expected, the server count is the one that is not updating (I have to restart my bot to get it to update the server count).
ready.js
const client = require("../index");
const config = require("../botconfig");
const chalk = require('chalk');
client.on("ready", () => {
client.logger.log("READY", `${client.user.tag} has logged in!`)
const arrayOfStatus = [
{ name: `version ${config.version} | ${config.defaultPrefix}help`, type: 'PLAYING'},
{ name: `${client.guilds.cache.size} servers`, type: 'WATCHING'},
{ name: `${client.users.cache.size} users`, type: 'WATCHING'}
];
let index = 0;
setInterval(() => {
if (index === arrayOfStatus.length) index = 0;
const status = arrayOfStatus[index];
client.user.setActivity(status);
index++;
}, 5000);
const clientDetails = {
guilds: client.guilds.cache.size,
users: client.users.cache.size,
};
});
Related
I am new to Firebase and I have to create a chat system. I found that the doc structure should be nested
e.g if a person sends a message, a new doc with its id will be created in the main collection and then a new collection will be added to the doc. now each doc in that nested collection will be considered as a message obj.
a rough sketch of how the new message in the nested document will be added
but the problem is when there is no doc with UI exist or no collection in that doc exist
firestore().collection("chatBox").doc(uid).collection("message").add(
{
text: "this is my first message",
user: {_id:356},
avatar: "link of avatar",
name: "john",
createdAt: new Date().getTime()
}
)
const sendMessage = async (messages = []) => {
const msg = messages[0];
const id = msg.user?._id?.toString();
const collectionRef = firestore().collection(CHATBOX);
const doc = collectionRef.doc(id);
const docExists = await doc.get().then(function (doc) {
return doc.exists;
});
if (docExists) {
const collection = doc.collection(MESSAGES);
const isCollectionEmpty = collection.get().then(col => {
return col.empty;
});
if (isCollectionEmpty) doc.set({id: MESSAGES});//creating new collection
else collection.add({...msg, createdAt: new Date().getTime()});//inserting doc if collection exist
} else {
collectionRef.add(id);// creating doc in main collection
}
};
The ability to create a document only if it does not exist can be done using the following Transaction. Here, the createDocIfNotExist method creates the document with the given data, only if it does not already exist. It returns a Promise<boolean> indicating whether the document was freshly created or not.
async createDocIfNotExist(docRef, initData) {
return docRef
.firestore
.runTransaction((transaction) => {
const docSnap = await transaction.get(docRef);
if (docSnap.exists)
return false; // exists already
transaction.set(docRef, initData);
return true; // was created
});
}
Applying this to your code then gives:
const sendMessage = async (messages = []) => {
const msg = messages[0];
const msgUserId = msg.user!._id!.toString(); // id renamed, consider using senderId/recipientId instead
const chatboxColRef = firestore().collection(CHATBOX); // collectionRef renamed
const userChatboxDocRef = chatboxColRef.doc(msgUserId); // doc renamed
const isNewChatbox = await createDocIfNotExist(
userChatboxDocRef,
{ id: msgUserId }
);
const userChatboxMessagesColRef = userChatboxDocRef.collection(MESSAGES); // collection renamed
return userChatboxMessagesColRef
.add({
...msg,
createdAt: new Date().getTime() // consider using firebase.firestore.FieldValue.serverTimestamp() instead
});
};
This can be further reduced to:
const sendMessage = async (messages = []) => {
const msg = messages[0];
const msgUserId = msg.user!._id!.toString();
const userChatboxDocRef = firestore()
.collection(CHATBOX);
.doc(msgUserId);
await createDocIfNotExist(
userChatboxDocRef,
{ id: msgUserId }
);
return userChatboxDocRef
.collection(MESSAGES)
.add({
...msg,
createdAt: new Date().getTime()
});
};
Note: Avoid using the variable name doc as it is ambiguous and could be an instance of DocumentData, DocumentReference, or DocumentSnapshot (at minimum, use docData, docRef and docSnap/docSnapshot respectively). Similarly, use colRef for a CollectionReference and qSnap/querySnap for QuerySnapshot objects.
How can I get a list of cars for a customer
clients:
w21rffa3:
name: Johny
phone: 123123
cars:
fn1jnr12:
brand: AUDi
model: a6
number: 24f1
dsdasgf122:
brand: AUDi
model: a3
number: 62s14
My code
const ref = firestore().collection('clients');
const [clientsList, setClientsList] = useState([]);
useEffect(() => {
return ref.onSnapshot(clientsSnapshot => {
const clients = [];
const cars = [];
clientsSnapshot.forEach(client => {
const carsRef = ref.doc(client.id).collection('cars').onSnapshot(carsSnapshot => {
carsSnapshot.forEach(car => {
if (car.data().brand.length > 0) {
const {
brand,
model,
number
} = car.data();
cars.push({
id: car.id,
brand,
model,
number,
});
}
});
//Good result`
console.log('After forEach: ', cars);
});
//Bad result
console.log('After snapshot: ', cars);
const {
name,
phone
} = client.data();
clients.push({
id: client.id,
name,
phone,
cars: cars,
});
});
setClientsList(clients);
});
}, []);
cars list for customers
The error you facing is due to misuse/misunderstanding of how async/callback-based functions works. As I said in my comment - good result and bad result - bad result scripts are executed before good result due to onSnapshot is async, and you pass a callback function to it, which will be executed when data is available from firebase, so a bit "later" than the rest of the code.
Now about what can be done. The code is a bit tricky and I didnt really test it, so if anything - please, let me know.
const [clientsList, setClientsList] = useState([]);
useEffect(() => {
let carsUnsubscribeFns = [];
const clientUnsubscribeFn = ref.onSnapshot((clientsSnapshot) => {
// Reset everything and stop previously created listeners for Cars
setClientsList([]);
carsUnsubscribeFns.forEach((x) => x());
carsUnsubscribeFns = [];
clientsSnapshot.forEach((c) => {
const { name, phone } = c.data();
const client = { id: c.id, name, phone };
// In case you dont want to use optional chaining,
// remove the const client = ... line above
// and uncomment the line below
// but optional chaining is prefered anyway
// const client = { id: c.id, name, phone, cars: [] };
const carsUnsubscribeFn = ref
.doc(client.id)
.collection("cars")
.onSnapshot((carsSnapshot) => {
// Mutate the Client object directly
client.cars = carsSnapshot.docs
.map((x) => ({ id: x.id, ...x.data() }))
.filter((x) => x.brand?.length > 0);
// mark ClientsList as updated to force a rerender
// due to we mutated one of the entities inside
setClientsList((curr) => [...curr]);
});
carsUnsubscribeFns.push(carsUnsubscribeFn);
setClientsList((curr) => {
curr.push(client);
return [...curr];
});
});
// clean-up function returned from hook to stop all the listeners
return () => {
[clientUnsubscribeFn, ...carsUnsubscribeFns].forEach((x) => x());
};
});
}, []);
My React code creates a WebSocket connection to our company's ActiveMQ 5.15.5 server, and then subscribes to the following two topics: salary and decoding. The problem is that the code is only able to subscribe to one of the topics. It cannot subscribe to both.
const client = window.Stomp.client(`ws://${ipAddress}:61614`, 'aj6.stomp');
const headers = { id: 'username' };
client.debug = null;
client.connect('user', 'pass', () => {
client.subscribe(
'/topic/salary', //BREAKPOINT was set here
message => {
const body = JSON.parse(message.body);
if (body && body.pcId) {
salaries[body.pcId] = body;
setState({ salaries});
}
},
headers,
);
client.subscribe(
'/topic/decoding', //BREAKPOINT was set here
message => {
const newBody = JSON.parse(message.body);
if (newBody && newBody.PcID) {
consoleMessage[newBody.PcID] = newBody;
setState({ consoleMessage });
}
},
headers,
);
});
So in the code above I put a break-point at client.subscribe('/topic/decoding... and client.subscribe('/topic/salary.... I saw that it only subscribes to /topic/decoding but not /topic/salary.
Does anyone know how I can fix this issue so that it subscribes to both topics?
From Stomp documentation:
Since a single connection can have multiple open subscriptions with a server, an id header MUST be included in the frame to uniquely identify the subscription. The id header allows the client and server to relate subsequent MESSAGE or UNSUBSCRIBE frames to the original subscription.
Within the same connection, different subscriptions MUST use different subscription identifiers.
Stomp API definition:
subscribe(destination, callback, headers = {})
So for my understanding, You can't have the same username id for both of your subscriptions
Try creating 2 clients, e.g.:
const salaryClient = window.Stomp.client(`ws://${ipAddress}:61614`, 'aj6.stomp');
const salaryHeaders = { id: 'salary' };
salaryClient.debug = null;
salaryClient.connect('user', 'pass', () => {
salaryClient.subscribe(
'/topic/salary',
message => {
const body = JSON.parse(message.body);
if (body && body.pcId) {
salaries[body.pcId] = body;
setState({ salaries});
}
},
salaryHeaders,
);
});
const decodingClient = window.Stomp.client(`ws://${ipAddress}:61614`, 'aj7.stomp');
const decodingHeaders = { id: 'decoding' };
decodingClient.debug = null;
decodingClient.connect('user', 'pass', () => {
decodingClient.subscribe(
'/topic/decoding',
message => {
const newBody = JSON.parse(message.body);
if (newBody && newBody.PcID) {
consoleMessage[newBody.PcID] = newBody;
setState({ consoleMessage });
}
},
decodingHeaders,
);
});
I have a React form where the user can upload multiple files. These are stored in fileList
async function uploadFiles(id) {
try {
const meta = await storageUploadFile(fileList, id);
console.log(meta);
} catch (e) {
console.log(e);
}
}
This calls my helper function that uploads the files to Firebase
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
return Promise.all(
files.map((file) => {
return storage.child(`designs/${user}/${id}/${file.name}`).put(file)
})
)
};
What I'd like is on calling uploadFiles, get the total filesize of all items, and then show the overall progress.
At the moment, my code is only returning the file status in an array on completion
[
{bytesTransferred: 485561, totalBytes: 485561, state: "success"},
{bytesTransferred: 656289, totalBytes: 656289, state: "success"}
]
This is the way i do it:
import Deferred from 'es6-deferred';
export const storageUploadFile = function(files, id) {
const user = firebase.auth().currentUser.uid;
// To track the remaining files
let itemsCount = files.length;
// To store our files refs
const thumbRef = [];
// Our main tasks
const tumbUploadTask = [];
// This will store our primses
const thumbCompleter = [];
for (let i = 0; i < files.length; i += 1) {
thumbRef[i] = storage.ref(`designs/${user}/${id}/${file.name}`);
tumbUploadTask[i] = thumbRef[i].put(files[i]);
thumbCompleter[i] = new Deferred();
tumbUploadTask[i].on('state_changed',
(snap) => {
// Here you can check the progress
console.log(i, (snap.bytesTransferred / snap.totalBytes) * 100);
},
(error) => {
thumbCompleter[i].reject(error);
}, () => {
const url = tumbUploadTask[i].snapshot.metadata.downloadURLs[0];
itemsCount -= 1;
console.log(`Items left: ${itemsCount}`)
thumbCompleter[i].resolve(url);
});
}
return Promise.all(thumbCompleter).then((urls) => {
// Here we can see our files urls
console.log(urls);
});
};
Hope it helps.
I have a smol Discord bot (with discord.js-commando), I have this code:
var activevar = ["with the &help command.", "with the developers console", "with some code", "with JavaScript"];
var activities = activevar[Math.floor(Math.random()*activevar.length)];
client.on('ready', () => {
client.user.setActivity(activities);
}
But that only changes it when I restart the bot. Can someone help me out here?
Edited for users on v12 which now uses bot instead of client
const activities = [
"with the &help command.",
"with the developers console.",
"with some code.",
"with JavaScript."
];
bot.on("ready", () => {
// run every 10 seconds
setInterval(() => {
// generate random number between 1 and list length.
const randomIndex = Math.floor(Math.random() * (activities.length - 1) + 1);
const newActivity = activities[randomIndex];
bot.user.setActivity(newActivity);
}, 10000);
});
I changed it so you can change the status from playing to watching or listening.
const activities_list = [
"For Rule Breakers",
"The purple names",
"#general",
"The mods do their job"
]; // creates an arraylist containing phrases you want your bot to switch through.
client.on('ready', () => {
setInterval(() => {
const index = Math.floor(Math.random() * (activities_list.length - 1) + 1); // generates a random number between 1 and the length of the activities array list (in this case 5).
client.user.setActivity(activities_list[index], { type: 'WATCHING' }); // sets bot's activities to one of the phrases in the arraylist.
}, 10000); // Runs this every 10 seconds.
});
Considering how often this is viewed, I thought that I'd provide an updated and clearer response.
const state = 0;
const presences = [
{ type: 'PLAYING', message: 'a game' },
{ type: 'WATCHING', message: 'a video' }
];
setInterval(() => {
state = (state + 1) % presences.length;
const presence = presences[state];
client.user.setActivity(presence.message, { type: presence.type });
}, 10000);
This will also work on v13 too.
const statuses = [
{ name: "to nothing", type: "LISTENING" },
{ name: "something", type: "PLAYING" },
{ name: "your commands", type: "WATCHING" },
];
client.on("ready", () => {
setInterval(() => {
var randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
client.user.setActivity(randomStatus);
}, 10000);
});
Haven't tested, but it should work in theory. It not, try to figure out what is wrong, it's good practice. Otherwise, let me know
client.on("ready", function() {
setInterval(function() {
var actID = Math.floor(Math.random() * Math.floor(activevar.length));
client.user.setActivity(activities);
}, 10000)
});
changes every 10s for playing, watching, listening activities
const activities_list = [
{ type: 'PLAYING', message: 'a game' },
{ type: 'WATCHING', message: 'a video' },
{ type: 'LISTENING', message: 'a music' }
];
client.on('ready', () => {
setInterval(() => {
const index = Math.floor(Math.random() * (activities_list.length - 1) + 1);
client.user.setActivity(activities_list[index].message, { type: activities_list[index].type });
}, 10000);
});
i'm use discord.js v12.
client.on("ready", () => {
console.log(`ok`);
const who = ["hi", "hello"];
setInterval(() => {
const burh = Math.floor(Math.random() * who.length);
client.user.setPresence({ activity: { name: who[burh]}, status: 'dnd'});
}, 5000);
});