qwtf_discord_bot 4.2.6 → 5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 724d0971cb9732c8095fa84f03c9be9ab7e215515ee9f65dcbe117fa8dc409c5
4
- data.tar.gz: 2c81f16c2ed703ec9d3671eb0f0731ffaa34f7590bf1a3241e729aa7bd13bcb5
3
+ metadata.gz: acbc8b37f3b73372cb4417b810a76a960ee5fd640330587ef97e0b889338be04
4
+ data.tar.gz: 47cc64ca3ca8cdf90e63a2197ac0b93e703427a26a0e5cf00ee6716938f73d9f
5
5
  SHA512:
6
- metadata.gz: d314677b730b1fdce5866120c97eb7448bcbab24ea46d2263f5dee35f8dacaec1ec433b4a5303942d80f2429a626673a7d1306956740f1579b3767993fb2181f
7
- data.tar.gz: 9499263c0c76de7590a2aacb0956fb7083d04ce378a17497b259b90ef3adbe6eb2c505a1e7077568c48391547e09e493d10c514d14c3d1b8e888619b1d629f0a
6
+ metadata.gz: 99276bcc5e6a1e53364176301f09da6089f72bdd266cfbb0e1e72e551e2421bd11116504c907db6649b14f3ba8b6bdcc4534b550ee749761e2d1b99df596dbb7
7
+ data.tar.gz: b1970a9a1465c72d1cdd3ab68f38d967eb8f9ea1d7072ef7da9c660d4b3ee15d5b3943498958e9f564d61e3a59d82455af1a6cd0e713d4a3240eb51b79b6e504
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- qwtf_discord_bot (4.2.4)
4
+ qwtf_discord_bot (5.0.4)
5
5
  discordrb (~> 3.3)
6
6
  redis (~> 4.1)
7
7
  thor (~> 0.20)
@@ -9,14 +9,15 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activesupport (5.2.3)
12
+ activesupport (6.0.3.2)
13
13
  concurrent-ruby (~> 1.0, >= 1.0.2)
14
14
  i18n (>= 0.7, < 2)
15
15
  minitest (~> 5.1)
16
16
  tzinfo (~> 1.1)
17
- coderay (1.1.2)
18
- concurrent-ruby (1.1.5)
19
- diff-lcs (1.3)
17
+ zeitwerk (~> 2.2, >= 2.2.2)
18
+ coderay (1.1.3)
19
+ concurrent-ruby (1.1.7)
20
+ diff-lcs (1.4.4)
20
21
  discordrb (3.3.0)
21
22
  discordrb-webhooks (~> 3.3.0)
22
23
  ffi (>= 1.9.24)
@@ -26,60 +27,61 @@ GEM
26
27
  websocket-client-simple (>= 0.3.0)
27
28
  discordrb-webhooks (3.3.0)
28
29
  rest-client (>= 2.1.0.rc1)
29
- domain_name (0.5.20180417)
30
+ domain_name (0.5.20190701)
30
31
  unf (>= 0.0.5, < 1.0.0)
31
32
  event_emitter (0.2.6)
32
- factory_bot (5.0.2)
33
- activesupport (>= 4.2.0)
34
- ffi (1.11.1)
33
+ factory_bot (6.1.0)
34
+ activesupport (>= 5.0.0)
35
+ ffi (1.13.1)
35
36
  http-accept (1.7.0)
36
37
  http-cookie (1.0.3)
37
38
  domain_name (~> 0.5)
38
- i18n (1.6.0)
39
+ i18n (1.8.5)
39
40
  concurrent-ruby (~> 1.0)
40
- method_source (0.9.2)
41
- mime-types (3.2.2)
41
+ method_source (1.0.0)
42
+ mime-types (3.3.1)
42
43
  mime-types-data (~> 3.2015)
43
- mime-types-data (3.2019.0331)
44
- minitest (5.11.3)
44
+ mime-types-data (3.2020.0512)
45
+ minitest (5.14.1)
45
46
  netrc (0.11.0)
