Skip to content

Commit

Permalink
>Release date: 2015-08-22
Browse files Browse the repository at this point in the history
[NEW] Will option on SessionManager closes #44
[NEW] Change SessionManager subscriptions while connected
[FIX] Correct SessionManager subscriptions according to server session present
  • Loading branch information
Christoph Krey committed Aug 22, 2015
1 parent 4897a23 commit 38cc064
Show file tree
Hide file tree
Showing 67 changed files with 766 additions and 423 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
MQTT-Client-Framework iOS Release Notes
=======================================

## MQTT-Client-Framework 0.2.5
>Release date: 2015-08-22
[NEW] Will option on SessionManager closes #44
[NEW] Change SessionManager subscriptions while connected
[FIX] Correct SessionManager subscriptions according to server session present

[NEW] zero message id is accepted on incoming publish closes #42

## MQTT-Client-Framework 0.2.4
>Release date: 2015-08-16
Expand Down
4 changes: 2 additions & 2 deletions MQTTClient.podspec
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = "MQTTClient"
s.version = "0.2.4"
s.version = "0.2.5"
s.summary = "IOS native ObjectiveC MQTT Framework"
s.homepage = "https://github.com/ckrey/MQTT-Client-Framework"
s.license = { :type => "MIT", :file => "LICENSE" }
s.author = { "Christoph Krey" => "[email protected]" }
s.source = { :git => "https://github.com/ckrey/MQTT-Client-Framework.git", :tag => "0.2.4" }
s.source = { :git => "https://github.com/ckrey/MQTT-Client-Framework.git", :tag => "0.2.5" }

