8
8
import sys
9
9
import time
10
10
import zlib
11
+ from enum import Enum
11
12
from pathlib import Path
12
13
from _socket import SHUT_RDWR
13
14
21
22
PYPY = hasattr (sys , 'pypy_version_info' )
22
23
23
24
24
- ERROR_MSGS = {
25
- "no_query" : "Error: Not query provided." ,
26
- "no_auth" : "Client dont have key&secret or auth token/jwt" ,
27
- "no_endpoint" : "Endpoint 'url' not found"
28
- }
25
+ class ERROR_MSGS (str , Enum ):
26
+ WRONG_FILE_TYPE = "'%s' is not a valid type to be opened as a file"
27
+ ADDRESS_TUPLE = "Devo-SenderConfigSSL| address must be a tuple (\" hostname\" , int(port))'" ,
28
+ WRONG_SSL_CONFIG = "Devo-SenderConfigSSL|Can't create SSL config: %s" ,
29
+ CONFIG_FILE_NOT_FOUND = "Error in the configuration, %s is not a file or the path does not exist" ,
30
+ CANT_READ_CONFIG_FILE = "Error in the configuration %s can't be read\n original error: %s" ,
31
+ CONFIG_FILE_PROBLEM = "Error in the configuration, %s problem related to: %s"
29
32
30
33
31
34
class DevoSenderException (Exception ):
32
35
""" Default Devo Sender Exception """
33
36
37
+ def __init__ (self , message ):
38
+ self .message = message
39
+ super ().__init__ (message )
40
+
41
+ def __str__ (self ):
42
+ return self .message
43
+
34
44
35
45
class SenderConfigSSL :
36
46
"""
@@ -55,13 +65,12 @@ class SenderConfigSSL:
55
65
Sender
56
66
57
67
"""
68
+
58
69
def __init__ (self , address = None , key = None , cert = None , chain = None ,
59
70
pkcs = None , sec_level = None , check_hostname = True ,
60
71
verify_mode = None , verify_config = False ):
61
72
if not isinstance (address , tuple ):
62
- raise DevoSenderException (
63
- "Devo-SenderConfigSSL| address must be a tuple "
64
- "'(\" hostname\" , int(port))'" )
73
+ raise DevoSenderException (ERROR_MSGS .ADDRESS_TUPLE )
65
74
try :
66
75
self .address = address
67
76
self .key = key
@@ -75,8 +84,7 @@ def __init__(self, address=None, key=None, cert=None, chain=None,
75
84
self .verify_mode = verify_mode
76
85
except Exception as error :
77
86
raise DevoSenderException (
78
- "Devo-SenderConfigSSL|Can't create SSL config: "
79
- "%s" % str (error ))
87
+ ERROR_MSGS .WRONG_SSL_CONFIG % str (error )) from error
80
88
81
89
if self .verify_config :
82
90
self .check_config_files_path ()
@@ -94,23 +102,20 @@ def check_config_files_path(self):
94
102
certificates = [self .key , self .chain , self .cert ]
95
103
for file in certificates :
96
104
try :
97
- if not Path (file ).is_file ():
105
+ if not (file .is_file () if isinstance (file , Path ) else Path (
106
+ file ).is_file ()):
98
107
raise DevoSenderException (
99
- "Error in the configuration, "
100
- + file +
101
- " is not a file or the path does not exist" )
108
+ ERROR_MSGS .CONFIG_FILE_NOT_FOUND % file )
102
109
except IOError as message :
103
110
if message .errno == errno .EACCES :
104
111
raise DevoSenderException (
105
- "Error in the configuration "
106
- + file + " can't be read" +
107
- "\n original error: " +
108
- str (message ))
112
+ ERROR_MSGS .CANT_READ_CONFIG_FILE % (
113
+ file , str (message ))) \
114
+ from message
109
115
else :
110
116
raise DevoSenderException (
111
- "Error in the configuration, "
112
- + file + " problem related to: " + str (message ))
113
-
117
+ ERROR_MSGS .CONFIG_FILE_PROBLEM % (file , str (message ))) \
118
+ from message
114
119
return True
115
120
116
121
def check_config_certificate_key (self ):
@@ -121,8 +126,8 @@ def check_config_certificate_key(self):
121
126
:return: Boolean true or raises an exception
122
127
"""
123
128
124
- with open (self .cert , "rb" ) as certificate_file , \
125
- open (self .key , "rb" ) as key_file :
129
+ with open_file (self .cert , mode = "rb" ) as certificate_file , \
130
+ open_file (self .key , mode = "rb" ) as key_file :
126
131
127
132
certificate_raw = certificate_file .read ()
128
133
key_raw = key_file .read ()
@@ -139,7 +144,7 @@ def check_config_certificate_key(self):
139
144
raise DevoSenderException (
140
145
"Error in the configuration, the key: " + self .key +
141
146
" is not compatible with the cert: " + self .cert +
142
- "\n original error: " + str (message ))
147
+ "\n original error: " + str (message )) from message
143
148
return True
144
149
145
150
def check_config_certificate_chain (self ):
@@ -149,8 +154,8 @@ def check_config_certificate_chain(self):
149
154
150
155
:return: Boolean true or raises an exception
151
156
"""
152
- with open (self .cert , "rb" ) as certificate_file , \
153
- open (self .chain , "rb" ) as chain_file :
157
+ with open_file (self .cert , mode = "rb" ) as certificate_file , \
158
+ open_file (self .chain , mode = "rb" ) as chain_file :
154
159
155
160
certificate_raw = certificate_file .read ()
156
161
chain_raw = chain_file .read ()
@@ -169,7 +174,7 @@ def check_config_certificate_chain(self):
169
174
raise DevoSenderException (
170
175
"Error in config, the chain: " + self .chain +
171
176
" is not compatible with the certificate: " + self .cert +
172
- "\n original error: " + str (message ))
177
+ "\n original error: " + str (message )) from message
173
178
return True
174
179
175
180
def check_config_certificate_address (self ):
@@ -190,18 +195,18 @@ def check_config_certificate_address(self):
190
195
raise DevoSenderException (
191
196
"Possible error in config, a timeout could be related " +
192
197
"to an incorrect address/port: " + str (self .address ) +
193
- "\n original error: " + str (message ))
198
+ "\n original error: " + str (message )) from message
194
199
except ConnectionRefusedError as message :
195
200
raise DevoSenderException (
196
201
"Error in config, incorrect address/port: "
197
202
+ str (self .address ) +
198
- "\n original error: " + str (message ))
203
+ "\n original error: " + str (message )) from message
199
204
sock .setblocking (True )
200
205
connection .do_handshake ()
201
206
server_chain = connection .get_peer_cert_chain ()
202
207
connection .close ()
203
208
204
- with open (self .chain , "rb" ) as chain_file :
209
+ with open_file (self .chain , mode = "rb" ) as chain_file :
205
210
chain = chain_file .read ()
206
211
chain_certs = []
207
212
for _ca in pem .parse (chain ):
@@ -226,15 +231,15 @@ def check_config_certificate_address(self):
226
231
def get_common_names (cert_chain , components_type ):
227
232
result = set ()
228
233
for temp_cert in cert_chain :
229
- for key , value in getattr (temp_cert , components_type )()\
234
+ for key , value in getattr (temp_cert , components_type )() \
230
235
.get_components ():
231
236
if key .decode ("utf-8" ) == "CN" :
232
237
result .add (value )
233
238
return result
234
239
235
240
@staticmethod
236
241
def fake_get_peer_cert_chain (chain ):
237
- with open (chain , "rb" ) as chain_file :
242
+ with open_file (chain , mode = "rb" ) as chain_file :
238
243
chain_certs = []
239
244
for _ca in pem .parse (chain_file .read ()):
240
245
chain_certs .append (
@@ -266,11 +271,12 @@ def __init__(self, address=None):
266
271
except Exception as error :
267
272
raise DevoSenderException (
268
273
"DevoSenderConfigTCP|Can't create TCP config: "
269
- "%s" % str (error ))
274
+ "%s" % str (error )) from error
270
275
271
276
272
277
class SenderBuffer :
273
278
"""Micro class for buffer values"""
279
+
274
280
def __init__ (self ):
275
281
self .length = 19500
276
282
self .compression_level = - 1
@@ -289,6 +295,7 @@ class Sender(logging.Handler):
289
295
:param debug: For more info in console/logger output
290
296
:param logger: logger. Default sys.console
291
297
"""
298
+
292
299
def __init__ (self , config = None , con_type = None ,
293
300
timeout = 30 , debug = False , logger = None ):
294
301
if config is None :
@@ -312,7 +319,7 @@ def __init__(self, config=None, con_type=None,
312
319
self .logger = logger if logger else \
313
320
get_log (handler = get_stream_handler (
314
321
msg_format = '%(asctime)s|%(levelname)s|Devo-Sender|%(message)s' )
315
- )
322
+ )
316
323
317
324
self ._sender_config = config
318
325
@@ -347,7 +354,8 @@ def __connect_tcp_socket(self):
347
354
except socket .error as error :
348
355
self .close ()
349
356
raise DevoSenderException (
350
- "TCP conn establishment socket error: %s" % str (error ))
357
+ "TCP conn establishment socket error: %s" % str (
358
+ error )) from error
351
359
352
360
self .timestart = int (round (time .time () * 1000 ))
353
361
@@ -373,7 +381,7 @@ def __connect_ssl(self):
373
381
self .close ()
374
382
raise DevoSenderException (
375
383
"PFX Certificate read failed: %s" %
376
- str (error ))
384
+ str (error )) from error
377
385
try :
378
386
try :
379
387
if self ._sender_config .key is not None \
@@ -418,7 +426,7 @@ def __connect_ssl(self):
418
426
self .close ()
419
427
raise DevoSenderException (
420
428
"SSL conn establishment socket error: %s" %
421
- str (error ))
429
+ str (error )) from error
422
430
423
431
def info (self , msg ):
424
432
"""
@@ -531,7 +539,7 @@ def __encode_multiline(record):
531
539
record = Sender .__encode_record (record )
532
540
return b'%d %s' % (len (record ), record )
533
541
except Exception as error :
534
- raise DevoSenderException (error )
542
+ raise DevoSenderException (error ) from error
535
543
536
544
@staticmethod
537
545
def __encode_record (record ):
@@ -590,14 +598,14 @@ def send_raw(self, record, multiline=False, zip=False):
590
598
except socket .error :
591
599
self .close ()
592
600
raise DevoSenderException (
593
- "Socket error: %s" % str (socket .error ))
601
+ "Socket error: %s" % str (socket .error )) from error
594
602
finally :
595
603
if self .debug :
596
604
self .logger .debug ('sent|%d|size|%d|msg|%s' %
597
605
(sent , len (record ), record ))
598
606
raise Exception ("Socket cant connect: unknown error" )
599
607
except Exception as error :
600
- raise DevoSenderException (error )
608
+ raise DevoSenderException (error ) from error
601
609
602
610
@staticmethod
603
611
def compose_mem (tag , ** kwargs ):
@@ -810,3 +818,20 @@ def emit(self, record):
810
818
severity = severity )
811
819
except Exception :
812
820
self .handleError (record )
821
+
822
+
823
+ def open_file (file , mode = 'r' , encoding = 'utf-8' ):
824
+ """
825
+ Helper class to open file whenever is provided as `Path` or `str` type
826
+ :param file File to open
827
+ :param mode Opening mode
828
+ :param encoding Encoding of content
829
+ """
830
+ if isinstance (file , Path ):
831
+ return file .open (mode = mode ,
832
+ encoding = encoding if not mode .endswith ('b' ) else None )
833
+ elif isinstance (file , str ):
834
+ return open (file , mode = mode ,
835
+ encoding = encoding if not mode .endswith ('b' ) else None )
836
+ else :
837
+ raise DevoSenderException (ERROR_MSGS .WRONG_FILE_TYPE % str (type (file )))
0 commit comments