46
47
  opus-ruby (1.0.1)
47
48
  ffi
48
- pry (0.12.2)
49
- coderay (~> 1.1.0)
50
- method_source (~> 0.9.0)
49
+ pry (0.13.1)
50
+ coderay (~> 1.1)
51
+ method_source (~> 1.0)
51
52
  rbnacl (3.4.0)
52
53
  ffi
53
- redis (4.1.3)
54
- rest-client (2.1.0.rc1)
54
+ redis (4.2.1)
55
+ rest-client (2.1.0)
55
56
  http-accept (>= 1.7.0, < 2.0)
56
57
  http-cookie (>= 1.0.2, < 2.0)
57
58
  mime-types (>= 1.16, < 4.0)
58
59
  netrc (~> 0.8)
59
- rspec (3.8.0)
60
- rspec-core (~> 3.8.0)
61
- rspec-expectations (~> 3.8.0)
62
- rspec-mocks (~> 3.8.0)
63
- rspec-core (3.8.1)
64
- rspec-support (~> 3.8.0)
65
- rspec-expectations (3.8.4)
60
+ rspec (3.9.0)
61
+ rspec-core (~> 3.9.0)
62
+ rspec-expectations (~> 3.9.0)
63
+ rspec-mocks (~> 3.9.0)
64
+ rspec-core (3.9.2)
65
+ rspec-support (~> 3.9.3)
66
+ rspec-expectations (3.9.2)
66
67
  diff-lcs (>= 1.2.0, < 2.0)
67
- rspec-support (~> 3.8.0)
68
- rspec-mocks (3.8.1)
68
+ rspec-support (~> 3.9.0)
69
+ rspec-mocks (3.9.1)
69
70
  diff-lcs (>= 1.2.0, < 2.0)
70
- rspec-support (~> 3.8.0)
71
- rspec-support (3.8.2)
71
+ rspec-support (~> 3.9.0)
72
+ rspec-support (3.9.3)
72
73
  thor (0.20.3)
73
74
  thread_safe (0.3.6)
74
- tzinfo (1.2.5)
75
+ tzinfo (1.2.7)
75
76
  thread_safe (~> 0.1)
76
77
  unf (0.1.4)
77
78
  unf_ext
78
- unf_ext (0.0.7.6)
79
+ unf_ext (0.0.7.7)
79
80
  websocket (1.2.8)
80
81
  websocket-client-simple (0.3.0)
81
82
  event_emitter
82
83
  websocket
84
+ zeitwerk (2.4.0)
83
85
 
84
86
  PLATFORMS
85
87
  ruby
@@ -95,4 +97,4 @@ DEPENDENCIES
95
97
  thor
96
98
 
97
99
  BUNDLED WITH
98
- 1.17.1
100
+ 1.17.2
data/README.md CHANGED
@@ -66,7 +66,7 @@ A Discord bot for checking the status of QuakeWorld Team Fortress servers
66
66
 
67
67
  ### Commands
68
68
 
69
- There are two modules:
69
+ There are three modules:
70
70
 
71
71
 
72
72
  #### Server
@@ -81,6 +81,19 @@ This responds to discord messages:
81
81
  ![screenshot of bot responding to !server command](server_screenshot.png)
82
82
 
83
83
 
84
+ #### Pug
85
+
86
+ qwtf-discord-bot pug
87
+
88
+ This responds to discord messages:
89
+ - `!join`
90
+ - `!leave`
91
+ - `!status`
92
+ - `!maxplayers <no_of_players>`
93
+ - `!notify <roles>`
94
+ - `!end`
95
+
96
+
84
97
  #### Watcher
85
98
 
86
99
  qwtf-discord-bot watcher
@@ -99,6 +112,12 @@ Build:
99
112
  gem build qwtf_discrd_bot.gemspec
100
113
 
101
114
 
