-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathchaton-watcher
executable file
·91 lines (81 loc) · 2.97 KB
/
chaton-watcher
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
#!/usr/bin/env gosh
;;;
;;; A simple command-line tool that observes one or more chaton rooms
;;; and prints out the posts.
;;;
(use chaton.client)
(use gauche.threads)
(use gauche.parseopt)
(use gauche.logger)
(use util.match)
(use util.queue)
(define *connections* '())
(define *mutex* (make-mutex))
(define *cv* (make-condition-variable))
(define *msgq* (make-queue))
(define (main args)
(let-args (cdr args) ([silent "s|silent"]
[else _ (usage)]
. args)
(when (null? args) (usage))
(set-signal-handler! (sys-sigset SIGINT SIGHUP SIGTERM)
(lambda (_) (cleanup 0)))
(chaton-log-open #t)
(log-open #t)
(guard (e [(<chaton-error> e) (print (~ e'message)) (cleanup 1)])
(dolist [room-url args]
(push! *connections* (chaton-connect room-url "chaton-watcher"
observe 3))))
;; We run a separate thread to print out the messages and let
;; the primordial thread to sleep. It is to allow the primordial
;; thread to catch the signal. If we make the primordial thread to
;; loop, it may fail to catch the signal since pthread_cont_wait is
;; not guaranteed to return when signal is received.
(thread-start! (make-thread
(lambda () (while #t
(for-each print (msg-dequeue!))
(unless silent (write-char #\x07) (flush))))))
(while #t (sys-pause))))
(define (usage)
(print "Usage: chaton-watcher [-s][-l logfile] <room-url> ...")
(print "Options:")
(print " -s, --silent Do not ring bell on new posts.")
(exit 0))
(define (cleanup code)
(dolist [conn *connections*]
(guard (e [else #f]) (chaton-bye conn)))
(exit code))
(define (observe client message)
(log-format "observer[~a]: ~s" (chaton-room-name client) message)
(guard (e [else (print e) #f])
(cond
[(<chaton-error> message)
(msg-enqueue! (format "[~a] CHATON-ERROR: ~a"
(chaton-room-name client) (~ message'message)))]
[(and-let* ([pos (assq-ref message 'pos)])
(< pos (chaton-pos client)))
#f]
[(assq-ref message 'content)
=> (lambda (msgs)
(dolist [m msgs]
(match m
[(nick (secs _) text . _)
(msg-enqueue! (format "~a [~a] ~a: ~a" (fmt-time secs)
(chaton-room-name client) nick text))]
[_ #f])))])
#f))
(define (msg-enqueue! message)
(with-locking-mutex *mutex*
(lambda ()
(enqueue! *msgq* message)
(condition-variable-broadcast! *cv*))))
(define (msg-dequeue!)
(let loop ()
(mutex-lock! *mutex*)
(cond [(queue-empty? *msgq*) (mutex-unlock! *mutex* *cv*) (loop)]
[else (rlet1 msgs (dequeue-all! *msgq*)
(mutex-unlock! *mutex*))])))
(define (fmt-time secs) (sys-strftime "%H:%M" (sys-localtime secs)))
;; Local variables:
;; mode: scheme
;; end: