I have a simple application using firebase. You login and it takes you to a chatroom / channel board where you can select the topic you would like to post in.
Everything works perfectly, writes to firebase, updates the message board.
The issue comes in after you post in one topic, back out (segue) and then select a different or same topic to post in. It duplicates (or triplicates depending on the number of times you exist and go back in) on the message board, but only writes to firebase the one time.
I tried to messages.removeAll() on Load, but it did not help.
Thank you,
I can offer more help if there are some code but from your problem I think the reason is you did not clear observer before back out of topic. Something like this:
conversationReference = Database.database().reference().child("conversations/{conversationId}")
//observe messages ...
//then before moving out
conversationReference.removeAllObservers()
Related
I am building a chat app using Flutter and Firebase.
The way it works in Firebase Firestore is really simple, I just have a conversationId which represents the documents where there are the messages, all of the users have a list of their conversations, when they tap on a conversation, a new screen pops up where they see the messages based on data from the stream of the "Messages" collection that is under the conversationId document. Basically that's the structure
col: Chats
doc: conversationId
col: Messages
message documents...
And this is how I get the messages inside the Chat Screen.
_firestore
.collection("Chats")
.doc(_messageCollectionId)
.collection("Messages")
.orderBy("sentOn", descending: true)
.snapshots()
.map(...)
The message document is basically the message text and when it was sent and who sent it.
I want to create the "seen" functionality, inherently I want the user to see what conversation he read or not (which ones have new messages, like instagram chat or discord)
I can not come up with a good solution to this, my main 2 problems are:
If I were to call a cloud function which fetches the messages and somehow marks them as being read, that would break my app, as I need a continous stream of live message data for the chat to feel good, I can not stream data from the cloud function.
I would like to create a system which is not write intensive. If I would have to mark each message document in particular with some "seenOn :timestamp" value, that would mean that if the user is reading 200 new messages, there are 200 new writes on each document, which seems too much to me, there should be another way.
I am asking for guidance on how I should go about the architecture of such a chat using Firebase. Maybe my chat model is not really fit for what I need, how should I tweak it?
Another problem is that I do not know how the "seen" signal should be sent. If I manually write to a document and change the boolean value of some "isRead" field from my client, the client could easily skip that line of code and break my whole seen system, they could read messages without sending the seen signal just with a break point. This is quite exploitable, there is no cloud function trigger on documents "onRead" that could help me move that logic outside the client, so what is the solution to make this also secure?
so if you want to create the seen function you could made the database structure look like this first
you should create 2 collection for the db, the users collection would only save user data and in the chats collection inside of the uid is saving the chat room id that would be look like this
that was the collection inside of users. only put the roomId of connection that been made when user trying to send a new message to other user. put the the field exactly look like that. after that you could create a chatroom collection that look like this
to be sure that random uid inside of chats collection is a room id that you should register in your users/doc/chats/ collection. the field inside of the roomId would be a connection between of the 2 user for accesing the message that've been send to db. and inside of the chat collection you would send message data in this format
and after you put that you could retrieve the chat data using stream function that would look like this
Stream<QuerySnapshot<Map<String, dynamic>>> streamChats(String chatId) {
CollectionReference chats = firestore.collection("chats");
return chats.doc(chatId).collection("chat").orderBy("time").snapshots();
}
each time of user sending message you could put the total of message that've been send to other user in the total_unread field and update it when other of user open the chat roomId. and tada your seen could work properly
oh and you can create a function that check the total_unread is 0 already and you can put the seen/check icon beside of your user message bubble.
In my Ionic app, I am trying to dynamically subscribe to topics based on the user's preference. So every time the app loads I am trying to re-subscribe them to their topics. I noticed that without resubscribing them, my callback code is not executed, and thus no popup notification is generated, when a notification comes for that given topic. Rather, the notification just ends up in the notification drawer (android).
So, the app boots up, I request the list of sub topics from my db and loop over each one calling the below function to subscribe:
addBillNotificationSubscription(topic: string){
console.log("Adding a bill notification subscription for topic: " + topic)
this.pushObject.subscribe(topic).then((res:any) =>{
console.log("Received test channel notification for topic: " + topic)
if (res.additionalData.foreground) {
this.showNotificationPopup(res);
}
})
console.log("Done Adding subscription")
}
Now when I call this in a loop, only the first iteration ever gets executed. I've double checked the elements in the list, there are several and even print them out in another loop right before the loop to subscribe. I'm assuming that I'm completely not understanding some fundamental thing, but I'm stumped. There's not much documentation (that I've found) on the proper way to even do these topic subscriptions or example use cases.
I've fully tested one topic subscription and have gotten it working in case the question arises.
We use the cumulocity REST API. Regular real time notifications work, e.g. we subscribe to /alarms/*, start our connection/polling loop and when we create an alarm we receive the expected JSON. We did not install any specific modules or statements, it just works.
But when we try to do the same with SmartREST we receive this error, as soon as the alarm is created:
40,,/alarms/177649296,Could not find any templates subscribed for the channel
Following the reference guide (http://cumulocity.com/guides/reference/smartrest/) we tried it like this, where all requests have the same X-Id-header and all requests result in the expected http status 200 and no error messages, except for the last one:
Register a smart response template by doing a POST to /s
Body: 11,102,,,$.channel
Handhake: POST to /cep/realtime
Body: 80
Response is our clientId (e.g. 191het1z38bp7iq1m96jqqt8jnef)
Subscribe: POST to /cep/realtime
Body: 81,191het1z38bp7iq1m96jqqt8jnef,/alarms/*
Connect: POST to /cep/realtime
Body: 83,191het1z38bp7iq1m96jqqt8jnef
In the normal REST case the notification consists of a JSON array with 2 elements, both of which have a property "channel". So that is what we would expect from our response template. Instead, we get the aforementioned error 40.
Is our response template wrong? Is it not properly matched by the X-Id? What does it mean, that there are no "templates subscribed for the channel"? The subscriptions are done for a clientId, and not for a specific response template, and the templates are supposed to be matched automatically anyway. So probably "template" means "X-Id" here? The documentation seems ambiguous as to the meaning of that word. But anyway, we did use the same X-Id header in all of the requests.
Any pointer about what we're doing wrong would be appreciated, since we tried pretty much anything by now.
The SmartREST protocol was developed for a IoT-device <-> platform communication. So there was never any design around using it to subscribing to realtime data (except of course for the operations a device needs) as usually devices to not need subscribe to the data that they created themselves.
That said it is possible to use it but with a couple of limitations. Your approach is basically correct but there is one problem with the subscription. The wildcard subscriptions will not work with SmartREST because on subscription it links your X-Id with the channel you subscribed to but there is never a message published on the channel /alarms/*. Thus this kind of weird error message that said that there was no template subscribed for the channel the alarm appeared on. Inside CometD you still receive the alarm because of the wildcard subscription but the SmartREST part does not work.
The messages are published on the channel with the deviceId (e.g. /alarms/12345).
If you subscribe to /alarms/12345 it will work. You can of course subscribe to as many channels as you want but wildcard subscription won't work.
Regarding the templates you need to know the following. The SmartREST parsing is not done on the raw JSON of CometD but on the payload inside it (e.g. the alarm). So a template for an alarm could look like this:
11,500,,$.severity,$.id,$.type,$.severity
This would trigger only if the object has a severity and would return id, type and severity.
I'm relativily new to databases and Parse, but I'm trying to set up an app that can recieve and send messages between users. I've managed to set up the sign up and log in process, now I need to get the devices communicating.
Do anynone have any idea how to make this happen? I can imagine you'll have to create PFObjects with ID's and classes with some user-details so that only the two users communicating can send and retrieve messages to each other.
Any suggestions on how to set this up would be very appreciated.
Sure enough there are huge ways to setup communication between devices. But it totally depends on your communication needs.
For example, if you need "real time" communication,
like peer-2-peer, then you need to start looking for external service, such as PubNub, because you can't do that with Parse.
If you are trying to build some chat like app, then you can go with manually refreshing and
push notifications.
So, to do what you want you need to create message object and setup ACL for it
PFObject *groupMessage = [PFObject objectWithClassName:#"Message"];
PFACL *groupACL = [PFACL ACL];
// userList is an NSArray with the users we are sending this message to.
for (PFUser *user in userList) {
[groupACL setReadAccess:YES forUser:user];
[groupACL setWriteAccess:YES forUser:user];
}
groupMessage.ACL = groupACL;
[groupMessage saveInBackground];
So, here we've added ACL(access control list) rule for our message, to allow all users from userList access that message.
Also, don't forget to include additional information for message like 'recipient', 'sender' etc to be able to create queries using it. For example, to retrieve all messages send from concrete user.
I'm using XEP-136 for message archiving in a chat system, when the user types his text, it will be displayed in the chat conversation for both users, and it will be automatically archived for further retrieving.
But when reloading the chat window, and re-connecting to the xmpp server (openfire), the last message won't be shown until one minute or more.
That means, the message won't be fully archived immediately.
Are there any settings in openfire that I must check out first? or do I have to try something other than message archiving?
This is my "retrieve collection" stanza (in strophe.js syntax) :
$iq({type: 'get'}).c('retrieve', {xmlns: 'urn:xmpp:archive', with : 'user#server',start:'13-10-28T16:30:00'}).c('set', {xmlns: 'http://jabber.org/protocol/rsm'}).c('max').t('100');
So far, The sending and receiving parts work great, the sole issue, is that when reloading page, messages less than 1 minute won't show up until reloading the page after another 1 minute.
it seems that messages take more than 1 minute before being archived.