s.source_files = "MQTTClient/MQTTClient", "MQTTClient/MQTTClient/**/*.{h,m}"
s.requires_arc = true
Expand Down
4 changes: 4 additions & 0 deletions MQTTClient/MQTTClient.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
/* Begin PBXBuildFile section */
840507C5193DCF2E002EBBD2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 840507C4193DCF2E002EBBD2 /* UIKit.framework */; };
840785A918A2AA26009158D5 /* MQTTClientPublishTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 840785A818A2AA26009158D5 /* MQTTClientPublishTests.m */; };
8429773F1B87CEF600A119FB /* MQTTSessionManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8429773E1B87CEF600A119FB /* MQTTSessionManagerTests.m */; };
8442BEE91A97B15100D00E55 /* SwiftTests2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442BEE81A97B15100D00E55 /* SwiftTests2.swift */; };
844C93AB1A81645D00CA4A03 /* MQTTACLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 844C93AA1A81645D00CA4A03 /* MQTTACLTests.m */; };
845DBE771884AAD700EDB183 /* MQTTClientSubscriptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 845DBE761884AAD700EDB183 /* MQTTClientSubscriptionTests.m */; };
Expand Down Expand Up @@ -132,6 +133,7 @@
840507C2193DCE4B002EBBD2 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
840507C4193DCF2E002EBBD2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
840785A818A2AA26009158D5 /* MQTTClientPublishTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MQTTClientPublishTests.m; sourceTree = "<group>"; };
8429773E1B87CEF600A119FB /* MQTTSessionManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MQTTSessionManagerTests.m; sourceTree = "<group>"; };
8442BEE81A97B15100D00E55 /* SwiftTests2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftTests2.swift; sourceTree = "<group>"; };
844C93AA1A81645D00CA4A03 /* MQTTACLTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MQTTACLTests.m; sourceTree = "<group>"; };
845DBE761884AAD700EDB183 /* MQTTClientSubscriptionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MQTTClientSubscriptionTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -325,6 +327,7 @@
848BB8F2195FF7A2004FCAE2 /* MQTTClientOnlyTests.m */,
845DBE761884AAD700EDB183 /* MQTTClientSubscriptionTests.m */,
840785A818A2AA26009158D5 /* MQTTClientPublishTests.m */,
8429773E1B87CEF600A119FB /* MQTTSessionManagerTests.m */,
84B739B21A66F07A00B103F4 /* SwiftTests.swift */,
8442BEE81A97B15100D00E55 /* SwiftTests2.swift */,
84B739B11A66F07900B103F4 /* MQTTClientTests-Bridging-Header.h */,
Expand Down Expand Up @@ -526,6 +529,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8429773F1B87CEF600A119FB /* MQTTSessionManagerTests.m in Sources */,
C21D3C711B1EBD730012DD2F /* MQTTSSLSecurityPolicyTests.m in Sources */,
840785A918A2AA26009158D5 /* MQTTClientPublishTests.m in Sources */,
8461914A1883E56800101409 /* MQTTClientTests.m in Sources */,
Expand Down
20 changes: 18 additions & 2 deletions MQTTClient/MQTTClient/MQTTSessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ typedef NS_ENUM(int, MQTTSessionManagerState) {
* @param auth specifies the user and pass parameters should be used for authenthication
* @param user an NSString object containing the user's name (or ID) for authentication. May be nil.
* @param pass an NSString object containing the user's password. If userName is nil, password must be nil as well.
* @param will indicates whether a will shall be sent
* @param willTopic the Will Topic is a string, must not be nil
* @param will the Will Message, might be zero length
* @param willMsg the Will Message, might be zero length
* @param willQos specifies the QoS level to be used when publishing the Will Message.
* @param willRetainFlag indicates if the server should publish the Will Messages with retainFlag.
* @param clientId The Client Identifier identifies the Client to the Server. If nil, a random clientId is generated.
Expand All @@ -92,7 +93,22 @@ typedef NS_ENUM(int, MQTTSessionManagerState) {
willRetainFlag:(BOOL)willRetainFlag
withClientId:(NSString *)clientId;

/** Backward compatability for calls without willSend*/
/** Connects to the MQTT broker and stores the parameters for subsequent reconnects
* @param host specifies the hostname or ip address to connect to. Defaults to @"localhost".
* @param port spefies the port to connect to
* @param tls specifies whether to use SSL or not
* @param keepalive The Keep Alive is a time interval measured in seconds. The MQTTClient ensures that the interval between Control Packets being sent does not exceed the Keep Alive value. In the absence of sending any other Control Packets, the Client sends a PINGREQ Packet.
* @param clean specifies if the server should discard previous session information.
* @param auth specifies the user and pass parameters should be used for authenthication
* @param user an NSString object containing the user's name (or ID) for authentication. May be nil.
* @param pass an NSString object containing the user's password. If userName is nil, password must be nil as well.
* @param willTopic the Will Topic is a string, must not be nil
* @param will the Will Message, might be zero length
* @param willQos specifies the QoS level to be used when publishing the Will Message.
* @param willRetainFlag indicates if the server should publish the Will Messages with retainFlag.
* @param clientId The Client Identifier identifies the Client to the Server. If nil, a random clientId is generated.
* @return the initialised MQTTSessionManager object
*/

- (void)connectTo:(NSString *)host
port:(NSInteger)port
Expand Down
58 changes: 32 additions & 26 deletions MQTTClient/MQTTClient/MQTTSessionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,12 @@ @interface MQTTSessionManager()
@property (nonatomic) UIBackgroundTaskIdentifier backgroundTask;
@property (strong, nonatomic) void (^completionHandler)(UIBackgroundFetchResult);



@end

#define RECONNECT_TIMER 1.0
#define RECONNECT_TIMER_MAX 64.0
#define BACKGROUND_DISCONNECT_AFTER 8.0


@implementation MQTTSessionManager
- (id)init
{
Expand Down Expand Up @@ -151,7 +148,7 @@ - (void)connectTo:(NSString *)host
![user isEqualToString:self.user] ||
![pass isEqualToString:self.pass] ||
![willTopic isEqualToString:self.willTopic] ||
//![willMsg isEqualToData:self.willMsg] ||
![willMsg isEqualToData:self.willMsg] ||
willQos != self.willQos ||
willRetainFlag != self.willRetainFlag ||
![clientId isEqualToString:self.clientId]) {
Expand All @@ -165,7 +162,7 @@ - (void)connectTo:(NSString *)host
self.pass = pass;
self.will = will;
self.willTopic = willTopic;
self.willMsg=willMsg;
self.willMsg = willMsg;
self.willQos = willQos;
self.willRetainFlag = willRetainFlag;
self.clientId = clientId;
Expand Down Expand Up @@ -223,27 +220,21 @@ - (void)handleEvent:(MQTTSession *)session event:(MQTTSessionEvent)eventCode err
@(MQTTSessionEventConnectionRefused): @"connection refused",
@(MQTTSessionEventConnectionClosed): @"connection closed",
@(MQTTSessionEventConnectionError): @"connection error",
@(MQTTSessionEventProtocolError): @"protocoll error"
@(MQTTSessionEventProtocolError): @"protocoll error",
@(MQTTSessionEventConnectionClosedByBroker): @"connection closed by broker"
};
NSLog(@"Connection MQTT eventCode: %@ (%ld) %@", events[@(eventCode)], (long)eventCode, error);
NSLog(@"MQTTSession eventCode: %@ (%ld) %@", events[@(eventCode)], (long)eventCode, error);
#endif
[self.reconnectTimer invalidate];
switch (eventCode) {
case MQTTSessionEventConnected:
{
self.lastErrorCode = nil;
self.state = MQTTSessionManagerStateConnected;

if (self.clean || !self.reconnectFlag) {
if (self.subscriptions && [self.subscriptions count]) {
[self.session subscribeToTopics:self.subscriptions];
}
self.reconnectFlag = TRUE;
}

break;
}
case MQTTSessionEventConnectionClosed:
case MQTTSessionEventConnectionClosedByBroker:
self.state = MQTTSessionManagerStateClosed;
if (self.backgroundTask) {
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
Expand Down Expand Up @@ -282,6 +273,16 @@ - (void)newMessage:(MQTTSession *)session data:(NSData *)data onTopic:(NSString
[self.delegate handleMessage:data onTopic:topic retained:retained];
}

- (void)connected:(MQTTSession *)session sessionPresent:(BOOL)sessionPresent {
if (self.clean || !self.reconnectFlag || !sessionPresent) {
if (self.subscriptions && [self.subscriptions count]) {
[self.session subscribeToTopics:self.subscriptions];
}
self.reconnectFlag = TRUE;
}
}


- (void)connectToInternal
{
if (self.state == MQTTSessionManagerStateStarting) {
Expand Down Expand Up @@ -312,17 +313,22 @@ - (void)connectToLast

- (void)setSubscriptions:(NSMutableDictionary *)newSubscriptions
{
if (self.state==MQTTSessionManagerStateConnected) {
if (self.subscriptions && [self.subscriptions count]) {
[self.session unsubscribeAndWaitTopics:self.subscriptions];
}
_subscriptions=newSubscriptions;
if (self.subscriptions && [self.subscriptions count]) {
[self.session subscribeToTopics:self.subscriptions];
}
} else {
_subscriptions=newSubscriptions;
}
if (self.state==MQTTSessionManagerStateConnected) {
for (NSString *topicFilter in self.subscriptions) {
if (![newSubscriptions objectForKey:topicFilter]) {
[self.session unsubscribeAndWaitTopic:topicFilter];
}
}

for (NSString *topicFilter in newSubscriptions) {
if (![self.subscriptions objectForKey:topicFilter]) {
NSNumber *number = newSubscriptions[topicFilter];
MQTTQosLevel qos = [number unsignedIntValue];
[self.session subscribeToTopic:topicFilter atLevel:qos];
}
}
}
_subscriptions=newSubscriptions;
}

@end
132 changes: 132 additions & 0 deletions MQTTClient/MQTTClientTests/MQTTSessionManagerTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//
// MQTTSessionManagerTests.m
// MQTTClient
//
// Created by Christoph Krey on 21.08.15.
// Copyright (c) 2015 Christoph Krey. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "MQTTSessionManager.h"
#import "MQTTClientTests.h"

@interface MQTTSessionManagerTests : XCTestCase <MQTTSessionManagerDelegate>
@property (nonatomic) int received;
@property (nonatomic) int sent;
@property (nonatomic) BOOL timeout;
@property (nonatomic) int step;
@end

@implementation MQTTSessionManagerTests

- (void)setUp {
[super setUp];
}

- (void)tearDown {
[super tearDown];
}

- (void)testMQTTSessionManagerClean {
[self testMQTTSessionManager:true];
}

- (void)testMQTTSessionManagerNoClean {
[self testMQTTSessionManager:false];
}

- (void)testMQTTSessionManager:(BOOL)clean {
for (NSString *broker in BROKERLIST) {
NSLog(@"testing broker %@", broker);
NSDictionary *parameters = BROKERS[broker];


self.step = -1;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:[parameters[@"timeout"] intValue]
target:self
selector:@selector(timeout:)
userInfo:nil
repeats:true];

self.received = 0;
MQTTSessionManager *manager = [[MQTTSessionManager alloc] init];
manager.delegate = self;
manager.subscriptions = [@{@"#": @(0)} mutableCopy];
[manager connectTo:parameters[@"host"]
port:[parameters[@"port"] intValue]
tls:[parameters[@"tls"] boolValue]
keepalive:60
clean:clean
auth:NO
user:nil
pass:nil
will:NO
willTopic:nil
willMsg:nil
willQos:MQTTQosLevelAtMostOnce
willRetainFlag:FALSE
withClientId:@"MQTTSessionManager"];
while (self.step == -1 && manager.state != MQTTSessionManagerStateConnected) {
NSLog(@"waiting for connect %d", manager.state);
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(manager.state, MQTTSessionManagerStateConnected);

while (self.step <= 0) {
NSLog(@"received %d on #", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelAtMostOnce retain:FALSE];
self.sent++;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{@"#": @(0),@"$SYS/#": @(0)} mutableCopy];
while (self.step == 1) {
NSLog(@"received %d on # or $SYS/#", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelAtMostOnce retain:FALSE];
self.sent++;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{@"$SYS/#": @(0)} mutableCopy];
while (self.step <= 2) {
NSLog(@"received %d on $SYS/#", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelAtMostOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(self.received, self.sent);

manager.subscriptions = [@{} mutableCopy];
while (self.step <= 3) {
NSLog(@"received %d on nothing", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelAtMostOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(self.received, self.sent);

[manager disconnect];
while (self.step <= 4) {
NSLog(@"received %d after disconnect", self.received);
[manager sendData:[@"data" dataUsingEncoding:NSUTF8StringEncoding] topic:@"MQTTSessionManager" qos:MQTTQosLevelAtMostOnce retain:FALSE];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
XCTAssertEqual(self.received, self.sent);
[timer invalidate];
}
}

- (void)handleMessage:(NSData *)data onTopic:(NSString *)topic retained:(BOOL)retained {
NSLog(@"handleMessage t:%@", topic);
if ([topic isEqualToString:@"MQTTSessionManager"]) {
self.received++;
}
}

- (void)timeout:(NSTimer *)timer {
NSLog(@"timeout s:%d", self.step);
self.step++;
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,8 @@ typedef NS_ENUM(NSInteger, MQTTSessionEvent) {
/** Control MQTT persistence by setting the properties of persistence before connecting to an MQTT broker.
The settings are specific to a clientId.
persistence.persistent = YES or NO (default) to establish file or in memory persistence
persistence.persistent = YES or NO (default) to establish file or in memory persistence. IMPORTANT: set immediately after creating the MQTTSession before calling any other method. Otherwise the default value (NO) will be used
for this session.
persistence.maxWindowSize (a positive number, default is 16) to control the number of messages sent before waiting for acknowledgement in Qos 1 or 2. Additional messages are
stored and transmitted later.
Expand Down
Binary file modified MQTTClient/dist/MQTTClient.framework/Versions/A/MQTTClient
Binary file not shown.
7 changes: 6 additions & 1 deletion MQTTClient/dist/documentation/html/Nodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<Subnodes>
<Node>
<Name>Classes</Name>
<Path></Path>
<Path>annotated.html</Path>
<Subnodes>
<Node>
<Name>Class List</Name>
Expand Down Expand Up @@ -419,6 +419,11 @@
<Name>MQTTSessionManager</Name>
<Path>interface_m_q_t_t_session_manager.html</Path>
<Subnodes>
<Node>
<Name>connectTo:port:tls:keepalive:clean:auth:user:pass:will:willTopic:willMsg:willQos:willRetainFlag:withClientId:</Name>
<Path>interface_m_q_t_t_session_manager.html</Path>
<Anchor>af50a6c56e8d19ef1e739cccb9e11722a</Anchor>
</Node>
<Node>
<Name>connectTo:port:tls:keepalive:clean:auth:user:pass:willTopic:will:willQos:willRetainFlag:withClientId:</Name>
<Path>interface_m_q_t_t_session_manager.html</Path>
Expand Down
11 changes: 11 additions & 0 deletions MQTTClient/dist/documentation/html/Tokens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,17 @@
<Path>interface_m_q_t_t_session_manager.html</Path>
<DeclaredIn>MQTTSessionManager.h</DeclaredIn>
</Token>
<Token>
<TokenIdentifier>
<Name>connectTo:port:tls:keepalive:clean:auth:user:pass:will:willTopic:willMsg:willQos:willRetainFlag:withClientId:</Name>
<APILanguage>occ</APILanguage>
<Type>instm</Type>
<Scope>MQTTSessionManager</Scope>
</TokenIdentifier>
<Path>interface_m_q_t_t_session_manager.html</Path>
<Anchor>af50a6c56e8d19ef1e739cccb9e11722a</Anchor>
<DeclaredIn>MQTTSessionManager.h</DeclaredIn>
</Token>
<Token>
<TokenIdentifier>
<Name>connectTo:port:tls:keepalive:clean:auth:user:pass:willTopic:will:willQos:willRetainFlag:withClientId:</Name>
Expand Down
Loading

0 comments on commit 38cc064

Please sign in to comment.