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.
Files changed (8) hide show
  1. data/ChangeLog +0 -0
  2. data/README +92 -0
  3. data/Rakefile +131 -0
  4. data/examples/lig.rb +276 -0
  5. data/examples/tig.rb +446 -0
  6. data/examples/wig.rb +132 -0
  7. data/lib/net/irc.rb +844 -0
  8. 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
+