-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtask.lisp
131 lines (104 loc) · 4.38 KB
/
task.lisp
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
(in-package #:displayer)
(defvar *task-runner* NIL)
(defvar *task-condition* (bt:make-condition-variable :name "task runner condition"))
(defvar *task-lock* (bt:make-lock "task runner lock"))
(defvar *tasks* (make-hash-table :test 'equal))
(define-trigger radiance:startup-done ()
(make-instance 'restart-video)
(restart-task-runner))
(defun tasks-running-p ()
(and *task-runner* (bt:thread-alive-p *task-runner*)))
(defun restart-task-runner ()
(when *task-runner*
(when (bt:thread-alive-p *task-runner*)
(let ((stop (make-instance 'stop-task-runner)))
(unwind-protect
(loop repeat 10
do (unless (bt:thread-alive-p *task-runner*)
(return))
(sleep 0.01)
finally (bt:destroy-thread *task-runner*))
(clear stop))))
(setf *task-runner* NIL))
(setf *task-runner* (bt:make-thread #'run-tasks :name "displayer task runner")))
(defun run-tasks ()
(with-simple-restart (stop-task-runner "Stop the task runner")
(loop (loop for task in (bt:with-lock-held (*task-lock*)
(loop for task being the hash-values of *tasks*
when (eql :pending (status task))
collect task))
do (with-simple-restart (abort "Abort the task")
(handler-bind ((error (lambda (e)
(l:debug :displayer e)
(l:error :displayer "Task ~a failed: ~a" task e)
(abort e))))
(execute task))))
(bt:with-lock-held (*task-lock*)
(bt:condition-wait *task-condition* *task-lock* :timeout 5)))))
(defmethod find-task ((id string))
(bt:with-lock-held (*task-lock*)
(gethash id *tasks*)))
(defun list-tasks ()
(sort (bt:with-lock-held (*task-lock*)
(alexandria:hash-table-values *tasks*))
#'> :key #'created-at))
(defmethod clear ((all (eql T)))
(bt:with-lock-held (*task-lock*)
(clrhash *tasks*)))
(defclass task ()
((id :initarg :id :initform (make-random-string) :accessor id)
(created-at :initarg :created-at :initform (get-universal-time) :accessor created-at)
(status :initform :pending :accessor status)
(message :initform NIL :accessor message)))
(defmethod initialize-instance :after ((task task) &key)
(bt:with-lock-held (*task-lock*)
(setf (gethash (id task) *tasks*) task))
(bt:condition-notify *task-condition*))
(defmethod print-object ((task task) stream)
(print-unreadable-object (task stream :type T)
(format stream "~a ~a" (id task) (status task))))
(defgeneric execute (task))
(defmethod execute :around ((task task))
(l:info :displayer "Running ~a" task)
(setf (status task) :running)
(handler-bind ((error (lambda (e)
(l:info :displayer e)
(l:error :displayer "Task ~a failed: ~a" task e)
(setf (message task) (princ-to-string e))
(setf (status task) :failed))))
(prog1 (call-next-method)
(setf (status task) :finished))))
(defmethod descriptor ((task task)) "")
(defmethod clear ((task task))
(bt:with-lock-held (*task-lock*)
(remhash (id task) *tasks*)))
(defclass ensure-video (task)
((name :initarg :name :accessor name :reader descriptor)))
(defmethod execute ((task ensure-video))
(video-thumbnail (name task))
(video-length (name task)))
(defclass add-video (task)
((input :initarg :input :accessor input)
(name :initarg :name :accessor name :reader descriptor)))
(defmethod execute ((task add-video))
(copy-video (input task) (name task))
(ignore-errors (add-to-playlist (name task))))
(defclass delete-video (task)
((name :initarg :name :accessor name :reader descriptor)))
(defmethod execute ((task delete-video))
(ignore-errors (remove-from-playlist (name task)))
(delete-video (name task)))
(defclass restart-video (task)
())
(defmethod execute ((task restart-video))
(unless (video-running-p)
(start-vlc))
(restart-playlist))
(defclass play-video (task)
((name :initarg :name :accessor name :reader descriptor)))
(defmethod execute ((task play-video))
(play-video (name task)))
(defclass stop-task-runner (task)
())
(defmethod execute ((task stop-task-runner))
(invoke-restart 'stop-task-runner))