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.
@@ -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
@@ -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