xrc 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.
- 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
|