I'm sending a message to a user like so..
#objc fileprivate func sendPressed() {
if let text = self.textView?.text {
sendMessage(text: text)
}
}
sendMessage is given like so...
func sendMessage(text: String) {
let element = XMLElement(name: XMPPConfig.Keys.GLInformation)
element.addAttribute(withName: XMPPConfig.Keys.GLMessageType, stringValue: MessageType.text.rawValue)
sendTheMessage(text, element: element)
}
Finally, sendTheMessage is given as,
fileprivate func sendTheMessage(_ body: String, element: XMLElement) {
print("sendMessage \(body)")
let message = XMPPMessage(type: "chat", to: RealmManager.shared.recipientUser?.JID)
message.addAttribute(withName: "id", stringValue: generateUUID())
message.addBody(body)
message.addReceiptRequest()
sendElement(message)
}
But the other user is not able to receive the message. When the message is being send the log that is printed is something like so...
RECV: <message xmlns="jabber:client" lang="en" to="2419#xmpp.abcstage.in/7330044482810331514281698"
from="2258#xmpp.abcstage.in" type="error" id="D59B969E-F33E-4FD2-BB4F-3ECD3BFD44B6"><request xmlns="urn:xmpp:receipts"/><error code="406"
type="modify"><not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" lang="en">Your
active privacy list has denied the routing of this stanza.</text></error><body>Kk</body></message>
What could be the reason for such an error..?
From the log you posted yourself:
Your active privacy list has denied the routing of this stanza.
Related
As I port some Objective-C code to Swift, I'm trying to better understand the new Combine framework and how I can use it to re-create a common design pattern.
In this case, the design pattern is a single object (Manager, Service, etc) that any number of "clients" can register with as a delegate to receive callbacks. It's a basic 1:Many pattern using delegates.
Combine looks ideal for this, but the sample code is a bit thin. Below is a working example but I'm not sure if it's correct or being used as intended. In particular, I'm curious about reference cycles between the objects.
class Service {
let tweets = PassthroughSubject<String, Never>()
func start() {
// Simulate the need send to send updates.
DispatchQueue.global(qos: .utility).async {
while true {
self.sendTweet()
usleep(100000)
}
}
}
func sendTweet() {
tweets.send("Message \(Date().timeIntervalSince1970)")
}
}
class Client : Subscriber {
typealias Input = String
typealias Failure = Never
let service:Service
var subscription:Subscription?
init(service:Service) {
self.service = service
// Is this a retain cycle?
// Is this thread-safe?
self.service.tweets.subscribe(self)
}
func receive(subscription: Subscription) {
print("Received subscription: \(subscription)")
self.subscription = subscription
self.subscription?.request(.unlimited)
}
func receive(_ input: String) -> Subscribers.Demand {
print("Received tweet: \(input)")
return .unlimited
}
func receive(completion: Subscribers.Completion<Never>) {
print("Received completion")
}
}
// Dependency injection is used a lot throughout the
// application in a similar fashion to this:
let service = Service()
let client = Client(service:service)
// In the real world, the service is started when
// the application is launched and clients come-and-go.
service.start()
Output is:
Received subscription: PassthroughSubject
Received tweet: Message 1560371698.300811
Received tweet: Message 1560371698.4087949
Received tweet: Message 1560371698.578027
...
Is this even remotely close to how Combine was intended to be used?
lets check it! the simplest way is add deinit to both classes and limit the live of service
class Service {
let tweets = PassthroughSubject<String, Never>()
func start() {
// Simulate the need send to send updates.
DispatchQueue.global(qos: .utility).async {
(0 ... 3).forEach { _ in
self.sendTweet()
usleep(100000)
}
}
}
func sendTweet() {
tweets.send("Message \(Date().timeIntervalSince1970)")
}
deinit {
print("server deinit")
}
}
now it is easy to check that
do {
let service = Service()
//_ = Client(service:service)
// In the real world, the service is started when
// the application is launched and clients come-and-go.
service.start()
}
will finished as expected
server deinit
modify it with subscribing client
do {
let service = Service()
_ = Client(service:service)
service.start()
}
and you immediately know the result
Received subscription: PassthroughSubject
Received tweet: Message 1580816649.7355099
Received tweet: Message 1580816649.8548698
Received tweet: Message 1580816650.001649
Received tweet: Message 1580816650.102639
there is a memory cycle, as you expected :-)
Generally, there is very low probability, that you need your own subscriber implementation.
First modify the service, so the client will know when no more messages will arrive
func start() {
// Simulate the need send to send updates.
DispatchQueue.global(qos: .utility).async {
// send some tweets
(0 ... 3).forEach { _ in
self.sendTweet()
usleep(100000)
}
// and send "finished"
self.tweets.send(completion: .finished)
}
}
and next use "build-in" subcriber in your publisher by invoking his .sink method. .sink return AnyCancelable (it is a reference type) which you have to store somewhere.
var cancelable: AnyCancellable?
do {
let service = Service()
service.start()
// client
cancelable = service.tweets.sink { (s) in
print(s)
}
}
now, everythig works, es expected ...
Message 1580818277.2908669
Message 1580818277.4674711
Message 1580818277.641886
server deinit
But what about cancelable? Let check it!
var cancelable: AnyCancellable?
do {
let service = Service()
service.start()
// client
cancelable = service.tweets.sink { (s) in
print(s)
}
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print(cancelable)
}
it prints
Message 1580819227.5750608
Message 1580819227.763901
Message 1580819227.9366078
Message 1580819228.072041
server deinit
Optional(Combine.AnyCancellable)
so you have to release it "manualy", if you don't need it anymore. .sink is there again!
var cancelable: AnyCancellable?
do {
let service = Service()
service.start()
// client
cancelable = service.tweets.sink(receiveCompletion: { (completion) in
print(completion)
// this inform publisher to "unsubscribe" (not necessery in this scenario)
cancelable?.cancel()
// and we can release our canceleble
cancelable = nil
}, receiveValue: { (message) in
print(message)
})
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print(cancelable)
}
and result
Message 1580819683.462331
Message 1580819683.638145
Message 1580819683.74383
finished
server deinit
nil
Combine has almost everything you need in real word application, the trouble is a lack of documentation, but a lot of sources are available on the internet.
Custom Combine Subscriber should also conform to Cancellable protocol that provides a method to forward cancellation to the received subscription object from Publisher. That way you do not have to expose Subscription property. According to doc:
If you create a custom Subscriber, the publisher sends a Subscription object when you first subscribe to it. Store this subscription, and then call its cancel() method when you want to cancel publishing. When you create a custom subscriber, you should implement the Cancellable protocol, and have your cancel() implementation forward the call to the stored subscription.
https://developer.apple.com/documentation/combine/receiving_and_handling_events_with_combine
On version 2, the sender app was able to send messages.
func deviceManager(_ deviceManager: GCKDeviceManager!,
didConnectToCastApplication
applicationMetadata: GCKApplicationMetadata!,
sessionID: String!,
launchedApplication: Bool) {
deviceManager.add(self.textChannel)
}
However, the API says that we are now using GCKSessionManager instead of GCKDeviceManager.
The API says I must have a GCKSession add the textChannel, which I did here:
Once the session starts, I add the textChannel (because sessionManager.currentCastSession was nil before the session started).
func sessionManager(_ sessionManager: GCKSessionManager, didStart session: GCKSession) {
if session.device == connectionQueue {
connectionQueue = nil
}
self.sessionManager!.currentCastSession!.add(textChannel)
print("")
}
Meanwhile, I send the text message in another function:
let result = self.textChannel.sendTextMessage("\(self.textField.text)", error: &error)
But the result is always false, and the error is always "Channel is not connected or is not registered with a session".
In addition, when I do:
print("isConnected1 \(self.textChannel.isConnected)")
the result is false.
Do you know what other steps I am missing for it to be connected?
Just learned that it was an issue of my namespace. It connects now.
Problem was the namespace wasn't matching the namespace from my receiver code.
fileprivate lazy var textChannel:TextChannel = {
return TextChannel(namespace: NAMESPACE)
}()
I already have a messaging app, and I would like to implement Siri to send a message. I have added the Intents extension and everything, I am just having problems figuring out how to send the message. I have tried to use the same function for sending the messages in the ChatVC, and copy and paste that into the IntentHandler.swift file but it gives me a bunch of compiler errors. Is there some type of framework that I should use to communicate to the app to do it or something? I am using Firebase as my database if that information is needed.
Updated code:
note, this code is the send function that I have when a user sends a normal message, and this is what I copied and pasted into the SiriIntent...
func handle(sendMessage intent: INSendMessageIntent, completion: #escaping (INSendMessageIntentResponse) -> Void) {
// Implement your application logic to send a message here.
sendMessage()
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
completion(response)
}
func sendMessage(text: String?, date: Date, picture: UIImage?, location: String?, video: NSURL?, audio: String?) {
var outgoingMessage: OutgoingMessage?
if let text = text {
let encryptedText = EncryptText(chatRoomID: chatRoomId, string: text)
outgoingMessage = OutgoingMessage(message: encryptedText, senderId: FUser.currentUser()!.objectId, senderName: FUser.currentUser()!.firstname, date: date, status: kDELIVERED, type: kTEXT)
}
}
Thank you so much for all the help!
I have a chat app, push notifications are already working. I want to create a log of sent push notifications to be able to show the user if the message was sent.
How can I do it?
I have a func to send push:
class func sendPushNotification(groupId: String, text: String) {
let query = PFQuery(className: PF_MESSAGES_CLASS_NAME)
query.whereKey(PF_MESSAGES_GROUPID, equalTo: groupId)
query.whereKey(PF_MESSAGES_USER, notEqualTo: PFUser.currentUser())
query.includeKey(PF_MESSAGES_USER)
query.limit = 1000
let installationQuery = PFInstallation.query()
installationQuery.whereKey(PF_INSTALLATION_USER, matchesKey: PF_MESSAGES_USER, inQuery: query)
let push = PFPush()
var badgeCount = 0
let data = [
"alert" : text,
"badge" : ++badgeCount,
"sounds" : "message.mp3"
]
push.setQuery(installationQuery)
push.setData(data as [NSObject : AnyObject])
push.sendPushInBackgroundWithBlock { (succeeded: Bool, error: NSError!) -> Void in
if error != nil {
print("sendPushNotification error")
}
}
}
Then I have a class to control the chat, it has a funct called sendMessage that calls in the end the funct: PushNotication.sendPushNotification(self.groupId, text: textPush)
Now I need to check if the push was sent and store it in a Parse class. I imagine it could be a class with columns: messageId, date the push was sent.
How to get all friends programmatically from openfire server in objective C, I am using XMPP Framework for chat Functionality.
Here is a function to fetch friends.
Add your host name in below function.
func getList() {
let query = try! XMLElement(xmlString: "<query xmlns='http://jabber.org/protocol/disco#items' node='all users'/>")
let iq = XMPPIQ(type: "get", to: XMPPJID(string: "Your Host Name"), elementID: xmppStream.generateUUID(), child: query)
iq?.addAttribute(withName: "id", stringValue: "get")
xmppStream.send(iq)
}
You will get the list in delegate method.
extension YourClassName: XMPPRosterDelegate {
func xmppRosterDidEndPopulating(_ sender: XMPPRoster!) {
if let jids = xmppRoster.xmppRosterStorage.jids(for: xmppStream) as? [XMPPJID] {
print("JIDS: \(String(describing: jids))")
for item in jids {
print(item.user)
}
}
}
}
You can have a look at my this link for XMPP Connection and different delegates.
https://stackoverflow.com/a/50149977/2781720
In iOS you can easily get Group members/friends using below function in xmpp
- (void)xmppRoom:(XMPPRoom *)sender didFetchModeratorsList:(NSArray *)items