blur 1.4

Sign up to get free protection for your applications and to get access to all the features.
data/library/blur.rb ADDED
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+
3
+ require 'pp'
4
+ require 'yaml'
5
+ require 'socket'
6
+ require 'ostruct'
7
+
8
+ Dir.glob("#{File.dirname __FILE__}/blur/**/*.rb").each &method(:require)
9
+
10
+ module Blur
11
+ class << Version = [1,4]
12
+ def to_s; join '.' end
13
+ end
14
+
15
+ def self.connect options, &block
16
+ Client.new(options).tap do |client|
17
+ client.instance_eval &block
18
+ end.connect
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+
3
+ require 'blur/handling'
4
+
5
+ module Blur
6
+ class Client
7
+ include Handling
8
+
9
+ attr_accessor :options, :networks
10
+
11
+ def initialize options
12
+ @options = options
13
+ @networks = []
14
+ @callbacks = {}
15
+ @connected = true
16
+
17
+ @options[:networks].each do |options|
18
+ @networks.<< Network.new options
19
+ end
20
+
21
+ trap 2, &method(:quit)
22
+ end
23
+
24
+ def connect
25
+ networks = @networks.select { |network| not network.connected? }
26
+
27
+ networks.each do |network|
28
+ network.delegate = self
29
+ network.connect
30
+ end
31
+
32
+ run_loop
33
+ end
34
+
35
+ def got_command network, command
36
+ puts "<- \e[1m#{network}\e[0m | #{command}"
37
+ name = :"got_#{command.name.downcase}"
38
+
39
+ if respond_to? name
40
+ __send__ name, network, command
41
+ end
42
+ end
43
+
44
+ def quit signal
45
+ @networks.each do |network|
46
+ network.transmit :QUIT, "Got SIGINT?"
47
+ network.transcieve
48
+ network.disconnect
49
+ end
50
+
51
+ @connected = false
52
+
53
+ exit 0
54
+ end
55
+
56
+ private
57
+
58
+ def run_loop
59
+ puts "Starting run loop ..."
60
+
61
+ while @connected
62
+ @networks.each do |network|
63
+ begin
64
+ network.transcieve
65
+ sleep 0.05
66
+ rescue StandardError => exception
67
+ puts "#{network} threw an exception: #{exception.class.name} #{exception.message} #{exception.backtrace.to_s}"
68
+
69
+ network.disconnect if network.connected?
70
+ @networks.delete network
71
+ end
72
+ end
73
+ end
74
+
75
+ puts "Ended run loop ..."
76
+ end
77
+
78
+ def emit name, *args
79
+ @callbacks[name].each do |callback|
80
+ callback.call *args
81
+ end if @callbacks[name]
82
+ end
83
+
84
+ def catch name, &block
85
+ (@callbacks[name] ||= []) << block
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ class Exception
4
+ def line; backtrace.first.match(/^.*?:(\d+):/)[1].to_i end
5
+ end
6
+
7
+ class String
8
+ alias_method :starts_with?, :start_with?
9
+ end
@@ -0,0 +1,114 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Client
5
+ module Handling
6
+
7
+ protected
8
+
9
+ # End of MOTD
10
+ def got_end_of_motd network, command
11
+ emit :connection_ready, network
12
+
13
+ network.options[:channels].each do |channel|
14
+ network.transmit :JOIN, channel
15
+ end
16
+ end
17
+
18
+ # The /NAMES list
19
+ def got_353 network, command
20
+ name = command[2]
21
+ users = command[3].split.map &Network::User.method(:new)
22
+
23
+ if channel = network.channel_by_name(name)
24
+ users.each do |user|
25
+ user.channel = channel
26
+ channel.users << user
27
+ end
28
+ else
29
+ network.channels.<< Network::Channel.new name, network, users
30
+ end
31
+ end
32
+
33
+ # Are we still breathing?
34
+ def got_ping network, command
35
+ network.transmit :PONG, command[0]
36
+ end
37
+
38
+ # Someone changed their nickname
39
+ def got_nick network, command
40
+ nick = command.sender.nickname
41
+
42
+ if channels = network.channels_with_user(nick)
43
+ channels.each do |channel|
44
+ if user = channel.user_by_nick(nick)
45
+ emit :user_rename, channel, user, command[0]
46
+ user.nick = command[0]
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ # Someone send a message
53
+ def got_privmsg network, command
54
+ return if command.sender.is_a? String # Ignore all server privmsgs
55
+
56
+ name, message = command.params
57
+
58
+ if channel = network.channel_by_name(name)
59
+ if user = channel.user_by_nick(command.sender.nickname)
60
+ emit :message, user, channel, message
61
+ else
62
+ # Odd… this shouldn't happen
63
+ end
64
+ end
65
+ end
66
+
67
+ # Someone joined a channel
68
+ def got_join network, command
69
+ name = command[0]
70
+ user = Network::User.new command.sender.nickname
71
+
72
+ if channel = network.channel_by_name(name)
73
+ user.name = command.sender.username
74
+ user.host = command.sender.hostname
75
+
76
+ channel.users << user
77
+
78
+ emit :user_entered, channel, user
79
+ end
80
+ end
81
+
82
+ # Someone left a channel
83
+ def got_part network, command
84
+ name = command[0]
85
+
86
+ if channel = network.channel_by_name(name)
87
+ if user = channel.user_by_nick(command.sender.nickname)
88
+ channel.users.delete user
89
+
90
+ emit :user_left, channel, user
91
+ end
92
+ end
93
+ end
94
+
95
+ # Someone quit irc
96
+ def got_quit network, command
97
+ nick = command.sender.nickname
98
+
99
+ if channels = network.channels_with_user(nick)
100
+ channels.each do |channel|
101
+ if user = channel.user_by_nick(nick)
102
+ channel.users.delete user
103
+
104
+ emit :user_quit, channel, user
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ alias_method :got_422, :got_end_of_motd
111
+ alias_method :got_376, :got_end_of_motd
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,71 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class ConnectionError < StandardError; end
6
+ attr_accessor :options, :channels, :delegate, :connection
7
+
8
+ def connected?; @connection.established? end
9
+
10
+ def host; @options[:hostname] end
11
+ def port; @options[:port] ||= (@options[:secure] == true) ? 6697 : 6667 end
12
+
13
+ def initialize options = {}
14
+ @options = options
15
+
16
+ unless options[:nickname]
17
+ raise ArgumentError, "nickname is missing from the network's option block"
18
+ end
19
+
20
+ @options[:username] ||= @options[:nickname]
21
+ @options[:realname] ||= @options[:username]
22
+ @options[:channels] ||= []
23
+
24
+ @channels = []
25
+ @connection = Connection.new self, host, port
26
+ end
27
+
28
+ def say recipient, message
29
+ transmit :PRIVMSG, recipient, message
30
+ end
31
+
32
+ def got_command command
33
+ @delegate.got_command self, command
34
+ end
35
+
36
+ def channel_by_name name
37
+ @channels.find { |channel| channel.name == name }
38
+ end
39
+
40
+ def channels_with_user nick
41
+ @channels.select { |channel| channel.user_by_nick nick }
42
+ end
43
+
44
+ def connect
45
+ @connection.establish
46
+
47
+ transmit :PASS, @options[:password] if @options[:password]
48
+ transmit :NICK, @options[:nickname]
49
+ transmit :USER, @options[:username], :void, :void, @options[:realname]
50
+ end
51
+
52
+ def disconnect
53
+ @connection.terminate
54
+ end
55
+
56
+ def transmit name, *arguments
57
+ command = Command.new name, arguments
58
+ puts "-> \e[1m#{self}\e[0m | #{command}"
59
+
60
+ @connection.transmit command
61
+ end
62
+
63
+ def transcieve
64
+ @connection.transcieve
65
+ end
66
+
67
+ def to_s
68
+ %{#<#{self.class.name} "#{host}:#{port}">}
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Channel
6
+ attr_accessor :name, :users
7
+
8
+ def initialize name, network = nil, users = []
9
+ @name = name
10
+ @users = users
11
+ @network = network
12
+
13
+ users.each { |user| user.channel = self }
14
+ end
15
+
16
+ def say message
17
+ @network.say self, message
18
+ end
19
+
20
+ def user_by_nick nick
21
+ @users.find { |user| user.nick == nick }
22
+ end
23
+
24
+ def inspect
25
+ %{#<#{self.class.name} @name=#{@name.inspect} @users=#{@users.inspect}}
26
+ end
27
+
28
+ def to_s
29
+ @name
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Command
6
+ attr_accessor :name, :params, :prefix
7
+
8
+ Pattern = /^(?:[:@]([^\s]+) )?([^\s]+)(?: ((?:[^:\s][^\s]* ?)*))?(?: ?:(.*))?$/
9
+
10
+ def self.parse data
11
+ match = data.strip.match Pattern
12
+ prefix, name, args, extra = match.captures
13
+ params = extra ? args.split << extra : args.split
14
+
15
+ new(name, params).tap do |this|
16
+ this.prefix = prefix
17
+ end
18
+ end
19
+
20
+ def [] index; @params[index] end
21
+
22
+ def initialize name, params = []
23
+ @name, @params = name, params
24
+ end
25
+
26
+ def sender
27
+ return @sender if @sender
28
+
29
+ if prefix =~ /^(\S+)!(\S+)@(\S+)$/
30
+ @sender = OpenStruct.new nickname: $1, username: $2, hostname: $3
31
+ else
32
+ @sender = prefix
33
+ end
34
+ end
35
+
36
+ def to_s
37
+ String.new.tap do |line|
38
+ line << "#{prefix} " if prefix
39
+ line << name.to_s
40
+
41
+ params.each_with_index do |param, index|
42
+ line << ' '
43
+ line << ?: if index == params.length - 1 and param =~ /[ :]/
44
+ line << param.to_s
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class Connection
6
+ def established?; @socket and not (@socket.closed? or @socket.eof?) end
7
+
8
+ def initialize delegate, host = nil, port = nil
9
+ @host = host
10
+ @port = port
11
+ @queue = []
12
+ @buffer = ""
13
+ @socket = nil
14
+ @delegate = delegate
15
+ end
16
+
17
+ def establish
18
+ @socket = TCPSocket.new @host, @port
19
+ end
20
+
21
+ def terminate
22
+ @socket.close
23
+ @socket = nil
24
+ end
25
+
26
+ def transmit command
27
+ @queue.push command
28
+ end
29
+
30
+ def transcieve
31
+ readable, writable = IO.select [@socket], [@socket]
32
+
33
+ # If the socket is ready to recieve, do so.
34
+ if socket = readable.first
35
+ @buffer.<< socket.read_nonblock 512
36
+
37
+ while index = @buffer.index(?\n)
38
+ command = Command.parse @buffer.slice! 0..index
39
+ @delegate.got_command command
40
+ end
41
+ end
42
+
43
+ # If it's ready to write, do that too until the outoing queue is empty.
44
+ if socket = writable.first
45
+ socket.write_nonblock "#{command}\n" while command = @queue.shift
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module Blur
4
+ class Network
5
+ class User
6
+ attr_accessor :nick, :name, :host, :channel
7
+
8
+ def initialize nick
9
+ @nick = nick.sub /^[@|~|\+|%|&]/, ''
10
+ end
11
+
12
+ def synchronize sender
13
+ @nick, @name, @host = sender.nickname, sender.username, sender.hostname
14
+ end
15
+
16
+ def inspect
17
+ %{#<#{self.class.name} @nick=#{@nick.inspect} @channel=#{@channel.name.inspect}>}
18
+ end
19
+
20
+ def to_s
21
+ @nick
22
+ end
23
+ end
24
+ end
25
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blur
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 4
8
+ version: "1.4"
9
+ platform: ruby
10
+ authors:
11
+ - Mikkel Kroman
12
+ autorequire:
13
+ bindir: executables
14
+ cert_chain: []
15
+
16
+ date: 2011-01-17 00:00:00 +01:00
17
+ default_executable:
18
+ dependencies: []
19
+
20
+ description:
21
+ email: mk@maero.dk
22
+ executables: []
23
+
24
+ extensions: []
25
+
26
+ extra_rdoc_files: []
27
+
28
+ files:
29
+ - library/blur/client.rb
30
+ - library/blur/enhancements.rb
31
+ - library/blur/handling.rb
32
+ - library/blur/network/channel.rb
33
+ - library/blur/network/command.rb
34
+ - library/blur/network/connection.rb
35
+ - library/blur/network/user.rb
36
+ - library/blur/network.rb
37
+ - library/blur.rb
38
+ has_rdoc: true
39
+ homepage:
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options: []
44
+
45
+ require_paths:
46
+ - library
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 1
54
+ - 9
55
+ - 1
56
+ version: 1.9.1
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.7
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Extensible IRC library
72
+ test_files: []
73
+