]> gitweb.factorcode.org Git - factor.git/blob - extra/irc/client/internals/internals.factor
2cf2975a93bffb72c5c410f7662eea479f1a0d1d
[factor.git] / extra / irc / client / internals / internals.factor
1 ! Copyright (C) 2009 Bruno Deferrari
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs arrays concurrency.mailboxes continuations destructors
4 hashtables io irc.client.base irc.client.chats irc.messages kernel namespaces
5 strings words.symbol irc.messages.base irc.client.participants fry threads
6 combinators irc.messages.parser math sequences ;
7 IN: irc.client.internals
8
9 : do-connect ( server port quot: ( host port -- stream ) attempts -- stream/f )
10     dup 0 > [
11         [ drop call( host port -- stream ) ]
12         [ drop 15 sleep 1 - do-connect ]
13         recover
14     ] [ 4drop f ] if ;
15
16 : /NICK ( nick -- ) "NICK " prepend irc-print ;
17 : /PONG ( text -- ) "PONG " prepend irc-print ;
18 : /PASS ( password -- ) "PASS " prepend irc-print ;
19
20 : /LOGIN ( nick -- )
21     dup /NICK
22     "USER " prepend " hostname servername :irc.factor" append irc-print ;
23
24 : /CONNECT ( server port -- stream )
25     irc> [ connect>> ] [ reconnect-attempts>> ] bi do-connect ;
26
27 : /JOIN ( channel password -- )
28     [ " :" glue ] when* "JOIN " prepend irc-print ;
29
30 : try-connect ( -- stream/f )
31     irc> profile>> [ server>> ] [ port>> ] bi /CONNECT ;
32
33 : (terminate-irc) ( -- )
34     irc> dup is-running>> [
35         f >>is-running
36         [ stream>> dispose ] keep
37         [ in-messages>> ] [ out-messages>> ] bi 2array
38         [ irc-end swap mailbox-put ] each
39     ] [ drop ] if ;
40
41 : (connect-irc) ( -- )
42     try-connect [
43         [ irc> ] dip >>stream t >>is-running
44         in-messages>> [ irc-connected ] dip mailbox-put
45     ] [ (terminate-irc) ] if* ;
46
47 : (do-login) ( -- )
48      irc>
49      [ profile>> password>> [ /PASS ] when* ]
50      [ nick>> /LOGIN ]
51      bi ;
52
53 GENERIC: initialize-chat ( chat -- )
54 M: irc-chat         initialize-chat drop ;
55 M: irc-channel-chat initialize-chat [ name>> ] [ password>> ] bi /JOIN ;
56
57 GENERIC: chat-put ( message obj -- )
58 M: irc-chat chat-put in-messages>> mailbox-put ;
59 M: symbol   chat-put chat> [ chat-put ] [ drop ] if* ;
60 M: string   chat-put chat> +server-chat+ or chat-put ;
61 M: sequence chat-put [ chat-put ] with each ;
62
63 : delete-chat ( name -- ) irc> chats>> delete-at ;
64 : unregister-chat ( name -- ) [ irc-chat-end chat-put ] [ delete-chat ] bi ;
65
66 ! Server message handling
67
68 GENERIC: message-forwards ( irc-message -- seq )
69 M: irc-message   message-forwards drop +server-chat+ ;
70 M: to-one-chat   message-forwards chat> ;
71 M: to-all-chats  message-forwards drop chats> ;
72 M: to-many-chats message-forwards sender>> participant-chats ;
73
74 GENERIC: process-message ( irc-message -- )
75 M: object process-message drop ;
76 M: ping   process-message trailing>> /PONG ;
77 ! FIXME: it shouldn't be checking for the presence of chat here...
78 M: irc.messages:join
79     process-message [ sender>> ] [ chat> ] bi
80     [ join-participant ] [ drop ] if* ;
81 M: part   process-message [ sender>> ] [ chat> ] bi [ part-participant ] [ drop ] if* ;
82 M: quit   process-message sender>> quit-participant ;
83 M: nick   process-message [ trailing>> ] [ sender>> ] bi rename-participant* ;
84 M: rpl-nickname-in-use process-message name>> "_" append /NICK ;
85
86 M: rpl-welcome process-message
87     irc>
88         swap nickname>> >>nick
89         t >>is-ready
90     chats>> values [ initialize-chat ] each ;
91
92 M: kick process-message
93     [ [ user>> ] [ chat> ] bi part-participant ]
94     [ dup user>> me? [ unregister-chat ] [ drop ] if ]
95     bi ;
96
97 M: participant-mode process-message ( participant-mode -- )
98     [ mode>> ] [ name>> ] [ parameter>> ] tri change-participant-mode ;
99
100 M: rpl-names process-message
101     [ nicks>> ] [ chat> ] bi dup ?clear-participants
102     '[ _ join-participant ] each ;
103
104 M: rpl-names-end process-message chat> t >>clear-participants drop ;
105
106 ! Client message handling
107
108 GENERIC: handle-outgoing-irc ( irc-message -- ? )
109 M: irc-end     handle-outgoing-irc drop f ;
110 M: irc-message handle-outgoing-irc irc-message>string irc-print t ;
111
112 ! Reader/Writer
113
114 : handle-reader-message ( irc-message -- ) irc> in-messages>> mailbox-put ;
115
116 : (handle-disconnect) ( -- )
117     irc-disconnected irc> in-messages>> mailbox-put
118     (connect-irc) (do-login) ;
119
120 : handle-disconnect ( error -- ? )
121     [ irc> exceptions>> push ] when*
122     irc> is-running>> [ (handle-disconnect) t ] [ f ] if ;
123
124 GENERIC: handle-input ( line/f -- ? )
125 M: string handle-input string>irc-message handle-reader-message t ;
126 M: f      handle-input handle-disconnect ;
127
128 : (reader-loop) ( -- ? )
129     stream> [ |dispose stream-readln handle-input ] with-destructors ;
130
131 : reader-loop ( -- ? ) [ (reader-loop) ] [ handle-disconnect ] recover ;
132 : writer-loop ( -- ? ) irc> out-messages>> mailbox-get handle-outgoing-irc ;
133
134 ! Processing loops
135
136 : in-multiplexer-loop ( -- ? )
137     irc> in-messages>> mailbox-get {
138         [ message-forwards ]
139         [ process-message ]
140         [ swap chat-put ]
141         [ irc-end? not ]
142     } cleave ;
143
144 : strings>privmsg ( name string -- privmsg )
145     " :" prepend append "PRIVMSG " prepend string>irc-message ;
146
147 GENERIC: annotate-message ( chat object -- object )
148 M: object     annotate-message nip ;
149 M: to-channel annotate-message swap name>> >>channel ;
150 M: to-target  annotate-message swap name>> >>target ;
151 M: mode       annotate-message swap name>> >>name ;
152 M: string     annotate-message [ name>> ] dip strings>privmsg ;
153
154 : spawn-irc ( -- )
155     [ reader-loop ] "irc-reader-loop" spawn-server
156     [ writer-loop ] "irc-writer-loop" spawn-server
157     [ in-multiplexer-loop ] "in-multiplexer-loop" spawn-server
158     3drop ;
159
160 GENERIC: (attach-chat) ( irc-chat -- )
161
162 M: irc-chat (attach-chat)
163     irc>
164     [ [ chats>> ] [ >>client name>> swap ] 2bi set-at ]
165     [ is-ready>> [ initialize-chat ] [ drop ] if ]
166     2bi ;
167
168 M: irc-server-chat (attach-chat)
169     irc> [ client<< ] [ chats>> +server-chat+ set-at ] 2bi ;
170
171 GENERIC: remove-chat ( irc-chat -- )
172 M: irc-nick-chat remove-chat name>> unregister-chat ;
173 M: irc-server-chat remove-chat drop +server-chat+ unregister-chat ;
174
175 M: irc-channel-chat remove-chat
176     [ name>> "PART " prepend string>irc-message irc-send ]
177     [ name>> unregister-chat ] bi ;
178
179 : (speak) ( message irc-chat -- ) swap annotate-message irc-send ;