Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more granular upload-to-blob functions, refactor u2b code #2498

Merged
merged 30 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1257313
Add more granular upload-to-blob functions, refactor u2b code
ewertons Jun 30, 2023
c49c3d1
[ACR] Expose upload-to-blob correlation ID and SAS URI in new API fun…
ewertons Jul 8, 2023
c4b3bee
Merge branch 'main' into ewertons/u2b
ewertons Jul 10, 2023
e176cef
Address code review comments (2)
ewertons Jul 11, 2023
161463c
Update unit tests for blob.c
ewertons Jul 12, 2023
136911a
Update iothub_client_ll_u2b_ut
ewertons Jul 12, 2023
969f6b7
Update iothub_client_ll_u2b_ut (continued) and other fixes
ewertons Jul 14, 2023
184ced4
Update iothub_client_ll_u2b_ut (continued 2)
ewertons Jul 15, 2023
824652a
Update iothub_client_ll_u2b_ut (continued 3)
ewertons Jul 16, 2023
3814713
Update iothub_client_ll_u2b_ut (continued 4)
ewertons Jul 17, 2023
96d4669
Merge branch 'main' into ewertons/u2b
ewertons Jul 17, 2023
e2ea53d
Updates to iothub_client_core_ll_ut
ewertons Jul 18, 2023
5c000b0
Updates to iothub_client_core_ll_ut (continued)
ewertons Jul 18, 2023
561dd8a
Additional unit test fixes
ewertons Jul 18, 2023
8cae131
Fix return of blob result in iothubclient_ll_u2b_ut
ewertons Jul 18, 2023
297cfb5
Fix size_t to int conversion in iothub_client_ll_uploadtoblob.c
ewertons Jul 18, 2023
2bce60f
Add fixes for clang build
ewertons Jul 18, 2023
20065e6
More fixes for clang and windows builds
ewertons Jul 19, 2023
8bec9ad
Fix DONT_USE_UPLOADTOBLOB guards in code
ewertons Jul 19, 2023
21eb23e
More build and test fixes
ewertons Jul 19, 2023
391e27a
More build fixes
ewertons Jul 19, 2023
3ef5d88
More test fixes in iothub_client_ll_u2b_ut for OSX pipeline
ewertons Jul 19, 2023
76c3aec
Reduce number of iterations of IoTHub_MQTT_UploadCloseHandle_Before_W…
ewertons Jul 19, 2023
276e03d
Address CR comments from Eric
ewertons Jul 19, 2023
e01a280
Add retry logic to iothub_client_sample_upload_to_blob_custom
ewertons Jul 19, 2023
2129550
Address code review comments (function renaming)
ewertons Jul 20, 2023
6619adc
Merge branch 'main' into ewertons/u2b
ewertons Jul 20, 2023
48e7fce
Verify and log http response status code in u2b functions
ewertons Jul 20, 2023
a31dacb
Update blob_ut
ewertons Jul 20, 2023
2db1cb9
Address final CR comments
ewertons Jul 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions iothub_client/inc/internal/iothub_client_ll_uploadtoblob.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,24 @@ extern "C"
#define BLOCK_SIZE (100*1024*1024)

typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA* IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE;

/*
* @remark `struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_STRUCT` contains information specifically
* related to an individual upload request currently active in Azure IoT Hub, mainly
* the correlation-id and Azure Blob SAS URI provided by the Azure IoT Hub when a new
* upload is started. The `struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE_DATA` on the other hand
* holds common information (independent from individual upload requests) that is used for
* upload-to-blob Rest API calls to Azure IoT Hub.
*/
typedef struct IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_STRUCT* IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE;

MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_UPLOADTOBLOB_HANDLE, IoTHubClient_LL_UploadToBlob_Create, const IOTHUB_CLIENT_CONFIG*, config, IOTHUB_AUTHORIZATION_HANDLE, auth_handle);

