rflow-components-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/.gitignore +4 -0
- data/Gemfile +3 -0
- data/Rakefile +15 -0
- data/lib/rflow/components/irc/client.rb +216 -0
- data/lib/rflow/components/irc/extensions.rb +27 -0
- data/lib/rflow/components/irc/version.rb +7 -0
- data/lib/rflow/components/irc.rb +25 -0
- data/lib/rflow-components-irc.rb +3 -0
- data/rflow-components-irc.gemspec +27 -0
- data/schema/irc_message.avsc +16 -0
- data/spec/extensions_spec.rb +47 -0
- data/spec/schema_spec.rb +27 -0
- data/spec/spec_helper.rb +19 -0
- metadata +110 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rdoc/task'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
|
+
t.verbose = true
|
8
|
+
t.rspec_opts = '--tty --color'
|
9
|
+
end
|
10
|
+
|
11
|
+
Rake::RDocTask.new do |rd|
|
12
|
+
rd.main = "README"
|
13
|
+
rd.rdoc_files.include("README", "lib/**/*.rb")
|
14
|
+
rd.rdoc_dir = File.join('doc', 'html')
|
15
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
require 'rflow'
|
4
|
+
|
5
|
+
class RFlow
|
6
|
+
module Components
|
7
|
+
module IRC
|
8
|
+
|
9
|
+
class Client < RFlow::Component
|
10
|
+
input_port :to_server
|
11
|
+
output_port :from_server
|
12
|
+
|
13
|
+
attr_accessor :config
|
14
|
+
attr_accessor :client_connection
|
15
|
+
|
16
|
+
attr_accessor :server, :port
|
17
|
+
|
18
|
+
DEFAULT_CONFIG = {
|
19
|
+
'server' => '127.0.0.1',
|
20
|
+
'port' => 6667,
|
21
|
+
'server_password' => nil,
|
22
|
+
'nickname' => 'rflow',
|
23
|
+
'username' => 'rflow',
|
24
|
+
'oper_user' => nil,
|
25
|
+
'oper_password' => nil,
|
26
|
+
'nickserv_password' => nil,
|
27
|
+
'reconnect_interval' => 2,
|
28
|
+
}
|
29
|
+
|
30
|
+
def configure!(config)
|
31
|
+
@config = DEFAULT_CONFIG.merge config
|
32
|
+
|
33
|
+
@config['port'] = @config['port'].to_i
|
34
|
+
@config['reconnect_interval'] = @config['reconnect_interval'].to_i
|
35
|
+
# TODO: More config sanitization
|
36
|
+
|
37
|
+
@server = @config['server']
|
38
|
+
@port = @config['port'].to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def run!
|
42
|
+
@client_connection = EM.connect(@server, @port, Connection) do |conn|
|
43
|
+
conn.client = self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def process_message(input_port, input_port_key, connection, message)
|
48
|
+
RFlow.logger.debug "Received a message"
|
49
|
+
return unless message.data_type_name == 'RFlow::Message::Data::IRC::Message'
|
50
|
+
|
51
|
+
RFlow.logger.debug "Received an IRC::Message message, determining if its mine"
|
52
|
+
my_events = message.provenance.find_all {|processing_event| processing_event.component_instance_uuid == instance_uuid}
|
53
|
+
RFlow.logger.debug "Found #{my_events.size} processing events from me"
|
54
|
+
# Attempt to send the data to each context match
|
55
|
+
my_events.each do |processing_event|
|
56
|
+
RFlow.logger.debug "Inspecting context #{client_connection.signature.to_s} == #{processing_event.context.to_s}"
|
57
|
+
if client_connection.signature.to_s == processing_event.context.to_s
|
58
|
+
RFlow.logger.debug "Found connection for #{processing_event.context}"
|
59
|
+
client_connection.send_irc_message message
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def shutdown!
|
65
|
+
end
|
66
|
+
|
67
|
+
def cleanup!
|
68
|
+
end
|
69
|
+
|
70
|
+
class Connection < EventMachine::Connection
|
71
|
+
include EventMachine::Protocols::LineText2
|
72
|
+
|
73
|
+
IRC_LINE_REGEX = /^(?::(\S+) )?(\S+)(?: (.+))?$/
|
74
|
+
|
75
|
+
attr_accessor :client
|
76
|
+
attr_reader :client_ip, :client_port, :server_ip, :server_port
|
77
|
+
|
78
|
+
def post_init
|
79
|
+
@client_port, @client_ip = Socket.unpack_sockaddr_in(get_peername) rescue ["?", "?.?.?.?"]
|
80
|
+
@server_port, @server_ip = Socket.unpack_sockaddr_in(get_sockname) rescue ["?", "?.?.?.?"]
|
81
|
+
RFlow.logger.debug "Connection from #{@client_ip}:#{@client_port} to #{@server_ip}:#{@server_port}"
|
82
|
+
super
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def connection_completed
|
87
|
+
@reconnecting = false
|
88
|
+
@connected = true
|
89
|
+
|
90
|
+
RFlow.logger.info("Connected to IRC server #{client.config['server']}:#{client.config['port']}")
|
91
|
+
|
92
|
+
command "PASS", [client.config['server_password']] unless client.config['server_password'].nil?
|
93
|
+
command "NICK", [client.config['nickname']]
|
94
|
+
command "USER", [client.config['username'], client.config['username'], client.config['username'], client.config['username']]
|
95
|
+
command "NickServ IDENTIFY", [client.config['nickname'], client.config['nickserv_password']] unless client.config['nickserv_password'].nil?
|
96
|
+
command "OPER", [client.config['oper_user'] || client.config['nickname'], client.config['oper_password']] unless client.config['oper_password'].nil?
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def receive_line(line)
|
101
|
+
RFlow.logger.debug("IRCClient#receive_line: #{line}")
|
102
|
+
processing_event = RFlow::Message::ProcessingEvent.new(client.instance_uuid, Time.now.utc)
|
103
|
+
|
104
|
+
prefix, cmd, params = parse_irc_line(line)
|
105
|
+
|
106
|
+
# Now have an optional prefix, required cmd, and optional
|
107
|
+
# param array
|
108
|
+
|
109
|
+
case cmd
|
110
|
+
when /PING/
|
111
|
+
command('PONG', params)
|
112
|
+
else
|
113
|
+
# create an IRC message here and send it along
|
114
|
+
RFlow.logger.debug("Sending IRC message '#{line}', signature '#{signature.class}:#{signature}', '#{signature.to_s.class}:#{signature.to_s}'")
|
115
|
+
irc_message = RFlow::Message.new('RFlow::Message::Data::IRC::Message')
|
116
|
+
|
117
|
+
irc_message.data.prefix = prefix
|
118
|
+
irc_message.data.command = cmd
|
119
|
+
irc_message.data.parameters = params
|
120
|
+
|
121
|
+
processing_event.context = signature.to_s
|
122
|
+
processing_event.completed_at = Time.now.utc
|
123
|
+
irc_message.provenance << processing_event
|
124
|
+
|
125
|
+
client.from_server.send_message irc_message
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def unbind(reason=nil)
|
131
|
+
if @connected or @reconnecting
|
132
|
+
RFlow.logger.error("Disconnected from IRC server #{client.config['server']}:#{client.config['port']} due to '#{reason}', reconnecting ...")
|
133
|
+
EM.add_timer(client.config['reconnect_interval']) do
|
134
|
+
RFlow.logger.error "Attempting reconnect to IRC server #{client.config['server']}:#{client.config['port']}"
|
135
|
+
reconnect(client.config['server'], client.config['port'])
|
136
|
+
end
|
137
|
+
@connected = false
|
138
|
+
@reconnecting = true
|
139
|
+
else
|
140
|
+
error_message = "Unable to connect to IRC server #{client.config['server']}:#{client.config['port']} due to '#{reason}'"
|
141
|
+
RFlow.logger.error error_message
|
142
|
+
raise RuntimeError, error_message
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def parse_irc_line(line)
|
148
|
+
match = IRC_LINE_REGEX.match(line)
|
149
|
+
unless match
|
150
|
+
RFlow.logger.error "Error parsing IRC line '#{line}'"
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
prefix, cmd, param_string = match[1..3]
|
155
|
+
|
156
|
+
param_string, trailing_param = param_string.split(' :', 1)
|
157
|
+
params = param_string.split(' ')
|
158
|
+
params << trailing_param
|
159
|
+
|
160
|
+
[prefix, cmd, params]
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
def send_irc_message(irc_message)
|
165
|
+
RFlow.logger.debug "Sending an IRC message to #{client_ip}:#{client_port}"
|
166
|
+
|
167
|
+
command irc_message.data.command, irc_message.data.parameters, irc_message.data.prefix
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
def send_irc_line(line)
|
172
|
+
RFlow.logger.debug "Sending line '#{line}'"
|
173
|
+
send_data "#{line}\r\n"
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
def privmsg(nick, msg)
|
178
|
+
msg.split("\n").each do |msg_line|
|
179
|
+
command("PRIVMSG #{nick} :#{msg_line}")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def command(cmd, args=[], prefix=nil)
|
185
|
+
RFlow.logger.debug("command: '#{cmd}' with args ['#{args.join("', '")}'] and prefix '#{prefix}'")
|
186
|
+
line = ''
|
187
|
+
if prefix
|
188
|
+
line << ":#{prefix} "
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
line << cmd.upcase
|
193
|
+
|
194
|
+
last_arg = args.pop
|
195
|
+
unless args.empty?
|
196
|
+
line << " #{args.join ' '}"
|
197
|
+
end
|
198
|
+
|
199
|
+
if last_arg =~ /\s/
|
200
|
+
line << ' :' << last_arg
|
201
|
+
else
|
202
|
+
line << ' ' << last_arg
|
203
|
+
end
|
204
|
+
|
205
|
+
send_irc_line line
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class RFlow
|
2
|
+
module Components
|
3
|
+
module IRC
|
4
|
+
|
5
|
+
# The set of extensions to add capability to IRC data types
|
6
|
+
module Extensions
|
7
|
+
|
8
|
+
module IRCMessageExtension
|
9
|
+
def self.extended(base_data)
|
10
|
+
base_data.data_object ||= {'prefix' => nil, 'command' => 'PRIVMSG', 'parameters' => []}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Default accessors
|
14
|
+
['prefix', 'command', 'parameters'].each do |name|
|
15
|
+
define_method name do |*args|
|
16
|
+
data_object[name]
|
17
|
+
end
|
18
|
+
define_method :"#{name}=" do |*args|
|
19
|
+
data_object[name] = args.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rflow/components/irc/extensions'
|
2
|
+
require 'rflow/components/irc/client'
|
3
|
+
|
4
|
+
class RFlow
|
5
|
+
module Components
|
6
|
+
module IRC
|
7
|
+
# Load the schemas
|
8
|
+
SCHEMA_DIRECTORY = ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'schema'))
|
9
|
+
|
10
|
+
SCHEMA_FILES = {
|
11
|
+
'irc_message.avsc' => 'RFlow::Message::Data::IRC::Message',
|
12
|
+
}
|
13
|
+
|
14
|
+
SCHEMA_FILES.each do |file_name, data_type_name|
|
15
|
+
schema_string = ::File.read(::File.join(SCHEMA_DIRECTORY, file_name))
|
16
|
+
RFlow::Configuration.add_available_data_type data_type_name, 'avro', schema_string
|
17
|
+
end
|
18
|
+
|
19
|
+
# Load the data extensions
|
20
|
+
RFlow::Configuration.add_available_data_extension('RFlow::Message::Data::IRC::Message',
|
21
|
+
RFlow::Components::IRC::Extensions::IRCMessageExtension)
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rflow/components/irc/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rflow-components-irc"
|
7
|
+
s.version = RFlow::Components::IRC::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.required_ruby_version = '>= 1.9'
|
10
|
+
s.authors = ["Michael L. Artz"]
|
11
|
+
s.email = ["michael.artz@redjack.com"]
|
12
|
+
s.homepage = "https://github.com/redjack/rflow-components-irc"
|
13
|
+
s.summary = %q{IRC client and server components for the RFlow FBP framework}
|
14
|
+
s.description = %q{IRC client and server components for the RFlow FBP framework. Also includes the necessary message types}
|
15
|
+
|
16
|
+
s.rubyforge_project = "rflow-components-irc"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency 'rflow', '~> 0.0.1'
|
24
|
+
|
25
|
+
s.add_development_dependency 'rspec', '~> 2.5.0'
|
26
|
+
s.add_development_dependency 'rake', '~> 0.8.7'
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"type": "record",
|
3
|
+
"name": "Message",
|
4
|
+
"namespace": "org.rflow.message.data.irc",
|
5
|
+
"aliases": [],
|
6
|
+
"fields": [
|
7
|
+
{"name": "client_ip", "type": ["string", "null"]},
|
8
|
+
{"name": "client_port", "type": ["int", "null"]},
|
9
|
+
{"name": "server_ip", "type": ["string", "null"]},
|
10
|
+
{"name": "server_port", "type": ["int", "null"]},
|
11
|
+
|
12
|
+
{"name": "prefix", "type": ["string", "null"]},
|
13
|
+
{"name": "command", "type": "string"},
|
14
|
+
{"name": "parameters", "type": {"type": "array", "items": ["bytes", "null"]}}
|
15
|
+
]
|
16
|
+
}
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
# describe RFlow::Components::File::Extensions::FileExtension do
|
4
|
+
# before(:each) do
|
5
|
+
# @schema_string = RFlow::Configuration.available_data_types['RFlow::Message::Data::File']['avro']
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# it "should add the extension to RFlow::Configuration" do
|
9
|
+
# RFlow::Configuration.available_data_extensions['RFlow::Message::Data::File'].should include(described_class)
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# it "should set the defaults" do
|
13
|
+
# file = RFlow::Message.new('RFlow::Message::Data::File')
|
14
|
+
#
|
15
|
+
# file.data.path.should == '/'
|
16
|
+
# file.data.size.should == 0
|
17
|
+
# file.data.content.should == ''
|
18
|
+
# file.data.creation_timestamp.should == nil
|
19
|
+
# file.data.modification_timestamp.should == nil
|
20
|
+
# file.data.accessed_timestamp.should == nil
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# it "should correctly use integers or strings for size field" do
|
24
|
+
# file = RFlow::Message.new('RFlow::Message::Data::File')
|
25
|
+
#
|
26
|
+
# file.data.size.should == 0
|
27
|
+
# file.data.size = 10
|
28
|
+
# file.data.size.should == 10
|
29
|
+
# file.data.size = '20'
|
30
|
+
# file.data.size == 20
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# it "should correctly use Time or xmlschema strings for timestamp fields" do
|
34
|
+
# file = RFlow::Message.new('RFlow::Message::Data::File')
|
35
|
+
#
|
36
|
+
# file.data.creation_timestamp.should == nil
|
37
|
+
# now = Time.now
|
38
|
+
#
|
39
|
+
# file.data.creation_timestamp = now
|
40
|
+
# file.data.creation_timestamp.should == Time.xmlschema(now.xmlschema(9))
|
41
|
+
#
|
42
|
+
# file.data.creation_timestamp = now.xmlschema
|
43
|
+
# file.data.creation_timestamp.should == Time.xmlschema(now.xmlschema)
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# end
|
data/spec/schema_spec.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe 'RFlow::Message::Data::IRC::Message Avro Schema' do
|
4
|
+
before(:each) do
|
5
|
+
@schema_string = RFlow::Configuration.available_data_types['RFlow::Message::Data::IRC::Message']['avro']
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should encode and decode an object" do
|
9
|
+
irc_message = {
|
10
|
+
# 'prefix' => nil,
|
11
|
+
'command' => 'PRIVMSG',
|
12
|
+
'parameters' => ['yo yo yo'],
|
13
|
+
}
|
14
|
+
|
15
|
+
expect {encode_avro(@schema_string, irc_message)}.to_not raise_error
|
16
|
+
avro_encoded_irc_message = encode_avro(@schema_string, irc_message)
|
17
|
+
|
18
|
+
expect {decode_avro(@schema_string, avro_encoded_irc_message)}.to_not raise_error
|
19
|
+
decoded_irc_message = decode_avro(@schema_string, avro_encoded_irc_message)
|
20
|
+
|
21
|
+
decoded_irc_message['prefix'].should == irc_message['prefix']
|
22
|
+
decoded_irc_message['command'].should == irc_message['command']
|
23
|
+
decoded_irc_message['parameters'].should == irc_message['parameters']
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'rflow-components-irc'))
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
def decode_avro(schema_string, serialized_object)
|
6
|
+
schema = Avro::Schema.parse(schema_string)
|
7
|
+
serialized_object.force_encoding 'BINARY'
|
8
|
+
sio = StringIO.new(serialized_object)
|
9
|
+
Avro::IO::DatumReader.new(schema, schema).read Avro::IO::BinaryDecoder.new(sio)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encode_avro(schema_string, object)
|
13
|
+
encoded_string = ''
|
14
|
+
encoded_string.force_encoding 'BINARY'
|
15
|
+
schema = Avro::Schema.parse(schema_string)
|
16
|
+
sio = StringIO.new(encoded_string)
|
17
|
+
Avro::IO::DatumWriter.new(schema).write object, Avro::IO::BinaryEncoder.new(sio)
|
18
|
+
encoded_string
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rflow-components-irc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael L. Artz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rflow
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.0.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.0.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.5.0
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.5.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.8.7
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7
|
62
|
+
description: IRC client and server components for the RFlow FBP framework. Also includes
|
63
|
+
the necessary message types
|
64
|
+
email:
|
65
|
+
- michael.artz@redjack.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- Rakefile
|
73
|
+
- lib/rflow-components-irc.rb
|
74
|
+
- lib/rflow/components/irc.rb
|
75
|
+
- lib/rflow/components/irc/client.rb
|
76
|
+
- lib/rflow/components/irc/extensions.rb
|
77
|
+
- lib/rflow/components/irc/version.rb
|
78
|
+
- rflow-components-irc.gemspec
|
79
|
+
- schema/irc_message.avsc
|
80
|
+
- spec/extensions_spec.rb
|
81
|
+
- spec/schema_spec.rb
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: https://github.com/redjack/rflow-components-irc
|
84
|
+
licenses: []
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '1.9'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project: rflow-components-irc
|
103
|
+
rubygems_version: 1.8.24
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: IRC client and server components for the RFlow FBP framework
|
107
|
+
test_files:
|
108
|
+
- spec/extensions_spec.rb
|
109
|
+
- spec/schema_spec.rb
|
110
|
+
- spec/spec_helper.rb
|