Skip to content

Commit

Permalink
Darwin: Address various MTRSetupPayload issues (project-chip#33286)
Browse files Browse the repository at this point in the history
* Darwin: Address various MTRSetupPayload issues

API:
- Conform to NSCopying and implement isEqual / hash
- Simplify a number of methods to not return NSError
- Add initWithPayload: as a replacement for setupPayloadWithOnboardingPayload:error:
- Add initWithQRCode: and initWithManualPairingCode: for cases where payload type is known.
- Add vendorElements as a replacement for getAllOptionalVendorData:
- Add vendorElementWithTag:
- Add removeVendorElementWithTag:
- Add addOrReplaceVendorElement:

Behaviour fixes:
- Allow QRCodes with unknown discovery methods to be parsed
- Correctly generate a long manualEntryCode when a non-standard flow is indicated
- Include vendor elements in qrCodeString
- Preserve vendor elements in encodeWithCoder / initWithCoder

Also simplify the implementation by acting as a direct wrapper of chip::SetupPayload.

Implement parsing in MTRSetupPayload directly and implement the deprecated
MTR*PayloadParser classes in terms of it, instead of the other way around.

* Fix lint check for 0x%[^x] to allow "*"

* Address review comments

* Address review comments around NSNumber

* Hide type-specific initializers as per review

* Misc tweaks
  • Loading branch information
ksperling-apple authored May 9, 2024
1 parent 550b1c1 commit 0d67568
Show file tree
Hide file tree
Showing 17 changed files with 906 additions and 493 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ jobs:
output.
if: always()
run: |
git grep -I -n '0x%[0-9l.-]*[^0-9lxX".-]' -- './*' ':(exclude).github/workflows/lint.yml' && exit 1 || exit 0
git grep -I -n '0x%[0-9l.*-]*[^xX"0-9l.*-]' -- './*' ':(exclude).github/workflows/lint.yml' && exit 1 || exit 0
# git grep exits with 0 if it finds a match, but we want
# to fail (exit nonzero) on match. And we want to exclude this file,
Expand Down
4 changes: 4 additions & 0 deletions src/darwin/Framework/CHIP/MTRDefines_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,9 @@
typedef struct {} variable_hidden_by_mtr_hide;
// clang-format on

// mtr_[un]likely(expr): Evaluates a boolean expression and hints to the compiler that it is [un]likely to be true.
#define mtr_likely(expr) __builtin_expect(!!(expr), 1)
#define mtr_unlikely(expr) __builtin_expect(!!(expr), 0)

// Default timed interaction timeout, in ms, if another one is not provided.
#define MTR_DEFAULT_TIMED_INTERACTION_TIMEOUT_MS 10000
12 changes: 12 additions & 0 deletions src/darwin/Framework/CHIP/MTRError.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#import "MTRError.h"
#import "MTRError_Internal.h"
#import "MTRLogging_Internal.h"

#import <app/MessageDef/StatusIB.h>
#import <inet/InetError.h>
Expand All @@ -43,6 +44,11 @@ - (instancetype)initWithError:(CHIP_ERROR)error;

@implementation MTRError

+ (NSError *)errorWithCode:(MTRErrorCode)code
{
return [NSError errorWithDomain:MTRErrorDomain code:code userInfo:nil];
}

+ (NSError *)errorForCHIPErrorCode:(CHIP_ERROR)errorCode
{
return [MTRError errorForCHIPErrorCode:errorCode logContext:nil];
Expand Down Expand Up @@ -337,3 +343,9 @@ - (instancetype)initWithError:(CHIP_ERROR)error
}

@end

void MTRThrowInvalidArgument(NSString * reason)
{
MTR_LOG_ERROR("Invalid argument: %@", reason);
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil];
}
15 changes: 14 additions & 1 deletion src/darwin/Framework/CHIP/MTRError_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,34 @@
*/

#import <Foundation/Foundation.h>
#import <Matter/MTRDefines.h>
#import <Matter/MTRError.h>

#import "MTRDefines_Internal.h"

#include <app/MessageDef/StatusIB.h>
#include <lib/core/CHIPError.h>
#include <protocols/interaction_model/StatusCode.h>

NS_ASSUME_NONNULL_BEGIN

MTR_DIRECT_MEMBERS
@interface MTRError : NSObject
+ (NSError *)errorWithCode:(MTRErrorCode)code;
+ (NSError * _Nullable)errorForCHIPErrorCode:(CHIP_ERROR)errorCode;
+ (NSError * _Nullable)errorForCHIPErrorCode:(CHIP_ERROR)errorCode logContext:(id _Nullable)contextToLog;
+ (NSError * _Nullable)errorForIMStatus:(const chip::app::StatusIB &)status;
+ (NSError * _Nullable)errorForIMStatusCode:(chip::Protocols::InteractionModel::Status)status;
+ (CHIP_ERROR)errorToCHIPErrorCode:(NSError * _Nullable)error;
@end

