kapsikkum-unmanic – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3  
4 """
5 unmanic.websocket.py
6  
7 Written by: Josh.5 <jsunnex@gmail.com>
8 Date: 23 Jul 2021, (6:08 PM)
9  
10 Copyright:
11 Copyright (C) Josh Sunnex - All Rights Reserved
12  
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19  
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22  
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
27 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
28 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
29 OR OTHER DEALINGS IN THE SOFTWARE.
30  
31 """
32 import json
33 import queue
34 import time
35 import uuid
36  
37 import tornado.web
38 import tornado.locks
39 import tornado.ioloop
40 import tornado.websocket
41 from tornado import gen, log
42  
43 from unmanic import config
44 from unmanic.libs import common, history, session
45 from unmanic.libs.uiserver import UnmanicDataQueues, UnmanicRunningTreads
46 from unmanic.webserver.helpers import completed_tasks, pending_tasks
47  
48  
49 class UnmanicWebsocketHandler(tornado.websocket.WebSocketHandler):
50 name = None
51 config = None
52 sending_frontend_message = False
53 sending_system_logs = False
54 sending_worker_info = False
55 sending_pending_tasks_info = False
56 sending_completed_tasks_info = False
57 close_event = False
58  
59 def __init__(self, *args, **kwargs):
60 self.name = 'UnmanicWebsocketHandler'
61 self.config = config.Config()
62 self.server_id = str(uuid.uuid4())
63 udq = UnmanicDataQueues()
64 urt = UnmanicRunningTreads()
65 self.data_queues = udq.get_unmanic_data_queues()
66 self.foreman = urt.get_unmanic_running_thread('foreman')
67 self.session = session.Session()
68 super(UnmanicWebsocketHandler, self).__init__(*args, **kwargs)
69  
70 def open(self):
71 tornado.log.app_log.warning('WS Opened', exc_info=True)
72 self.close_event = tornado.locks.Event()
73  
74 def on_message(self, message):
75 try:
76 message_data = json.loads(message)
77 if message_data.get('command'):
78 # Execute the function
79 getattr(self, message_data.get('command', 'default_failure_response'))(params=message_data.get('params', {}))
80 except json.decoder.JSONDecodeError:
81 tornado.log.app_log.error('Received incorrectly formatted message - {}'.format(message), exc_info=False)
82  
83 def on_close(self):
84 tornado.log.app_log.warning('WS Closed', exc_info=True)
85 self.close_event.set()
86 self.stop_frontend_messages()
87 self.stop_workers_info()
88 self.stop_pending_tasks_info()
89 self.stop_completed_tasks_info()
90  
91 def default_failure_response(self, params=None):
92 """
93 WS Command - default_failure_response
94 Returns a failure response
95  
96 :param params:
97 :type params:
98 :return:
99 :rtype:
100 """
101 self.write_message({'success': False})
102  
103 def start_frontend_messages(self, params=None):
104 """
105 WS Command - start_frontend_messages
106 Start sending messages from the application to the frontend.
107  
108 :param params:
109 :type params:
110 :return:
111 :rtype:
112 """
113 if not self.sending_frontend_message:
114 self.sending_frontend_message = True
115 tornado.ioloop.IOLoop.current().spawn_callback(self.async_frontend_message)
116  
117 def stop_frontend_messages(self, params=None):
118 """
119 WS Command - stop_frontend_messages
120 Stop sending messages from the application to the frontend.
121  
122 :param params:
123 :type params:
124 :return:
125 :rtype:
126 """
127 self.sending_frontend_message = False
128  
129 def start_system_logs(self, params=None):
130 """
131 WS Command - start_system_logs
132 Start sending system logs from the application to the frontend.
133  
134 :param params:
135 :type params:
136 :return:
137 :rtype:
138 """
139 if not self.sending_system_logs:
140 self.sending_system_logs = True
141 tornado.ioloop.IOLoop.current().spawn_callback(self.async_system_logs)
142  
143 def stop_system_logs(self, params=None):
144 """
145 WS Command - stop_system_logs
146 Stop sending system logs from the application to the frontend.
147  
148 :param params:
149 :type params:
150 :return:
151 :rtype:
152 """
153 self.sending_system_logs = False
154  
155 def start_workers_info(self, params=None):
156 """
157 WS Command - start_workers_info
158 Start sending information pertaining to the workers
159  
160 :param params:
161 :type params:
162 :return:
163 :rtype:
164 """
165 if not self.sending_worker_info:
166 self.sending_worker_info = True
167 tornado.ioloop.IOLoop.current().spawn_callback(self.async_workers_info)
168  
169 def stop_workers_info(self, params=None):
170 """
171 WS Command - stop_workers_info
172 Stop sending information pertaining to the workers
173  
174 :param params:
175 :type params:
176 :return:
177 :rtype:
178 """
179 self.sending_worker_info = False
180  
181 def start_pending_tasks_info(self, params=None):
182 """
183 WS Command - start_pending_tasks_info
184 Start sending information pertaining to the pending tasks list
185  
186 :param params:
187 :type params:
188 :return:
189 :rtype:
190 """
191 if not self.sending_pending_tasks_info:
192 self.sending_pending_tasks_info = True
193 tornado.ioloop.IOLoop.current().spawn_callback(self.async_pending_tasks_info)
194  
195 def stop_pending_tasks_info(self, params=None):
196 """
197 WS Command - stop_pending_tasks_info
198 Stop sending information pertaining to the pending tasks list
199  
200 :param params:
201 :type params:
202 :return:
203 :rtype:
204 """
205 self.sending_pending_tasks_info = False
206  
207 def start_completed_tasks_info(self, params=None):
208 """
209 WS Command - start_completed_tasks_info
210 Start sending information pertaining to the completed tasks list
211  
212 :param params:
213 :type params:
214 :return:
215 :rtype:
216 """
217 if not self.sending_completed_tasks_info:
218 self.sending_completed_tasks_info = True
219 tornado.ioloop.IOLoop.current().spawn_callback(self.async_completed_tasks_info)
220  
221 def stop_completed_tasks_info(self, params=None):
222 """
223 WS Command - stop_completed_tasks_info
224 Stop sending information pertaining to the completed tasks list
225  
226 :param params:
227 :type params:
228 :return:
229 :rtype:
230 """
231 self.sending_completed_tasks_info = False
232  
233 def dismiss_message(self, params=None):
234 """
235 WS Command - dismiss_message
236 Dismiss a specified message by id.
237  
238 params:
239 - message_id - The ID of the message to be dismissed
240  
241 :param params:
242 :type params:
243 :return:
244 :rtype:
245 """
246 frontend_messages = self.data_queues.get('frontend_messages')
247 frontend_messages.remove_item(params.get('message_id', ''))
248  
249 async def send(self, message):
250 if self.ws_connection:
251 await self.write_message(message)
252  
253 async def async_frontend_message(self):
254 while self.sending_frontend_message:
255 frontend_messages = self.data_queues.get('frontend_messages')
256 frontend_message_items = frontend_messages.read_all_items()
257 # Send message to client
258 await self.send(
259 {
260 'success': True,
261 'server_id': self.server_id,
262 'type': 'frontend_message',
263 'data': frontend_message_items,
264 }
265 )
266  
267 # Sleep for X seconds
268 await gen.sleep(.2)
269  
270 async def async_system_logs(self):
271 while self.sending_system_logs:
272 system_logs = self.config.read_system_logs(lines=35)
273  
274 # Send message to client
275 await self.send(
276 {
277 'success': True,
278 'server_id': self.server_id,
279 'type': 'system_logs',
280 'data': {
281 "logs_path": self.config.get_log_path(),
282 'system_logs': system_logs,
283 },
284 }
285 )
286  
287 # Sleep for X seconds
288 await gen.sleep(1)
289  
290 async def async_workers_info(self):
291 while self.sending_worker_info:
292 workers_info = self.foreman.get_all_worker_status()
293  
294 # Send message to client
295 await self.send(
296 {
297 'success': True,
298 'server_id': self.server_id,
299 'type': 'workers_info',
300 'data': workers_info,
301 }
302 )
303  
304 # Sleep for X seconds
305 await gen.sleep(.2)
306  
307 async def async_pending_tasks_info(self):
308 while self.sending_pending_tasks_info:
309 results = []
310 params = {
311 'start': '0',
312 'length': '10',
313 'search_value': '',
314 'order': {
315 "column": 'priority',
316 "dir": 'desc',
317 }
318 }
319 task_list = pending_tasks.prepare_filtered_pending_tasks(params)
320  
321 for task_result in task_list.get('results', []):
322 # Append the task to the results list
323 results.append(
324 {
325 'id': task_result['id'],
326 'label': task_result['abspath'],
327 'priority': task_result['priority'],
328 'status': task_result['status'],
329 }
330 )
331  
332 # Send message to client
333 await self.send(
334 {
335 'success': True,
336 'server_id': self.server_id,
337 'type': 'pending_tasks',
338 'data': {
339 'results': results
340 },
341 }
342 )
343  
344 # Sleep for X seconds
345 await gen.sleep(3)
346  
347 async def async_completed_tasks_info(self):
348 while self.sending_completed_tasks_info:
349 results = []
350 params = {
351 'start': '0',
352 'length': '10',
353 'search_value': '',
354 'order': {
355 "column": 'finish_time',
356 "dir": 'desc',
357 }
358 }
359 task_list = completed_tasks.prepare_filtered_completed_tasks(params)
360  
361 for task_result in task_list.get('results', []):
362 # Set human readable time
363 if (int(task_result['finish_time']) + 60) > int(time.time()):
364 human_readable_time = 'Just Now'
365 else:
366 human_readable_time = common.make_timestamp_human_readable(int(task_result['finish_time']))
367  
368 # Append the task to the results list
369 results.append(
370 {
371 'id': task_result['id'],
372 'label': task_result['task_label'],
373 'success': task_result['task_success'],
374 'finish_time': task_result['finish_time'],
375 'human_readable_time': human_readable_time,
376 }
377 )
378  
379 # Send message to client
380 await self.send(
381 {
382 'success': True,
383 'server_id': self.server_id,
384 'type': 'completed_tasks',
385 'data': {
386 'results': results
387 },
388 }
389 )
390  
391 # Sleep for X seconds
392 await gen.sleep(3)