115
+ Install:
116
+
117
+
118
+ gem install --local qwtf_discord_bot-$(cat VERSION).gem
119
+
120
+
102
121
  Push:
103
122
 
104
123
  gem push qwtf_discord_bot-$(cat VERSION).gem
@@ -129,6 +148,14 @@ Only discord-bot watcher:
129
148
  discord-bot watcher
130
149
 
131
150
 
151
+ Only discord-bot pug:
152
+
153
+ docker run -it \
154
+ --env QWTF_DISCORD_BOT_CONFIG_FILE=config.yaml \
155
+ --mount type=bind,source="$(pwd)"/config.yaml,target=/discord-bot/config.yaml \
156
+ discord-bot pug
157
+
158
+
132
159
  Build:
133
160
 
134
161
  docker build --tag=discord-bot .
@@ -140,6 +167,19 @@ Push:
140
167
  docker push fortressone/discord-bot:latest
141
168
 
142
169
 
170
+ Create AWS instance:
171
+
172
+ ```
173
+ docker-machine create \
174
+ --driver amazonec2 \
175
+ --amazonec2-access-key <AWS_ACCESS_KEY> \
176
+ --amazonec2-secret-key <AWS_SECRET_KEY> \
177
+ --amazonec2-root-size 30 \
178
+ --amazonec2-region ap-southeast-2 \
179
+ discord-bot
180
+ ```
181
+
182
+
143
183
  ## License
144
184
 
145
185
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.2.6
1
+ 5.1.0
@@ -26,3 +26,15 @@ services:
26
26
  - type: bind
27
27
  source: "/home/ubuntu/.config/qwtf_discord_bot/config.yaml"
28
28
  target: /discord-bot/config.yaml
29
+ discord-pug-bot:
30
+ image: fortressone/discord-bot:latest
31
+ command: pug
32
+ restart: always
33
+ depends_on:
34
+ - redis
35
+ environment:
36
+ - REDIS_URL=redis://redis
37
+ volumes:
38
+ - type: bind
39
+ source: "/home/ubuntu/.config/qwtf_discord_bot/config.yaml"
40
+ target: /discord-bot/config.yaml
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'qwtf_discord_bot'
4
4
  require 'thor'
5
+ require 'pry'
5
6
 
6
7
  class QwtfDiscordBotExe < Thor
7
8
  def self.exit_on_failure?
@@ -14,6 +15,12 @@ class QwtfDiscordBotExe < Thor
14
15
  server_bot.run
15
16
  end
16
17
 
18
+ desc 'pug', 'Start, join, leave, record pick-up games.'
19
+ def pug
20
+ pug_bot = QwtfDiscordBotPug.new
21
+ pug_bot.run
22
+ end
23
+
17
24
  desc 'watcher', 'Watches servers and accounces when a player joins'
18
25
  def watcher
19
26
  watcher_bot = QwtfDiscordBotWatcher.new
