I have a collection like this into firebase realtime database:
I need to delete the first element (the one that finishes with Wt6J) from server side using firebase-admin.
I have this simple code:
const deleteNotification = () => {
const key1 = 'FhN6Ntw8gyPLwJYVzcHy0E8Wq5z2';
const key2 = '-MzGhZ2psGLivIfTWt6J';
const notsRef = db.ref(`notifications/${key1}/${key2}`);
notsRef.remove();
};
This doesn't work. What method should I use to delete a specific field? How do you think I can do it?
I would think to use await in a try catch block.
Await starts another thread which returns once it has completed.
As people said above - your cloud function is likely being killed before the remove actually happens.
const deleteNotification = async () => {
try{
const key1 = 'FhN6Ntw8gyPLwJYVzcHy0E8Wq5z2';
const key2 = '-MzGhZ2psGLivIfTWt6J';
const notsRef = db.ref(`notifications/${key1}/${key2}`);
await notsRef.remove();
} catch( err ) {
console.log( 'failed to remove record.' );
console.log( err );
}
console.log( 'removed record successfully.' );
};
Here's one of my query
async function getCatlogEntities (articleId) {
// fetch catalog entities
let catalogEntities = await realm.objects('catalogentity')
// stringify
catalogEntities = JSON.parse(JSON.stringify(catalogEntities))
// fetch taxanomies
let taxonomies = await publicRealm.objects('taxonomy')
// stringify
taxonomies = JSON.parse(JSON.stringify(taxonomies))
// fetch catalog article entities
let catalogArticleEntities = await realm.objects('catalogarticleentity')
// stringify
catalogArticleEntities = JSON.parse(JSON.stringify(catalogArticleEntities))
console.log('catalogEntities', catalogEntities)
// create the required response
const articleEntities = _.map(catalogEntities, entity => {
// find taxonomies
const findTaxonomy = .find(taxonomies, {id: entity.taxonomy_id})
entity.taxonomy = !.isEmpty(findTaxonomy) ? findTaxonomy : {}
console.log('present catalog entity', entity)
if (!.isEmpty(entity.article_entity)) {
entity.article_entity = _.filter(entity.article_entity, articleEntity => {
const findArticleEntity = _.find(catalogArticleEntities, {id: articleEntity})
console.log('findArticleEntity', findArticleEntity)
// filter out the entities if not found OR article id present and didn't matched with current article id
if (!.isEmpty(findArticleEntity) && ((articleId && findArticleEntity.article_id === articleId) || (!articleId))) return findArticleEntity
})
}
return entity
})
return articleEntities
}
Can I improve it in a way so that it doesn't block the UI thread?
I'm facing 7-8 seconds UI block when the data is too heavy or when we are making multiple queries and mapping them together(as Realm doesn't support joins(aggregation)).
I am using twilio TURN server for webRTC peer connecting two browsers located on different sides of the world, still the connection does not open.
Log shows the local and remote descriptions are set on both sides. Audio/video tracks are also pushed and received, but the "onopen" method on either of the data channels are not firing. Below is the code extract.
create offer code
async createOffer(){
this.initiated = true
this.conn = new RTCPeerConnection(this.servers);
if (this.conn){
this.conn.ontrack = e => {
e.streams[0].getTracks().forEach(track => {
this.calleeStream?.addTrack(track);
this.logs.push('received track:' + track.label);
})
}
if (this.callerStream)
{
const s = this.callerStream;
this.callerStream.getTracks().forEach(track =>
{
this.conn?.addTrack(track,s);
this.logs.push('pushed track:' + track.label);
});
}
}
this.channel = this.conn.createDataChannel('channelX');
this.channel.onmessage = e => this.logs.push('received =>'+ e.data);
this.channel.onopen = e => {
this.logs.push('connection OPENED!!!');
this.enabletestmessage = true;
};
this.conn.onicecandidate = async e=> {
if (e.candidate===null && !this.iceCandiSent){
this.iceCandiSent = true;
this.logs.push('new ICE candidate received- reprinting SDP'+JSON.stringify(this.conn?.localDescription));
await this.dataService.createOffer(this.data.callerid,this.data.calleeid,JSON.stringify(this.conn?.localDescription));
this.logs.push('offer set in db');
this.logs.push('waiting for answer...');
}
}
const offer = await this.conn.createOffer();
await this.conn?.setLocalDescription(offer);
this.logs.push('local description (offer) set');
}
create answer code
async createAnswer(offerSDP:string){
this.initiated = true;
this.conn = new RTCPeerConnection(this.servers);
if (this.conn)
{
this.conn.ontrack = e => {
e.streams[0].getTracks().forEach(track => {
this.callerStream?.addTrack(track);
this.logs.push('received track:' + track.label);
})
}
if (this.calleeStream)
{
const s = this.calleeStream;
this.calleeStream.getTracks().forEach(track =>
{
this.conn?.addTrack(track,s);
this.logs.push('pushed track:' + track.label);
});
}
}
await this.conn.setRemoteDescription(JSON.parse(offerSDP));
this.logs.push('remote description (offer) set');
this.conn.onicecandidate = async e => {
if (e.candidate === null && !this.iceCandiSent){
this.iceCandiSent=true;
this.logs.push('new ICE candidate received- reprinting SDP'+JSON.stringify(this.conn?.localDescription));
await this.dataService.updateAnswer(this.data.callerid,this.data.calleeid,JSON.stringify(this.conn?.localDescription));
this.logs.push('answer set in db');
}
}
this.conn.ondatachannel = e => {
this.channel = e.channel;
this.channel.onmessage = e => this.logs.push('received =>'+ e.data);
this.channel.onopen = e => {
this.logs.push('connection RECEIVED!!!');
this.enabletestmessage = true;
};
}
const answer = await this.conn.createAnswer();
await this.conn.setLocalDescription(answer);
this.logs.push('local description (answer) set');
}
server side code for retrieving ice servers from Twillio
const twilio = require('twilio');
const client = twilio(<MY ACCOUNT SID>,<MY AUTH TOKEN>);
const result = await client.tokens.create();
return result.iceServers; //this is set to this.servers in the code above
Everything works when I run on two browser windows in my local machine. However even afer implementing TURN they dont work between browsers in Nepal and USA. The onopen event handlers on data channel does notfire even though local and remote descriptions are set on both sides. What am I missing ?
NOTE: signalling is done inside the onicecandidate event handler ( the line that calls dataService createOffer/updateAnswer methods)
I am working on a chat-app with Socket.IO (server using flask-SocketIO). Users can create new channels (rooms) and switch between them. In my code below for some reason, every time I switch (back) to a room (even having a single room and "switching" back to it), the "broadcast message"-handler function gets executed an additional time. I.e. if I send "Hello" on "channel_1", switch back to another channel and then back to "channel_1", then send "Hello again", it gets broadcasted (console.log in my example) TWICE. And next time I switch back to "channel_1", 3 TIMES, etc. I figured it must have something to do with the JS-code, maybe the way connectSocket() is called, because the flask-app only emits "broadcast message" once each time. Apologies for the lengthy code - I left out irrelevant bits as best I could.
document.addEventListener('DOMContentLoaded', () => {
// IF USER SWITCHES / SELECTS EXISTING CHANNEL
document.querySelector('#select_channel').onsubmit = () => {
var channel = document.querySelector('select').value;
const r2 = newXHR();
r2.open('POST', '/select_channel');
const data = new FormData();
data.append('channel', channel);
r2.onload = () => {
connectSocket(channel);
};
r2.send(data);
return false;
}
// IF USER CREATES NEW CHANNEL
document.querySelector('#new_channel').onsubmit = () => {
const new_channel_name = document.querySelector('#new_channel_name').value;
const r1 = newXHR();
r1.open('POST', '/new_channel');
const data = new FormData();
data.append('new_channel_name', new_channel_name);
r1.onload = () => {
const response = JSON.parse(r1.responseText);
if (response.channel_exists) {
alert("Channel already exists");
return false;
}
else {
const option = document.createElement('option');
option.innerHTML = new_channel_name;
document.querySelector('select').append(option);
connectSocket(new_channel_name);
document.getElementById('new_channel').reset();
}
};
r1.send(data);
return false;
};
});
function connectSocket(channel) {
var socket = io();
socket.on('connect', () => {
// if user previously connected to any channel, disconnect him
if (localStorage.getItem('channel') != null)
{
socket.emit('leave', {'room': localStorage.getItem('channel'), 'username': display_name});
}
socket.emit('join', {'room': channel, 'username': display_name});
localStorage.setItem('channel', channel);
const data = new FormData();
data.append('username', display_name);
data.append('room', channel);
document.querySelector('#current_channel').innerHTML = channel;
});
document.querySelector('#send_message').onsubmit = () => {
var message = document.querySelector('#message').value;
socket.emit('send', {'message': message, 'room': channel});
console.log(`SENDING ${message}`);
return false;
}
// PROBLEM: EVERY TIME CHANNEL CHANGED AND MSG SENT IN THAT CHANNEL -> 1 EXTRA COPY OF THAT MESSAGE IS BROADCAST - I>E> THE BELOW IS DONE +1 TIMES
socket.on('broadcast message', function handle_broadcast (data) {
console.log(data);
});
}
The Python snippets:
# [IMPORT & CONFIG STATEMENTS...]
socketio = SocketIO(app, logger=True, engineio_logger=True)
# Global variables
channels = []
messagetext = None
#app.route("/select_channel", methods=["GET", "POST"])
def select_channel():
if request.method == "POST":
channel = request.form.get("channel")
session["channel"] = channel
return jsonify({"success": True})
return render_template("chat.html", channels = channels)
#app.route("/new_channel", methods=["GET", "POST"])
def new_channel():
if request.method == "POST":
new_channel = request.form.get("new_channel_name")
if new_channel in channels:
return jsonify({"channel_exists": True})
else:
channels.append(new_channel)
session["channel"] = new_channel
return json.dumps(channels)
return render_template("chat.html", channels = channels)
#socketio.on('join')
def on_join(data):
username = data['username']
room = data['room']
join_room(room)
send(username + ' has entered the room.', room=room)
#socketio.on('leave')
def on_leave(data):
username = data['username']
room = data['room']
leave_room(room)
send(username + ' has left the room.', room=room)
#socketio.on("send")
def handle_send(data):
messagetext = data["message"]
room = data["room"]
emit("broadcast message", {"message": messagetext}, room=room)
if __name__ == '__main__':
socketio.run(app, debug=True)
I think what's happening is that in the Flask-SocketIO library, when you join a room, if you don't pass in a sid, it uses flask.request.sid. I'm not sure what Flask-SocketIO is using for that property, but my guess is that when you join a room, one sid is set. And when you leave a room, maybe a different sid is being used, which means that your original client didn't actually leave the room. So when they join again, a new connection is made (meaning a second, concurrent connection) which could explain why you get a broadcast message multiple times.
I would recommending trying to create your own sid to pass into the join_room() and leave_room() functions to see if that resolves the issue. You can pass it in from the client to your server and just for testing it could be something simple like session1.
I hope this helps.
In my app, there are two processes for manipulating the db library: the first is the polling task, which is used to schedule the data from Table A to the server side, and the second is to store the data in Table B when the user clicks on the menu. But the end result is that the data that should have been deposited on Form B is stored in Form A. I suspect that two processes are the cause of concurrent occurrence, but this phenomenon cannot be repeated. I would like to ask what circumstances will cause this to happen (Table represents the objectstore in IndexedDB IndexedDB API)
export function IDBSaveData(data, dbTableName){
return new Promise((resolve, reject) => {
let name = dbTableName ? dbTableName : 'A';
var tx = db.transaction(name,'readwrite');
var store = tx.objectStore(name);
var req = store.put(data);
let returnData = '', result = false;
req.onsuccess = function(){
returnData = this.result
result = true
}
req.onerror = function(e){
returnData = e.target.result
}
tx.oncomplete = function(){
if (result) {
console.log('success save');
resolve(true)
} else {
console.log('save error!');
reject(returnData)
}
}
tx.onerror = function(){
console.log(returnData.error)
reject(returnData)
}
})
}
The polling task:
setTimeout(async ()=>{
let json = await DBSearchData('B'); // Query Table A data
for(let i=0,i<json.length;i++){
// ... Asynchronous operations
await DBSaveData(json[i], 'C') // Put this piece of data into Table C
await DBDeleteData(json[i], 'B') // Delete this piece of data from Table B
}
}, 10000)
user clicks on the menu:
IDBSaveData(data, 'A')
The above code is my method of putting data into IndexedDB, and I checked my code and there was no error in the table name that was passed in when the method was called.