/*
* @remark This is a function left in this module for legacy compatibility with the exposed public API for
* @remark This is a legacy function that provides compatibility with the exposed public API for
* upload to blob in iothub_(device|module)_client(_ll) that allowed passing a callback for obtaining the
* blob blocks data. Since there was quite a lot of (specific) logic put into this function that it
* better reside in this API module.
* blob blocks data. Since there was quite a lot of (specific) logic put into this function, it
* better remain in this API module.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubClient_LL_UploadToBlob_UploadMultipleBlocks, IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE, uploadContextHandle, IOTHUB_CLIENT_FILE_UPLOAD_GET_DATA_CALLBACK_EX, getDataCallbackEx, void*, context);

Expand Down
1 change: 0 additions & 1 deletion iothub_client/inc/iothub_client_core_ll.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

Expand Down
26 changes: 24 additions & 2 deletions iothub_client/inc/iothub_device_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ extern "C"
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather move the list of how-to things either in the DevDoc or in a header (a single block, instead of copy/pasting everything) then referencing that doxygen block.

* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
*
Expand All @@ -378,7 +381,10 @@ extern "C"
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
*
Expand All @@ -392,14 +398,19 @@ extern "C"
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE, IoTHubDeviceClient_CreateUploadContext, IOTHUB_DEVICE_CLIENT_HANDLE, iotHubClientHandle, const char*, azureBlobSasUri);

/**
* @brief This API upload a single blob block to Azure Storage (performs a PUT BLOCK operation).
* @brief This API uploads a single blob block to Azure Storage (performs a PUT BLOCK operation).
* @remark It is part of a set of functions for more granular control over Azure IoT-based blob uploads.
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
* For more information about Azure Storage PUT BLOCK, its parameters and behavior, please refer to
* https://learn.microsoft.com/en-us/rest/api/storageservices/put-block
*
* @param uploadContextHandle The handle created with `IoTHubDeviceClient_CreateUploadContext`.
* @param blockNumber Number of the block being uploaded.
Expand All @@ -418,12 +429,17 @@ extern "C"
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
* If this function fails (due to any HTTP error to Azure Storage) it can
* be run again for a discretionary number of times in an attempt to succeed after, for example,
* an internet connectivity disruption is over.
* an internet connectivity disruption is over.
* For more information about Azure Storage PUT BLOCK LIST, please refer to
* https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list
*
* @param uploadContextHandle The handle created with `IoTHubDeviceClient_CreateUploadContext`.
*
Expand All @@ -439,6 +455,9 @@ extern "C"
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
Expand All @@ -457,7 +476,10 @@ extern "C"
* This function is expected to be used along with:
* `IoTHubDeviceClient_CreateUploadContext`
* `IoTHubDeviceClient_AzureStoragePutBlock`
* `IoTHubDeviceClient_AzureStoragePutBlockList`
* `IoTHubDeviceClient_DestroyUploadContext`
* `IoTHubDeviceClient_InitializeUpload`
* `IoTHubDeviceClient_NotifyUploadCompletion`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_UploadToBlobAsync` or `IoTHubDeviceClient_UploadMultipleBlocksToBlobAsync`.
* If this function fails (due to any HTTP error to either Azure Storage or Azure IoT Hub) it can
Expand Down
16 changes: 14 additions & 2 deletions iothub_client/inc/iothub_device_client_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param azureBlobSasUri Variable where to store the Azure Storage SAS URI for the new upload.
*
* @warning This is a synchronous/blocking function.
* This function only attempts to send HTTP requests once, it does not retry in case of failure.
* Any retries must be explicitly implemented by the calling application.
* `uploadCorrelationId` and `azureBlobSasUri` must be freed by the calling application
* after the blob upload process is done (e.g., after calling `IoTHubDeviceClient_LL_NotifyUploadCompletion`).
*
Expand Down Expand Up @@ -422,21 +424,25 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE, IoTHubDeviceClient_LL_CreateUploadContext, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, azureBlobSasUri);

/**
* @brief This API upload a single blob block to Azure Storage (performs a PUT BLOCK operation).
* @brief This API uploads a single blob block to Azure Storage (performs a PUT BLOCK operation).
* @remark It is part of a set of functions for more granular control over Azure IoT-based blob uploads.
* This function is expected to be used along with:
* `IoTHubDeviceClient_LL_CreateUploadContext`
* `IoTHubDeviceClient_LL_NotifyUploadCompletion`
* `IoTHubDeviceClient_LL_DestroyUploadContext`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_LL_UploadToBlob` or `IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob`.
* For more information about Azure Storage PUT BLOCK, its parameters and behavior, please refer to
* https://learn.microsoft.com/en-us/rest/api/storageservices/put-block
*
* @param uploadContextHandle The handle created with `IoTHubDeviceClient_LL_CreateUploadContext`.
* @param blockNumber Number of the block being uploaded.
* @param dataPtr Pointer to the block data to be uploaded to Azure Storage blob.
* @param dataSize Size of the block data pointed by `dataPtr`.
*
* @warning This is a synchronous/blocking function.
* This function only attempts to send HTTP requests once, it does not retry in case of failure.
* Any retries must be explicitly implemented by the calling application.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
Expand All @@ -451,10 +457,14 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* `IoTHubDeviceClient_LL_DestroyUploadContext`
* For the standard less-granular uploads to blob please use either
* `IoTHubDeviceClient_LL_UploadToBlob` or `IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob`.
* For more information about Azure Storage PUT BLOCK LIST, please refer to
* https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list
*
* @param uploadContextHandle The handle created with `IoTHubDeviceClient_LL_CreateUploadContext`.
*
* @warning This is a synchronous/blocking function.
* This function only attempts to send HTTP requests once, it does not retry in case of failure.
* Any retries must be explicitly implemented by the calling application.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
Expand Down Expand Up @@ -498,7 +508,9 @@ typedef struct IOTHUB_CLIENT_CORE_LL_HANDLE_DATA_TAG* IOTHUB_DEVICE_CLIENT_LL_HA
* @param responseMessage An user-defined status message to go along with `responseCode` on the notification to Azure IoT Hub.
*
* @warning This is a synchronous/blocking function.
*
* This function only attempts to send HTTP requests once, it does not retry in case of failure.
* Any retries must be explicitly implemented by the calling application.
*
* @return IOTHUB_CLIENT_OK upon success or an error code upon failure.
*/
MOCKABLE_FUNCTION(, IOTHUB_CLIENT_RESULT, IoTHubDeviceClient_LL_NotifyUploadCompletion, IOTHUB_DEVICE_CLIENT_LL_HANDLE, iotHubClientHandle, const char*, uploadCorrelationId, bool, isSuccess, int, responseCode, const char*, responseMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static const char* connectionString = "[device connection string]";
static const char* proxyHost = NULL;
static int proxyPort = 0;

static const char* azureStorageBlobPath = "subdir/hello_world.txt";
#define HELLO_WORLD "Hello World from IoTHubDeviceClient_LL_UploadToBlob"

int main(void)
Expand Down Expand Up @@ -73,7 +74,7 @@ int main(void)
}
else
{
if (IoTHubDeviceClient_LL_UploadToBlob(device_ll_handle, "subdir/hello_world.txt", (const unsigned char*)HELLO_WORLD, sizeof(HELLO_WORLD) - 1) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_LL_UploadToBlob(device_ll_handle, azureStorageBlobPath, (const unsigned char*)HELLO_WORLD, sizeof(HELLO_WORLD) - 1) != IOTHUB_CLIENT_OK)
{
(void)printf("hello world failed to upload\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ static const char* connectionString = "[device connection string]";
static const char* proxyHost = NULL;
static int proxyPort = 0;

static const char* azureStorageBlobPath = "subdir/hello_world_custom_mb.txt";
static const char* data_to_upload_format = "Hello World from iothub_client_sample_upload_to_blob_custom: %d\n";
static char data_to_upload[128];

Expand Down Expand Up @@ -76,10 +77,9 @@ int main(void)
{
char* uploadCorrelationId;
char* azureBlobSasUri;
const char* bla = "subdir/hello_world_custom_mb.txt";

if (IoTHubDeviceClient_LL_InitializeUpload(
device_ll_handle, bla, &uploadCorrelationId, &azureBlobSasUri) != IOTHUB_CLIENT_OK)
device_ll_handle, azureStorageBlobPath, &uploadCorrelationId, &azureBlobSasUri) != IOTHUB_CLIENT_OK)
{
printf("failed initializing upload in IoT Hub\n");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static const char* connectionString = "[device connection string]";
/*Optional string with http proxy host and integer for http proxy port (Linux only) */
static const char* proxyHost = NULL;
static int proxyPort = 0;
static const char* azureStorageBlobPath = "subdir/hello_world_mb.txt";
static const char* data_to_upload_format = "Hello World from IoTHubDeviceClient_LL_UploadToBlob block: %d\n";
static char data_to_upload[128];
static int block_count = 0;
Expand Down Expand Up @@ -124,7 +125,7 @@ int main(void)
}
else
{
if (IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob(device_ll_handle, "subdir/hello_world_mb.txt", getDataCallback, NULL) != IOTHUB_CLIENT_OK)
if (IoTHubDeviceClient_LL_UploadMultipleBlocksToBlob(device_ll_handle, azureStorageBlobPath, getDataCallback, NULL) != IOTHUB_CLIENT_OK)
{
(void)printf("hello world failed to upload\n");
}
Expand Down
14 changes: 11 additions & 3 deletions iothub_client/src/blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ static const char blockListUriMarker[] = "&comp=blocklist";
static const char blockListLatestTagXmlBegin[] = "<Latest>";
static const char blockListLatestTagXmlEnd[] = "</Latest>";

// Size of the string containing an Azure Blob Block ID.
// For more details please see
// https://learn.microsoft.com/en-us/rest/api/storageservices/put-block?tabs=azure-ad#uri-parameters
#define AZURE_BLOB_BLOCK_ID_SIZE 7

// Length of the string representation of an Azure Blob Block ID (enough to represent "049999").
#define AZURE_BLOB_BLOCK_ID_LENGTH 6

static STRING_HANDLE createBlockIdListXml(SINGLYLINKEDLIST_HANDLE blockIDList)
{
STRING_HANDLE blockIdListXml;
Expand Down Expand Up @@ -147,9 +155,9 @@ BLOB_RESULT Blob_PutBlock(
result = BLOB_ERROR;
}
else
{
char blockIdString[7]; /*this will contain 000000... 049999*/
if (sprintf(blockIdString, "%6u", (unsigned int)blockID) != 6) /*produces 000000... 049999*/
{
char blockIdString[AZURE_BLOB_BLOCK_ID_SIZE]; /*this will contain 000000... 049999*/
if (sprintf(blockIdString, "%6u", (unsigned int)blockID) != AZURE_BLOB_BLOCK_ID_LENGTH) /*produces 000000... 049999*/
{
LogError("failed to sprintf");
result = BLOB_ERROR;
Expand Down
4 changes: 1 addition & 3 deletions iothub_client/src/iothub_client_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2509,9 +2509,7 @@ IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE IoTHubClientCore_CreateUploadContex
{
IOTHUB_CLIENT_LL_UPLOADTOBLOB_CONTEXT_HANDLE result;

if (
(iotHubClientHandle == NULL)
)
if (iotHubClientHandle == NULL)
{
LogError("invalid parameters iotHubClientHandle = %p", iotHubClientHandle);
result = NULL;
Expand Down