Skip to content

Commit 8507975

Browse files
zhuxiaolong37huiguangjun
authored andcommitted
Added async process object (#338)
1 parent d51aca6 commit 8507975

File tree

7 files changed

+166
-3
lines changed

7 files changed

+166
-3
lines changed

examples/async_process_object.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import base64
2+
import os
3+
import time
4+
import oss2
5+
6+
# Specify access information, such as AccessKeyId, AccessKeySecret, and Endpoint.
7+
# You can obtain access information from evironment variables or replace sample values in the code, such as <your AccessKeyId> with actual values.
8+
#
9+
# For example, if your bucket is located in the China (Hangzhou) region, you can set Endpoint to one of the following values:
10+
# http://oss-cn-hangzhou.aliyuncs.com
11+
# https://oss-cn-hangzhou.aliyuncs.com
12+
13+
14+
access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', '<yourAccessKeyId>')
15+
access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', '<yourAccessKeySecret>')
16+
bucket_name = os.getenv('OSS_TEST_BUCKET', '<yourBucketName>')
17+
endpoint = os.getenv('OSS_TEST_ENDPOINT', '<yourEndpoint>')
18+
19+
key = 'test-video.mp4'
20+
dest_key = 'dest_test-video'
21+
video_path = 'your mp4 video path'
22+
23+
# Make sure that all parameters are correctly configured
24+
for param in (access_key_id, access_key_secret, bucket_name, endpoint):
25+
assert '<' not in param, 'Please set parameters:' + param
26+
27+
28+
# Create a bucket. You can use the bucket to call all object-related operations
29+
bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)
30+
31+
# Upload local video files
32+
put_result = bucket.put_object_from_file(key, video_path)
33+
print("put object result status: %s" % put_result.status)
34+
35+
try:
36+
# Set process
37+
process = "video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas,o_{0},b_{1}".format(
38+
oss2.compat.to_string(base64.urlsafe_b64encode(oss2.compat.to_bytes(dest_key))).replace('=', ''),
39+
oss2.compat.to_string(base64.urlsafe_b64encode(oss2.compat.to_bytes(bucket.bucket_name))).replace('=', ''))
40+
41+
# Call async_ process_ Object interface
42+
result = bucket.async_process_object(key, process)
43+
print("async process object result status: %s" % result.status)
44+
print(result.request_id)
45+
print("event_id: %s" % result.event_id)
46+
print("async_request_id: %s" % result.async_request_id)
47+
print("task_id: %s" % result.task_id)
48+
49+
# Sleep for a period of time, waiting for asynchronous video processing to complete
50+
time.sleep(10)
51+
52+
# Check if the processed video exists
53+
exists = bucket.object_exists(dest_key+".mp4")
54+
print("is exists: %s" % exists)
55+
except oss2.exceptions.OssError as e:
56+
pass
57+
finally:
58+
# Delete video files and processed files
59+
del_key = bucket.delete_object(key)
60+
print("delete key result: %s" % del_key.status)
61+
del_dest_key = bucket.delete_object(dest_key+".mp4")
62+
print("delete dest key result: %s" % del_dest_key.status)
63+
64+
65+
66+

oss2/api.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ class Bucket(_Base):
432432
RESOURCE_GROUP = 'resourceGroup'
433433
STYLE = 'style'
434434
STYLE_NAME = 'styleName'
435+
ASYNC_PROCESS = 'x-oss-async-process'
435436

436437

437438
def __init__(self, auth, endpoint, bucket_name,
@@ -2776,6 +2777,25 @@ def delete_bucket_style(self, styleName):
27762777
logger.debug("delete bucket style done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
27772778
return RequestResult(resp)
27782779

2780+
def async_process_object(self, key, process, headers=None):
2781+
"""异步处理多媒体接口。
2782+
2783+
:param str key: 处理的多媒体的对象名称
2784+
:param str process: 处理的字符串,例如"video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
2785+
2786+
:param headers: HTTP头部
2787+
:type headers: 可以是dict,建议是oss2.CaseInsensitiveDict
2788+
"""
2789+
2790+
headers = http.CaseInsensitiveDict(headers)
2791+
2792+
logger.debug("Start to async process object, bucket: {0}, key: {1}, process: {2}".format(
2793+
self.bucket_name, to_string(key), process))
2794+
process_data = "%s=%s" % (Bucket.ASYNC_PROCESS, process)
2795+
resp = self.__do_object('POST', key, params={Bucket.ASYNC_PROCESS: ''}, headers=headers, data=process_data)
2796+
logger.debug("Async process object done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
2797+
return self._parse_result(resp, xml_utils.parse_async_process_object, AsyncProcessObject)
2798+
27792799
def __do_object(self, method, key, **kwargs):
27802800
return self._do(method, self.bucket_name, key, **kwargs)
27812801

oss2/auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class ProviderAuth(AuthBase):
9090
'callback-var', 'worm', 'wormId', 'wormExtend', 'replication', 'replicationLocation',
9191
'replicationProgress', 'transferAcceleration', 'cname', 'metaQuery',
9292
'x-oss-ac-source-ip', 'x-oss-ac-subnet-mask', 'x-oss-ac-vpc-id', 'x-oss-ac-forward-allow',
93-
'resourceGroup', 'style', 'styleName']
93+
'resourceGroup', 'style', 'styleName', 'x-oss-async-process']
9494
)
9595

9696
def _sign_request(self, req, bucket_name, key):

oss2/models.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2681,4 +2681,19 @@ class DescribeRegionsResult(RequestResult):
26812681

