PubNub message text returning nil? - ios

When I send a message using iOS to a PubNub channel, I can use the didReceiveMessage function to get that message and put it in my tableView. However, if I send a message via a client in the Dev Dashboard, message.data.message returns nil after I try to cast it as a String. Here's the function in question:
func client(client: PubNub, didReceiveMessage message: PNMessageResult) {
print("Received: %", message.data.message)
let newMessage:String? = message.data.message as? String
print(newMessage) // returns nil
self.messagesArray.append(newMessage!)
dispatch_async(dispatch_get_main_queue()) {
self.messageTableView.reloadData()
}
}
I get the following response in console from print("Received: %", message.data.message):
Received: % Optional({
text = test;
})
However, print(newMessage) is returning nil. What am I doing wrong?
Thanks!
EDIT: I'm getting the same thing when I try to get messages from the historyForChannel function.
//get history
pubNub.historyForChannel("channelname" as String, withCompletion: { (result, status) -> Void in
print(status)
if status == nil {
if result!.data.messages.count > 0 {
let historyMessages = result!.data.messages.description as? [String]
print(result)
for item in historyMessages!{
self.messagesArray.append(item)
}
}
}
})
historyMessages is nil, even though result prints:
Optional({
Operation = History;
Request = {
Authorization = "not set";
Method = GET;
Origin = "pubsub.pubnub.com";
"POST Body size" = 0;
Secure = YES;
URL = "...redacted";
UUID = "...redacted";
};
Response = {
"Processed data" = {
end = 14609023551682481;
messages = (
"technically ",
{
text = "Well..ok then";
},
hi,
"really ",
{
text = "Well..ok then";
},
How do I get the text from these returned messages?

From behaviour and fact what history fetch printed out status object means what you probably configured your client with cipherKey. That status object which you receive probably has category set to decryption error.
If you want to use encryption - you should use same key for all clients, or they won't be able to decrypt sent messages. If cipherKey is set, client automatically try to decrypt data and it will fail if regular text has been received.
Make sure both (console and iOS client) configured with same cipherKey or if you don't need it, make sure what it not set on any of clients.
Best regards,
Sergey.

Related

How to fetch the inbox from email agent in swift/objective c using mailcore framework or Any framework?

Step 1: Link (https://github.com/MailCore/MailCore2)
Step 2: I have added mailcore-framework in my project
Step 3: pod install for UICKeyChainStore in my project done
Step 4: Send mail successfully using MCOSMTPSession, MCOMessageBuilder.
Step 5: My problem is that I am not able to fetch using mailcore. Is there any other framework for fetching mail (inbox)?
Sorry for late answer. I have two apps in the App Store, both of them use MailCore2, so I can explain you a thing or two about that.
Of course you can fetch the emails with MailCore2, this is the code. If you have any other doubt with MailCore2 write about that, I will try to find the answer.
var imapsession:MCOIMAPSession = MCOIMAPSession()
func prepareImapSession()
{
// CONFIGURE THAT DEPENDING OF YOUR NEEDS
imapsession.hostname = imapHostname // String
imapsession.username = userName // String
imapsession.password = password // String
imapsession.port = portIMAP // UInt32 number
imapsession.authType = MCOAuthType.saslLogin
imapsession.connectionType = MCOConnectionType.TLS
}
func useImapWithUIDS()
{
// There is more than one option here, explore depending of your needs
let requestKind : MCOIMAPMessagesRequestKind = .headers
let folder : String = "INBOX"
// HERE ALSO EXPLORE DEPENDING OF YOUR NEEDS, RANGE IT IS THE RANGE OF THE UIDS THAT YOU WANT TO FETCH, I SUGGEST TO YOU TO CHANGE THE // NUMBER ONE IF YOU HAVE A LOWER BOUND TO FETCH EMAIL
let uids : MCOIndexSet = MCOIndexSet(range: MCORangeMake(1, UINT64_MAX))
let fetchOperation = imapsession.fetchMessagesOperation(withFolder: folder, requestKind: requestKind, uids: uids)
fetchOperation?.start
{ (err, msg, vanished) -> Void in
if (err != nil)
{
error = err
NSLog((err?.localizedDescription)!)
}
else
{
guard let msgs = msg as? [MCOIMAPMessage]
else
{
print("ERROR GETTING THE MAILS")
return
}
for i in 0..<msgs.count
{
// THE SUBJECT
let subject = msgs[i].header.subject
// THE uid for this email. The uid is unique for one email
let uid = msgs[i].uid
// The sequenceNumber like the nomber say it is the sequence for the emails in the INBOX from the first one // (sequenceNumber = 1) to the last one , it not represent always the same email. Because if you delete one email then //next one will get the sequence number of that email that was deleted
let sequenceNumber = msgs[i].sequenceNumber
}
}
}
// MARK: - EXTRACT THE CONTENT OF ONE EMAIL, IN THIS FUNCTION YOU NEED THE uid, THE UNIQUE NUMBER FOR ONE EMAIL
func useImapFetchContent(uidToFetch uid: UInt32)
{
let operation: MCOIMAPFetchContentOperation = imapsession.fetchMessageOperation(withFolder: "INBOX", uid: uid)
operation.start { (Error, data) in
if (Error != nil)
{
NSLog("ERROR")
return
}
let messageParser: MCOMessageParser = MCOMessageParser(data: data)
// IF YOU HAVE ATTACHMENTS USE THIS
let attachments = messageParser.attachments() as? [MCOAttachment]
// THEN YOU NEED THIS PROPERTIE, IN THIS EXAMPLE I TAKE THI FIRST, USE WHAT EVER YOU WANT
let attachData = attachments?.first?.data
// FOR THE MESSAGEPARSER YOU CAN EPLORE MORE THAN ONE OPTION TO OBTAIN THE TEXT
let msgPlainBody = messageParser.plainTextBodyRendering()
}
You can give https://github.com/snipsco/Postal a try. This is a framework which aims to provide simple access to common email providers.

How to parse a optional JSON object using JSONJoy?

https://github.com/daltoniam/JSONJoy-Swift
For example :
JSON1 = {
"message": "Sorry! Password does not match.",
"code": "4"
}
JOSN2 = {
"data": {
"id": 21
},
"message": "Signup Successful.",
"code": "1"
},
Here json key “data” is optional. Then how I can handle both response using the same model object??
JSONJoy natively sets not found elements to nil, you just have to declare them optional and then check for nil before using them.
From the docs
This also has automatic optional validation like most Swift JSON libraries.
//some randomly incorrect key. This will work fine and the property
will just be nil.
firstName = decoder[5]["wrongKey"]["MoreWrong"].string
//firstName is nil, but no crashing!
Here is my example that my be illustrative. I have a complex object set where my top level object (UserPrefs) has arrays of secondary objects (SmartNetworkNotification and SmartNotificationTime).
Note that notifications and times are both declared as optional. What I do is check for nil after attempting to parse the secondary object arrays. Without the nil check the attempt to iterate on the parsed list fails since its nil. With the nil check it just moves past it if its empty.
This works for me but isn't deeply tested yet. YMMV! Curious how others are handling it.
struct UserPrefs: JSONJoy {
var notifications: [SmartNetworkNotification]?
var times: [SmartNotificationTime]?
init(_ decoder: JSONDecoder) throws {
// Extract notifications
let notificationsJson = try decoder["notifications"].array
if(notificationsJson != nil){
var collectNotifications = [SmartNetworkNotification]()
for notificationDecoder in notificationsJson! {
do {
try collectNotifications.append(SmartNetworkNotification(notificationDecoder))
} catch let error {
print("Error.. on notifications decoder")
print(error)
}
}
notifications = collectNotifications
}
// Extract time of day settings
let timesJson = try decoder["times"].array
if(timesJson != nil){
var collectTimes = [SmartNotificationTime]()
for timesDecoder in timesJson! {
do {
try collectTimes.append(SmartNotificationTime(timesDecoder))
} catch let error {
print("Error.. on timesJson decoder")
print(error)
}
}
times = collectTimes
}
}

Can I use SwiftyJSON to get at error contents in Siesta?

I'm writing a test for my Siesta-based class, and I'm trying to access the error I received from the server. In my object, I configured the service like so:
self.service.configure {
$0.config.pipeline[.parsing].add(SwiftyJSONTransformer, contentTypes: ["*/json"])
// other configuration setup
}
My test contains the following:
api.fetchApiToken(libraryRequiringAuth).onSuccess({ _ in
// Then
XCTFail("Expected request failure, got success")
}).onFailure({ [weak self] (error) in
XCTAssertEqual(error.httpStatusCode, expectedStatusCode)
let serverError: JSON? = error.entity?.typedContent()
XCTAssertEqual(serverError![0]["title"].string, expectedErrorMessage)
print("Expected error is: \(error)")
XCTAssertNil(self?.api.bearerAuthHeader)
expectation.fulfill()
})
The line let serverError: JSON? = error.entity?.typedContent() is setting serverError to nil, but in the debugger, I can see that error.entity exists and has the content I expect. Can I not use SwiftyJSON at this point?
Edit:
Here are the contents of the error:
Error Error(userMessage: "Forbidden", httpStatusCode: Optional(403), entity: Optional(Siesta.Entity(content: [{
ipRangeError = {
libraryId = 657;
libraryName = "Test library";
requestIp = "my.ip.address.was_here";
};
status = 403;
title = "Authentication Failed";
userData = {
};
}], charset: Optional("utf-8"), headers: ["content-type": "application/json; charset=utf-8"], timestamp: 490978565.82571602)), cause: nil, timestamp: 490978565.825499)
It looks like your SwiftyJSONTransformer is leaving errors untouched. Try configuring it with transformErrors: true:
private let SwiftyJSONTransformer =
ResponseContentTransformer(transformErrors: true)
{ JSON($0.content as AnyObject) }
Without that flag, the error entity is still an NSDictionary instead of a SwiftyJSON JSON, and typedContent() sees those as mismatched types and gives you a nil.
(And to the question in the title: yes, you can get the full error content, as well as response headers and any underlying ErrorType / NSError info from the underlying networking layer.)

Verification code always invalid Swift Parse

Im using SMS verification to verify users. My problem is that when I enter a code to verify I get invalid code. I can't for the life of me figure out why.
Calling cloud code function:
#IBAction func verifyCodeButtonTapped(sender: AnyObject) {
var verificationCode: String = verificationCodeTextField.text!
let textFieldText = verificationCodeTextField.text ?? ""
if verificationCode.utf16.count < 4 || verificationCode.utf16.count > 4 {
displayAlert("Error", message: "You must entert the 4 digit verification code sent yo your phone")
} else {
let params = ["verificationCode" : textFieldText]
PFCloud.callFunctionInBackground("verifyPhoneNumber", withParameters: params, block: { (object: AnyObject?, error) -> Void in
if error == nil {
self.performSegueWithIdentifier("showVerifyCodeView", sender: self)
} else {
self.displayAlert("Sorry", message: "We couldnt verify you. Please check that you enterd the correct 4 digit code sent to your phone")
}
})
}
}
Cloud code to verify code:
Parse.Cloud.define("verifyPhoneNumber", function(request, response) {
var user = Parse.User.current();
var verificationCode = user.get("phoneVerificationCode");
if (verificationCode == request.params.phoneVerificationCode) {
user.set("phoneNumber", request.params.phoneNumber);
user.save();
response.success("Success");
} else {
response.error("Invalid verification code.");
}
});
Your parameter names are mismatched between the iOS and JS code.
verificationCode vs phoneVerificationCode
Change
let params = ["verificationCode" : textFieldText]
To use the same parameter name:
let params = ["phoneVerificationCode" : textFieldText]
EDIT
Other issues I see with the code:
The first two lines of the iOS code create a variable and a constant from the textField's text value. Get rid of the verificationCode variable and just use the textFieldText constant.
I would add some more error states to the Cloud Code before you check if the codes are equivalent. First check if the parameter exists and the expected type and length:
var requestCode = request.params.phoneVerificationCode;
if ((typeof requestCode !== "string") || (requestCode.length !== 4)) {
// The verification code did not come through from the client
}
Then perform the same checks on the value from the user object:
else if ((typeof verificationCode !== "string) || (verificationCode.length !== 4)) {
// There is not a verification code on the Parse User
}
Then you can continue to checking if requestCode and verificationCode are equivalent.

Fail to send Quickblox group chat invitation message

After successfully creating a group QBChatDialog, I try to sent invitation messages to all occupants by
if self.chatDialog.join() == true {
for occupantID in self.chatDialog.occupantIDs {
var inviteMessage = self.createChatNotificationForGroupChatCreation(self.chatDialog)
var timestamp = NSDate().timeIntervalSince1970
inviteMessage.customParameters["date_sent"] = timestamp
// send notification
//
inviteMessage.recipientID = occupantID as! UInt
//QBChat.instance().sendMessage(inviteMessage)
//QBChatDialog. sendMessage(inviteMessage)
if self.chatDialog.sendMessage(inviteMessage) == true {
println("################# Send ok ######################")
} else {
println("!!!!!!!!!!!!!!!! error sending !!!!!!!!!!!!!!!!!!")
}
}
}
but I always get the error. It keeps telling me that "Room is not joined". I did join the room using "self.chatDialog.join()" command. I even check that the process is ok before I send the message. Please help.

Resources