Skip to content

Commit

Permalink
fix CI errors
Browse files Browse the repository at this point in the history
  • Loading branch information
nivi-apple committed Nov 18, 2023
1 parent 1078039 commit 8cb17b6
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 9 deletions.
6 changes: 5 additions & 1 deletion src/darwin/Framework/CHIP/MTRDiagnosticsLogDownloadTask.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
* limitations under the License.
*/

#import "MTRDevice.h"
#import <Foundation/Foundation.h>
#import <Matter/MTRDefines.h>

#import "MTRDevice.h"

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -26,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
* messages and transfer events and downloads the file.
*
*/
MTR_HIDDEN
@interface MTRDiagnosticsLogDownloadTask : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
Expand All @@ -39,3 +42,4 @@ NS_ASSUME_NONNULL_BEGIN
@end

NS_ASSUME_NONNULL_END

1 change: 1 addition & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticsLogDownloadTask.mm
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,4 @@ - (void)downloadLogOfType:(MTRDiagnosticLogType)type
}

@end

42 changes: 42 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticsLogDownloadTask1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
*
* Copyright (c) 2023 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Foundation/Foundation.h>

#import "MTRDevice.h"

NS_ASSUME_NONNULL_BEGIN

/**
* This class handles the task downloading a log file requested by the MTRDevice. It creates a new
* MTRDiagnosticsLogTransferHandler to prepare for the BDX transfer session and handle the BDX
* messages and transfer events and downloads the file.
*
*/
@interface MTRDiagnosticsLogDownloadTask : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

- (instancetype)initWithDevice:(MTRDevice *)device;

- (void)downloadLogOfType:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion;
@end

