artaius 0.2.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.
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/LICENSE +19 -0
- data/README.md +19 -0
- data/Rakefile +3 -0
- data/artaius.gemspec +36 -0
- data/bin/artaius +5 -0
- data/config/locales/en.yml +40 -0
- data/config/locales/ru.yml +47 -0
- data/config/plugins/.gitignore +1 -0
- data/db/.gitignore +1 -0
- data/db/migrations/001_create_players.rb +35 -0
- data/lib/artaius.rb +16 -0
- data/lib/artaius/bot.rb +50 -0
- data/lib/artaius/database.rb +36 -0
- data/lib/artaius/models/player.rb +16 -0
- data/lib/artaius/plugins/archivarius.rb +62 -0
- data/lib/artaius/plugins/identify.rb +56 -0
- data/lib/artaius/plugins/mixer.rb +335 -0
- data/lib/artaius/version.rb +3 -0
- data/spec/lib/artaius/bot_spec.rb +54 -0
- data/spec/lib/artaius/plugins/archivarius_spec.rb +59 -0
- data/spec/lib/artaius/plugins/identify_spec.rb +94 -0
- data/spec/lib/artaius/plugins/mixer_spec.rb +199 -0
- data/spec/lib/artaius/version_spec.rb +0 -0
- data/spec/spec_helper.rb +7 -0
- data/tasks/db.rake +15 -0
- data/tasks/environment.rake +3 -0
- data/tasks/test.rake +6 -0
- metadata +213 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2012 Kyrylo Silin
|
2
|
+
|
3
|
+
This software is provided 'as-is', without any express or implied
|
4
|
+
warranty. In no event will the authors be held liable for any damages
|
5
|
+
arising from the use of this software.
|
6
|
+
|
7
|
+
Permission is granted to anyone to use this software for any purpose,
|
8
|
+
including commercial applications, and to alter it and redistribute it
|
9
|
+
freely, subject to the following restrictions:
|
10
|
+
|
11
|
+
1. The origin of this software must not be misrepresented; you must not
|
12
|
+
claim that you wrote the original software. If you use this software
|
13
|
+
in a product, an acknowledgment in the product documentation would be
|
14
|
+
appreciated but is not required.
|
15
|
+
|
16
|
+
2. Altered source versions must be plainly marked as such, and must not be
|
17
|
+
misrepresented as being the original software.
|
18
|
+
|
19
|
+
3. This notice may not be removed or altered from any source distribution.
|
data/README.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
![Artaius][logo]
|
2
|
+
================
|
3
|
+
|
4
|
+
* [https://github.com/kyrylo/artaius/][rkag]
|
5
|
+
|
6
|
+
Description
|
7
|
+
-----------
|
8
|
+
|
9
|
+
Artaius is a [King Arthur's Gold][kag] (KAG) IRC bot. Currently it's not
|
10
|
+
suitable for a public use. Artaius dwells at #kag2d.ru@irc.quakenet.org.
|
11
|
+
|
12
|
+
License
|
13
|
+
-------
|
14
|
+
|
15
|
+
The project uses Zlib License. See LICENSE file for more information.
|
16
|
+
|
17
|
+
[logo]: http://img-fotki.yandex.ru/get/6210/98991937.9/0_7735e_6d44a25d_orig "Artaius logo"
|
18
|
+
[rkag]: https://github.com/kyrylo/artaius/ "Home page"
|
19
|
+
[kag]: http://kag2d.com/
|
data/Rakefile
ADDED
data/artaius.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require './lib/artaius/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'artaius'
|
5
|
+
s.version = Artaius::VERSION
|
6
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
7
|
+
s.summary = "IRC bot serving King Arthur's Gold players."
|
8
|
+
s.author = 'Kyrylo Silin'
|
9
|
+
s.email = 'kyrylosilin@gmail.com'
|
10
|
+
s.homepage = 'https://github.com/kyrylo/artaius'
|
11
|
+
s.license = 'zlib'
|
12
|
+
|
13
|
+
s.require_path = 'lib'
|
14
|
+
s.files = `git ls-files`.split "\n"
|
15
|
+
s.test_files = `git ls-files -- spec`.split "\n"
|
16
|
+
|
17
|
+
s.extra_rdoc_files = %W{README.md LICENSE}
|
18
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'cinch', '~>2.0'
|
21
|
+
s.add_runtime_dependency 'kag', '0.0.1'
|
22
|
+
s.add_runtime_dependency 'r18n-desktop', '>=0.4.14'
|
23
|
+
s.add_runtime_dependency 'sequel', '>=3.34.1'
|
24
|
+
s.add_runtime_dependency 'sqlite3', '>=1.3.6'
|
25
|
+
|
26
|
+
s.add_development_dependency 'rake'
|
27
|
+
s.add_development_dependency 'minitest', '>=2.12.1'
|
28
|
+
s.add_development_dependency 'fivemat', '>=1.0.0'
|
29
|
+
|
30
|
+
s.required_ruby_version = '~>1.9'
|
31
|
+
|
32
|
+
s.description = <<description
|
33
|
+
Artaius is an IRC (Internet Relay Chat) bot for KAG (King Arthur's Gold)
|
34
|
+
game. It cannot everything for the time being.
|
35
|
+
description
|
36
|
+
end
|
data/bin/artaius
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
identify:
|
3
|
+
send_challenge: "Identifying with Q, using CHALLENGEAUTH"
|
4
|
+
challenge: "[CHALLENGE received] Challenge: %1"
|
5
|
+
|
6
|
+
mixer:
|
7
|
+
players: "Players: %1."
|
8
|
+
need_players: !!pl
|
9
|
+
1: "Need 1 more player to start the game."
|
10
|
+
n: "Need %1 more players to start the game"
|
11
|
+
cancel: "%1, you are not in the game anymore."
|
12
|
+
last_left: "The last player has left the game. The game is cancelled."
|
13
|
+
new_initiator: "New game inititator is %1."
|
14
|
+
roster: "Roster: %1."
|
15
|
+
n_slots_added: "%1 slots have been added. %2"
|
16
|
+
slot_added: "Slot added. %1"
|
17
|
+
n_slots_removed: "%1 slots have been removed. %2"
|
18
|
+
slot_removed: "Slot removed. %1"
|
19
|
+
slot_stats: "Slots: %1/%2."
|
20
|
+
blue_team: "Blue team: %1."
|
21
|
+
red_team: "Red team: %1."
|
22
|
+
glhf: "Good luck & have a good fun!"
|
23
|
+
slots_overall: "Total number of slots are %1."
|
24
|
+
game_cancelled: "The game has been cancelled due to shortage of players."
|
25
|
+
m:
|
26
|
+
game: "game"
|
27
|
+
play: "play"
|
28
|
+
cancel: "cancel"
|
29
|
+
roster: "roster"
|
30
|
+
start: "start"
|
31
|
+
slot: "slot"
|
32
|
+
slots: "slots"
|
33
|
+
|
34
|
+
archivarius:
|
35
|
+
exists: "%1, you are already registered and bonded your KAG account and IRC authname (%2)."
|
36
|
+
not_found: "Player %1 does not exist. Did you make a typing error?"
|
37
|
+
authname_required: "In order to bond your KAG account and IRC authname, you need to authorize on this server or register your nickname"
|
38
|
+
success: "Yay, registration complete! Enjoy KAG ;-)"
|
39
|
+
m:
|
40
|
+
reg: "reg"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
---
|
2
|
+
identify:
|
3
|
+
send_challenge: "Идентифицируюсь с помощью Q, используя CHALLENGEAUTH"
|
4
|
+
challenge: "[CHALLENGE получен] Challenge: %1"
|
5
|
+
|
6
|
+
mixer:
|
7
|
+
players: "Игроки: %1."
|
8
|
+
need_players: !!pl
|
9
|
+
1: "Для начала игры нужен еще 1 игрок."
|
10
|
+
2: "Для начала игры нужно еще %1 игрока."
|
11
|
+
n: "Для начала игры нужно еще %1 игроков."
|
12
|
+
cancel: "%1, вы вышли из игры."
|
13
|
+
last_left: "Последний игрок покинул игру. Игра отменена."
|
14
|
+
new_initiator: "%1 - новый инициатор игры."
|
15
|
+
roster: "Состав: %1."
|
16
|
+
n_slots_added: !!pl
|
17
|
+
1: "Добавлен 1 слот. %2"
|
18
|
+
2: "Добавлено %1 слота. %2"
|
19
|
+
n: "Добавлено %1 слотов. %2"
|
20
|
+
slot_added: "Слот добавлен. %1"
|
21
|
+
n_slots_removed: !!pl
|
22
|
+
1: "Убран 1 слот. %2"
|
23
|
+
2: "Убрано %1 слота. %2"
|
24
|
+
n: "Убрано %1 слотов. %2"
|
25
|
+
slot_removed: "Слот убран. %1"
|
26
|
+
slot_stats: "Слоты: %1/%2."
|
27
|
+
blue_team: "Команда синих: %1."
|
28
|
+
red_team: "Команда красных: %1."
|
29
|
+
glhf: "Удачи. Победит сильнейший!"
|
30
|
+
slots_overall: "Общее количество слотов: %1."
|
31
|
+
game_cancelled: "Игра была отменена из-за нехватки игроков."
|
32
|
+
m:
|
33
|
+
game: "игра"
|
34
|
+
play: "играть"
|
35
|
+
cancel: "отмена"
|
36
|
+
roster: "состав"
|
37
|
+
start: "старт"
|
38
|
+
slot: "слот"
|
39
|
+
slots: "слоты"
|
40
|
+
|
41
|
+
archivarius:
|
42
|
+
exists: "%1, вы уже привязали свой аккаунт в КАГ-е к вашему логину в ИРЦ (%2)."
|
43
|
+
not_found: "Игрок %1 не существует. Опечатались?"
|
44
|
+
authname_required: "Чтобы связать ваш аккаунт в КАГ-е и ИРЦ логин, вы должны авторизироваться на этом сервере или зарегистрировать свой ник."
|
45
|
+
success: "Ура, регистрация завершена! Наслаждайтеь КАГ-ом ;-)"
|
46
|
+
m:
|
47
|
+
reg: "регь"
|
@@ -0,0 +1 @@
|
|
1
|
+
identify.yml
|
data/db/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.db
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Create initial schema for the table of registered players.
|
2
|
+
#
|
3
|
+
# Note, that while KAG's maximum length of nicknames is equal to 20,
|
4
|
+
# QuakeNet allows only 15 letters (NICKLEN field in the ISUPPORT message).
|
5
|
+
#
|
6
|
+
# +--------------+--------------------------------------+
|
7
|
+
# | Field | Description |
|
8
|
+
# +--------------+--------------------------------------+
|
9
|
+
# | id | Player id number. |
|
10
|
+
# | irc_authname | IRC authname of player. |
|
11
|
+
# | kag_nick | King Arthur's Gold in-game nickname. |
|
12
|
+
# | role | Role of the player [1] |
|
13
|
+
# | premium | Account type (true if premium). |
|
14
|
+
# +--------------+--------------------------------------+
|
15
|
+
#
|
16
|
+
# [1] Roles:
|
17
|
+
# 0: Normal player account
|
18
|
+
# 1: KAG dev/team member
|
19
|
+
# 2: KAG Guard.
|
20
|
+
# 4: KAG team member ("admin" level, more or less the same as type 1)
|
21
|
+
# 5: Possibly a tester, but most testers are not currently flagged
|
22
|
+
#
|
23
|
+
Sequel.migration do
|
24
|
+
change do
|
25
|
+
create_table :players do
|
26
|
+
primary_key :id
|
27
|
+
String :irc_authname, :unique => true, :size => 15, :null => false
|
28
|
+
String :kag_nick, :unique => true, :size => 20, :null => false
|
29
|
+
Fixnum :role, :null => false
|
30
|
+
FalseClass :premium, :null => false
|
31
|
+
DateTime :created_at
|
32
|
+
DateTime :updated_at
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/artaius.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'cinch'
|
2
|
+
require 'kag'
|
3
|
+
require 'yaml'
|
4
|
+
require 'r18n-desktop'
|
5
|
+
require 'sequel'
|
6
|
+
require 'sequel/extensions/migration'
|
7
|
+
|
8
|
+
require_relative 'artaius/bot'
|
9
|
+
require_relative 'artaius/version'
|
10
|
+
|
11
|
+
require_relative 'artaius/database'
|
12
|
+
require_relative 'artaius/models/player'
|
13
|
+
|
14
|
+
require_relative 'artaius/plugins/identify'
|
15
|
+
require_relative 'artaius/plugins/mixer'
|
16
|
+
require_relative 'artaius/plugins/archivarius'
|
data/lib/artaius/bot.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Artaius
|
2
|
+
|
3
|
+
# Internal: Turn the bot into a polyglot.
|
4
|
+
I18n = R18n.from_env('config/locales/', :ru)
|
5
|
+
|
6
|
+
class Bot < Cinch::Bot
|
7
|
+
|
8
|
+
# Internal: Name.
|
9
|
+
FIRST_NAME = 'Artaius'
|
10
|
+
|
11
|
+
# Internal: Surname.
|
12
|
+
SECOND_NAME = 'Lucius'
|
13
|
+
|
14
|
+
# Internal: IRC server to join.
|
15
|
+
SERVER = 'irc.quakenet.org'
|
16
|
+
|
17
|
+
# Internal: Port of IRC server.
|
18
|
+
PORT = 6667
|
19
|
+
|
20
|
+
# Internal: Channels, that bot should be present on..
|
21
|
+
CHANNELS = ['#kag2d.ru']
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
super
|
25
|
+
|
26
|
+
# Bot configuration.
|
27
|
+
configure do |c|
|
28
|
+
c.nick = FIRST_NAME
|
29
|
+
c.realname = "#{FIRST_NAME} #{SECOND_NAME}"
|
30
|
+
c.user = "#{FIRST_NAME} #{SECOND_NAME}"
|
31
|
+
c.server = SERVER
|
32
|
+
c.port = PORT
|
33
|
+
c.channels = CHANNELS
|
34
|
+
c.plugins.plugins = [
|
35
|
+
Artaius::Plugins::Identify,
|
36
|
+
Artaius::Plugins::Mixer,
|
37
|
+
Artaius::Plugins::Archivarius
|
38
|
+
]
|
39
|
+
|
40
|
+
# Set up plugins to be used.
|
41
|
+
c.plugins.options[Artaius::Plugins::Identify] = {
|
42
|
+
:username => FIRST_NAME,
|
43
|
+
:password => Psych.load_file('config/plugins/identify.yml')[:password]
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Artaius
|
2
|
+
# Internal: Connect Artaius to the database via Sequel interface.
|
3
|
+
Database = Sequel.sqlite(File.join(File.expand_path('db'), 'artaius.db'))
|
4
|
+
|
5
|
+
class << Database
|
6
|
+
|
7
|
+
# Internal: Migrate database from older version to the new one or vice
|
8
|
+
# versa. Without given arguments, migrate database to the latest version
|
9
|
+
# available.
|
10
|
+
#
|
11
|
+
# to - The Integer, describes version, to version till which migrations
|
12
|
+
# should be applied (default: nil).
|
13
|
+
# from - The Integer, describes version, from which migration should start
|
14
|
+
# its work (default: nil).
|
15
|
+
#
|
16
|
+
# Returns nothing.
|
17
|
+
def migrate(to = nil, from = nil)
|
18
|
+
migrations = File.join(File.expand_path('db'), 'migrations')
|
19
|
+
if to == 0 && from == 0
|
20
|
+
Sequel::Migrator.apply(self, migrations)
|
21
|
+
else
|
22
|
+
Sequel::Migrator.apply(self, migrations, to, from)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Internal: Rollback current version of database to the previous one. This
|
27
|
+
# method returns database exactly one step back.
|
28
|
+
#
|
29
|
+
# Returns nothing
|
30
|
+
def rollback
|
31
|
+
current_version = self[:schema_info].first[:version]
|
32
|
+
migrate(current_version.pred)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Artaius
|
2
|
+
# Internal: Represents KAG player.
|
3
|
+
class Player < Sequel::Model(:players)
|
4
|
+
plugin :timestamps, :update_on_create => true
|
5
|
+
|
6
|
+
# Internal: Check database for given authname.
|
7
|
+
#
|
8
|
+
# irc_authname - The String, represents IRC authname of the player.
|
9
|
+
#
|
10
|
+
# Returns true if the given authname is in database or false otherwise.
|
11
|
+
def self.exists?(irc_authname)
|
12
|
+
filter(:irc_authname => irc_authname).select(:irc_authname).any?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Artaius
|
2
|
+
module Plugins
|
3
|
+
# The plugin handles registration of users. The aim of the plugin is to
|
4
|
+
# associate KAG account and IRC authname together.
|
5
|
+
class Archivarius
|
6
|
+
include Cinch::Plugin
|
7
|
+
|
8
|
+
set react_on: :private
|
9
|
+
|
10
|
+
match /#{I18n.archivarius.m.reg} (\w{3,20})$/,
|
11
|
+
method: :sign_up,
|
12
|
+
use_suffix: false
|
13
|
+
|
14
|
+
# Internal: Sign up a new player with some restrictions: it won't sign up
|
15
|
+
# neither already registered players, nor players, that doesn't have IRC
|
16
|
+
# autname, nor nonexistent KAG players.
|
17
|
+
#
|
18
|
+
# m - The recieved message.
|
19
|
+
# kag_nick - The String, represents KAG nickname to be associated with
|
20
|
+
# caller's IRC authanme.
|
21
|
+
#
|
22
|
+
# Returns nothing.
|
23
|
+
def sign_up(m, kag_nick)
|
24
|
+
authname = m.user.authname
|
25
|
+
nick = m.user.nick
|
26
|
+
|
27
|
+
if authname.nil?
|
28
|
+
m.reply I18n.archivarius.authname_required and return
|
29
|
+
end
|
30
|
+
|
31
|
+
if already_exists?(authname)
|
32
|
+
m.reply I18n.archivarius.exists(nick, authname) and return
|
33
|
+
end
|
34
|
+
|
35
|
+
player = KAG::Player.new(kag_nick)
|
36
|
+
|
37
|
+
if player.info['statusMessage'] == 'Player not found'
|
38
|
+
m.reply I18n.archivarius.not_found(kag_nick) and return
|
39
|
+
end
|
40
|
+
|
41
|
+
Player.create(
|
42
|
+
:irc_authname => authname,
|
43
|
+
:kag_nick => player.username,
|
44
|
+
:role => player.role,
|
45
|
+
:premium => player.gold?
|
46
|
+
)
|
47
|
+
|
48
|
+
m.reply I18n.archivarius.success
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# Internal: Ask database for whether the IRC authname is in it or not.
|
54
|
+
#
|
55
|
+
# Returns true, if the IRC authname is there of false otherwise.
|
56
|
+
def already_exists?(irc_authname)
|
57
|
+
Player.exists?(irc_authname)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
3
|
+
module Artaius
|
4
|
+
module Plugins
|
5
|
+
# The plugin handles authentication via CHALLENGEAUTH. It requires two
|
6
|
+
# parameters: username and password of the bot. For details go here:
|
7
|
+
# http://www.quakenet.org/development/challengeauth/
|
8
|
+
class Identify
|
9
|
+
include Cinch::Plugin
|
10
|
+
|
11
|
+
set :required_options, [:username, :password]
|
12
|
+
|
13
|
+
# Internal: Q bot of QuakeNet. Nine times out of ten you write him a PM.
|
14
|
+
Q = 'Q@CServe.quakenet.org'
|
15
|
+
|
16
|
+
|
17
|
+
listen_to :connect,
|
18
|
+
method: :send_challenge
|
19
|
+
|
20
|
+
# Internal: Identify a bot with Q.
|
21
|
+
#
|
22
|
+
# Returns nothing.
|
23
|
+
def send_challenge(m)
|
24
|
+
debug I18n.identify.send_challenge
|
25
|
+
User(Q).privmsg('CHALLENGE')
|
26
|
+
end
|
27
|
+
|
28
|
+
match /^CHALLENGE (.+?) (.+)$/,
|
29
|
+
method: :challengeauth,
|
30
|
+
use_prefix: false,
|
31
|
+
use_suffix: false,
|
32
|
+
react_on: :notice
|
33
|
+
|
34
|
+
# Internal: Authenticate bot with safe CHALLENGEAUTH method.
|
35
|
+
#
|
36
|
+
# m - The recieved message.
|
37
|
+
# challenge - The CHALLENGE parameter, given by Q bot.
|
38
|
+
#
|
39
|
+
# Returns nothing.
|
40
|
+
def challengeauth(m, challenge)
|
41
|
+
# Q is the only trusted user.
|
42
|
+
return unless m.user && m.user.nick == 'Q'
|
43
|
+
|
44
|
+
debug I18n.identify.challenge(challenge)
|
45
|
+
|
46
|
+
username = config[:username].irc_downcase(:rfc1459)
|
47
|
+
password = config[:password][0, 10]
|
48
|
+
|
49
|
+
sha256 = OpenSSL::Digest::SHA256.new
|
50
|
+
key = sha256.hexdigest("#{ username }:#{ sha256.hexdigest(password) }")
|
51
|
+
response = OpenSSL::HMAC.hexdigest('SHA256', key, challenge)
|
52
|
+
User(Q).privmsg("CHALLENGEAUTH #{ username } #{ response } HMAC-SHA-256")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|