Skip to content

Commit

Permalink
large_file_upload azure: update code so that filename can be changed
Browse files Browse the repository at this point in the history
Updated the code so that when the cloud service provider is set to "azure",
the filename is updated via the env.default request instead of the filename
parameter in web.put/web.post.
  • Loading branch information
youssifsaeed1 committed Oct 28, 2024
1 parent c2e8372 commit 4702522
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 6 deletions.
8 changes: 4 additions & 4 deletions python-large-file-upload/doc/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@
- `x-ms-blob-type: BlockBlob`

6. **Specify the Destination Path**
- Add a forward slash `/` followed by the filename where you want to save the Notecard data. In the example below, the filename **datafile** is used. You can modify this later once the data has been transferred.
- Add a forward slash `/` followed by `[$filename]` before the first "?" as can be seen in the image below. This is needed so that the source filename is copied to Azure.

<img src="azure_images/azure_notehub_setup.png" style="border: 1px solid lightgray;">
<img src="azure_images/azure_notehub_setup_filename.png" style="border: 1px solid lightgray;">


7. **Create the Route**
Expand All @@ -118,11 +118,11 @@
Once Azure and Notehub have been configured correctly, you can launch the Python script with the following command:

```bash
python main.py -B 100000 -w put -u <notehub_product_uid> -f <path_to_file_to_send>
python main.py -B 100000 -w put -i -s "azure" -u <notehub_product_uid> -f <path_to_file_to_send>
```

**Example:**

```bash
python main.py -B 100000 -w put -u com.blues.large_file_transfer -f image.png -p /dev/tty.usbmodemNOTE1
python main.py -B 100000 -w put -i -s "azure" -u com.blues.large_file_transfer -f image.png -p /dev/tty.usbmodemNOTE1
```
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions python-large-file-upload/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def parseCommandLineArgs():
p.add("--legacy", help="Use legacy method to upload file. Uses base64 encoding in web transaction payloads", action='store_true')
p.add("-B", "--binary-size", help="Size of binary data to send in each transaction", type=int)
p.add("-w", "--web-req-method", help="HTTP request method (PUT, POST, etc)", default="POST")
p.add("-s", "--cloud-service", type=str, choices=['azure', 'aws', 'gcp'], help="Specify the cloud provider (azure, aws, gcp)")

opts = p.parse_args()
hub_config = {}
Expand Down Expand Up @@ -137,6 +138,9 @@ def main():
timeout=opts.timeout,
)

if opts.cloud_service:
uploader.setCloudService(opts.cloud_service)

if opts.include_file_name:
fileName = os.path.basename(os.path.normpath(opts.file))
uploader.setFileName(fileName)
Expand Down
48 changes: 46 additions & 2 deletions python-large-file-upload/notecardDataTransfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

DEFAULT_WEB_TRANSACTION_TIMEOUT_SEC = 30
DEFAULT_CARD_WEB_REQUEST = "web.post"

DEFAULT_MS_AZURE_FILENAME = "datafile"

class BinaryDataUploader:

Expand All @@ -30,6 +30,37 @@ def __init__(self, card, req, route, timeout=DEFAULT_WEB_TRANSACTION_TIMEOUT_SEC
self.webReqRoot['seconds'] = timeout
self._fileName = None
self._binaryBuffSize = None
self._cloud_service = None

def setFileNameViaEnvDefault(self, fileName):
"""
Set the filename via the env.default method
This method is needed for cloud providers such as Microsoft Azure, where the filename
cannot be set via a web request. Instead, the filename must be set via the env.default
method. For this to work, the route URL in notehub must have a $filename placeholder in
it. For more information, check doc/azure.md
"""

# Get the current sync time
rsp = self._sendRequest("hub.sync.status")
last_sync_time = current_sync_time = rsp.get('time', 0)

# Set the filename via env.default and force a sync to update the value on Notehub
envReq = {"req":"env.default", "name":"filename", "text":fileName}
rsp = self._sendRequest(envReq)
rsp = self._sendRequest("hub.sync")

# Wait for the sync to complete
startTime = time.time()
while current_sync_time <= last_sync_time:
if (time.time() - startTime) > self.ConnectionTimeoutSeconds:
raise TimeoutError(f"Timeout of {self.ConnectionTimeoutSeconds} " +
"seconds expired while waiting to sync env.default")

rsp = self._sendRequest("hub.sync.status")
current_sync_time = rsp.get('time', current_sync_time)
time.sleep(1)

def setFileName(self, fileName):
self._fileName = fileName
Expand All @@ -45,6 +76,15 @@ def upload(self, data:io.BytesIO, unsetFileName=True):
self._print(f"Waiting for Notehub connection")
self._waitForConnection()

if self._cloud_service == "azure":
# Due to a limitation in MS Azure where the filename cannot be set via a web request,
# the filename is instead set via the env.default method. This means that the filename
# must be set before the data is uploaded to Notehub. If the filename is not set, the
# default filename is used. For more info, check setFileNameViaEnvDefault().
if self._fileName is None:
self._fileName = DEFAULT_MS_AZURE_FILENAME
self.setFileNameViaEnvDefault(self._fileName)

self._writeAndFlushBytes(data)

if self.SetTemporaryContinuousMode:
Expand Down Expand Up @@ -73,7 +113,9 @@ def _writeWebReqBinary(self, offset, total):
webReq = self.webReqRoot
webReq['offset'] = offset
webReq['total'] = total
if self._fileName is not None:
# If the filename is set, add it to the web request. This is not supported for Azure
# which doesn't have a filename field in the web request, and adding it will cause an error
if (self._fileName is not None) and (self._cloud_service != "azure"):
webReq['name'] = self._fileName

rsp = self._sendRequest(webReq)
Expand Down Expand Up @@ -141,6 +183,8 @@ def _unsetTempContinuousMode(self):
def setBinaryBuffSize(self, binaryBuffSize):
self._binaryBuffSize = binaryBuffSize

def setCloudService(self, cloudService):
self._cloud_service = cloudService

import binascii
class BinaryDataUploaderLegacy(BinaryDataUploader):
Expand Down

0 comments on commit 4702522

Please sign in to comment.