alexyoung (owner)

Forks

Revisions

gist: 131415 Download_button fork
public
Public Clone URL: git://gist.github.com/131415.git
jschat-bot.clj
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
;; I'm not saying this is good Clojure, but it was off the top of my head
;; It's a title bot for jschat.org
 
(import '(java.io BufferedReader InputStreamReader PrintWriter))
(import '(java.net Socket))
(import '(java.net HttpURLConnection URL))
(use '[clojure.contrib.json.read :only (read-json)])
(use '[clojure.contrib.json.write :only (json-str)])
 
;; Data structures
(defstruct jschat-server :address :port)
(defstruct message :message :channel)
 
;; Settings
(def server (struct jschat-server "127.0.0.1" 6789))
(def username "titlebot")
(def channel "#jschat")
 
(def socket (new Socket (server :address) (server :port)))
(def reader (new BufferedReader (new InputStreamReader (. socket (getInputStream)))))
(def writer (new PrintWriter (. socket getOutputStream) true))
 
;; HTTP requests with length
(defn fetch-url
  "Fetches 1000 lines of text from a URL."
  [url]
  (let [connection (. (new URL url) openConnection)]
    (let [stream (new BufferedReader (new InputStreamReader (. connection getInputStream)))]
      (if (re-find #"html" (. connection getContentType))
        (apply str (take 1000 (line-seq stream)))))))
 
(defn title-url
  "Return the title of a web page"
  [url]
  (try
    (let [src (fetch-url url)
          title (second (re-find #"(?i)\s?<title>(.*)</title>" src))]
          (str "Title: " (.trim title)))
    (catch java.io.FileNotFoundException _ "Error: Page not found")
    (catch Exception _ false)))
 
;; Connection
(defn write-jschat [data]
  (. writer println (json-str data)))
 
(defn read-jschat []
  (read-json (. reader readLine)))
 
;; JsChat commands
(defn identify [name]
  (write-jschat { "identify" name }))
 
(defn join [channel]
  (write-jschat { "join" channel }))
 
(defn send-message [message channel]
  (write-jschat { "send" message "to" channel }))
 
;; Return the significant part of a response
(defmulti jschat-response (fn [response] (response "display")))
(defmethod jschat-response "message" [message] ((message "message") "message"))
(defmethod jschat-response "join" [message] (println "Joining room: " ((message "join") "room")))
 
(defn extract-url [text]
  (str "http://" (second (re-find #"http://([^\s]*)" text))))
 
(defn extract-url-from-response [response]
  (extract-url (jschat-response response)))
 
(defn get-title [response]
  (try
    (title-url (extract-url-from-response response))
  (catch Exception _ false)))
 
(.start (Thread. (fn []
  (while true
    (let [title (get-title (read-jschat))]
      (if title
        (send-message title channel)))))))
 
;; Identify and join a channel
(identify username)
(join channel)