1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# -*- coding: utf-8 -*-
from __future__ import division, absolute_import, print_function, unicode_literals
#################################################################################################
import json
import logging
import threading
import ssl
import certifi
import websocket
from .keepalive import KeepAlive
##################################################################################################
LOG = logging.getLogger('JELLYFIN.' + __name__)
##################################################################################################
class WSClient(threading.Thread):
multi_client = False
global_wsc = None
global_stop = False
def __init__(self, client, allow_multiple_clients=False):
LOG.debug("WSClient initializing...")
self.client = client
self.keepalive = None
self.wsc = None
self.stop = False
self.message_ids = set()
if self.multi_client or allow_multiple_clients:
self.multi_client = True
threading.Thread.__init__(self)
def send(self, message, data=""):
if self.wsc is None:
raise ValueError("The websocket client is not started.")
self.wsc.send(json.dumps({'MessageType': message, "Data": data}))
def run(self):
token = self.client.config.data['auth.token']
device_id = self.client.config.data['app.device_id']
server = self.client.config.data['auth.server']
server = server.replace('https', "wss") if server.startswith('https') else server.replace('http', "ws")
wsc_url = "%s/socket?api_key=%s&device_id=%s" % (server, token, device_id)
verify = self.client.config.data.get('auth.ssl', False)
LOG.info("Websocket url: %s", wsc_url)
self.wsc = websocket.WebSocketApp(wsc_url,
on_message=lambda ws, message: self.on_message(ws, message),
on_error=lambda ws, error: self.on_error(ws, error))
self.wsc.on_open = lambda ws: self.on_open(ws)
if not self.multi_client:
if self.global_wsc is not None:
self.global_wsc.close()
self.global_wsc = self.wsc
while not self.stop and not self.global_stop:
if not verify:
# https://stackoverflow.com/questions/48740053/
self.wsc.run_forever(
ping_interval=10, sslopt={"cert_reqs": ssl.CERT_NONE}
)
else:
self.wsc.run_forever(ping_interval=10, sslopt={"ca_certs": certifi.where()})
if not self.stop:
break
LOG.info("---<[ websocket ]")
self.client.callback('WebSocketDisconnect', None)
def on_error(self, ws, error):
LOG.error(error)
self.client.callback('WebSocketError', error)
def on_open(self, ws):
LOG.info("--->[ websocket ]")
self.client.callback('WebSocketConnect', None)
def on_message(self, ws, message):
message = json.loads(message)
# If a message is received multiple times, ignore repeats.
message_id = message.get("MessageId")
if message_id is not None:
if message_id in self.message_ids:
return
self.message_ids.add(message_id)
data = message.get('Data', {})
if message['MessageType'] == "ForceKeepAlive":
self.send("KeepAlive")
if self.keepalive is not None:
self.keepalive.stop()
self.keepalive = KeepAlive(data, self)
self.keepalive.start()
LOG.debug("ForceKeepAlive received from server.")
return
elif message['MessageType'] == "KeepAlive":
LOG.debug("KeepAlive received from server.")
return
if data is None:
data = {}
elif type(data) is not dict:
data = {"value": data}
if not self.client.config.data['app.default']:
data['ServerId'] = self.client.auth.server_id
self.client.callback(message['MessageType'], data)
def stop_client(self):
self.stop = True
if self.keepalive is not None:
self.keepalive.stop()
if self.wsc is not None:
self.wsc.close()
if not self.multi_client:
self.global_stop = True
self.global_wsc = None
|