// Similar to VerifyOrDie, but throws an NSInvalidArgumentException
#define MTRVerifyArgumentOrDie(cond, reason) \
do { \
if (mtr_unlikely(!(cond))) { \
MTRThrowInvalidArgument(reason); \
} \
} while (0)

MTR_EXTERN _Noreturn void MTRThrowInvalidArgument(NSString * reason);

NS_ASSUME_NONNULL_END
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

NS_ASSUME_NONNULL_BEGIN

MTR_DEPRECATED("Please use [MTRSetupPayload setupPayloadWithOnboardingPayload:error:]", ios(16.1, 16.4), macos(13.0, 13.3),
MTR_DEPRECATED("Please use -[MTRSetupPayload initWithPayload:]", ios(16.1, 16.4), macos(13.0, 13.3),
watchos(9.1, 9.4), tvos(16.1, 16.4))
@interface MTRManualSetupPayloadParser : NSObject
- (instancetype)initWithDecimalStringRepresentation:(NSString *)decimalStringRepresentation;
Expand Down
40 changes: 7 additions & 33 deletions src/darwin/Framework/CHIP/MTRManualSetupPayloadParser.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,56 +14,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "MTRManualSetupPayloadParser.h"

#import "MTRError_Internal.h"
#import "MTRFramework.h"
#import "MTRLogging_Internal.h"
#import "MTRSetupPayload_Internal.h"

#import <setup_payload/ManualSetupPayloadParser.h>
#import <setup_payload/SetupPayload.h>

#include <string>

@implementation MTRManualSetupPayloadParser {
NSString * _decimalStringRepresentation;
chip::ManualSetupPayloadParser * _chipManualSetupPayloadParser;
}

+ (void)initialize
{
MTRFrameworkInit();
}

- (id)initWithDecimalStringRepresentation:(NSString *)decimalStringRepresentation
{
if (self = [super init]) {
_decimalStringRepresentation = decimalStringRepresentation;
_chipManualSetupPayloadParser = new chip::ManualSetupPayloadParser(std::string([decimalStringRepresentation UTF8String]));
}
self = [super init];
_decimalStringRepresentation = decimalStringRepresentation;
return self;
}

- (MTRSetupPayload *)populatePayload:(NSError * __autoreleasing *)error
{
chip::SetupPayload cPlusPluspayload;
MTRSetupPayload * payload;

CHIP_ERROR chipError = _chipManualSetupPayloadParser->populatePayload(cPlusPluspayload);
if (chipError == CHIP_NO_ERROR) {
payload = [[MTRSetupPayload alloc] initWithSetupPayload:cPlusPluspayload];
} else if (error) {
*error = [MTRError errorForCHIPErrorCode:chipError];
MTRSetupPayload * payload = [[MTRSetupPayload alloc] initWithManualPairingCode:_decimalStringRepresentation];
if (!payload && error) {
*error = [MTRError errorWithCode:MTRErrorCodeInvalidArgument];
}

return payload;
}

- (void)dealloc
{
delete _chipManualSetupPayloadParser;
_chipManualSetupPayloadParser = nullptr;
}

@end
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/MTROnboardingPayloadParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ typedef NS_ENUM(NSUInteger, MTROnboardingPayloadType) {
MTROnboardingPayloadTypeNFC
} MTR_DEPRECATED("MTROnboardingPayloadType is unused", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0));

MTR_DEPRECATED("Please use [MTRSetupPayload setupPayloadWithOnboardingPayload:error:]", ios(16.1, 17.0), macos(13.0, 14.0),
MTR_DEPRECATED("Please use [MTRSetupPayload initWithPayload:]", ios(16.1, 17.0), macos(13.0, 14.0),
watchos(9.1, 10.0), tvos(16.1, 17.0))
@interface MTROnboardingPayloadParser : NSObject

Expand Down
41 changes: 3 additions & 38 deletions src/darwin/Framework/CHIP/MTROnboardingPayloadParser.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,50 +16,15 @@
*/

#import "MTROnboardingPayloadParser.h"
#import "MTRManualSetupPayloadParser.h"
#import "MTRQRCodeSetupPayloadParser.h"

#import "MTRSetupPayload.h"

@implementation MTROnboardingPayloadParser

+ (bool)isQRCode:(NSString *)codeString
{
return [codeString hasPrefix:@"MT:"];
}

+ (MTRSetupPayload * _Nullable)setupPayloadForOnboardingPayload:(NSString *)onboardingPayload
error:(NSError * __autoreleasing *)error
{
MTRSetupPayload * payload;
// MTROnboardingPayloadTypeNFC is of type QR code and handled same as QR code
MTROnboardingPayloadType type =
[self isQRCode:onboardingPayload] ? MTROnboardingPayloadTypeQRCode : MTROnboardingPayloadTypeManualCode;
switch (type) {
case MTROnboardingPayloadTypeManualCode:
payload = [self setupPayloadForManualCodeOnboardingPayload:onboardingPayload error:error];
break;
case MTROnboardingPayloadTypeQRCode:
payload = [self setupPayloadForQRCodeOnboardingPayload:onboardingPayload error:error];
break;
default:
break;
}
return payload;
return [MTRSetupPayload setupPayloadWithOnboardingPayload:onboardingPayload error:error];
}

+ (MTRSetupPayload * _Nullable)setupPayloadForQRCodeOnboardingPayload:(NSString *)onboardingPayload
error:(NSError * __autoreleasing *)error
{
MTRQRCodeSetupPayloadParser * qrCodeParser =
[[MTRQRCodeSetupPayloadParser alloc] initWithBase38Representation:onboardingPayload];
return [qrCodeParser populatePayload:error];
}

+ (MTRSetupPayload * _Nullable)setupPayloadForManualCodeOnboardingPayload:(NSString *)onboardingPayload
error:(NSError * __autoreleasing *)error
{
MTRManualSetupPayloadParser * manualParser =
[[MTRManualSetupPayloadParser alloc] initWithDecimalStringRepresentation:onboardingPayload];
return [manualParser populatePayload:error];
}
@end
2 changes: 1 addition & 1 deletion src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

NS_ASSUME_NONNULL_BEGIN

MTR_DEPRECATED("Please use [MTRSetupPayload setupPayloadWithOnboardingPayload:error:]", ios(16.1, 16.4), macos(13.0, 13.3),
MTR_DEPRECATED("Please use [MTRSetupPayload -initWithPayload:]", ios(16.1, 16.4), macos(13.0, 13.3),
watchos(9.1, 9.4), tvos(16.1, 16.4))
@interface MTRQRCodeSetupPayloadParser : NSObject
- (instancetype)initWithBase38Representation:(NSString *)base38Representation;
Expand Down
40 changes: 7 additions & 33 deletions src/darwin/Framework/CHIP/MTRQRCodeSetupPayloadParser.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020-2024 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,54 +16,28 @@
*/

#import "MTRQRCodeSetupPayloadParser.h"

#import "MTRError_Internal.h"
#import "MTRFramework.h"
#import "MTRLogging_Internal.h"
#import "MTRSetupPayload_Internal.h"

#import <setup_payload/QRCodeSetupPayloadParser.h>
#import <setup_payload/SetupPayload.h>

#include <string>

@implementation MTRQRCodeSetupPayloadParser {
NSString * _base38Representation;
chip::QRCodeSetupPayloadParser * _chipQRCodeSetupPayloadParser;
}

+ (void)initialize
{
MTRFrameworkInit();
}

- (id)initWithBase38Representation:(NSString *)base38Representation
{
if (self = [super init]) {
_base38Representation = base38Representation;
_chipQRCodeSetupPayloadParser = new chip::QRCodeSetupPayloadParser(std::string([base38Representation UTF8String]));
}
self = [super init];
_base38Representation = base38Representation;
return self;
}

- (MTRSetupPayload *)populatePayload:(NSError * __autoreleasing *)error
{
chip::SetupPayload cPlusPluspayload;
MTRSetupPayload * payload;

CHIP_ERROR chipError = _chipQRCodeSetupPayloadParser->populatePayload(cPlusPluspayload);
if (chipError == CHIP_NO_ERROR) {
payload = [[MTRSetupPayload alloc] initWithSetupPayload:cPlusPluspayload];
} else if (error) {
*error = [MTRError errorForCHIPErrorCode:chipError];
MTRSetupPayload * payload = [[MTRSetupPayload alloc] initWithQRCode:_base38Representation];
if (!payload && error) {
*error = [MTRError errorWithCode:MTRErrorCodeInvalidArgument];
}

return payload;
}

- (void)dealloc
{
delete _chipQRCodeSetupPayloadParser;
_chipQRCodeSetupPayloadParser = nullptr;
}

@end
Loading

0 comments on commit 0d67568

Please sign in to comment.