@@ -0,0 +1,54 @@
1
+ class EventDecorator
2
+ def initialize(event)
3
+ @event = event
4
+ end
5
+
6
+ def channel
7
+ @event.channel
8
+ end
9
+
10
+ def channel_id
11
+ @event.channel.id
12
+ end
13
+
14
+ def username
15
+ user.username
16
+ end
17
+
18
+ def user_id
19
+ user.id
20
+ end
21
+
22
+ def users
23
+ server.users
24
+ end
25
+
26
+ def mentions_for(user_ids)
27
+ find_users(user_ids).map(&:mention)
28
+ end
29
+
30
+ def usernames_for(user_ids)
31
+ find_users(user_ids).map(&:username)
32
+ end
33
+
34
+ private
35
+
36
+ def find_users(user_ids)
37
+ user_ids.map do |user_id|
38
+ find_user(user_id)
39
+ end
40
+ end
41
+
42
+ def find_user(user_id)
43
+ users.find { |user| user.id == user_id }
44
+ end
45
+
46
+ def server
47
+ @event.server
48
+ end
49
+
50
+ def user
51
+ @event.user
52
+ end
53
+ end
54
+
@@ -0,0 +1,91 @@
1
+ class Pug
2
+ DEFAULT_MAXPLAYERS = 8
3
+
4
+ def self.for(channel_id)
5
+ new(channel_id)
6
+ end
7
+
8
+ def initialize(channel_id)
9
+ @channel_id = channel_id
10
+ end
11
+
12
+ def join(user_id)
13
+ redis.setnx(pug_key, Time.now)
14
+ redis.sadd(players_key, user_id)
15
+ end
16
+
17
+ def joined_players
18
+ redis.smembers(players_key).map(&:to_i)
19
+ end
20
+
21
+ def full?
22
+ joined_player_count >= maxplayers
23
+ end
24
+
25
+ def joined_player_count
26
+ redis.scard(players_key).to_i
27
+ end
28
+
29
+ def player_slots
30
+ "#{joined_player_count}/#{maxplayers}"
31
+ end
32
+
33
+ def slots_left
34
+ maxplayers - joined_player_count
35
+ end
36
+
37
+ def notify_roles=(roles)
38
+ redis.set(notify_roles_key, roles)
39
+ end
40
+
41
+ def notify_roles
42
+ redis.get(notify_roles_key) || "@here"
43
+ end
44
+
45
+ def maxplayers=(maxplayers)
46
+ redis.set(maxplayers_key, maxplayers)
47
+ end
48
+
49
+ def maxplayers
50
+ (redis.get(maxplayers_key) || DEFAULT_MAXPLAYERS).to_i
51
+ end
52
+
53
+ def active?
54
+ redis.get(pug_key)
55
+ end
56
+
57
+ def leave(player_id)
58
+ redis.srem(players_key, player_id)
59
+ end
60
+
61
+ def empty?
62
+ joined_player_count == 0
63
+ end
64
+
65
+ def end_pug
66
+ redis.del(pug_key)
67
+ redis.del(players_key)
68
+ end
69
+
70
+ private
71
+
72
+ def maxplayers_key
73
+ [pug_key, "maxplayers"].join(":")
74
+ end
75
+
76
+ def players_key
77
+ [pug_key, "players"].join(":")
78
+ end
79
+
80
+ def pug_key
81
+ ["pug", "channel", @channel_id].join(":")
82
+ end
83
+
84
+ def notify_roles_key
85
+ [pug_key, "role"].join(":")
86
+ end
87
+
88
+ def redis
89
+ Redis.current
90
+ end
91
+ end
@@ -1,9 +1,11 @@
1
1
  require 'qwtf_discord_bot/version'
2
2
  require 'qwtf_discord_bot/qwtf_discord_bot_server'
3
+ require 'qwtf_discord_bot/qwtf_discord_bot_pug'
3
4
  require 'qwtf_discord_bot/qwtf_discord_bot_watcher'
4
5
  require 'qwtf_discord_bot/config'
5
6
  require 'discordrb'
6
7
  require 'yaml'
8
+ require 'redis'
7
9
 
8
10
  require 'qstat_request'
9
11
  require 'player'
@@ -12,9 +14,17 @@ require 'emoji'
12
14
  require 'roster'
13
15
 
14
16
  module QwtfDiscordBot # :nodoc:
15
- CONFIG_FILE = ENV['QWTF_DISCORD_BOT_CONFIG_FILE'] || "#{Dir.pwd}/config.yaml"
16
-
17
17
  def self.config
18
- @config ||= Config.new(CONFIG_FILE)
18
+ @config ||= Config.new(config_file)
19
+ end
20
+
21
+ def self.config_file
22
+ return ENV['QWTF_DISCORD_BOT_CONFIG_FILE'] if ENV['QWTF_DISCORD_BOT_CONFIG_FILE']
23
+ return "#{Dir.pwd}/config.yaml" if FileTest.exist?("#{Dir.pwd}/config.yaml")
24
+ "#{Dir.home}/.config/qwtf_discord_bot/config.yaml"
25
+ end
26
+
27
+ def redis
28
+ Redis.current
19
29
  end
20
30
  end
@@ -0,0 +1,147 @@
1
+ require 'pug'
2
+ require 'event_decorator'
3
+
4
+ class QwtfDiscordBotPug
5
+ include QwtfDiscordBot
6
+
7
+ FOUR_HOURS = 4 * 60 * 60
8
+
9
+ def run
10
+ bot = Discordrb::Commands::CommandBot.new(
11
+ token: QwtfDiscordBot.config.token,
12
+ client_id: QwtfDiscordBot.config.client_id,
13
+ help_command: false,
14
+ prefix: '!'
15
+ )
16
+
17
+ bot.command :join do |event, *_args|
18
+ e = EventDecorator.new(event)
19
+ pug = Pug.for(e.channel_id)
20
+
21
+ pug.join(e.user_id)
22
+
23
+ message = if pug.full?
24
+ time_to_play_message(
25
+ pug.player_slots,
26
+ e.mentions_for(pug.joined_players)
27
+ )
28
+ elsif pug.joined_player_count == 1
29
+ [
30
+ "#{e.username} creates a PUG",
31
+ pug.player_slots,
32
+ pug.notify_roles
33
+ ].join(' | ')
34
+ elsif pug.slots_left <= 3
35
+ [
36
+ "#{e.username} joins the PUG",
37
+ pug.player_slots,
38
+ "#{pug.slots_left} more",
39
+ pug.notify_roles
40
+ ].join(' | ')
41
+ else
42
+ [
43
+ "#{e.username} joins the PUG",
44
+ pug.player_slots
45
+ ].join(' | ')
46
+ end
47
+
48
+ send_and_log_message(message, e.channel)
49
+ end
50
+
51
+ bot.command :status do |event, *_args|
52
+ e = EventDecorator.new(event)
53
+ pug = Pug.for(e.channel_id)
54
+
55
+ message = if pug.active?
56
+ [
57
+ "#{e.usernames_for(pug.joined_players).join(' ')} joined",
58
+ pug.player_slots
59
+ ].join(' | ')
60
+ else
61
+ 'No PUG has been started. `!join` to create'
62
+ end
63
+
64
+ send_and_log_message(message, e.channel)
65
+ end
66
+
67
+ bot.command :maxplayers do |event, *args|
68
+ e = EventDecorator.new(event)
69
+ pug = Pug.for(e.channel_id)
70
+ new_maxplayers = args[0]
71
+
72
+ message = if new_maxplayers
73
+ pug.maxplayers = new_maxplayers
74
+ "Max number of players set to #{pug.maxplayers} | #{pug.player_slots} joined"
75
+ else
76
+ "Current max number of players is #{pug.maxplayers} | #{pug.player_slots} joined"
77
+ end
78
+
79
+ send_and_log_message(message, e.channel)
80
+
81
+ if pug.full?
82
+ message = time_to_play_message(
83
+ pug.player_slots,
84
+ e.mentions_for(pug.joined_players)
85
+ )
86
+
87
+ send_and_log_message(message, e.channel)
88
+ end
89
+ end
90
+
91
+ bot.command :leave do |event, *_args|
92
+ e = EventDecorator.new(event)
93
+ pug = Pug.for(e.channel_id)
94
+
95
+ pug.leave(e.user_id)
96
+
97
+ message = "#{e.username} leaves the PUG | #{pug.player_slots} remain"
98
+
99
+ send_and_log_message(message, e.channel)
100
+
101
+ if pug.empty?
102
+ pug.end_pug
103
+
104
+ message = 'PUG ended'
105
+ send_and_log_message(message, e.channel)
106
+ end
107
+ end
108
+
109
+ bot.command :end do |event, *_args|
110
+ e = EventDecorator.new(event)
111
+ pug = Pug.for(e.channel_id)
112
+
113
+ pug.end_pug
114
+
115
+ message = 'PUG ended'
116
+ send_and_log_message(message, e.channel)
117
+ end
118
+
119
+ bot.command :notify do |event, *args|
120
+ e = EventDecorator.new(event)
121
+ pug = Pug.for(e.channel_id)
122
+ roles = args.join(' ')
123
+ pug.notify_roles = roles
124
+
125
+ message = if roles.empty?
126
+ 'Notification removed'
127
+ else
128
+ "Notification role set to #{roles}"
129
+ end
130
+
131
+ send_and_log_message(message, e.channel)
132
+ end
133
+
134
+ bot.run
135
+ end
136
+
137
+ private
138
+
139
+ def time_to_play_message(player_slots, mentions)
140
+ ['Time to play!', player_slots, mentions.join(' ')].join(' | ')
141
+ end
142
+
143
+ def send_and_log_message(message, channel)
144
+ channel.send_message(message)
145
+ puts message
146
+ end
147
+ end
@@ -3,6 +3,7 @@ class QwtfDiscordBotServer
3
3
  bot = Discordrb::Commands::CommandBot.new(
4
4
  token: QwtfDiscordBot.config.token,
5
5
  client_id: QwtfDiscordBot.config.client_id,
6
+ help_command: false,
6
7
  prefix: '!'
7
8
  )
