xrc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +34 -0
- data/Rakefile +2 -0
- data/lib/xrc.rb +43 -0
- data/lib/xrc/client.rb +318 -0
- data/lib/xrc/connection.rb +40 -0
- data/lib/xrc/connection/connector.rb +42 -0
- data/lib/xrc/connection/tsl_connector.rb +37 -0
- data/lib/xrc/elements/auth.rb +41 -0
- data/lib/xrc/elements/bind.rb +18 -0
- data/lib/xrc/elements/join.rb +20 -0
- data/lib/xrc/elements/message.rb +20 -0
- data/lib/xrc/elements/ping.rb +21 -0
- data/lib/xrc/elements/presence.rb +9 -0
- data/lib/xrc/elements/roster.rb +13 -0
- data/lib/xrc/elements/session.rb +13 -0
- data/lib/xrc/elements/starttls.rb +10 -0
- data/lib/xrc/elements/stream.rb +22 -0
- data/lib/xrc/hosts_resolver.rb +43 -0
- data/lib/xrc/jid.rb +44 -0
- data/lib/xrc/message_builder.rb +62 -0
- data/lib/xrc/messages/base.rb +37 -0
- data/lib/xrc/messages/message.rb +29 -0
- data/lib/xrc/messages/null.rb +6 -0
- data/lib/xrc/messages/private_message.rb +6 -0
- data/lib/xrc/messages/room_message.rb +6 -0
- data/lib/xrc/messages/subject.rb +29 -0
- data/lib/xrc/method_loggable.rb +22 -0
- data/lib/xrc/namespaces.rb +11 -0
- data/lib/xrc/parser.rb +89 -0
- data/lib/xrc/roster.rb +28 -0
- data/lib/xrc/socket.rb +7 -0
- data/lib/xrc/user.rb +27 -0
- data/lib/xrc/version.rb +3 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/xrc/client_spec.rb +75 -0
- data/spec/xrc/jid_spec.rb +35 -0
- data/xrc.gemspec +24 -0
- metadata +158 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Xrc
|
2
|
+
module Messages
|
3
|
+
class Base
|
4
|
+
# @return [REXML::Element] Raw element object
|
5
|
+
attr_reader :element
|
6
|
+
|
7
|
+
# @param [REXML::Element] element A message element
|
8
|
+
def initialize(element)
|
9
|
+
@element = element
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a JID of message sender
|
13
|
+
# @return [String]
|
14
|
+
# @example
|
15
|
+
# message.from #=> "alice@example.com"
|
16
|
+
def from
|
17
|
+
@element.attribute("from").to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns a JID of message address
|
21
|
+
# @return [String]
|
22
|
+
# @example
|
23
|
+
# message.to #=> "bob@example.com"
|
24
|
+
def to
|
25
|
+
@element.attribute("to").to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the type of the message
|
29
|
+
# @return [String]
|
30
|
+
# @example
|
31
|
+
# message.type #=> "groupchat"
|
32
|
+
def type
|
33
|
+
@element.attribute("type").to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Xrc
|
2
|
+
module Messages
|
3
|
+
class Message < Base
|
4
|
+
# Returns the message body (e.g. Hello)
|
5
|
+
# @return [String]
|
6
|
+
# @example
|
7
|
+
# message.body #=> "Hello"
|
8
|
+
def body
|
9
|
+
@element.elements["body/text()"].to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns this message in Hash format
|
13
|
+
# @return [Hash]
|
14
|
+
# @example
|
15
|
+
# message.to_hash #=> {
|
16
|
+
# :body => "bob@example.com",
|
17
|
+
# :from => "alice@example.com",
|
18
|
+
# :to => "bob@example.com",
|
19
|
+
# }
|
20
|
+
def to_hash
|
21
|
+
{
|
22
|
+
body: body,
|
23
|
+
from: from,
|
24
|
+
to: to,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Xrc
|
2
|
+
module Messages
|
3
|
+
class Subject < Base
|
4
|
+
# Returns the message subject (e.g. Room1)
|
5
|
+
# @return [String]
|
6
|
+
# @example
|
7
|
+
# message.subject #=> "Room1"
|
8
|
+
def subject
|
9
|
+
@element.elements["subject/text()"].to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns this message in Hash format
|
13
|
+
# @return [Hash]
|
14
|
+
# @example
|
15
|
+
# message.to_hash #=> {
|
16
|
+
# :from => "alice@example.com",
|
17
|
+
# :subject => "Room1",
|
18
|
+
# :to => "bob@example.com",
|
19
|
+
# }
|
20
|
+
def to_hash
|
21
|
+
{
|
22
|
+
from: from,
|
23
|
+
to: to,
|
24
|
+
subject: subject,
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "active_support/core_ext/module/aliasing"
|
2
|
+
require "active_support/logger"
|
3
|
+
|
4
|
+
module Xrc
|
5
|
+
module MethodLoggable
|
6
|
+
class << self
|
7
|
+
attr_writer :logger
|
8
|
+
|
9
|
+
def logger
|
10
|
+
@logger ||= ActiveSupport::Logger.new(STDOUT)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def log(method_name, &block)
|
15
|
+
define_method("#{method_name}_with_log") do |*args|
|
16
|
+
Xrc::MethodLoggable.logger.info(instance_exec(*args, &block))
|
17
|
+
__send__("#{method_name}_without_log", *args)
|
18
|
+
end
|
19
|
+
alias_method_chain method_name, :log
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Xrc
|
2
|
+
module Namespaces
|
3
|
+
BIND = "urn:ietf:params:xml:ns:xmpp-bind"
|
4
|
+
MUC = "http://jabber.org/protocol/muc"
|
5
|
+
PING = "urn:xmpp:ping"
|
6
|
+
ROSTER = "jabber:iq:roster"
|
7
|
+
SASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
8
|
+
SESSION = "urn:ietf:params:xml:ns:xmpp-session"
|
9
|
+
TLS = "urn:ietf:params:xml:ns:xmpp-tls"
|
10
|
+
end
|
11
|
+
end
|
data/lib/xrc/parser.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module Xrc
|
2
|
+
class Parser < REXML::Parsers::SAX2Parser
|
3
|
+
EVENTS = [
|
4
|
+
:cdata,
|
5
|
+
:characters,
|
6
|
+
:end_document,
|
7
|
+
:end_element,
|
8
|
+
:start_element,
|
9
|
+
]
|
10
|
+
|
11
|
+
attr_accessor :current
|
12
|
+
|
13
|
+
attr_reader :block, :options
|
14
|
+
|
15
|
+
def initialize(options, &block)
|
16
|
+
super(options[:socket])
|
17
|
+
@block = block
|
18
|
+
bind
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def bind
|
24
|
+
EVENTS.each do |event|
|
25
|
+
listen(event) do |*args|
|
26
|
+
send(event, *args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def cdata(text)
|
32
|
+
if current
|
33
|
+
cdata = REXML::CData.new(text)
|
34
|
+
current.add(cdata)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def characters(text)
|
39
|
+
if current
|
40
|
+
text = REXML::Text.new(text, current.whitespace, nil, true)
|
41
|
+
current.add(text)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def end_document
|
46
|
+
end
|
47
|
+
|
48
|
+
def end_element(uri, localname, qname)
|
49
|
+
consume if has_current? && !has_parent?
|
50
|
+
pop
|
51
|
+
end
|
52
|
+
|
53
|
+
def start_element(uri, localname, qname, attributes)
|
54
|
+
element = REXML::Element.new(qname)
|
55
|
+
element.add_attributes(attributes)
|
56
|
+
if qname == "stream:stream"
|
57
|
+
consume(element)
|
58
|
+
else
|
59
|
+
push(element)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def push(element)
|
64
|
+
if current
|
65
|
+
self.current = current.add_element(element)
|
66
|
+
else
|
67
|
+
self.current = element
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def pop
|
72
|
+
if current
|
73
|
+
self.current = current.parent
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def consume(element = current)
|
78
|
+
block.call(element)
|
79
|
+
end
|
80
|
+
|
81
|
+
def has_current?
|
82
|
+
!!current
|
83
|
+
end
|
84
|
+
|
85
|
+
def has_parent?
|
86
|
+
!current.parent.nil?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/xrc/roster.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Xrc
|
2
|
+
class Roster
|
3
|
+
# @param [REXML::Element] element An element of the response of roster requirement
|
4
|
+
def initialize(element)
|
5
|
+
@element = element
|
6
|
+
end
|
7
|
+
|
8
|
+
# Find a Xrc::User object from its JID
|
9
|
+
# @param [String] jid JID
|
10
|
+
# @return [Xrc::User]
|
11
|
+
# @return [nil]
|
12
|
+
def [](jid)
|
13
|
+
users.find {|user| user.jid == jid }
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def users
|
19
|
+
@users ||= @element.elements.collect("query/item") do |item|
|
20
|
+
User.new(
|
21
|
+
jid: item.attribute("jid").to_s,
|
22
|
+
mention_name: item.attribute("mention_name").to_s,
|
23
|
+
name: item.attribute("name").to_s,
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/xrc/socket.rb
ADDED
data/lib/xrc/user.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Xrc
|
2
|
+
class User
|
3
|
+
# @option attributes [String] :jid JID
|
4
|
+
# @option attributes [String] :mention_name Mention name
|
5
|
+
# @option attributes [String] :name Full name
|
6
|
+
# @example
|
7
|
+
# Xrc::Client.new(jid: "alice@example.com", mention_name: "alice", name: "Alice Liddel")
|
8
|
+
def initialize(attributes)
|
9
|
+
@attributes = attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [Xrc::Jid] JID represented in a Xrc::Jid object
|
13
|
+
def jid
|
14
|
+
@jid ||= Jid.new(@attributes[:jid])
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String] Mention name
|
18
|
+
def mention_name
|
19
|
+
@attributes[:mention_name]
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String] Full name
|
23
|
+
def name
|
24
|
+
@attributes[:name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/xrc/version.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "active_support/core_ext/string/strip"
|
3
|
+
require "stringio"
|
4
|
+
|
5
|
+
describe Xrc::Client do
|
6
|
+
after do
|
7
|
+
server.close
|
8
|
+
end
|
9
|
+
|
10
|
+
let!(:server) do
|
11
|
+
TCPServer.new(port)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:instance) do
|
15
|
+
described_class.new(*args)
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:args) do
|
19
|
+
[options]
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:options) do
|
23
|
+
{
|
24
|
+
jid: jid,
|
25
|
+
port: port,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
let(:port) do
|
30
|
+
5222
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:jid) do
|
34
|
+
"#{node}@#{domain}/#{resource}"
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:node) do
|
38
|
+
"alice"
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:domain) do
|
42
|
+
"localhost"
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:resource) do
|
46
|
+
"bot"
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:socket) do
|
50
|
+
StringIO.new <<-EOS.strip_heredoc
|
51
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
52
|
+
<stream:stream
|
53
|
+
from='#{domain}'
|
54
|
+
id='5d29a171a9472e73'
|
55
|
+
xmlns:stream='http://etherx.jabber.org/streams'
|
56
|
+
version='1.0'
|
57
|
+
xmlns='jabber:client'>
|
58
|
+
<stream:features>
|
59
|
+
<starttls xmlns='#{Namespaces::TLS}'/>
|
60
|
+
<required/>
|
61
|
+
</stream:features>
|
62
|
+
EOS
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#run" do
|
66
|
+
before do
|
67
|
+
pending
|
68
|
+
instance.stub(socket: socket)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "parses received XML message" do
|
72
|
+
instance.run
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Xrc::Jid do
|
4
|
+
let(:instance) do
|
5
|
+
described_class.new(*args)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:args) do
|
9
|
+
[jid]
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:jid) do
|
13
|
+
"#{node}@#{domain}/#{resource}"
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:node) do
|
17
|
+
"alice"
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:domain) do
|
21
|
+
"example.com"
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:resource) do
|
25
|
+
"bot"
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#initialize" do
|
29
|
+
it "parses node, domain, resource sections" do
|
30
|
+
instance.node.should == node
|
31
|
+
instance.domain.should == domain
|
32
|
+
instance.resource.should == resource
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|