-
Notifications
You must be signed in to change notification settings - Fork 427
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,136 additions
and
135 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
__version__ = "1.3.1" | ||
__version__ = "1.4.0" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# /* | ||
# * Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# * | ||
# * Licensed under the Apache License, Version 2.0 (the "License"). | ||
# * You may not use this file except in compliance with the License. | ||
# * A copy of the License is located at | ||
# * | ||
# * http://aws.amazon.com/apache2.0 | ||
# * | ||
# * or in the "license" file accompanying this file. This file 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 json | ||
|
||
_BASE_THINGS_TOPIC = "$aws/things/" | ||
_NOTIFY_OPERATION = "notify" | ||
_NOTIFY_NEXT_OPERATION = "notify-next" | ||
_GET_OPERATION = "get" | ||
_START_NEXT_OPERATION = "start-next" | ||
_WILDCARD_OPERATION = "+" | ||
_UPDATE_OPERATION = "update" | ||
_ACCEPTED_REPLY = "accepted" | ||
_REJECTED_REPLY = "rejected" | ||
_WILDCARD_REPLY = "#" | ||
|
||
#Members of this enum are tuples | ||
_JOB_ID_REQUIRED_INDEX = 1 | ||
_JOB_OPERATION_INDEX = 2 | ||
|
||
_STATUS_KEY = 'status' | ||
_STATUS_DETAILS_KEY = 'statusDetails' | ||
_EXPECTED_VERSION_KEY = 'expectedVersion' | ||
_EXEXCUTION_NUMBER_KEY = 'executionNumber' | ||
_INCLUDE_JOB_EXECUTION_STATE_KEY = 'includeJobExecutionState' | ||
_INCLUDE_JOB_DOCUMENT_KEY = 'includeJobDocument' | ||
_CLIENT_TOKEN_KEY = 'clientToken' | ||
|
||
#The type of job topic. | ||
class jobExecutionTopicType(object): | ||
JOB_UNRECOGNIZED_TOPIC = (0, False, '') | ||
JOB_GET_PENDING_TOPIC = (1, False, _GET_OPERATION) | ||
JOB_START_NEXT_TOPIC = (2, False, _START_NEXT_OPERATION) | ||
JOB_DESCRIBE_TOPIC = (3, True, _GET_OPERATION) | ||
JOB_UPDATE_TOPIC = (4, True, _UPDATE_OPERATION) | ||
JOB_NOTIFY_TOPIC = (5, False, _NOTIFY_OPERATION) | ||
JOB_NOTIFY_NEXT_TOPIC = (6, False, _NOTIFY_NEXT_OPERATION) | ||
JOB_WILDCARD_TOPIC = (7, False, _WILDCARD_OPERATION) | ||
|
||
#Members of this enum are tuples | ||
_JOB_SUFFIX_INDEX = 1 | ||
#The type of reply topic, or #JOB_REQUEST_TYPE for topics that are not replies. | ||
class jobExecutionTopicReplyType(object): | ||
JOB_UNRECOGNIZED_TOPIC_TYPE = (0, '') | ||
JOB_REQUEST_TYPE = (1, '') | ||
JOB_ACCEPTED_REPLY_TYPE = (2, '/' + _ACCEPTED_REPLY) | ||
JOB_REJECTED_REPLY_TYPE = (3, '/' + _REJECTED_REPLY) | ||
JOB_WILDCARD_REPLY_TYPE = (4, '/' + _WILDCARD_REPLY) | ||
|
||
_JOB_STATUS_INDEX = 1 | ||
class jobExecutionStatus(object): | ||
JOB_EXECUTION_STATUS_NOT_SET = (0, None) | ||
JOB_EXECUTION_QUEUED = (1, 'QUEUED') | ||
JOB_EXECUTION_IN_PROGRESS = (2, 'IN_PROGRESS') | ||
JOB_EXECUTION_FAILED = (3, 'FAILED') | ||
JOB_EXECUTION_SUCCEEDED = (4, 'SUCCEEDED') | ||
JOB_EXECUTION_CANCELED = (5, 'CANCELED') | ||
JOB_EXECUTION_REJECTED = (6, 'REJECTED') | ||
JOB_EXECUTION_UNKNOWN_STATUS = (99, None) | ||
|
||
def _getExecutionStatus(jobStatus): | ||
try: | ||
return jobStatus[_JOB_STATUS_INDEX] | ||
except KeyError: | ||
return None | ||
|
||
def _isWithoutJobIdTopicType(srcJobExecTopicType): | ||
return (srcJobExecTopicType == jobExecutionTopicType.JOB_GET_PENDING_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_START_NEXT_TOPIC | ||
or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) | ||
|
||
class thingJobManager: | ||
def __init__(self, thingName, clientToken = None): | ||
self._thingName = thingName | ||
self._clientToken = clientToken | ||
|
||
def getJobTopic(self, srcJobExecTopicType, srcJobExecTopicReplyType=jobExecutionTopicReplyType.JOB_REQUEST_TYPE, jobId=None): | ||
if self._thingName is None: | ||
return None | ||
|
||
#Verify topics that only support request type, actually have request type specified for reply | ||
if (srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_TOPIC or srcJobExecTopicType == jobExecutionTopicType.JOB_NOTIFY_NEXT_TOPIC) and srcJobExecTopicReplyType != jobExecutionTopicReplyType.JOB_REQUEST_TYPE: | ||
return None | ||
|
||
#Verify topics that explicitly do not want a job ID do not have one specified | ||
if (jobId is not None and _isWithoutJobIdTopicType(srcJobExecTopicType)): | ||
return None | ||
|
||
#Verify job ID is present if the topic requires one | ||
if jobId is None and srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: | ||
return None | ||
|
||
#Ensure the job operation is a non-empty string | ||
if srcJobExecTopicType[_JOB_OPERATION_INDEX] == '': | ||
return None | ||
|
||
if srcJobExecTopicType[_JOB_ID_REQUIRED_INDEX]: | ||
return '{0}{1}/jobs/{2}/{3}{4}'.format(_BASE_THINGS_TOPIC, self._thingName, str(jobId), srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) | ||
elif srcJobExecTopicType == jobExecutionTopicType.JOB_WILDCARD_TOPIC: | ||
return '{0}{1}/jobs/#'.format(_BASE_THINGS_TOPIC, self._thingName) | ||
else: | ||
return '{0}{1}/jobs/{2}{3}'.format(_BASE_THINGS_TOPIC, self._thingName, srcJobExecTopicType[_JOB_OPERATION_INDEX], srcJobExecTopicReplyType[_JOB_SUFFIX_INDEX]) | ||
|
||
def serializeJobExecutionUpdatePayload(self, status, statusDetails=None, expectedVersion=0, executionNumber=0, includeJobExecutionState=False, includeJobDocument=False): | ||
executionStatus = _getExecutionStatus(status) | ||
if executionStatus is None: | ||
return None | ||
payload = {_STATUS_KEY: executionStatus} | ||
if statusDetails: | ||
payload[_STATUS_DETAILS_KEY] = statusDetails | ||
if expectedVersion > 0: | ||
payload[_EXPECTED_VERSION_KEY] = str(expectedVersion) | ||
if executionNumber > 0: | ||
payload[_EXEXCUTION_NUMBER_KEY] = str(executionNumber) | ||
if includeJobExecutionState: | ||
payload[_INCLUDE_JOB_EXECUTION_STATE_KEY] = True | ||
if includeJobDocument: | ||
payload[_INCLUDE_JOB_DOCUMENT_KEY] = True | ||
if self._clientToken is not None: | ||
payload[_CLIENT_TOKEN_KEY] = self._clientToken | ||
return json.dumps(payload) | ||
|
||
def serializeDescribeJobExecutionPayload(self, executionNumber=0, includeJobDocument=True): | ||
payload = {_INCLUDE_JOB_DOCUMENT_KEY: includeJobDocument} | ||
if executionNumber > 0: | ||
payload[_EXEXCUTION_NUMBER_KEY] = executionNumber | ||
if self._clientToken is not None: | ||
payload[_CLIENT_TOKEN_KEY] = self._clientToken | ||
return json.dumps(payload) | ||
|
||
def serializeStartNextPendingJobExecutionPayload(self, statusDetails=None): | ||
payload = {} | ||
if self._clientToken is not None: | ||
payload[_CLIENT_TOKEN_KEY] = self._clientToken | ||
if statusDetails is not None: | ||
payload[_STATUS_DETAILS_KEY] = statusDetails | ||
return json.dumps(payload) | ||
|
||
def serializeClientTokenPayload(self): | ||
return json.dumps({_CLIENT_TOKEN_KEY: self._clientToken}) if self._clientToken is not None else '{}' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# /* | ||
# * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# * | ||
# * Licensed under the Apache License, Version 2.0 (the "License"). | ||
# * You may not use this file except in compliance with the License. | ||
# * A copy of the License is located at | ||
# * | ||
# * http://aws.amazon.com/apache2.0 | ||
# * | ||
# * or in the "license" file accompanying this file. This file 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. | ||
# */ | ||
|
||
|
||
try: | ||
import ssl | ||
except: | ||
ssl = None | ||
|
||
|
||
class SSLContextBuilder(object): | ||
|
||
def __init__(self): | ||
self.check_supportability() | ||
self._ssl_context = ssl.create_default_context() | ||
|
||
def check_supportability(self): | ||
if ssl is None: | ||
raise RuntimeError("This platform has no SSL/TLS.") | ||
if not hasattr(ssl, "SSLContext"): | ||
raise NotImplementedError("This platform does not support SSLContext. Python 2.7.10+/3.5+ is required.") | ||
if not hasattr(ssl.SSLContext, "set_alpn_protocols"): | ||
raise NotImplementedError("This platform does not support ALPN as TLS extensions. Python 2.7.10+/3.5+ is required.") | ||
|
||
def with_protocol(self, protocol): | ||
self._ssl_context.protocol = protocol | ||
return self | ||
|
||
def with_ca_certs(self, ca_certs): | ||
self._ssl_context.load_verify_locations(ca_certs) | ||
return self | ||
|
||
def with_cert_key_pair(self, cert_file, key_file): | ||
self._ssl_context.load_cert_chain(cert_file, key_file) | ||
return self | ||
|
||
def with_cert_reqs(self, cert_reqs): | ||
self._ssl_context.verify_mode = cert_reqs | ||
return self | ||
|
||
def with_check_hostname(self, check_hostname): | ||
self._ssl_context.check_hostname = check_hostname | ||
return self | ||
|
||
def with_ciphers(self, ciphers): | ||
if ciphers is not None: | ||
self._ssl_context.set_ciphers(ciphers) # set_ciphers() does not allow None input. Use default (do nothing) if None | ||
return self | ||
|
||
def with_alpn_protocols(self, alpn_protocols): | ||
self._ssl_context.set_alpn_protocols(alpn_protocols) | ||
return self | ||
|
||
def build(self): | ||
return self._ssl_context |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.