net-irc 0.0.1
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/ChangeLog +0 -0
- data/README +92 -0
- data/Rakefile +131 -0
- data/examples/lig.rb +276 -0
- data/examples/tig.rb +446 -0
- data/examples/wig.rb +132 -0
- data/lib/net/irc.rb +844 -0
- metadata +72 -0
data/ChangeLog
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
= net-irc
|
3
|
+
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
IRC library. This is mostly conform to RFC1459 but partly not for convenience.
|
8
|
+
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
=== Archive Installation
|
13
|
+
|
14
|
+
rake install
|
15
|
+
|
16
|
+
=== Gem Installation
|
17
|
+
|
18
|
+
gem install net-irc
|
19
|
+
|
20
|
+
|
21
|
+
== Features/Problems
|
22
|
+
|
23
|
+
* IRC client (for bot)
|
24
|
+
* IRC server (for gateway to webservices)
|
25
|
+
|
26
|
+
== Synopsis
|
27
|
+
|
28
|
+
=== Client
|
29
|
+
|
30
|
+
require "net/irc"
|
31
|
+
|
32
|
+
class SimpleClient < Net::IRC::Client
|
33
|
+
def on_privmsg(m)
|
34
|
+
super
|
35
|
+
channel, message = *m
|
36
|
+
if message =~ /Hello/
|
37
|
+
post NOTICE, channel, "Hello!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Net::IRC::Client manages channel status and the information is set in @channels.
|
43
|
+
So, be careful to use @channels instance variable and call super surely.
|
44
|
+
|
45
|
+
=== Server
|
46
|
+
|
47
|
+
see example/lig.rb
|
48
|
+
|
49
|
+
|
50
|
+
== IRC Gateways
|
51
|
+
|
52
|
+
There are some gateways connecting to webservices.
|
53
|
+
|
54
|
+
* Lingr
|
55
|
+
* Twitter
|
56
|
+
* Wassr
|
57
|
+
|
58
|
+
If you want to run it, type following:
|
59
|
+
|
60
|
+
$ cd `ruby -rubygems -e 'print Gem.searcher.find("net/irc").full_gem_path+"/examples"'`
|
61
|
+
|
62
|
+
Lingr:
|
63
|
+
$ sudo gem install pit # for configuration
|
64
|
+
$ ./lig.rb
|
65
|
+
|
66
|
+
Twitter:
|
67
|
+
$ ./tig.rb
|
68
|
+
|
69
|
+
Wassr:
|
70
|
+
$ ./wig.rb
|
71
|
+
|
72
|
+
Run as daemon in default. If you want to help:
|
73
|
+
|
74
|
+
$ ./lig.rb --help
|
75
|
+
Usage: ./lig.rb [opts]
|
76
|
+
|
77
|
+
|
78
|
+
Options:
|
79
|
+
-p, --port [PORT=16669] listen port number
|
80
|
+
-h, --host [HOST=localhost] listen host
|
81
|
+
-l, --log LOG log file
|
82
|
+
-a, --api_key API_KEY Your api key on Lingr
|
83
|
+
--debug Enable debug mode
|
84
|
+
|
85
|
+
|
86
|
+
== Copyright
|
87
|
+
|
88
|
+
This library is based on RICE ( http://arika.org/ruby/rice ) written by akira yamada.
|
89
|
+
|
90
|
+
Author:: cho45 <cho45@lowreal.net>
|
91
|
+
Copyright:: Copyright (c) 2008 cho45
|
92
|
+
License:: Ruby's
|
data/Rakefile
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require "shipit"
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'rake/contrib/sshpublisher'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'spec/rake/spectask'
|
12
|
+
|
13
|
+
include FileUtils
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift "lib"
|
16
|
+
require "net/irc"
|
17
|
+
|
18
|
+
NAME = "net-irc"
|
19
|
+
AUTHOR = "cho45"
|
20
|
+
EMAIL = "cho45@lowreal.net"
|
21
|
+
DESCRIPTION = ""
|
22
|
+
RUBYFORGE_PROJECT = "lowreal"
|
23
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
24
|
+
BIN_FILES = %w( )
|
25
|
+
VERS = Net::IRC::VERSION
|
26
|
+
|
27
|
+
REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
28
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config']
|
29
|
+
RDOC_OPTS = [
|
30
|
+
'--title', "#{NAME} documentation",
|
31
|
+
"--charset", "utf-8",
|
32
|
+
"--opname", "index.html",
|
33
|
+
"--line-numbers",
|
34
|
+
"--main", "README",
|
35
|
+
"--inline-source",
|
36
|
+
]
|
37
|
+
|
38
|
+
task :default => [:spec]
|
39
|
+
task :package => [:clean]
|
40
|
+
|
41
|
+
Spec::Rake::SpecTask.new do |t|
|
42
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
43
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
44
|
+
end
|
45
|
+
|
46
|
+
spec = Gem::Specification.new do |s|
|
47
|
+
s.name = NAME
|
48
|
+
s.version = VERS
|
49
|
+
s.platform = Gem::Platform::RUBY
|
50
|
+
s.has_rdoc = true
|
51
|
+
s.extra_rdoc_files = ["README", "ChangeLog"]
|
52
|
+
s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
|
53
|
+
s.summary = DESCRIPTION
|
54
|
+
s.description = DESCRIPTION
|
55
|
+
s.author = AUTHOR
|
56
|
+
s.email = EMAIL
|
57
|
+
s.homepage = HOMEPATH
|
58
|
+
s.executables = BIN_FILES
|
59
|
+
s.rubyforge_project = RUBYFORGE_PROJECT
|
60
|
+
s.bindir = "bin"
|
61
|
+
s.require_path = "lib"
|
62
|
+
s.autorequire = ""
|
63
|
+
|
64
|
+
#s.add_dependency('activesupport', '>=1.3.1')
|
65
|
+
#s.required_ruby_version = '>= 1.8.2'
|
66
|
+
|
67
|
+
s.files = %w(README ChangeLog Rakefile) +
|
68
|
+
Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
|
69
|
+
Dir.glob("ext/**/*.{h,c,rb}") +
|
70
|
+
Dir.glob("examples/**/*.rb") +
|
71
|
+
Dir.glob("tools/*.rb")
|
72
|
+
|
73
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
74
|
+
end
|
75
|
+
|
76
|
+
Rake::GemPackageTask.new(spec) do |p|
|
77
|
+
p.need_tar = true
|
78
|
+
p.gem_spec = spec
|
79
|
+
end
|
80
|
+
|
81
|
+
task :install do
|
82
|
+
name = "#{NAME}-#{VERS}.gem"
|
83
|
+
sh %{rake package}
|
84
|
+
sh %{sudo gem install pkg/#{name}}
|
85
|
+
end
|
86
|
+
|
87
|
+
task :uninstall => [:clean] do
|
88
|
+
sh %{sudo gem uninstall #{NAME}}
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
Rake::RDocTask.new do |rdoc|
|
93
|
+
rdoc.rdoc_dir = 'html'
|
94
|
+
rdoc.options += RDOC_OPTS
|
95
|
+
rdoc.template = "resh"
|
96
|
+
#rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
97
|
+
if ENV['DOC_FILES']
|
98
|
+
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
99
|
+
else
|
100
|
+
rdoc.rdoc_files.include('README', 'ChangeLog')
|
101
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
102
|
+
rdoc.rdoc_files.include('ext/**/*.c')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
desc "Publish to RubyForge"
|
107
|
+
task :rubyforge => [:rdoc, :package] do
|
108
|
+
require 'rubyforge'
|
109
|
+
@local_dir = "html"
|
110
|
+
@host = "cho45@rubyforge.org"
|
111
|
+
@remote_dir = "/var/www/gforge-projects/#{RUBYFORGE_PROJECT}/#{NAME}"
|
112
|
+
sh %{rsync -r --delete --verbose #{@local_dir}/ #{@host}:#{@remote_dir}}
|
113
|
+
end
|
114
|
+
|
115
|
+
Rake::ShipitTask.new do |s|
|
116
|
+
s.Step.new {
|
117
|
+
system("svn", "up")
|
118
|
+
}.and {}
|
119
|
+
s.Step.new {
|
120
|
+
raise "changelog-with-hatenastar.rb is not found" unless system("which", "changelog-with-hatenastar.rb")
|
121
|
+
}.and {
|
122
|
+
system("changelog-with-hatenastar.rb > ChangeLog")
|
123
|
+
}
|
124
|
+
s.ChangeVersion "lib/net/irc.rb", "VERSION"
|
125
|
+
s.Commit
|
126
|
+
s.Task :clean, :package
|
127
|
+
s.RubyForge
|
128
|
+
s.Tag
|
129
|
+
s.Twitter
|
130
|
+
s.Task :rubyforge
|
131
|
+
end
|
data/examples/lig.rb
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << "lib"
|
4
|
+
$LOAD_PATH << "../lib"
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
|
8
|
+
# http://svn.lingr.com/api/toolkits/ruby/infoteria/api_client.rb
|
9
|
+
begin
|
10
|
+
require "api_client"
|
11
|
+
rescue LoadError
|
12
|
+
require "net/http"
|
13
|
+
require "uri"
|
14
|
+
File.open("api_client.rb", "w") do |f|
|
15
|
+
f.puts Net::HTTP.get(URI("http://svn.lingr.com/api/toolkits/ruby/infoteria/api_client.rb"))
|
16
|
+
end
|
17
|
+
require "api_client"
|
18
|
+
end
|
19
|
+
|
20
|
+
require "net/irc"
|
21
|
+
require "pit"
|
22
|
+
|
23
|
+
|
24
|
+
class LingrIrcGateway < Net::IRC::Server::Session
|
25
|
+
def server_name
|
26
|
+
"lingrgw"
|
27
|
+
end
|
28
|
+
|
29
|
+
def server_version
|
30
|
+
"0.0.0"
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(*args)
|
34
|
+
super
|
35
|
+
@channels = {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_user(m)
|
39
|
+
super
|
40
|
+
@real, @copts = @real.split(/\s/)
|
41
|
+
@copts ||= []
|
42
|
+
|
43
|
+
log "Hello #{@nick}, this is Lingr IRC Gateway."
|
44
|
+
log "Client Option: #{@copts.join(", ")}"
|
45
|
+
@log.info "Client Option: #{@copts.join(", ")}"
|
46
|
+
@log.info "Client initialization is completed."
|
47
|
+
|
48
|
+
@lingr = Lingr::ApiClient.new(@opts.api_key)
|
49
|
+
@lingr.create_session('human')
|
50
|
+
@lingr.login(@real, @pass)
|
51
|
+
@user_info = @lingr.get_user_info[:response]
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_privmsg(m)
|
55
|
+
target, message = *m.params
|
56
|
+
@lingr.say(@channels[target.downcase][:ticket], message)
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_whois(m)
|
60
|
+
nick = m.params[0]
|
61
|
+
# TODO
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_who(m)
|
65
|
+
channel = m.params[0]
|
66
|
+
info = @channels[channel.downcase]
|
67
|
+
res = @lingr.get_room_info(info[:chan_id], nil, info[:password])
|
68
|
+
if res[:succeeded]
|
69
|
+
res = res[:response]
|
70
|
+
res["occupants"].each do |o|
|
71
|
+
u_id, o_id, nick = *make_ids(o)
|
72
|
+
post nil, RPL_WHOREPLY, channel, o_id, "lingr.com", "lingr.com", nick, "H", "0 #{o["description"].to_s.gsub(/\s+/, " ")}"
|
73
|
+
end
|
74
|
+
post nil, RPL_ENDOFWHO, channel
|
75
|
+
else
|
76
|
+
log "Maybe gateway don't know password for channel #{channel}. Please part and join."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def on_join(m)
|
81
|
+
channels = m.params[0].split(/\s*,\s*/)
|
82
|
+
password = m.params[1]
|
83
|
+
channels.each do |channel|
|
84
|
+
next if @channels.key? channel.downcase
|
85
|
+
@log.debug "Enter room -> #{channel}"
|
86
|
+
res = @lingr.enter_room(channel.sub(/^#/, ""), @nick, password)
|
87
|
+
if res[:succeeded]
|
88
|
+
res[:response]["password"] = password
|
89
|
+
o_id = res[:response]["occupant_id"]
|
90
|
+
post "#{@nick}!#{o_id}@lingr.com", JOIN, channel
|
91
|
+
create_observer(channel, res[:response])
|
92
|
+
else
|
93
|
+
log "Error: #{(res && rese['error']) ? res[:response]["error"]["message"] : "socket error"}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def on_part(m)
|
99
|
+
channel = m.params[0]
|
100
|
+
info = @channels[channel].downcase
|
101
|
+
|
102
|
+
if info
|
103
|
+
info[:observer].kill
|
104
|
+
@lingr.exit_room(info[:ticket])
|
105
|
+
@channels.delete(channel.downcase)
|
106
|
+
post @nick, PART, channel, "Parted"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def create_observer(channel, response)
|
113
|
+
Thread.start(channel, response) do |chan, res|
|
114
|
+
begin
|
115
|
+
post server_name, TOPIC, chan, "#{res["room"]["url"]} #{res["room"]["description"]}"
|
116
|
+
@channels[chan.downcase] = {
|
117
|
+
:ticket => res["ticket"],
|
118
|
+
:counter => res["counter"],
|
119
|
+
:o_id => res["occupant_id"],
|
120
|
+
:chan_id => res["room"]["id"],
|
121
|
+
:password => res["password"],
|
122
|
+
:hcounter => 0,
|
123
|
+
:observer => Thread.current,
|
124
|
+
}
|
125
|
+
first = true
|
126
|
+
while true
|
127
|
+
info = @channels[chan.downcase]
|
128
|
+
res = @lingr.observe_room info[:ticket], info[:counter]
|
129
|
+
@log.debug "observe_room returned"
|
130
|
+
if res[:succeeded]
|
131
|
+
info[:counter] = res[:response]["counter"] if res[:response]["counter"]
|
132
|
+
(res[:response]["messages"] || []).each do |m|
|
133
|
+
next if m["id"].to_i <= info[:hcounter]
|
134
|
+
|
135
|
+
u_id, o_id, nick = *make_ids(m)
|
136
|
+
|
137
|
+
case m["type"]
|
138
|
+
when "user"
|
139
|
+
if first
|
140
|
+
post nick, NOTICE, chan, m["text"]
|
141
|
+
else
|
142
|
+
post nick, PRIVMSG, chan, m["text"] unless info[:o_id] == o_id
|
143
|
+
end
|
144
|
+
when "private"
|
145
|
+
# TODO
|
146
|
+
post nick, PRIVMSG, chan, "\x01ACTION Sent private: #{m["text"]}\x01" unless info[:o_id] == o_id
|
147
|
+
when "system:enter"
|
148
|
+
post "#{nick}!#{o_id}@lingr.com", JOIN, chan unless nick == @nick
|
149
|
+
when "system:leave"
|
150
|
+
#post "#{nick}!#{o_id}@lingr.com", PART, chan unless nick == @nick
|
151
|
+
when "system:nickname_change"
|
152
|
+
post nick, NOTICE, chan, m["text"]
|
153
|
+
when "system:broadcast"
|
154
|
+
post nil, NOTICE, chan, m["text"]
|
155
|
+
end
|
156
|
+
|
157
|
+
info[:hcounter] = m["id"].to_i if m["id"]
|
158
|
+
end
|
159
|
+
|
160
|
+
if res["occupants"]
|
161
|
+
res["occupants"].each do |o|
|
162
|
+
# new_roster[o["id"]] = o["nickname"]
|
163
|
+
if o["nickname"]
|
164
|
+
nick = o["nickname"]
|
165
|
+
o_id = m["occupant_id"]
|
166
|
+
post "#{nick}!#{o_id}@lingr.com", JOIN, chan
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
else
|
171
|
+
@log.debug "observe failed : #{res[:response].inspect}"
|
172
|
+
log "Error: #{(res && res['error']) ? res[:response]["error"]["message"] : "socket error"}"
|
173
|
+
end
|
174
|
+
first = false
|
175
|
+
end
|
176
|
+
rescue Exception => e
|
177
|
+
puts e
|
178
|
+
puts e.backtrace
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def log(str)
|
184
|
+
str.gsub!(/\s/, " ")
|
185
|
+
post nil, NOTICE, @nick, str
|
186
|
+
end
|
187
|
+
|
188
|
+
def make_ids(o)
|
189
|
+
u_id = o["user_id"]
|
190
|
+
o_id = o["occupant_id"] || o["id"]
|
191
|
+
nick = o["nickname"].gsub(/\s+/, "") + "^#{u_id || "anon"}"
|
192
|
+
[u_id, o_id, nick]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
if __FILE__ == $0
|
198
|
+
require "rubygems"
|
199
|
+
require "optparse"
|
200
|
+
require "pit"
|
201
|
+
|
202
|
+
opts = {
|
203
|
+
:port => 16669,
|
204
|
+
:host => "localhost",
|
205
|
+
:debug => false,
|
206
|
+
:log => nil,
|
207
|
+
:debug => false,
|
208
|
+
}
|
209
|
+
|
210
|
+
OptionParser.new do |parser|
|
211
|
+
parser.instance_eval do
|
212
|
+
self.banner = <<-EOB.gsub(/^\t+/, "")
|
213
|
+
Usage: #{$0} [opts]
|
214
|
+
|
215
|
+
EOB
|
216
|
+
|
217
|
+
separator ""
|
218
|
+
|
219
|
+
separator "Options:"
|
220
|
+
on("-p", "--port [PORT=#{opts[:port]}]", "listen port number") do |port|
|
221
|
+
opts[:port] = port
|
222
|
+
end
|
223
|
+
|
224
|
+
on("-h", "--host [HOST=#{opts[:host]}]", "listen host") do |host|
|
225
|
+
opts[:host] = host
|
226
|
+
end
|
227
|
+
|
228
|
+
on("-l", "--log LOG", "log file") do |log|
|
229
|
+
opts[:log] = log
|
230
|
+
end
|
231
|
+
|
232
|
+
on("-a", "--api_key API_KEY", "Your api key on Lingr") do |key|
|
233
|
+
opts[:api_key] = key
|
234
|
+
end
|
235
|
+
|
236
|
+
on("--debug", "Enable debug mode") do |debug|
|
237
|
+
opts[:log] = $stdout
|
238
|
+
opts[:debug] = true
|
239
|
+
end
|
240
|
+
|
241
|
+
parse!(ARGV)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
opts[:logger] = Logger.new(opts[:log], "daily")
|
246
|
+
opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
|
247
|
+
|
248
|
+
def daemonize(debug=false)
|
249
|
+
return yield if $DEBUG || debug
|
250
|
+
Process.fork do
|
251
|
+
Process.setsid
|
252
|
+
Dir.chdir "/"
|
253
|
+
trap("SIGINT") { exit! 0 }
|
254
|
+
trap("SIGTERM") { exit! 0 }
|
255
|
+
trap("SIGHUP") { exit! 0 }
|
256
|
+
File.open("/dev/null") {|f|
|
257
|
+
STDIN.reopen f
|
258
|
+
STDOUT.reopen f
|
259
|
+
STDERR.reopen f
|
260
|
+
}
|
261
|
+
yield
|
262
|
+
end
|
263
|
+
exit! 0
|
264
|
+
end
|
265
|
+
|
266
|
+
opts[:api_key] = Pit.get("lig.rb", :require => {
|
267
|
+
"api_key" => "API key of lingr"
|
268
|
+
})["api_key"] unless opts[:api_key]
|
269
|
+
|
270
|
+
daemonize(opts[:debug]) do
|
271
|
+
Net::IRC::Server.new(opts[:host], opts[:port], LingrIrcGateway, opts).start
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
|