Class: Tkellem::Backlog
Overview
This is implemented as a plugin – in theory, it could be switched out for a different backlog implementation. Right now, it’s always loaded though.
Defined Under Namespace
Classes: Device
Class Method Summary
collapse
Instance Method Summary
collapse
-
#all_existing_ctxs ⇒ Object
-
#client_connected(conn) ⇒ Object
-
#client_msg(msg) ⇒ Object
-
#get_device(conn) ⇒ Object
-
#get_stream(ctx, for_reading = false) ⇒ Object
-
#initialize(bouncer) ⇒ Backlog
constructor
A new instance of Backlog.
-
#log_name ⇒ Object
-
#now_timestamp ⇒ Object
-
#send_backlog(conn, ctx_name, stream, time_zone) ⇒ Object
-
#send_backlog_since(conn, start_time, contexts) ⇒ Object
-
#send_connect_backlogs(conn, device, contexts) ⇒ Object
-
#server_msg(msg) ⇒ Object
-
#stream_path(ctx) ⇒ Object
-
#stream_size(ctx) ⇒ Object
-
#update_pos(ctx_name, pos) ⇒ Object
-
#write_msg(ctx, processed_msg) ⇒ Object
Methods included from EasyLogger
#failsafe, logger, logger=, trace, #trace, trace=
Constructor Details
#initialize(bouncer) ⇒ Backlog
Returns a new instance of Backlog.
96
97
98
99
100
101
102
|
# File 'lib/tkellem/plugins/backlog.rb', line 96
def initialize(bouncer)
@bouncer = bouncer
@network_user = bouncer.network_user
@devices = {}
@dir = Pathname.new(File.expand_path("~/.tkellem/logs/#{bouncer.user.username}/#{bouncer.network.name}"))
@dir.mkpath()
end
|
Class Method Details
.client_msg(bouncer, client, msg) ⇒ Object
37
38
39
40
41
|
# File 'lib/tkellem/plugins/backlog.rb', line 37
def self.client_msg(bouncer, client, msg)
instance = get_instance(bouncer)
instance.client_msg(msg)
true
end
|
.geoip(conn) ⇒ Object
51
52
53
54
55
56
57
58
59
60
61
62
63
|
# File 'lib/tkellem/plugins/backlog.rb', line 51
def self.geoip(conn)
if !defined?(@geoip)
begin
@geoip = GeoIP.new('/usr/share/GeoIP/GeoIPCity.dat')
rescue Errno::ENOENT
@geoip = nil
end
end
geoip_info = @geoip && @geoip.country(Socket.unpack_sockaddr_in(conn.get_peername).last)
tz = geoip_info.respond_to?(:timezone) && geoip_info.timezone && ActiveSupport::TimeZone[geoip_info.timezone]
country = geoip_info.respond_to?(:country_code2) && geoip_info.country_code2
[tz, country]
end
|
.get_instance(bouncer) ⇒ Object
28
29
30
|
# File 'lib/tkellem/plugins/backlog.rb', line 28
def self.get_instance(bouncer)
bouncer.data(self)[:instance] ||= self.new(bouncer)
end
|
.new_client_connected(bouncer, client) ⇒ Object
32
33
34
35
|
# File 'lib/tkellem/plugins/backlog.rb', line 32
def self.new_client_connected(bouncer, client)
instance = get_instance(bouncer)
instance.client_connected(client)
end
|
.parse_line(line, ctx_name) ⇒ Object
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
# File 'lib/tkellem/plugins/backlog.rb', line 238
def self.parse_line(line, ctx_name)
timestamp = Time.parse(line[0, 20])
case line[20..-1]
when %r{^ ?> (\* )?(.+)$}
msg = IrcMessage.new(nil, 'PRIVMSG', [ctx_name, $2])
if $1 == '* '
msg.ctcp = 'ACTION'
end
return timestamp, msg
when %r{^ ?< (\* )?([^ ]+): (.+)$}
msg = IrcMessage.new($2, 'PRIVMSG', [ctx_name, $3])
if $1 == '* '
msg.ctcp = 'ACTION'
end
return timestamp, msg
else
nil
end
end
|
.server_msg(bouncer, msg) ⇒ Object
43
44
45
46
47
|
# File 'lib/tkellem/plugins/backlog.rb', line 43
def self.server_msg(bouncer, msg)
instance = get_instance(bouncer)
instance.server_msg(msg)
true
end
|
Instance Method Details
#all_existing_ctxs ⇒ Object
108
109
110
|
# File 'lib/tkellem/plugins/backlog.rb', line 108
def all_existing_ctxs
@dir.entries.select { |e| e.extname == ".log" }.map { |e| e.basename(".log").to_s }
end
|
#client_connected(conn) ⇒ Object
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
# File 'lib/tkellem/plugins/backlog.rb', line 133
def client_connected(conn)
device = get_device(conn)
tz, country = self.class.geoip(conn)
device.time_zone = tz || device.time_zone
device.country = country || device.country
behind = all_existing_ctxs.select do |ctx_name|
eof = stream_size(ctx_name)
device.pos(ctx_name, eof) < eof
end
if !behind.empty?
send_connect_backlogs(conn, device, behind)
end
end
|
#client_msg(msg) ⇒ Object
183
184
185
186
187
188
189
190
|
# File 'lib/tkellem/plugins/backlog.rb', line 183
def client_msg(msg)
case msg.command
when 'PRIVMSG'
return if msg.ctcp? && !msg.action?
ctx = msg.args.first
write_msg(ctx, "#{now_timestamp} > #{'* ' if msg.action?}#{msg.args.last}")
end
end
|
#get_device(conn) ⇒ Object
129
130
131
|
# File 'lib/tkellem/plugins/backlog.rb', line 129
def get_device(conn)
@devices[conn.device_name] ||= Device.new(@network_user, conn.device_name)
end
|
#get_stream(ctx, for_reading = false) ⇒ Object
112
113
114
115
116
117
118
119
120
121
122
123
|
# File 'lib/tkellem/plugins/backlog.rb', line 112
def get_stream(ctx, for_reading = false)
mode = for_reading ? 'rb:utf-8' : 'ab:utf-8'
ctx = ctx.gsub(%r{[\./\\]}, '')
path = stream_path(ctx)
return nil if !path.file? && for_reading
path.open(mode) do |stream|
if !for_reading
stream.seek(0, IO::SEEK_END)
end
yield stream
end
end
|
#log_name ⇒ Object
159
160
161
|
# File 'lib/tkellem/plugins/backlog.rb', line 159
def log_name
"backlog:#{@bouncer.log_name}"
end
|
#now_timestamp ⇒ Object
163
164
165
|
# File 'lib/tkellem/plugins/backlog.rb', line 163
def now_timestamp
Time.now.utc.iso8601
end
|
#send_backlog(conn, ctx_name, stream, time_zone) ⇒ Object
227
228
229
230
231
232
233
234
235
236
|
# File 'lib/tkellem/plugins/backlog.rb', line 227
def send_backlog(conn, ctx_name, stream, time_zone)
while line = stream.gets
timestamp, msg = self.class.parse_line(line, ctx_name)
timestamp = timestamp.in_time_zone(time_zone) if timestamp && time_zone
timestamp = timestamp.localtime if timestamp && !time_zone
next unless msg
msg.readdress_to(@bouncer.nick)
conn.send_msg(msg.with_timestamp(timestamp))
end
end
|
#send_backlog_since(conn, start_time, contexts) ⇒ Object
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
# File 'lib/tkellem/plugins/backlog.rb', line 210
def send_backlog_since(conn, start_time, contexts)
debug "scanning for backlog from #{start_time.iso8601}"
contexts.each do |ctx_name|
get_stream(ctx_name, true) do |stream|
last_line_len = 0
BackwardsFileReader.scan(stream) do |line|
last_line_len = line.length
timestamp = Time.parse(line[0,20]) rescue nil
!timestamp || timestamp >= start_time
end
stream.seek(last_line_len, IO::SEEK_CUR)
send_backlog(conn, ctx_name, stream, get_device(conn).time_zone)
end
end
end
|
#send_connect_backlogs(conn, device, contexts) ⇒ Object
199
200
201
202
203
204
205
206
207
208
|
# File 'lib/tkellem/plugins/backlog.rb', line 199
def send_connect_backlogs(conn, device, contexts)
contexts.each do |ctx_name|
start_pos = device.pos(ctx_name)
get_stream(ctx_name, true) do |stream|
stream.seek(start_pos)
send_backlog(conn, ctx_name, stream, device.time_zone)
device.update_pos(ctx_name, stream.pos)
end
end
end
|
#server_msg(msg) ⇒ Object
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
# File 'lib/tkellem/plugins/backlog.rb', line 167
def server_msg(msg)
case msg.command
when /3\d\d/, 'JOIN', 'PART'
return
when 'PRIVMSG'
return if msg.ctcp? && !msg.action?
ctx = msg.args.first
if ctx == @bouncer.nick
ctx = msg.prefix.split(/[!~@]/, 2).first
end
write_msg(ctx, "#{now_timestamp} < #{'* ' if msg.action?}#{msg.prefix}: #{msg.args.last}")
end
end
|
#stream_path(ctx) ⇒ Object
104
105
106
|
# File 'lib/tkellem/plugins/backlog.rb', line 104
def stream_path(ctx)
@dir + "#{ctx}.log"
end
|
#stream_size(ctx) ⇒ Object
125
126
127
|
# File 'lib/tkellem/plugins/backlog.rb', line 125
def stream_size(ctx)
stream_path(ctx).size
end
|
#update_pos(ctx_name, pos) ⇒ Object
150
151
152
153
154
155
156
157
|
# File 'lib/tkellem/plugins/backlog.rb', line 150
def update_pos(ctx_name, pos)
@bouncer.active_conns.each do |conn|
device = get_device(conn)
device.update_pos(ctx_name, pos)
end
end
|
#write_msg(ctx, processed_msg) ⇒ Object
192
193
194
195
196
197
|
# File 'lib/tkellem/plugins/backlog.rb', line 192
def write_msg(ctx, processed_msg)
get_stream(ctx) do |stream|
stream.puts(processed_msg)
update_pos(ctx, stream.pos)
end
end
|