blob: 28da2f3a34dad276f1d941b51249d4f45eb1ac83 (
plain)
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
|
(ns app.portmaster
(:import java.io.File
(java.util.concurrent Executors TimeUnit)
net.sf.expectit.ExpectBuilder
net.sf.expectit.matcher.Matchers))
(def prompt (Matchers/contains "pm>"))
(def the-unexpected (Matchers/anyString)) ; I couldn't help myself
(def pm (agent nil))
(defn parse-status
[s]
(map rest (re-seq #" ([0-9]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)" s)))
(defn parse-current
[s]
(map rest (re-seq #"#([0-9]+).* ([0-9.]+)A.* ([0-9.]+)A" s)))
(defn login-maybe
[expect username password]
; flush input
(try
(.. expect
(withTimeout 1 TimeUnit/MILLISECONDS)
(expect the-unexpected))
(catch Exception e))
(let [matchers (into-array [(Matchers/contains "Username:")
(Matchers/contains "Enter choice (1 or 2):")
prompt])
results (.getResults (.. expect
(withTimeout 100 TimeUnit/MILLISECONDS)
(sendLine)
(expect (Matchers/anyOf matchers))))]
(when (.isSuccessful (first results))
(.. expect
(sendLine username)
(expect (Matchers/contains "Password:")))
(.. expect
(sendLine password)
(expect prompt)))
(when (.isSuccessful (second results))
(.. expect
(withTimeout 5000 TimeUnit/MILLISECONDS)
(sendLine "2")
(expect (Matchers/contains "Username:")))
(login-maybe expect username password))))
(defn do-command
([expect command]
(.. expect (sendLine command) (expect prompt)))
([command]
(send pm (fn [{:keys [expect] :as state}]
(do-command expect command)
state))))
(defn poll
[{:keys [expect] :as state} username password]
(try
(login-maybe expect username password)
(let [result (do-command expect "status all")
status (parse-status (.getBefore result))
state (if (nil? status)
state
(assoc state :status status))
result (do-command expect "current")
current (parse-current (.getBefore result))
state (if (nil? current)
state
(assoc state :current current))]
state)
(catch Exception e
(println "poll failed")
(println (.getMessage e))
state)))
(defn turn-on
[port]
; TODO: update the status
(do-command (str "on " port)))
(defn turn-off
[port]
(do-command (str "off " port)))
(defn init
[port-name username password]
(let [socat (.. (ProcessBuilder.
(into-array ["socat"
"-v"
(str "OPEN:" port-name ",b9600,raw")
"-"]))
(redirectError (File. "/tmp/portmaster.log"))
(start))
expect (.. (new ExpectBuilder)
(withInputs (into-array [(.getInputStream socat)]))
(withOutput (.getOutputStream socat))
(withTimeout 1000 TimeUnit/MILLISECONDS)
(withExceptionOnFailure)
(build))
executor (Executors/newSingleThreadScheduledExecutor)]
(send pm assoc :socat socat :expect expect)
(.scheduleAtFixedRate executor
#(send pm poll username password)
2
10
TimeUnit/SECONDS)))
|