ssc.bot 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +25 -0
- data/LICENSE.txt +165 -0
- data/README.md +115 -0
- data/Rakefile +52 -0
- data/lib/ssc.bot.rb +44 -0
- data/lib/ssc.bot/chat_log.rb +283 -0
- data/lib/ssc.bot/chat_log/message.rb +86 -0
- data/lib/ssc.bot/chat_log/message_parsable.rb +62 -0
- data/lib/ssc.bot/chat_log/message_parser.rb +562 -0
- data/lib/ssc.bot/chat_log/messages.rb +193 -0
- data/lib/ssc.bot/chat_log_file.rb +52 -0
- data/lib/ssc.bot/error.rb +61 -0
- data/lib/ssc.bot/ssc_file.rb +132 -0
- data/lib/ssc.bot/user/jrobot_message_sender.rb +194 -0
- data/lib/ssc.bot/user/message_sender.rb +378 -0
- data/lib/ssc.bot/util.rb +90 -0
- data/lib/ssc.bot/version.rb +26 -0
- data/ssc.bot.gemspec +68 -0
- data/test/test_helper.rb +28 -0
- metadata +179 -0
@@ -0,0 +1,378 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
#--
|
6
|
+
# This file is part of SSC.Bot.
|
7
|
+
# Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
|
8
|
+
#
|
9
|
+
# SSC.Bot is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# SSC.Bot is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public License
|
20
|
+
# along with SSC.Bot. If not, see <https://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'attr_bool'
|
25
|
+
require 'time'
|
26
|
+
|
27
|
+
require 'ssc.bot/error'
|
28
|
+
require 'ssc.bot/util'
|
29
|
+
|
30
|
+
|
31
|
+
module SSCBot
|
32
|
+
module User
|
33
|
+
###
|
34
|
+
# @author Jonathan Bradley Whited (@esotericpig)
|
35
|
+
# @since 0.1.0
|
36
|
+
###
|
37
|
+
class MessageSender
|
38
|
+
DEFAULT_ESCAPE_STR = '.'
|
39
|
+
DEFAULT_FLOOD_COUNT = 8
|
40
|
+
DEFAULT_FLOOD_MIN_SLEEP = 0.001
|
41
|
+
DEFAULT_FLOOD_SECS = 6
|
42
|
+
|
43
|
+
# Message Macros
|
44
|
+
# - In order of F1 Help box.
|
45
|
+
MM_TICKNAME = '%tickname'
|
46
|
+
MM_SELFNAME = '%selfname'
|
47
|
+
MM_SQUAD = '%squad'
|
48
|
+
MM_FREQ = '%freq'
|
49
|
+
MM_BOUNTY = '%bounty'
|
50
|
+
MM_FLAGS = '%flags'
|
51
|
+
MM_ENERGY = '%energy'
|
52
|
+
MM_KILLER = '%killer'
|
53
|
+
MM_KILLED = '%killed'
|
54
|
+
MM_COORD = '%coord'
|
55
|
+
MM_AREA = '%area'
|
56
|
+
MM_RED = '%red'
|
57
|
+
MM_REDNAME = '%redname'
|
58
|
+
MM_REDBOUNTY = '%redbounty'
|
59
|
+
MM_REDFLAGS = '%redflags'
|
60
|
+
|
61
|
+
attr_accessor? :escape_percent
|
62
|
+
attr_accessor? :escape_space
|
63
|
+
attr_accessor :escape_str
|
64
|
+
attr_accessor :flood_count
|
65
|
+
attr_accessor :flood_min_sleep
|
66
|
+
attr_accessor :flood_secs
|
67
|
+
attr_reader :message_count
|
68
|
+
attr_reader :message_time
|
69
|
+
attr_accessor? :staff
|
70
|
+
|
71
|
+
def put(message)
|
72
|
+
raise AbstractMethodError
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_message()
|
76
|
+
raise AbstractMethodError
|
77
|
+
end
|
78
|
+
|
79
|
+
def type(message)
|
80
|
+
raise AbstractMethodError
|
81
|
+
end
|
82
|
+
|
83
|
+
def initialize(escape_percent: false,escape_space: true,escape_str: DEFAULT_ESCAPE_STR,flood_count: DEFAULT_FLOOD_COUNT,flood_min_sleep: DEFAULT_FLOOD_MIN_SLEEP,flood_secs: DEFAULT_FLOOD_SECS,staff: false)
|
84
|
+
super()
|
85
|
+
|
86
|
+
@escape_percent = escape_percent
|
87
|
+
@escape_space = escape_space
|
88
|
+
@escape_str = escape_str
|
89
|
+
@flood_count = flood_count
|
90
|
+
@flood_min_sleep = flood_min_sleep
|
91
|
+
@flood_secs = flood_secs
|
92
|
+
@message_count = 0
|
93
|
+
@message_time = Time.now()
|
94
|
+
@staff = staff
|
95
|
+
end
|
96
|
+
|
97
|
+
def escape_pub(message,escape_percent: @escape_percent,escape_space: @escape_space,escape_str: @escape_str,staff: @staff)
|
98
|
+
if escape_percent
|
99
|
+
message = message.gsub('%','%%')
|
100
|
+
end
|
101
|
+
|
102
|
+
escape = false
|
103
|
+
|
104
|
+
case message[0]
|
105
|
+
when '#'
|
106
|
+
escape = true
|
107
|
+
else
|
108
|
+
if escape_space && message[0] =~ /[[:space:]]/
|
109
|
+
escape = true
|
110
|
+
else
|
111
|
+
stripped_message = Util.u_lstrip(message)
|
112
|
+
|
113
|
+
case stripped_message[0]
|
114
|
+
when ':'
|
115
|
+
if stripped_message.index(':',1)
|
116
|
+
escape = true
|
117
|
+
end
|
118
|
+
when '/',%q{'},'"',';','='
|
119
|
+
escape = true
|
120
|
+
when '?'
|
121
|
+
if stripped_message[1] =~ /[[:alpha:]]/
|
122
|
+
escape = true
|
123
|
+
end
|
124
|
+
when '*','-'
|
125
|
+
escape = true if staff
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
if escape
|
131
|
+
message = "#{escape_str}#{message}"
|
132
|
+
end
|
133
|
+
|
134
|
+
return message
|
135
|
+
end
|
136
|
+
|
137
|
+
def prevent_flood()
|
138
|
+
@message_count += 1
|
139
|
+
|
140
|
+
if @message_count >= @flood_count
|
141
|
+
diff_time = Time.now() - @message_time
|
142
|
+
|
143
|
+
if diff_time <= @flood_secs
|
144
|
+
sleep_secs = (@flood_secs - diff_time).round(4) + 0.001
|
145
|
+
sleep_secs = @flood_min_sleep if sleep_secs < @flood_min_sleep
|
146
|
+
else
|
147
|
+
sleep_secs = @flood_min_sleep
|
148
|
+
end
|
149
|
+
|
150
|
+
sleep(sleep_secs)
|
151
|
+
|
152
|
+
@message_count = 0
|
153
|
+
end
|
154
|
+
|
155
|
+
@message_time = Time.now()
|
156
|
+
end
|
157
|
+
|
158
|
+
def put_or_type(message)
|
159
|
+
put(message)
|
160
|
+
end
|
161
|
+
|
162
|
+
def send(message)
|
163
|
+
put(message)
|
164
|
+
send_message()
|
165
|
+
end
|
166
|
+
|
167
|
+
def send_or_types(message)
|
168
|
+
send(message)
|
169
|
+
end
|
170
|
+
|
171
|
+
def send_or_types_safe(message)
|
172
|
+
send_or_types(message)
|
173
|
+
prevent_flood()
|
174
|
+
end
|
175
|
+
|
176
|
+
def send_safe(message)
|
177
|
+
send(message)
|
178
|
+
prevent_flood()
|
179
|
+
end
|
180
|
+
|
181
|
+
def types(message)
|
182
|
+
type(message)
|
183
|
+
send_message()
|
184
|
+
end
|
185
|
+
|
186
|
+
def types_safe(message)
|
187
|
+
types(message)
|
188
|
+
prevent_flood()
|
189
|
+
end
|
190
|
+
|
191
|
+
def send_chat(message)
|
192
|
+
send_safe(";#{message}")
|
193
|
+
end
|
194
|
+
|
195
|
+
def send_chat_to(channel,message)
|
196
|
+
send_safe(";#{channel};#{message}")
|
197
|
+
end
|
198
|
+
|
199
|
+
def send_freq(message)
|
200
|
+
send_safe(%Q{"#{message}})
|
201
|
+
end
|
202
|
+
|
203
|
+
def send_freq_eq(freq)
|
204
|
+
send_safe("=#{freq}")
|
205
|
+
end
|
206
|
+
|
207
|
+
def send_private(message)
|
208
|
+
send_safe("/#{message}")
|
209
|
+
end
|
210
|
+
|
211
|
+
def send_private_to(name,message)
|
212
|
+
send_safe(":#{name}:#{message}")
|
213
|
+
end
|
214
|
+
|
215
|
+
def send_private_to_last(message,last=1)
|
216
|
+
put_or_type('::')
|
217
|
+
|
218
|
+
while (last -= 1) > 0
|
219
|
+
put_or_type(':')
|
220
|
+
end
|
221
|
+
|
222
|
+
send_safe(message)
|
223
|
+
end
|
224
|
+
|
225
|
+
def send_pub(message,**kargs)
|
226
|
+
send_safe(escape_pub(message,**kargs))
|
227
|
+
end
|
228
|
+
|
229
|
+
def send_q_chat()
|
230
|
+
send_safe('?chat')
|
231
|
+
end
|
232
|
+
|
233
|
+
def send_q_chat_eq(*names)
|
234
|
+
send_safe("?chat=#{names.join(',')}")
|
235
|
+
end
|
236
|
+
|
237
|
+
def send_q_enter()
|
238
|
+
send_safe('?enter')
|
239
|
+
end
|
240
|
+
|
241
|
+
def send_q_find(player)
|
242
|
+
send_safe("?find #{player}")
|
243
|
+
end
|
244
|
+
|
245
|
+
def send_q_kill()
|
246
|
+
send_safe('?kill')
|
247
|
+
end
|
248
|
+
|
249
|
+
def send_q_leave()
|
250
|
+
send_safe('?leave')
|
251
|
+
end
|
252
|
+
|
253
|
+
def send_q_loadmacro(filename)
|
254
|
+
send_safe("?loadmacro #{filename}")
|
255
|
+
end
|
256
|
+
|
257
|
+
def send_q_log()
|
258
|
+
send_safe('?log')
|
259
|
+
end
|
260
|
+
|
261
|
+
def send_q_log_to(filename)
|
262
|
+
send_safe("?log #{filename}")
|
263
|
+
end
|
264
|
+
|
265
|
+
def send_q_logbuffer()
|
266
|
+
send_safe('?logbuffer')
|
267
|
+
end
|
268
|
+
|
269
|
+
def send_q_logbuffer_to(filename)
|
270
|
+
send_safe("?logbuffer #{filename}")
|
271
|
+
end
|
272
|
+
|
273
|
+
def send_q_namelen()
|
274
|
+
send_safe('?namelen')
|
275
|
+
end
|
276
|
+
|
277
|
+
def send_q_namelen_eq(namelen)
|
278
|
+
send_safe("?namelen=#{namelen}")
|
279
|
+
end
|
280
|
+
|
281
|
+
def send_q_lines()
|
282
|
+
send_safe('?lines')
|
283
|
+
end
|
284
|
+
|
285
|
+
def send_q_lines_eq(lines)
|
286
|
+
send_safe("?lines=#{lines}")
|
287
|
+
end
|
288
|
+
|
289
|
+
def send_q_savemacro(filename)
|
290
|
+
send_safe("?savemacro #{filename}")
|
291
|
+
end
|
292
|
+
|
293
|
+
def send_q_spec()
|
294
|
+
send_safe('?spec')
|
295
|
+
end
|
296
|
+
|
297
|
+
def send_q_team()
|
298
|
+
send_safe('?team')
|
299
|
+
end
|
300
|
+
|
301
|
+
def send_squad(message)
|
302
|
+
send_safe("##{message}")
|
303
|
+
end
|
304
|
+
|
305
|
+
def send_squad_to(squad,message)
|
306
|
+
send_safe(":##{squad}:#{message}")
|
307
|
+
end
|
308
|
+
|
309
|
+
def send_team(message)
|
310
|
+
send_safe("//#{message}")
|
311
|
+
end
|
312
|
+
|
313
|
+
def send_team2(message)
|
314
|
+
send_safe("'#{message}")
|
315
|
+
end
|
316
|
+
|
317
|
+
def mm_tickname()
|
318
|
+
return MM_TICKNAME
|
319
|
+
end
|
320
|
+
|
321
|
+
def mm_selfname()
|
322
|
+
return MM_SELFNAME
|
323
|
+
end
|
324
|
+
|
325
|
+
def mm_squad()
|
326
|
+
return MM_SQUAD
|
327
|
+
end
|
328
|
+
|
329
|
+
def mm_freq()
|
330
|
+
return MM_FREQ
|
331
|
+
end
|
332
|
+
|
333
|
+
def mm_bounty()
|
334
|
+
return MM_BOUNTY
|
335
|
+
end
|
336
|
+
|
337
|
+
def mm_flags()
|
338
|
+
return MM_FLAGS
|
339
|
+
end
|
340
|
+
|
341
|
+
def mm_energy()
|
342
|
+
return MM_ENERGY
|
343
|
+
end
|
344
|
+
|
345
|
+
def mm_killer()
|
346
|
+
return MM_KILLER
|
347
|
+
end
|
348
|
+
|
349
|
+
def mm_killed()
|
350
|
+
return MM_KILLED
|
351
|
+
end
|
352
|
+
|
353
|
+
def mm_coord()
|
354
|
+
return MM_COORD
|
355
|
+
end
|
356
|
+
|
357
|
+
def mm_area()
|
358
|
+
return MM_AREA
|
359
|
+
end
|
360
|
+
|
361
|
+
def mm_red()
|
362
|
+
return MM_RED
|
363
|
+
end
|
364
|
+
|
365
|
+
def mm_redname()
|
366
|
+
return MM_REDNAME
|
367
|
+
end
|
368
|
+
|
369
|
+
def mm_redbounty()
|
370
|
+
return MM_REDBOUNTY
|
371
|
+
end
|
372
|
+
|
373
|
+
def mm_redflags()
|
374
|
+
return MM_REDFLAGS
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
data/lib/ssc.bot/util.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
#--
|
6
|
+
# This file is part of SSC.Bot.
|
7
|
+
# Copyright (c) 2020 Jonathan Bradley Whited (@esotericpig)
|
8
|
+
#
|
9
|
+
# SSC.Bot is free software: you can redistribute it and/or modify
|
10
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# SSC.Bot is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public License
|
20
|
+
# along with SSC.Bot. If not, see <https://www.gnu.org/licenses/>.
|
21
|
+
#++
|
22
|
+
|
23
|
+
|
24
|
+
require 'rbconfig'
|
25
|
+
|
26
|
+
|
27
|
+
module SSCBot
|
28
|
+
###
|
29
|
+
# Your typical utility methods that
|
30
|
+
# should be moved into a separate Gem one day...
|
31
|
+
#
|
32
|
+
# @author Jonathan Bradley Whited (@esotericpig)
|
33
|
+
# @since 0.1.0
|
34
|
+
###
|
35
|
+
module Util
|
36
|
+
def self.os(host_os=RbConfig::CONFIG['host_os'])
|
37
|
+
os = :unknown
|
38
|
+
|
39
|
+
case host_os
|
40
|
+
when /darwin/i
|
41
|
+
os = :macos
|
42
|
+
# I think 'cygwin' here makes sense.
|
43
|
+
when /linux|arch|cygwin/i
|
44
|
+
os = :linux
|
45
|
+
else
|
46
|
+
# Here so that 'win' doesn't capture 'darwin'.
|
47
|
+
case host_os
|
48
|
+
# windows|mswin|bccwin|wince
|
49
|
+
when /win|mingw|emx/i
|
50
|
+
os = :windows
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return os
|
55
|
+
end
|
56
|
+
|
57
|
+
OS = os()
|
58
|
+
|
59
|
+
def self.quote_str_or_regex(value)
|
60
|
+
if value.respond_to?(:source)
|
61
|
+
return value.source.gsub(' ','\\ ') # For //x
|
62
|
+
else
|
63
|
+
return Regexp.quote(value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Universally, is +str+ empty after stripping or +nil+?
|
68
|
+
def self.u_blank?(str)
|
69
|
+
return str.nil?() || strip(str).empty?()
|
70
|
+
end
|
71
|
+
|
72
|
+
# Universally, left strip +str+'s leading (head) space.
|
73
|
+
def self.u_lstrip(str)
|
74
|
+
return nil if str.nil?()
|
75
|
+
return str.gsub(/\A[[:space:]]+/,'')
|
76
|
+
end
|
77
|
+
|
78
|
+
# Universally, right strip +str+'s trailing (tail) space.
|
79
|
+
def self.u_rstrip(str)
|
80
|
+
return nil if str.nil?()
|
81
|
+
return str.gsub(/[[:space:]]+\z/,'')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Universally, strip +str+'s space.
|
85
|
+
def self.u_strip(str)
|
86
|
+
return nil if str.nil?()
|
87
|
+
return str.gsub(/\A[[:space:]]+|[[:space:]]+\z/,'')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|