nakiircbot 0.0.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/LICENSE +21 -0
- data/lib/nakiircbot.rb +135 -0
- data/nakiircbot.gemspec +14 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3fd605975fa07fb8ad61f317912b32c6d9525a46
|
4
|
+
data.tar.gz: a6a9a41301909099d2e71d57101232b22c1bbbf1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 46f06a8b677e230df7543238d94cf9321bae53e7dcf9144e74bea95aa030e947e90cc6361672fa7bab9672118f7643b1488c923b39a3ff0425b640ace7e81b06
|
7
|
+
data.tar.gz: 0fdd39f22e6bb874c380a368638a463a0a013019888883b65e5d059829234653e49c15e2481c24036a3344563c72e01012f9825cc23d08ff52b220bd5099e0eb
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Victor Maslov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/lib/nakiircbot.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
module NakiIRCBot
|
2
|
+
# @@channels = []
|
3
|
+
# class << self
|
4
|
+
# attr_accessor :channels
|
5
|
+
# end
|
6
|
+
def self.start server, port, bot_name, master_name, welcome001, *channels, password: nil, masterword: nil, processors: [], twitch: false
|
7
|
+
# @@channels.replace channels.dup
|
8
|
+
|
9
|
+
abort "matching bot_name and master_name may cause infinite recursion" if bot_name == master_name
|
10
|
+
require "base64"
|
11
|
+
require "fileutils"
|
12
|
+
FileUtils.mkdir_p "logs"
|
13
|
+
require "logger"
|
14
|
+
original_formatter = Logger::Formatter.new
|
15
|
+
logger = Logger.new "logs/txt", "daily",
|
16
|
+
progname: bot_name, datetime_format: "%y%m%d %H%M%S",
|
17
|
+
formatter: lambda{ |severity, datetime, progname, msg|
|
18
|
+
puts "#{datetime.strftime "%H%M%S"} #{severity.to_s[0]} #{progname} #{msg.scrub.inspect[1..-2]}"
|
19
|
+
original_formatter.call severity, datetime, progname, Base64.strict_encode64(msg)
|
20
|
+
# TODO: maybe encode the whole string for a case of invalid progname?
|
21
|
+
}
|
22
|
+
logger.level = ENV["LOGLEVEL_#{name}"].to_sym if ENV.include? "LOGLEVEL_#{name}"
|
23
|
+
puts "#{name} logger.level = #{logger.level}"
|
24
|
+
|
25
|
+
# https://en.wikipedia.org/wiki/List_of_Internet_Relay_Chat_commands
|
26
|
+
loop do
|
27
|
+
logger.info "reconnect"
|
28
|
+
require "socket"
|
29
|
+
socket = TCPSocket.new server, port
|
30
|
+
|
31
|
+
# https://stackoverflow.com/a/49476047/322020
|
32
|
+
socket_send = lambda do |str|
|
33
|
+
logger.info "> #{str}"
|
34
|
+
socket.send str + "\n", 0
|
35
|
+
end
|
36
|
+
socket_send.call "PASS #{password.strip}" if twitch
|
37
|
+
socket_send.call "NICK #{bot_name}"
|
38
|
+
socket_send.call "USER #{bot_name} #{bot_name} #{bot_name} #{bot_name}" unless twitch
|
39
|
+
|
40
|
+
queue = []
|
41
|
+
prev_socket_time = prev_privmsg_time = Time.now
|
42
|
+
loop do
|
43
|
+
begin
|
44
|
+
addr, msg = queue.shift
|
45
|
+
next unless addr && msg
|
46
|
+
fail "I should not PRIVMSG myself" if addr == bot_name
|
47
|
+
msg.scrub!
|
48
|
+
msg.gsub! "\n", " "
|
49
|
+
msg.gsub! "\r", " "
|
50
|
+
privmsg = "PRIVMSG #{addr} :#{msg}"
|
51
|
+
privmsg = "PRIVMSG #{addr} :*flood*" if privmsg.bytes.size > 500 && addr.start_with?("#")
|
52
|
+
prev_socket_time = prev_privmsg_time = Time.now
|
53
|
+
socket_send.call privmsg
|
54
|
+
break
|
55
|
+
end until queue.empty? if prev_privmsg_time + 5 < Time.now
|
56
|
+
|
57
|
+
unless _ = Kernel::select([socket], nil, nil, 1)
|
58
|
+
break if Time.now - prev_socket_time > 300
|
59
|
+
next
|
60
|
+
end
|
61
|
+
prev_socket_time = Time.now
|
62
|
+
socket_str = _[0][0].gets(chomp: true)
|
63
|
+
break unless socket_str
|
64
|
+
str = socket_str.force_encoding("utf-8").scrub
|
65
|
+
if /\A:\S+ 372 /.match? str # MOTD
|
66
|
+
logger.debug "< #{str}"
|
67
|
+
elsif /\APING :/.match? str
|
68
|
+
logger.debug "< #{str}"
|
69
|
+
else
|
70
|
+
logger.info "< #{str}"
|
71
|
+
end
|
72
|
+
break if /\AERROR :Closing Link: /.match? str
|
73
|
+
|
74
|
+
# if str[/^:\S+ 433 * #{Regexp.escape bot_name} :Nickname is already in use\.$/]
|
75
|
+
# socket_send.call "NICK #{bot_name + "_"}"
|
76
|
+
# next
|
77
|
+
# end
|
78
|
+
|
79
|
+
# next socket.send("JOIN #{$2}"+"\n"),0 if str[/^:(.+?)!\S+ KICK (\S+) #{Regexp.escape bot_name} /i]
|
80
|
+
case str
|
81
|
+
when /\A:[a-z.]+ 001 #{Regexp.escape bot_name} :Welcome to the #{Regexp.escape welcome001} #{Regexp.escape bot_name}\z/
|
82
|
+
# we join only when we are sure we are on the correct server
|
83
|
+
# TODO: maybe abort if the server is wrong?
|
84
|
+
next socket_send.call "JOIN #{channels.join ","}"
|
85
|
+
when /\A:tmi.twitch.tv 001 #{Regexp.escape bot_name} :Welcome, GLHF!\z/
|
86
|
+
socket_send.call "JOIN #{channels.join ","}"
|
87
|
+
socket_send.call "CAP REQ :twitch.tv/membership twitch.tv/tags twitch.tv/commands"
|
88
|
+
next
|
89
|
+
when /\A:NickServ!NickServ@services\. NOTICE #{Regexp.escape bot_name} :This nickname is registered. Please choose a different nickname, or identify via \x02\/msg NickServ identify <password>\x02\.\z/
|
90
|
+
abort "no password" unless password
|
91
|
+
logger.info "password"
|
92
|
+
# next socket.send "PASS #{password.strip}\n", 0
|
93
|
+
next socket.send "PRIVMSG NickServ :identify #{bot_name} #{password.strip}\n", 0
|
94
|
+
when /\APING :/
|
95
|
+
next socket.send "PONG :#{$'}\n", 0 # Quakenet uses timestamp, Freenode and Twitch use server name
|
96
|
+
when /\A:([^!]+)!\S+ PRIVMSG #{Regexp.escape bot_name} :\x01VERSION\x01\z/
|
97
|
+
next socket_send.call "NOTICE #{$1} :\x01VERSION name 0.0.0\x01"
|
98
|
+
# when /^:([^!]+)!\S+ PRIVMSG #{Regexp.escape bot_name} :\001PING (\d+)\001$/
|
99
|
+
# socket_send.call "NOTICE",$1,"\001PING #{rand 10000000000}\001"
|
100
|
+
# when /^:([^!]+)!\S+ PRIVMSG #{Regexp.escape bot_name} :\001TIME\001$/
|
101
|
+
# socket_send.call "NOTICE",$1,"\001TIME 6:06:06, 6 Jun 06\001"
|
102
|
+
when /\A#{'\S+ ' if twitch}:(?<who>[^!]+)!\S+ PRIVMSG (?<where>\S+) :(?<what>.+)/
|
103
|
+
next( if processors.empty?
|
104
|
+
queue.push [master_name, "nothing to reload"]
|
105
|
+
else
|
106
|
+
processors.each do |processor|
|
107
|
+
queue.push [master_name, "reloading #{processor}"]
|
108
|
+
load File.absolute_path processor
|
109
|
+
end
|
110
|
+
end ) if $~.named_captures == {"who"=>master_name, "where"=>bot_name, "what"=>"#{twitch ? "@#{bot_name} " : "#{masterword.strip} "}reload"}
|
111
|
+
end
|
112
|
+
|
113
|
+
begin
|
114
|
+
yield str, ->(where, what){ queue.push [where, what] }
|
115
|
+
rescue => e
|
116
|
+
puts e.full_message
|
117
|
+
queue.push [master_name, "yield error: #{e}"]
|
118
|
+
end
|
119
|
+
|
120
|
+
rescue => e
|
121
|
+
puts e.full_message
|
122
|
+
case e
|
123
|
+
when Errno::ECONNRESET, Errno::ECONNABORTED, Errno::ETIMEDOUT, Errno::EPIPE
|
124
|
+
sleep 5
|
125
|
+
break
|
126
|
+
else
|
127
|
+
queue.push [master_name, "unhandled error: #{e}"]
|
128
|
+
sleep 5
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
data/nakiircbot.gemspec
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "nakiircbot"
|
3
|
+
spec.version = "0.0.0"
|
4
|
+
spec.summary = "IRC bot framework"
|
5
|
+
|
6
|
+
spec.author = "Victor Maslov aka Nakilon"
|
7
|
+
spec.email = "nakilon@gmail.com"
|
8
|
+
spec.license = "MIT"
|
9
|
+
spec.metadata = {"source_code_uri" => "https://github.com/nakilon/nakiircbot"}
|
10
|
+
|
11
|
+
spec.required_ruby_version = ">=2.5" # for Exception#full_message and block rescue
|
12
|
+
|
13
|
+
spec.files = %w{ LICENSE nakiircbot.gemspec lib/nakiircbot.rb }
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nakiircbot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Victor Maslov aka Nakilon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-05-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: nakilon@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- LICENSE
|
20
|
+
- lib/nakiircbot.rb
|
21
|
+
- nakiircbot.gemspec
|
22
|
+
homepage:
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata:
|
26
|
+
source_code_uri: https://github.com/nakilon/nakiircbot
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '2.5'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.5.2.3
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: IRC bot framework
|
47
|
+
test_files: []
|