├── .gitignore
├── README.md
├── bin
├── JpgDll.dll
├── SavePhoto.dll
├── Sdtapi.dll
├── Sdtapi.lib
├── WltRS.dll
└── dewlt.dll
├── demo.html
├── reader.py
├── sdk
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-37.pyc
│ └── sdk.cpython-37.pyc
└── sdk.py
├── snapshot.png
└── websocket_server
├── __init__.py
├── __pycache__
├── __init__.cpython-37.pyc
└── websocket_server.cpython-37.pyc
└── websocket_server.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python 语言开发的集成“身份证阅读器”和“打开摄像头”功能 附EXE可执行软件和源代码
2 | #另有golang语言和rust语言版本的源码,纯个人业余开发,可商用定制,欢迎交流
3 | #实现“在线身份证读取”和“在线拍照认证”功能
4 |
5 | # B/S框架 idcardReader
6 | 精伦iDR210,千景J15S,华视CVR-100U,华旭HX-FDX3S,神思SS628-100U,新中新DKQ-A16D,普天CP IDMR02/TG,神盾ICR-100U身份证阅读器Web版,提供web服务,基于HTTP协议
7 |
8 | # B/S框架 camera
9 | 打开本地摄像头,提供web服务,基于WebSocket协议
10 |
11 | # 快照
12 | 
13 |
--------------------------------------------------------------------------------
/bin/JpgDll.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/JpgDll.dll
--------------------------------------------------------------------------------
/bin/SavePhoto.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/SavePhoto.dll
--------------------------------------------------------------------------------
/bin/Sdtapi.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/Sdtapi.dll
--------------------------------------------------------------------------------
/bin/Sdtapi.lib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/Sdtapi.lib
--------------------------------------------------------------------------------
/bin/WltRS.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/WltRS.dll
--------------------------------------------------------------------------------
/bin/dewlt.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/bin/dewlt.dll
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 身份证阅读器Web版 - Power by 明珠玮玉
5 |
82 |
119 |
120 |
121 |
200 |
201 |
202 |
--------------------------------------------------------------------------------
/reader.py:
--------------------------------------------------------------------------------
1 | from websocket_server import WebsocketServer
2 | import sdk
3 | import json
4 |
5 |
6 | # 处理客户端消息
7 | def handle_message(message):
8 | if message == '--OpenReader':
9 | # 打开设备
10 | ret = sdk.API().init_comm()
11 | if ret == 1:
12 | sdk.Init.Initialization['comm'] = True
13 | elif message == '--ReadCard':
14 | # 读取身份证信息
15 | if not sdk.Init.Initialization['comm']:
16 | ret = sdk.API().init_comm()
17 | if ret['ret'] == 1:
18 | sdk.Init.Initialization['comm'] = True
19 | else:
20 | return ret
21 | # 卡认证
22 | sdk.API().authenticate()
23 | # 判断卡
24 | ret = sdk.API().card_on()
25 | if ret['ret'] != 1:
26 | return ret
27 | # 读取卡
28 | ret = sdk.API().read_base_infos()
29 | if ret['ret'] != 1:
30 | return ret
31 | elif message == '--CloseReader':
32 | # 关闭设备
33 | ret = sdk.API().close_comm()
34 | if ret == 1:
35 | sdk.Init.Initialization['comm'] = False
36 | else:
37 | ret = {'ret': 0, 'msg': '未知指令', 'data': ''}
38 | return ret
39 |
40 |
41 |
42 | # 客户端上线
43 | def new_client(client, server):
44 | pass
45 | ret = sdk.API().init_comm()
46 | if ret['ret'] == 1:
47 | sdk.Init.Initialization['comm'] = True
48 | print(ret)
49 | server.send_message(client, json.dumps(ret))
50 |
51 |
52 |
53 | # 客户端离线
54 | def client_left(client, server):
55 | pass
56 | ret = sdk.API().close_comm()
57 | if ret['ret'] == 1:
58 | sdk.Init.Initialization['comm'] = False
59 | print(ret)
60 |
61 |
62 | # 接收客户端消息
63 | def message_received(client, server, message):
64 | pass
65 | if len(message) > 200:
66 | message = message[:200] + '..'
67 | received = handle_message(message)
68 | server.send_message(client, json.dumps(received))
69 |
70 |
71 | PORT = 9000
72 | server = WebsocketServer(PORT)
73 | server.set_fn_new_client(new_client)
74 | server.set_fn_client_left(client_left)
75 | server.set_fn_message_received(message_received)
76 | server.run_forever()
77 |
--------------------------------------------------------------------------------
/sdk/__init__.py:
--------------------------------------------------------------------------------
1 | from .sdk import *
2 |
--------------------------------------------------------------------------------
/sdk/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/sdk/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/sdk/__pycache__/sdk.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/sdk/__pycache__/sdk.cpython-37.pyc
--------------------------------------------------------------------------------
/sdk/sdk.py:
--------------------------------------------------------------------------------
1 | # -*- coding: UTF-8 -*-
2 | import ctypes
3 | import base64
4 | import os
5 | import cv2
6 |
7 |
8 | class Init:
9 | # 初始化状态
10 | Initialization = {
11 | 'comm': False,
12 | }
13 |
14 |
15 | class API:
16 | try:
17 | dll = ctypes.windll.LoadLibrary("bin/Sdtapi.dll")
18 | except Exception as e:
19 | ctypes.windll.user32.MessageBoxA(0, str(e).encode('gbk'), '提示'.encode('gbk'), 0)
20 | os._exit(0)
21 |
22 | # 4.1.1.端口初始化函数
23 | def init_comm(self):
24 | # 根据实际情况选择USB口和串口循环次数
25 | # USB型iDR, 1001 - 1016
26 | for i in range(1001, 1006):
27 | ret = self.dll.InitComm(i)
28 | if ret == 1:
29 | break
30 | # 串口型iDR,1--16
31 | if ret != 1:
32 | for i in range(1, 16):
33 | ret = self.dll.InitComm(i)
34 | if ret == 1:
35 | break
36 | if ret == 1:
37 | return {'ret': 1, 'msg': '端口初始化成功', 'data': ''}
38 | else:
39 | return {'ret': 0, 'msg': '端口初始化失败', 'data': ''}
40 |
41 | # 4.1.2.端口关闭接口
42 | def close_comm(self):
43 | ret = self.dll.CloseComm()
44 | if ret == 1:
45 | return {'ret': 1, 'msg': '端口关闭成功', 'data': ''}
46 | elif ret == -1:
47 | return {'ret': 0, 'msg': '端口未打开', 'data': ''}
48 | else:
49 | return {'ret': 0, 'msg': '端口关闭失败', 'data': ''}
50 |
51 | # 4.2.1.卡认证接口
52 | def authenticate(self):
53 | ret = self.dll.Authenticate()
54 | if ret == 1:
55 | return {'ret': 1, 'msg': '卡认证成功', 'data': ''}
56 | else:
57 | return {'ret': 0, 'msg': '卡认证失败', 'data': ''}
58 |
59 | # 4.2.6.判断身份证是否在设备上
60 | def card_on(self):
61 | ret = self.dll.CardOn()
62 | if ret == 1:
63 | return {'ret': 1, 'msg': '有身份证', 'data': ''}
64 | else:
65 | return {'ret': 0, 'msg': '无身份证', 'data': ''}
66 |
67 | # 4.2.2.读卡信息接口
68 | # 原型4
69 | def read_base_infos(self):
70 | name, gender, folk, birthDay, code, address, agency, expireStart, expireEnd = bytes(192), bytes(192), bytes(
71 | 192), bytes(
72 | 192), bytes(192), bytes(192), bytes(192), bytes(192), bytes(192),
73 | ret = self.dll.ReadBaseInfos(name, gender, folk, birthDay, code, address, agency, expireStart, expireEnd)
74 | if ret == 1:
75 | info = {}
76 | info['name'] = name.decode('gbk').strip('\x00')
77 | info['gender'] = gender.decode('gbk').strip('\x00')
78 | info['folk'] = folk.decode('gbk').strip('\x00')
79 | info['birthDay'] = birthDay.decode('gbk').strip('\x00')
80 | info['code'] = code.decode('gbk').strip('\x00')
81 | info['address'] = address.decode('gbk').strip('\x00')
82 | info['agency'] = agency.decode('gbk').strip('\x00')
83 | info['expireStart'] = expireStart.decode('gbk').strip('\x00')
84 | info['expireEnd'] = expireEnd.decode('gbk').strip('\x00')
85 |
86 | try:
87 | with open("bin/photo.bmp", 'rb') as f:
88 | base64_data = base64.b64encode(f.read())
89 | s = base64_data.decode()
90 | except Exception as e:
91 | s = ''
92 | info['photo'] = "data:image/bmp;base64," + s
93 | return {'ret': 1, 'msg': '读卡成功', 'data': info}
94 | elif ret == 0:
95 | return {'ret': 0, 'msg': '读卡失败', 'data': ''}
96 | elif ret == -4:
97 | return {'ret': 0, 'msg': '缺少文件', 'data': ''}
98 | else:
99 | return {'ret': 0, 'msg': '未知错误', 'data': ''}
100 |
101 | class OpenCV:
102 | cap = cv2.VideoCapture(0)
103 | # 从摄像头中取得视频
104 | def video_capture(self):
105 | if self.cap.isOpened():
106 | # 读取帧摄像头
107 | ret, frame = self.cap.read()
108 | img_str = cv2.imencode('.jpg', frame)[1].tostring() # 将图片编码成流数据,放到内存缓存中,然后转化成string格式
109 | b64_code = base64.b64encode(img_str) # 编码成base64
110 | return {'ret': 1, 'msg': '视频捕获成功', 'data': 'data:image/jpg;base64,' + b64_code.decode()}
111 | else:
112 | return {'ret': 0, 'msg': '未发现摄像头', 'data': ''}
113 |
114 | # 回收资源
115 | def destroy(self):
116 | self.cap.release()
117 |
--------------------------------------------------------------------------------
/snapshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/snapshot.png
--------------------------------------------------------------------------------
/websocket_server/__init__.py:
--------------------------------------------------------------------------------
1 | from .websocket_server import *
2 |
--------------------------------------------------------------------------------
/websocket_server/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/websocket_server/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/websocket_server/__pycache__/websocket_server.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zjw939057120/idcardReader-camera/bcb3e5a8ad35c0a2365b80d865712a65aff851d7/websocket_server/__pycache__/websocket_server.cpython-37.pyc
--------------------------------------------------------------------------------
/websocket_server/websocket_server.py:
--------------------------------------------------------------------------------
1 | # Author: Johan Hanssen Seferidis
2 | # License: MIT
3 |
4 | import sys
5 | import struct
6 | from base64 import b64encode
7 | from hashlib import sha1
8 | import logging
9 | from socket import error as SocketError
10 | import errno
11 |
12 | if sys.version_info[0] < 3:
13 | from SocketServer import ThreadingMixIn, TCPServer, StreamRequestHandler
14 | else:
15 | from socketserver import ThreadingMixIn, TCPServer, StreamRequestHandler
16 |
17 | logger = logging.getLogger(__name__)
18 | logging.basicConfig()
19 |
20 | '''
21 | +-+-+-+-+-------+-+-------------+-------------------------------+
22 | 0 1 2 3
23 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
24 | +-+-+-+-+-------+-+-------------+-------------------------------+
25 | |F|R|R|R| opcode|M| Payload len | Extended payload length |
26 | |I|S|S|S| (4) |A| (7) | (16/64) |
27 | |N|V|V|V| |S| | (if payload len==126/127) |
28 | | |1|2|3| |K| | |
29 | +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
30 | | Extended payload length continued, if payload len == 127 |
31 | + - - - - - - - - - - - - - - - +-------------------------------+
32 | | Payload Data continued ... |
33 | +---------------------------------------------------------------+
34 | '''
35 |
36 | FIN = 0x80
37 | OPCODE = 0x0f
38 | MASKED = 0x80
39 | PAYLOAD_LEN = 0x7f
40 | PAYLOAD_LEN_EXT16 = 0x7e
41 | PAYLOAD_LEN_EXT64 = 0x7f
42 |
43 | OPCODE_CONTINUATION = 0x0
44 | OPCODE_TEXT = 0x1
45 | OPCODE_BINARY = 0x2
46 | OPCODE_CLOSE_CONN = 0x8
47 | OPCODE_PING = 0x9
48 | OPCODE_PONG = 0xA
49 |
50 |
51 | # -------------------------------- API ---------------------------------
52 |
53 | class API():
54 |
55 | def run_forever(self):
56 | try:
57 | logger.info("Listening on port %d for clients.." % self.port)
58 | self.serve_forever()
59 | except KeyboardInterrupt:
60 | self.server_close()
61 | logger.info("Server terminated.")
62 | except Exception as e:
63 | logger.error(str(e), exc_info=True)
64 | exit(1)
65 |
66 | def new_client(self, client, server):
67 | pass
68 |
69 | def client_left(self, client, server):
70 | pass
71 |
72 | def message_received(self, client, server, message):
73 | pass
74 |
75 | def set_fn_new_client(self, fn):
76 | self.new_client = fn
77 |
78 | def set_fn_client_left(self, fn):
79 | self.client_left = fn
80 |
81 | def set_fn_message_received(self, fn):
82 | self.message_received = fn
83 |
84 | def send_message(self, client, msg):
85 | self._unicast_(client, msg)
86 |
87 | def send_message_to_all(self, msg):
88 | self._multicast_(msg)
89 |
90 |
91 | # ------------------------- Implementation -----------------------------
92 |
93 | class WebsocketServer(ThreadingMixIn, TCPServer, API):
94 | """
95 | A websocket server waiting for clients to connect.
96 |
97 | Args:
98 | port(int): Port to bind to
99 | host(str): Hostname or IP to listen for connections. By default 127.0.0.1
100 | is being used. To accept connections from any client, you should use
101 | 0.0.0.0.
102 | loglevel: Logging level from logging module to use for logging. By default
103 | warnings and errors are being logged.
104 |
105 | Properties:
106 | clients(list): A list of connected clients. A client is a dictionary
107 | like below.
108 | {
109 | 'id' : id,
110 | 'handler' : handler,
111 | 'address' : (addr, port)
112 | }
113 | """
114 |
115 | allow_reuse_address = True
116 | daemon_threads = True # comment to keep threads alive until finished
117 |
118 | clients = []
119 | id_counter = 0
120 |
121 | def __init__(self, port, host='127.0.0.1', loglevel=logging.WARNING):
122 | logger.setLevel(loglevel)
123 | TCPServer.__init__(self, (host, port), WebSocketHandler)
124 | self.port = self.socket.getsockname()[1]
125 |
126 | def _message_received_(self, handler, msg):
127 | self.message_received(self.handler_to_client(handler), self, msg)
128 |
129 | def _ping_received_(self, handler, msg):
130 | handler.send_pong(msg)
131 |
132 | def _pong_received_(self, handler, msg):
133 | pass
134 |
135 | def _new_client_(self, handler):
136 | self.id_counter += 1
137 | client = {
138 | 'id': self.id_counter,
139 | 'handler': handler,
140 | 'address': handler.client_address
141 | }
142 | self.clients.append(client)
143 | self.new_client(client, self)
144 |
145 | def _client_left_(self, handler):
146 | client = self.handler_to_client(handler)
147 | self.client_left(client, self)
148 | if client in self.clients:
149 | self.clients.remove(client)
150 |
151 | def _unicast_(self, to_client, msg):
152 | to_client['handler'].send_message(msg)
153 |
154 | def _multicast_(self, msg):
155 | for client in self.clients:
156 | self._unicast_(client, msg)
157 |
158 | def handler_to_client(self, handler):
159 | for client in self.clients:
160 | if client['handler'] == handler:
161 | return client
162 |
163 |
164 | class WebSocketHandler(StreamRequestHandler):
165 |
166 | def __init__(self, socket, addr, server):
167 | self.server = server
168 | StreamRequestHandler.__init__(self, socket, addr, server)
169 |
170 | def setup(self):
171 | StreamRequestHandler.setup(self)
172 | self.keep_alive = True
173 | self.handshake_done = False
174 | self.valid_client = False
175 |
176 | def handle(self):
177 | while self.keep_alive:
178 | if not self.handshake_done:
179 | self.handshake()
180 | elif self.valid_client:
181 | self.read_next_message()
182 |
183 | def read_bytes(self, num):
184 | # python3 gives ordinal of byte directly
185 | bytes = self.rfile.read(num)
186 | if sys.version_info[0] < 3:
187 | return map(ord, bytes)
188 | else:
189 | return bytes
190 |
191 | def read_next_message(self):
192 | try:
193 | b1, b2 = self.read_bytes(2)
194 | except SocketError as e: # to be replaced with ConnectionResetError for py3
195 | if e.errno == errno.ECONNRESET:
196 | logger.info("Client closed connection.")
197 | print("Error: {}".format(e))
198 | self.keep_alive = 0
199 | return
200 | b1, b2 = 0, 0
201 | except ValueError as e:
202 | b1, b2 = 0, 0
203 |
204 | fin = b1 & FIN
205 | opcode = b1 & OPCODE
206 | masked = b2 & MASKED
207 | payload_length = b2 & PAYLOAD_LEN
208 |
209 | if opcode == OPCODE_CLOSE_CONN:
210 | logger.info("Client asked to close connection.")
211 | self.keep_alive = 0
212 | return
213 | if not masked:
214 | logger.warn("Client must always be masked.")
215 | self.keep_alive = 0
216 | return
217 | if opcode == OPCODE_CONTINUATION:
218 | logger.warn("Continuation frames are not supported.")
219 | return
220 | elif opcode == OPCODE_BINARY:
221 | logger.warn("Binary frames are not supported.")
222 | return
223 | elif opcode == OPCODE_TEXT:
224 | opcode_handler = self.server._message_received_
225 | elif opcode == OPCODE_PING:
226 | opcode_handler = self.server._ping_received_
227 | elif opcode == OPCODE_PONG:
228 | opcode_handler = self.server._pong_received_
229 | else:
230 | logger.warn("Unknown opcode %#x." % opcode)
231 | self.keep_alive = 0
232 | return
233 |
234 | if payload_length == 126:
235 | payload_length = struct.unpack(">H", self.rfile.read(2))[0]
236 | elif payload_length == 127:
237 | payload_length = struct.unpack(">Q", self.rfile.read(8))[0]
238 |
239 | masks = self.read_bytes(4)
240 | message_bytes = bytearray()
241 | for message_byte in self.read_bytes(payload_length):
242 | message_byte ^= masks[len(message_bytes) % 4]
243 | message_bytes.append(message_byte)
244 | opcode_handler(self, message_bytes.decode('utf8'))
245 |
246 | def send_message(self, message):
247 | self.send_text(message)
248 |
249 | def send_pong(self, message):
250 | self.send_text(message, OPCODE_PONG)
251 |
252 | def send_text(self, message, opcode=OPCODE_TEXT):
253 | """
254 | Important: Fragmented(=continuation) messages are not supported since
255 | their usage cases are limited - when we don't know the payload length.
256 | """
257 |
258 | # Validate message
259 | if isinstance(message, bytes):
260 | message = try_decode_UTF8(message) # this is slower but ensures we have UTF-8
261 | if not message:
262 | logger.warning("Can\'t send message, message is not valid UTF-8")
263 | return False
264 | elif sys.version_info < (3,0) and (isinstance(message, str) or isinstance(message, unicode)):
265 | pass
266 | elif isinstance(message, str):
267 | pass
268 | else:
269 | logger.warning('Can\'t send message, message has to be a string or bytes. Given type is %s' % type(message))
270 | return False
271 |
272 | header = bytearray()
273 | payload = encode_to_UTF8(message)
274 | payload_length = len(payload)
275 |
276 | # Normal payload
277 | if payload_length <= 125:
278 | header.append(FIN | opcode)
279 | header.append(payload_length)
280 |
281 | # Extended payload
282 | elif payload_length >= 126 and payload_length <= 65535:
283 | header.append(FIN | opcode)
284 | header.append(PAYLOAD_LEN_EXT16)
285 | header.extend(struct.pack(">H", payload_length))
286 |
287 | # Huge extended payload
288 | elif payload_length < 18446744073709551616:
289 | header.append(FIN | opcode)
290 | header.append(PAYLOAD_LEN_EXT64)
291 | header.extend(struct.pack(">Q", payload_length))
292 |
293 | else:
294 | raise Exception("Message is too big. Consider breaking it into chunks.")
295 | return
296 |
297 | self.request.send(header + payload)
298 |
299 | def read_http_headers(self):
300 | headers = {}
301 | # first line should be HTTP GET
302 | http_get = self.rfile.readline().decode().strip()
303 | assert http_get.upper().startswith('GET')
304 | # remaining should be headers
305 | while True:
306 | header = self.rfile.readline().decode().strip()
307 | if not header:
308 | break
309 | head, value = header.split(':', 1)
310 | headers[head.lower().strip()] = value.strip()
311 | return headers
312 |
313 | def handshake(self):
314 | headers = self.read_http_headers()
315 |
316 | try:
317 | assert headers['upgrade'].lower() == 'websocket'
318 | except AssertionError:
319 | self.keep_alive = False
320 | return
321 |
322 | try:
323 | key = headers['sec-websocket-key']
324 | except KeyError:
325 | logger.warning("Client tried to connect but was missing a key")
326 | self.keep_alive = False
327 | return
328 |
329 | response = self.make_handshake_response(key)
330 | self.handshake_done = self.request.send(response.encode())
331 | self.valid_client = True
332 | self.server._new_client_(self)
333 |
334 | @classmethod
335 | def make_handshake_response(cls, key):
336 | return \
337 | 'HTTP/1.1 101 Switching Protocols\r\n'\
338 | 'Upgrade: websocket\r\n' \
339 | 'Connection: Upgrade\r\n' \
340 | 'Sec-WebSocket-Accept: %s\r\n' \
341 | '\r\n' % cls.calculate_response_key(key)
342 |
343 | @classmethod
344 | def calculate_response_key(cls, key):
345 | GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
346 | hash = sha1(key.encode() + GUID.encode())
347 | response_key = b64encode(hash.digest()).strip()
348 | return response_key.decode('ASCII')
349 |
350 | def finish(self):
351 | self.server._client_left_(self)
352 |
353 |
354 | def encode_to_UTF8(data):
355 | try:
356 | return data.encode('UTF-8')
357 | except UnicodeEncodeError as e:
358 | logger.error("Could not encode data to UTF-8 -- %s" % e)
359 | return False
360 | except Exception as e:
361 | raise(e)
362 | return False
363 |
364 |
365 | def try_decode_UTF8(data):
366 | try:
367 | return data.decode('utf-8')
368 | except UnicodeDecodeError:
369 | return False
370 | except Exception as e:
371 | raise(e)
372 |
--------------------------------------------------------------------------------