26822682
def __init__(self, resp):
26832683
super(DescribeRegionsResult, self).__init__(resp)
2684-
self.regions = []
2684+
self.regions = []
2685+
2686+
2687+
class AsyncProcessObject(RequestResult):
2688+
"""异步多媒体处理返回信息。
2689+
2690+
:param str event_id: 事件id。
2691+
:param str async_request_id: 请求id。
2692+
:param str task_id: 任务id。
2693+
"""
2694+
2695+
def __init__(self, resp):
2696+
super(AsyncProcessObject, self).__init__(resp)
2697+
self.event_id = None
2698+
self.async_request_id = None
2699+
self.task_id = None

oss2/xml_utils.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2021,4 +2021,12 @@ def parse_describe_regions(result, body):
20212021
tmp.internal_endpoint = _find_tag_with_default(region, 'InternalEndpoint', None)
20222022
tmp.accelerate_endpoint = _find_tag_with_default(region, 'AccelerateEndpoint', None)
20232023

2024-
result.regions.append(tmp)
2024+
result.regions.append(tmp)
2025+
2026+
def parse_async_process_object(result, body):
2027+
if body:
2028+
body_dict = eval(body.decode('utf-8'))
2029+
result.event_id = body_dict['EventId']
2030+
result.async_request_id = body_dict['RequestId']
2031+
result.task_id = body_dict['TaskId']
2032+
return result

tests/test_object.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,29 @@ def test_list_objects(self):
14611461
result = bucket.list_objects()
14621462
self.assertTrue(result.object_list[0].restore_info.__contains__('ongoing-request="true"'))
14631463
self.assertTrue(result.object_list[1].restore_info.__contains__('ongoing-request="true"'))
1464+
1465+
def test_async_process_object(self):
1466+
try:
1467+
key = self.random_key(".jpg")
1468+
result = self.bucket.put_object_from_file(key, "tests/example.jpg")
1469+
self.assertEqual(result.status, 200)
1470+
dest_key = self.random_key(".jpg")
1471+
1472+
process = "image/resize,w_100|sys/saveas,o_{0},b_{1}".format(
1473+
oss2.compat.to_string(base64.urlsafe_b64encode(oss2.compat.to_bytes(dest_key))).replace('=', ''),
1474+
oss2.compat.to_string(base64.urlsafe_b64encode(oss2.compat.to_bytes(self.bucket.bucket_name))).replace('=', ''))
1475+
1476+
result = self.bucket.async_process_object(key, process)
1477+
1478+
# imm dont support process image in async mode
1479+
self.assertFalse(True, 'should not here')
1480+
except oss2.exceptions.OssError as e:
1481+
# expect Imm Client Error
1482+
self.assertEqual(e.code, 'Imm Client')
1483+
self.assertEqual(e.message, 'The specified resource Route is not found.')
1484+
except:
1485+
self.assertFalse(True, 'should not here')
1486+
14641487

14651488
class TestSign(TestObject):
14661489
"""

unittests/test_bucket.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,5 +2444,36 @@ def test_describe_regions(self, do_request):
24442444
self.assertEqual(result.regions[1].internal_endpoint, 'oss-cn-shanghai-internal.aliyuncs.com')
24452445
self.assertEqual(result.regions[1].accelerate_endpoint, 'oss-accelerate.aliyuncs.com')
24462446

2447+
@patch('oss2.Session.do_request')
2448+
def test_async_process_object(self, do_request):
2449+
request_text = '''POST /test-video.mp4?x-oss-async-process HTTP/1.1
2450+
Date: Fri , 30 Apr 2021 13:08:38 GMT
2451+
Content-Length:443
2452+
x-oss-async-process=video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas
2453+
Host: ming-oss-share.oss-cn-hangzhou.aliyuncs.com
2454+
Authorization: OSS qn6qrrqxo2oawuk53otf****:PYbzsdWAIWAlMW8luk****
2455+
'''
2456+
2457+
response_text = '''HTTP/1.1 200 OK
2458+
Server: AliyunOSS
2459+
Date: Sat, 12 Dec 2015 00:35:42 GMT
2460+
Content-Type: application/xml
2461+
Content-Length: 96
2462+
Connection: keep-alive
2463+
x-oss-request-id: 566B6BDD68248CE14F729DC0
2464+
x-oss-async-process=video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas
2465+
2466+
{"EventId":"3D7-1XxFtV2t3VtcOn2CXqI2ldsMN3i","RequestId":"8DF65942-D483-5E7E-BC1A-B25C617A9C32","TaskId":"MediaConvert-d2280366-cd33-48f7-90c6-a0dab65bed63"}
2467+
'''
2468+
req_info = mock_response(do_request, response_text)
2469+
key = "test-video.mp4"
2470+
result = bucket().async_process_object(key, 'video/convert,f_mp4,vcodec_h265,s_1920x1080,vb_2000000,fps_30,acodec_aac,ab_100000,sn_1|sys/saveas')
2471+
2472+
self.assertEqual(result.request_id, '566B6BDD68248CE14F729DC0')
2473+
self.assertEqual(result.async_request_id, '8DF65942-D483-5E7E-BC1A-B25C617A9C32')
2474+
self.assertEqual(result.event_id, '3D7-1XxFtV2t3VtcOn2CXqI2ldsMN3i')
2475+
self.assertEqual(result.task_id, 'MediaConvert-d2280366-cd33-48f7-90c6-a0dab65bed63')
2476+
2477+
24472478
if __name__ == '__main__':
24482479
unittest.main()

0 commit comments

Comments
 (0)