NS_ASSUME_NONNULL_END
262 changes: 262 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticsLogDownloadTask1.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
//
/**
* Copyright (c) 2023 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "MTRDiagnosticsLogDownloadTask.h"
#import "MTRCluster.h"
#import "MTRClusterConstants.h"
#import "MTRDefines_Internal.h"
#import "MTRDeviceController.h"
#import "MTRDeviceController_Internal.h"
#import "MTRDevice_Internal.h"
#import "MTRDiagnosticsLogTransferHandler.h"
#import "MTRError.h"
#import <Matter/MTRClusters.h>
#import <Matter/MTRDefines.h>

#import "zap-generated/MTRCommandPayloads_Internal.h"

#import <os/lock.h>

#include <controller/CHIPDeviceControllerFactory.h>
#include <platform/CHIPDeviceLayer.h>

using namespace chip;

@interface MTRDiagnosticsLogDownloadTask ()
@property (nonatomic, readonly) os_unfair_lock lock;
@property (nonatomic) dispatch_source_t timerSource;
@property (nonatomic) MTRDiagnosticsLogTransferHandler * diagnosticLogsTransferHandler;
@property (nonatomic, readonly, weak) MTRDevice * device;
@property (strong, nonatomic) dispatch_queue_t queue;

@end

@implementation MTRDiagnosticsLogDownloadTask
- (instancetype)initWithDevice:(MTRDevice *)device
{
if (self = [super init]) {
_lock = OS_UNFAIR_LOCK_INIT;
_device = device;
_queue = dispatch_queue_create("org.csa-iot.matter.framework.device.workqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
}
return self;
}

- (NSString *)_toLogTypeString:(MTRDiagnosticLogType)type
{
switch (type) {
case MTRDiagnosticLogTypeEndUserSupport:
return @"EndUserSupport";
case MTRDiagnosticLogTypeNetworkDiagnostics:
return @"NetworkDiag";
case MTRDiagnosticLogTypeCrash:
return @"Crash";
default:
return @"";
}
}

- (NSString *)_getFileDesignatorForLogType:(MTRDiagnosticLogType)type
{
NSString * fileDesignator = [NSString stringWithFormat:@"bdx:/%0llx/%s", _device.nodeID.unsignedLongLongValue, [self _toLogTypeString:type].UTF8String];
return fileDesignator;
}

- (void)_startTimerForDownload:(NSTimeInterval)timeout
{
// TODO: Fix #30538 Fix the timeout code when downloadLogOfType API is called with a timeout value.
self->_timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, self.queue);
VerifyOrDie(self->_timerSource != nullptr);

dispatch_source_set_timer(
self->_timerSource, dispatch_walltime(nullptr, static_cast<int64_t>(timeout * NSEC_PER_MSEC)), DISPATCH_TIME_FOREVER, 2 * NSEC_PER_MSEC);

dispatch_source_set_event_handler(self->_timerSource, ^{
dispatch_async(self.queue, ^{
os_unfair_lock_lock(&self->_lock);
if (self->_diagnosticLogsTransferHandler != nil) {
self->_diagnosticLogsTransferHandler->AbortTransfer(chip::bdx::StatusCode::kUnknown);
}
os_unfair_lock_unlock(&self->_lock);
});
dispatch_source_cancel(self->_timerSource);
});
dispatch_resume(self->_timerSource);
}

- (NSURL * _Nullable)_temporaryFileURLForDownload:(MTRDiagnosticLogType)type
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
{
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyy-MM-dd_HH:mm:ss.SSSZZZ";

NSString * timeString = [dateFormatter stringFromDate:NSDate.now];

NSString * fileName = [NSString stringWithFormat:@"%s_%0llx_%s", timeString.UTF8String, _device.nodeID.unsignedLongLongValue, [self _toLogTypeString:type].UTF8String];

NSURL * filePath = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName] isDirectory:YES];
NSError * error = nil;

NSURL * downloadFileURL = [[NSFileManager defaultManager] URLForDirectory:NSItemReplacementDirectory
inDomain:NSUserDomainMask
appropriateForURL:filePath
create:YES
error:&error];
if (downloadFileURL == nil || error != nil) {
return nil;
}

if ([[NSFileManager defaultManager] createFileAtPath:[filePath path] contents:nil attributes:nil]) {
return filePath;
}
return nil;
}

using namespace chip::app::Clusters::DiagnosticLogs;
- (bool)_isErrorResponse:(MTRDiagnosticLogsClusterRetrieveLogsResponseParams * _Nullable)response
{
if (response == nil || response.status == nil) {
return true;
}
StatusEnum statusValue = static_cast<StatusEnum>(response.status.intValue);
return ((statusValue != StatusEnum::kNoLogs && statusValue != StatusEnum::kExhausted) || response.logContent.length == 0);
}

- (void)_invokeCompletion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
filepath:(NSURL * _Nullable)filepath
queue:(dispatch_queue_t)queue
error:(NSError * _Nullable)error
{
dispatch_async(queue, ^{
completion(filepath, error);
});

dispatch_async(self.queue, ^{
if (self->_diagnosticLogsTransferHandler != nil) {
delete (self->_diagnosticLogsTransferHandler);
self->_diagnosticLogsTransferHandler = nil;
}
});
}

- (void)_invokeCompletionWithError:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
queue:(dispatch_queue_t)queue
error:(NSError * _Nullable)error
{
[self _invokeCompletion:completion filepath:nil queue:queue error:error];
}

- (void)_handleResponse:(NSError *)error
filepath:(NSURL * _Nullable)filepath
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
{
if (self->_timerSource) {
dispatch_source_cancel(self->_timerSource);
}

if (error == nil && filepath != nil) {
[self _invokeCompletion:completion filepath:filepath queue:queue error:nil];
} else {
[self _invokeCompletionWithError:completion queue:queue error:error];
}
[self->_device removeDiagnosticsLogDownloadTask];
}

- (void)_downloadLogOfType:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
{
if (type != MTRDiagnosticLogTypeEndUserSupport && type != MTRDiagnosticLogTypeNetworkDiagnostics && type != MTRDiagnosticLogTypeCrash) {
[self _invokeCompletionWithError:completion queue:queue error:[NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidArgument userInfo:nil]];
return;
}

NSURL * filePath = [self _temporaryFileURLForDownload:type queue:queue completion:completion];
if (filePath == nil) {
[self _invokeCompletionWithError:completion queue:queue error:[NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidState userInfo:nil]];
return;
}

os_unfair_lock_lock(&self->_lock);
self->_diagnosticLogsTransferHandler = new MTRDiagnosticsLogTransferHandler(filePath, ^(bool result) {
if (result == YES) {
[self _handleResponse:nil filepath:filePath queue:queue completion:completion];
} else {
[self _handleResponse:[NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidState userInfo:nil] filepath:nil queue:queue completion:completion];
}
});
os_unfair_lock_unlock(&self->_lock);

// Get the device commissionee and get the exchange manager to register for unsolicited message handler for BDX messages
[_device.deviceController asyncGetCommissionerOnMatterQueue:^(Controller::DeviceCommissioner * commissioner) {
os_unfair_lock_lock(&self->_lock);
commissioner->ExchangeMgr()->RegisterUnsolicitedMessageHandlerForProtocol(Protocols::BDX::Id, self->_diagnosticLogsTransferHandler);
os_unfair_lock_unlock(&self->_lock);

dispatch_async(self.queue, ^{
// Start a timer if a timeout is provided
if (timeout > 0) {
[self _startTimerForDownload:timeout];
}

MTRDiagnosticLogsClusterRetrieveLogsRequestParams * requestParams = [[MTRDiagnosticLogsClusterRetrieveLogsRequestParams alloc] init];
requestParams.intent = @(type);
requestParams.requestedProtocol = @(chip::to_underlying(chip::app::Clusters::DiagnosticLogs::TransferProtocolEnum::kBdx));
requestParams.transferFileDesignator = [self _getFileDesignatorForLogType:type];

MTRClusterDiagnosticLogs * cluster = [[MTRClusterDiagnosticLogs alloc] initWithDevice:self->_device endpointID:@(0) queue:self.queue];
[cluster retrieveLogsRequestWithParams:requestParams expectedValues:nil expectedValueInterval:nil
completion:^(MTRDiagnosticLogsClusterRetrieveLogsResponseParams * _Nullable response, NSError * _Nullable error) {
os_unfair_lock_lock(&self->_lock);
// If we are in a BDX session and there is no error, do nothing. Completion will be called when BDX succeeds or fails.
if (self->_diagnosticLogsTransferHandler != nil && error == nil) {
return;
}
os_unfair_lock_unlock(&self->_lock);

if ([self _isErrorResponse:response]) {
[self _handleResponse:error filepath:nil queue:queue completion:completion];
return;
}

// If the response has a log content, copy it into the temporary location and send the URL.
if (response != nil && response.logContent != nil && response.logContent.length > 0) {
if ([response.logContent writeToURL:filePath atomically:YES]) {
[self _handleResponse:nil filepath:filePath queue:queue completion:completion];
return;
}
}
}];
});
}
errorHandler:^(NSError * error) {
[self _handleResponse:error filepath:nil queue:queue completion:completion];
}];
}

- (void)downloadLogOfType:(MTRDiagnosticLogType)type
timeout:(NSTimeInterval)timeout
queue:(dispatch_queue_t)queue
completion:(void (^)(NSURL * _Nullable logResult, NSError * error))completion
{
[self _downloadLogOfType:type timeout:timeout queue:queue completion:completion];
}

@end
2 changes: 2 additions & 0 deletions src/darwin/Framework/CHIP/MTRDiagnosticsLogTransferHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
* limitations under the License.
*/

#import <Foundation/Foundation.h>

#include <protocols/bdx/TransferFacilitator.h>

/**
Expand Down
Loading

0 comments on commit 8cb17b6

Please sign in to comment.