8000 cPython ssl socket feature · RustyPixel/lib-python@5f44be8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5f44be8

Browse files
author
amorozenko
committed
cPython ssl socket feature
1 parent 62fb5ee commit 5f44be8

File tree

9 files changed

+178
-103
lines changed

9 files changed

+178
-103
lines changed

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pip install --user -e .
6060
```
6161

6262
#### Testing
63-
You can run unit tests on cPython systems using the command:
63+
You can run unit tests for cPython version of library (blynklib_cp.py) systems using the command:
6464

6565
python setup.py test
6666

@@ -115,15 +115,12 @@ blynk = blynklib.Blynk(BLYNK_AUTH)
115115

116116
# advanced options of lib init
117117
# from __future__ import print_function
118-
# blynk = blynklib.Blynk(BLYNK_AUTH, server='blynk-cloud.com', port=80, ssl=False, heartbeat=10, rcv_buffer=1024, log=print)
118+
# blynk = blynklib.Blynk(BLYNK_AUTH, server='blynk-cloud.com', port=80, ssl_cert=None, heartbeat=10, rcv_buffer=1024, log=print)
119119

120-
# Lib init with hardware SSL connection example
121-
# blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='default')
122-
# the ssl_cert='default' is for default blynk server (blynk-cloud.com) or self hosted server with Let's Encrypt certificate.
123-
124-
# if you have self hosted server with your own self signed certificate, then you can change ssl_cert with your
125-
# own CA file. For example if you have CA file in /home/blynk/ca.crt, then the param will be
126-
# blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_mode='/home/blynk/ca.crt')
120+
# Lib init with SSL socket connection
121+
# blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='<path to local blynk server certificate>')
122+
# current blynk-cloud.com certificate stored in project as
123+
# https://github.com/blynkkk/lib-python/blob/master/certificate/blynk-cloud.com.crt
127124

128125
# register handler for Virtual Pin V22 reading by Blynk App.
129126
# when a widget in Blynk App asks Virtual Pin data from server within given configurable interval (1,2,5,10 sec etc)
@@ -170,6 +167,7 @@ Examples can be found **[here][blynk-py-examples]** Check them all to get famili
170167
- [08_blynk_timer.py](https://github.com/blynkkk/lib-python/blob/master/examples/08_blynk_timer.py): How send data periodically from hardware by using **[Blynk Timer][blynktimer-doc]**
171168
- [09_sync_virtual_pin.py](https://github.com/blynkkk/lib-python/blob/master/examples/09_sync_virtual_pin.py): How to sync virtual pin states and properties
172169
- [10_rtc_sync.py](https://github.com/blynkkk/lib-python/blob/master/examples/10_rtc_sync.py): How to perform RTC sync with blynk server
170+
- [11_ssl_socket.py](https://github.com/blynkkk/lib-python/blob/master/examples/10_ssl_socket.py): SSL server connection. Feature available only fo cPython.
173171

174172
##### Raspberry Pi (any):
175173
Read [Raspberry Pi guide](https://github.com/blynkkk/lib-python/tree/master/examples/raspberry) first.

blynklib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Protocol(object):
6767
STATUS_OK = const(200)
6868
VPIN_MAX_NUM = const(32)
6969

70-
_msg_id = 0
70+
_msg_id = 1
7171

7272
def _get_msg_id(self, **kwargs):
7373
if 'msg_id' in kwargs:
@@ -381,4 +381,4 @@ def run(self):
381381
self.log(b_err)
382382
self.disconnect()
383383
except Exception as g_exc:
384-
self.log(g_exc)
384+
self.log(g_exc)

blynklib_cp.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
# Copyright (c) 2015-2019 Volodymyr Shymanskyy.
33
# See the file LICENSE for copying permission.
44

5-
__version__ = '0.2.5'
5+
__version__ = '0.2.6'
66

7-
import os
87
import socket
98
import ssl
109
import struct
@@ -147,7 +146,8 @@ class Connection(Protocol):
147146
_last_ping_time = 0
148147
_last_send_time = 0
149148

150-
def __init__(self, token, server='blynk-cloud.com', port=80, ssl_cert=None, heartbeat=10, rcv_buffer=1024, log=stub_log):
149+
def __init__(self, token, server='blynk-cloud.com', port=80, ssl_cert=None, heartbeat=10, rcv_buffer=1024,
150+
log=stub_log):
151151
self.token = token
152152
self.server = server
153153
self.port = port
@@ -175,7 +175,7 @@ def receive(self, length, timeout):
175175
d_buff = d_buff[:length]
176176
return d_buff
177177
except (IOError, OSError) as err:
178-
if str(err) == 'timed out':
178+
if 'timed out' in str(err):
179179
return b''
180180
if str(self.EAGAIN) in str(err) or str(self.ETIMEDOUT) in str(err):
181181
return b''
@@ -202,16 +202,14 @@ def _get_socket(self):
202202
self._socket.connect(socket.getaddrinfo(self.server, self.port)[0][4])
203203
self._socket.settimeout(self.SOCK_TIMEOUT)
204204
if self.ssl_cert:
205+
# system’s default CA certificates case
206+
if self.ssl_cert == "default":
207+
self.ssl_cert = None
205208
self.log('Using SSL socket...')
206-
if (self.ssl_cert == "default"):
207-
sslContext = ssl.create_default_context()
208-
caFile = os.path.dirname(__file__) + "/certificate/_blynk-cloudcom.crt"
209-
sslContext.load_verify_locations(cafile=caFile)
210-
else:
211-
sslContext = ssl.create_default_context(cafile=self.ssl_cert)
212-
sslContext.verify_mode = ssl.CERT_REQUIRED
209+
ssl_context = ssl.create_default_context(cafile=self.ssl_cert)
210+
ssl_context.verify_mode = ssl.CERT_REQUIRED
213211
self._socket.settimeout(self.SOCK_SSL_TIMEOUT)
214-
self._socket = sslContext.wrap_socket(sock=self._socket, server_hostname=self.server)
212+
self._socket = ssl_context.wrap_socket(sock=self._socket, server_hostname=self.server)
215213
self.log('Connected to blynk server')
216214
except Exception as g_exc:
217215
raise BlynkError('Connection with the Blynk server failed: {}'.format(g_exc))
Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
-----BEGIN CERTIFICATE-----
2-
MIID5TCCAs2gAwIBAgIJAIHSnb+cv4ECMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
3-
VQQGEwJVQTENMAsGA1UECAwES3lpdjENMAsGA1UEBwwES3lpdjELMAkGA1UECgwC
4-
SVQxEzARBgNVBAsMCkJseW5rIEluYy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNv
5-
bTEfMB0GCSqGSIb3DQEJARYQZG1pdHJpeUBibHluay5jYzAeFw0xNjAzMTcxMTU4
6-
MDdaFw0yMTAzMTYxMTU4MDdaMIGIMQswCQYDVQQGEwJVQTENMAsGA1UECAwES3lp
7-
djENMAsGA1UEBwwES3lpdjELMAkGA1UECgwCSVQxEzARBgNVBAsMCkJseW5rIElu
8-
Yy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNvbTEfMB0GCSqGSIb3DQEJARYQZG1p
9-
dHJpeUBibHluay5jYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALso
10-
bhbXQuNlzYBFa9h9pd69n43yrGTL4Ba6k5Q1zDwY9HQbMdfC5ZfnCkqT7Zf+R5MO
11-
RW0Q9nLsFNLJkwKnluRCYGyUES8NAmDLQBbZoVc8mv9K3mIgAQvGyY2LmKak5GSI
12-
V0PC3x+iN03xU2774+Zi7DaQd7vTl/9RGk8McyHe/s5Ikbe14bzWcY9ZV4PKgCck
13-
p1chbmLhSfGbT3v64sL8ZbIppQk57/JgsZMrVpjExvxQPZuJfWbtoypPfpYO+O8l
14-
1szaMlTEPIZVMoYi9uE+DnOlhzJFn6Ac4FMrDzJXzMmCweSX3IxguvXALeKhUHQJ
15-
+VP3G6Q3pkZRVKz+5XsCAwEAAaNQME4wHQYDVR0OBBYEFJtqtI62Io66cZgiTR5L
16-
A5Tl5m+xMB8GA1UdIwQYMBaAFJtqtI62Io66cZgiTR5LA5Tl5m+xMAwGA1UdEwQF
17-
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKphjtEOGs7oC3S87+AUgIw4gFNOuv+L
18-
C98/l47OD6WtsqJKvCZ1lmKxY5aIro9FBPk8ktCOsbwEjE+nyr5wul+6CLFr+rnv
19-
7OHYGwLpjoz+rZgYJiQ61E1m0AZ4y9Fyd+D90HW6247vrBXyEiUXOhN/oDDVfDQA
20-
eqmNBx1OqWel81D3tA7zPMA7vUItyWcFIXNjOCP+POy7TMxZuhuPMh5bVu+/cthl
21-
/Q9u/Z2lKl4CWV0Ivt2BtlN6iefva0e2AP/As+gfwjxrb0t11zSILLNJ+nxRIwg+
22-
k4MGb1zihKbIXUzsjslONK4FY5rlQUSwKJgEAVF0ClxB4g6dECm0ckc=
23-
-----END CERTIFICATE-----
1+
-----BEGIN CERTIFICATE-----
2+
MIID5TCCAs2gAwIBAgIJAIHSnb+cv4ECMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYD
3+
VQQGEwJVQTENMAsGA1UECAwES3lpdjENMAsGA1UEBwwES3lpdjELMAkGA1UECgwC
4+
SVQxEzARBgNVBAsMCkJseW5rIEluYy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNv
5+
bTEfMB0GCSqGSIb3DQEJARYQZG1pdHJpeUBibHluay5jYzAeFw0xNjAzMTcxMTU4
6+
MDdaFw0yMTAzMTYxMTU4MDdaMIGIMQswCQYDVQQGEwJVQTENMAsGA1UECAwES3lp
7+
djENMAsGA1UEBwwES3lpdjELMAkGA1UECgwCSVQxEzARBgNVBAsMCkJseW5rIElu
8+
Yy4xGDAWBgNVBAMMD2JseW5rLWNsb3VkLmNvbTEfMB0GCSqGSIb3DQEJARYQZG1p
9+
dHJpeUBibHluay5jYzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALso
10+
bhbXQuNlzYBFa9h9pd69n43yrGTL4Ba6k5Q1zDwY9HQbMdfC5ZfnCkqT7Zf+R5MO
11+
RW0Q9nLsFNLJkwKnluRCYGyUES8NAmDLQBbZoVc8mv9K3mIgAQvGyY2LmKak5GSI
12+
V0PC3x+iN03xU2774+Zi7DaQd7vTl/9RGk8McyHe/s5Ikbe14bzWcY9ZV4PKgCck
13+
p1chbmLhSfGbT3v64sL8ZbIppQk57/JgsZMrVpjExvxQPZuJfWbtoypPfpYO+O8l
14+
1szaMlTEPIZVMoYi9uE+DnOlhzJFn6Ac4FMrDzJXzMmCweSX3IxguvXALeKhUHQJ
15+
+VP3G6Q3pkZRVKz+5XsCAwEAAaNQME4wHQYDVR0OBBYEFJtqtI62Io66cZgiTR5L
16+
A5Tl5m+xMB8GA1UdIwQYMBaAFJtqtI62Io66cZgiTR5LA5Tl5m+xMAwGA1UdEwQF
17+
MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKphjtEOGs7oC3S87+AUgIw4gFNOuv+L
18+
C98/l47OD6WtsqJKvCZ1lmKxY5aIro9FBPk8ktCOsbwEjE+nyr5wul+6CLFr+rnv
19+
7OHYGwLpjoz+rZgYJiQ61E1m0AZ4y9Fyd+D90HW6247vrBXyEiUXOhN/oDDVfDQA
20+
eqmNBx1OqWel81D3tA7zPMA7vUItyWcFIXNjOCP+POy7TMxZuhuPMh5bVu+/cthl
21+
/Q9u/Z2lKl4CWV0Ivt2BtlN6iefva0e2AP/As+gfwjxrb0t11zSILLNJ+nxRIwg+
22+
k4MGb1zihKbIXUzsjslONK4FY5rlQUSwKJgEAVF0ClxB4g6dECm0ckc=
23+
-----END CERTIFICATE-----

examples/11_ssl_socket.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
[SSL CONNECT/DISCONNECT EVENTS EXAMPLE] =================================================================
3+
NOTE!
4+
This example works correctly only fo cPython version of library (blynklib_cp.py)
5+
For micropython present limitation that keyword arguments of wrap_socket may be not supported
6+
7+
8+
Environment prepare:
9+
- define your auth token for current example and run it
10+
11+
12+
This started program after successful connect operation will call and execute "connect event handler"
13+
Within handler after short sleep delay blynk disconnect call will be performed that will trigger
14+
"disconnect event handler" execution.
15+
16+
Schema:
17+
=====================================================================================================
18+
+-----------+ +--------------+
19+
| | | |
20+
| blynk lib | | blynk server |
21+
| | | virtual pin |
22+
| | | |
23+
+-----+-----+ +------+-------+
24+
| |
25+
| connect/authenticate request |
26+
+------------------------------------>+
27+
connect handler | |
28+
(user function) | connected successfully |
29+
+-----------<------------------------------------+
30+
| | |
31+
| | disconnect request |
32+
+--------->------------------------------------->+
33+
| |
34+
| |
35+
disconnect handler | |
36+
(user function) | disconnected successfully |
37+
+-----------<------------------------------------+
38+
| | |
39+
| | |
40+
+--------->+ |
41+
| reconnect request |
42+
| performed by lib automatically |
43+
+------------------------------------>+
44+
+ +
45+
46+
47+
====================================================================================================
48+
Additional info about blynk you can find by examining such resources:
49+
50+
Downloads, docs, tutorials: https://blynk.io
51+
Sketch generator: http://examples.blynk.cc
52+
Blynk community: http://community.blynk.cc
53+
Social networks: http://www.fb.com/blynkapp
54+
http://twitter.com/blynk_app
55+
=====================================================================================================
56+
"""
57+
58+
import blynklib_cp as blynklib
59+
import time
60+
import logging
61+
62+
# tune console logging
63+
_log = logging.getLogger('BlynkLog')
64+
logFormatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
65+
consoleHandler = logging.StreamHandler()
66+
consoleHandler.setFormatter(logFormatter)
67+
_log.addHandler(consoleHandler)
68+
_log.setLevel(logging.DEBUG)
69+
70+
BLYNK_AUTH = 'YourAuthToken'
71+
72+
blynk = blynklib.Blynk(BLYNK_AUTH, port=443, ssl_cert='../certificate/blynk-cloud.com.crt', log=_log.info)
73+
74+
CONNECT_PRINT_MSG = '[CONNECT_EVENT]'
75+
DISCONNECT_PRINT_MSG = '[DISCONNECT_EVENT]'
76+
77+
78+
@blynk.handle_event("connect")
79+
def connect_handler():
80+
print(CONNECT_PRINT_MSG)
81+
print('Sleeping 4 sec in SSL connect handler...')
82+
time.sleep(4)
83+
blynk.disconnect()
84+
85+
86+
@blynk.handle_event("disconnect")
87+
def disconnect_handler():
88+
print(DISCONNECT_PRINT_MSG)
89+
print('Sleeping 3 sec in SSL disconnect handler...')
90+
time.sleep(5)
91+
92+
93+
###########################################################
94+
# infinite loop that waits for event
95+
###########################################################
96+
while True:
97+
blynk.run()

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name='blynklib',
8-
version='0.2.5',
8+
version='0.2.6',
99
description='Blynk Python/Micropython library',
1010
long_description=long_description,
1111
long_description_content_type="text/markdown",
@@ -15,7 +15,7 @@
1515
author_email='antoha.ua@gmail.com',
1616
setup_requires=['pytest-runner', ],
1717
tests_require=['pytest', 'pytest-mock', ],
18-
py_modules=['blynklib', 'blynktimer'],
18+
py_modules=['blynklib_cp', 'blynktimer'],
1919
classifiers=[
2020
"Programming Language :: Python :: 2.7",
2121
"Programming Language :: Python :: 3",

test/test_blynk_connection.py

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import time
44
import pytest
55
import socket
6-
from blynklib import Connection, BlynkError, RedirectError
6+
from blynklib_cp import Connection, BlynkError, RedirectError
77

88

99
class TestBlynkConnection:
@@ -12,18 +12,6 @@ def cb(self):
1212
connection = Connection('1234', log=print)
1313
yield connection
1414

15-
def test_set_socket_timeout_positive(self, cb):
16-
in_timeout = 10
17-
cb._socket = socket.socket()
18-
cb._set_socket_timeout(in_timeout)
19-
timeout = cb._socket.gettimeout()
20-
assert timeout == in_timeout
21-
22-
def test_set_socket_timeout_via_poll(self, cb):
23-
in_timeout = 10
24-
cb._socket = 2222
25-
cb._set_socket_timeout(in_timeout)
26-
2715
def test_send(self, cb, mocker):
2816
cb._socket = socket.socket()
2917
with mocker.patch('socket.socket.send', return_value=5):
@@ -57,46 +45,40 @@ def test_send_error_retry_count(self, cb, mocker):
5745

5846
def test_receive(self, cb, mocker):
5947
cb._socket = socket.socket()
60-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
61-
with mocker.patch('socket.socket.recv', return_value=b'12345'):
62-
result = cb.receive(10, 1)
63-
assert result == b'12345'
48+
with mocker.patch('socket.socket.recv', return_value=b'12345'):
49+
result = cb.receive(10, 1)
50+
assert result == b'12345'
6451

6552
def test_receive_timeout(self, cb, mocker):
6653
cb._socket = socket.socket()
67-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
68-
with mocker.patch('socket.socket.recv', side_effect=OSError('timed out')):
69-
result = cb.receive(10, 1)
70-
assert result == b''
54+
with mocker.patch('socket.socket.recv', side_effect=OSError('timed out')):
55+
result = cb.receive(10, 1)
56+
assert result == b''
7157

7258
def test_receive_timeout_2(self, cb, mocker):
7359
cb._socket = socket.socket()
74-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
75-
with mocker.patch('socket.socket.recv', side_effect=socket.timeout('timed out')):
76-
result = cb.receive(10, 1)
77-
assert result == b''
60+
with mocker.patch('socket.socket.recv', side_effect=socket.timeout('timed out')):
61+
result = cb.receive(10, 1)
62+
assert result == b''
7863

7964
def test_receive_eagain(self, cb, mocker):
8065
cb._socket = socket.socket()
81-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
82-
with mocker.patch('socket.socket.recv', side_effect=IOError('[Errno 11]')):
83-
result = cb.receive(10, 1)
84-
assert result == b''
66+
with mocker.patch('socket.socket.recv', side_effect=IOError('[Errno 11]')):
67+
result = cb.receive(10, 1)
68+
assert result == b''
8569

8670
def test_receive_etimeout(self, cb, mocker):
8771
cb._socket = socket.socket()
88-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
89-
with mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 60]')):
90-
result = cb.receive(10, 1)
91-
assert result == b''
72+
with mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 60]')):
73+
result = cb.receive(10, 1)
74+
assert result == b''
9275

9376
def test_receive_raise_other_oserror(self, cb, mocker):
9477
cb._socket = socket.socket()
95-
with mocker.patch.object(cb, '_set_socket_timeout', return_value=None):
96-
with mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 13]')):
97-
with pytest.raises(OSError) as os_err:
98-
cb.receive(10, 1)
99-
assert '[Errno 13]' in str(os_err.value)
78+
with mocker.patch('socket.socket.recv', side_effect=OSError('[Errno 13]')):
79+
with pytest.raises(OSError) as os_err:
80+
cb.receive(10, 1)
81+
assert '[Errno 13]' in str(os_err.value)
10082

10183
def test_is_server_alive_negative(self, cb):
10284
result = cb.is_server_alive()

test/test_blynk_main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import print_function
33
import socket
44
import pytest
5-
import blynklib
5+
import blynklib_cp as blynklib
66

77

88
class TestBlynk:

0 commit comments

Comments
 (0)
0