8
9
 
@@ -1,5 +1,3 @@
1
- require "redis"
2
-
3
1
  class QwtfDiscordBotWatcher
4
2
  include QwtfDiscordBot
5
3
 
@@ -14,7 +12,7 @@ class QwtfDiscordBotWatcher
14
12
  next if request.is_empty?
15
13
 
16
14
  request.player_names.each do |name|
17
- redis_key = "#{address}:#{name}"
15
+ redis_key = ["watcher", address, name].join(":")
18
16
 
19
17
  unless seen_recently?(redis_key)
20
18
  endpoint.channel_ids.each do |channel_id|
@@ -51,7 +49,7 @@ class QwtfDiscordBotWatcher
51
49
  end
52
50
 
53
51
  def report_joined(name:, channel_id:, server_summary:)
54
- message = "#{name} has joined #{server_summary}"
52
+ message = "#{name} joins #{server_summary}"
55
53
 
56
54
  Discordrb::API::Channel.create_message(
57
55
  "Bot #{QwtfDiscordBot.config.token}",
@@ -61,10 +59,4 @@ class QwtfDiscordBotWatcher
61
59
 
62
60
  puts message
63
61
  end
64
-
65
- private
66
-
67
- def redis
68
- @redis ||= Redis.new
69
- end
70
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qwtf_discord_bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.6
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sheldon Johnson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-19 00:00:00.000000000 Z
11
+ date: 2020-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: discordrb
@@ -104,10 +104,13 @@ files:
104
104
  - exe/qwtf_discord_bot
105
105
  - lib/emoji.rb
106
106
  - lib/endpoint.rb
107
+ - lib/event_decorator.rb
107
108
  - lib/player.rb
109
+ - lib/pug.rb
108
110
  - lib/qstat_request.rb
109
111
  - lib/qwtf_discord_bot.rb
110
112
  - lib/qwtf_discord_bot/config.rb
113
+ - lib/qwtf_discord_bot/qwtf_discord_bot_pug.rb
111
114
  - lib/qwtf_discord_bot/qwtf_discord_bot_server.rb
112
115
  - lib/qwtf_discord_bot/qwtf_discord_bot_watcher.rb
113
116
  - lib/qwtf_discord_bot/version.rb
@@ -135,8 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
138
  - !ruby/object:Gem::Version
136
139
  version: '0'
137
140
  requirements: []
138
- rubyforge_project:
139
- rubygems_version: 2.7.6.2
141
+ rubygems_version: 3.1.2
140
142
  signing_key:
141
143
  specification_version: 4
142
144
  summary: Works by wrapping the excellent CLI server query tool qstat. Accepts !server,