jacha 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +49 -0
- data/Rakefile +1 -0
- data/config.ru +12 -0
- data/jacha.gemspec +21 -0
- data/lib/jacha/connection.rb +96 -0
- data/lib/jacha/connection_pool.rb +71 -0
- data/lib/jacha/server.rb +18 -0
- data/lib/jacha/version.rb +3 -0
- data/lib/jacha.rb +9 -0
- data/lib/xmpp4r_monkeypatch.rb +29 -0
- metadata +74 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
## What is this?
|
2
|
+
|
3
|
+
Jacha is a xmpp4r based bot. Currently, it only handles XMPP connection pool and checks whether given JID is online.
|
4
|
+
Also, it can be started as a dedicated service.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
gem 'jacha'
|
9
|
+
|
10
|
+
## Configuration
|
11
|
+
|
12
|
+
Put somewhere in your initializers the following code:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
Jacha.configure do |config|
|
16
|
+
config.jid = 'jid@example.com'
|
17
|
+
config.password = 'password'
|
18
|
+
config.size = 3
|
19
|
+
# uncomment to apply charset related xmpp4r monkeypatch
|
20
|
+
# config.fix_charset!
|
21
|
+
end
|
22
|
+
|
23
|
+
if some_environment_specific_condition
|
24
|
+
Jacha::ConnectionPool.spawn
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
Then you anytime can get a random connection from the pool and perform some actions.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
jacha_connection = Jacha::ConnectionPool.get_connection
|
32
|
+
jacha_connection.jabber # here is wrapped Jabber::Client from xmpp4r
|
33
|
+
jacha_connection.online? 'someone@example.com'
|
34
|
+
jacha_connection.online? 'another@example.com', optional_timeout_in_seconds
|
35
|
+
```
|
36
|
+
|
37
|
+
Credits
|
38
|
+
-------
|
39
|
+
|
40
|
+
<img src="http://roundlake.ru/assets/logo.png" align="right" />
|
41
|
+
|
42
|
+
* Alexander Pavlenko ([@alerticus](http://twitter.com/#!/alerticus))
|
43
|
+
|
44
|
+
<br/>
|
45
|
+
|
46
|
+
LICENSE
|
47
|
+
-------
|
48
|
+
|
49
|
+
It is free software, and may be redistributed under the terms of MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/config.ru
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
|
3
|
+
require 'jacha'
|
4
|
+
require 'jacha/server'
|
5
|
+
|
6
|
+
config = ::File.expand_path(ENV['JACHACONFIG'] || 'jacha.rb')
|
7
|
+
if ::File.exists?(config)
|
8
|
+
load config
|
9
|
+
end
|
10
|
+
|
11
|
+
use Rack::ShowExceptions
|
12
|
+
run Jacha::Server.new
|
data/jacha.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "jacha/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "jacha"
|
7
|
+
s.version = Jacha::VERSION
|
8
|
+
s.authors = ["AlexanderPavlenko"]
|
9
|
+
s.email = ["a.pavlenko@roundlake.ru"]
|
10
|
+
s.homepage = "http://github.com/roundlake/jacha"
|
11
|
+
s.summary = %q{Simple xmpp4r bot}
|
12
|
+
s.description = %q{xmpp4r bot that can be included to project as well as started as a standalone service}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
# s.add_development_dependency "rspec"
|
20
|
+
s.add_runtime_dependency "xmpp4r"
|
21
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'xmpp4r'
|
2
|
+
|
3
|
+
module Jacha
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
attr_reader :jabber
|
7
|
+
attr_accessor :pool
|
8
|
+
|
9
|
+
def initialize(jid, password)
|
10
|
+
@password = password
|
11
|
+
@jabber = Jabber::Client.new "#{jid}/#{Time.now.to_f}"
|
12
|
+
@jabber.on_exception do
|
13
|
+
unless broken?
|
14
|
+
broken!
|
15
|
+
logger.warn "#{Time.now}: broken XmppConnection: #{self}"
|
16
|
+
destroy
|
17
|
+
pool.respawn
|
18
|
+
end
|
19
|
+
end
|
20
|
+
connect!
|
21
|
+
@pinger = Thread.new do
|
22
|
+
while true
|
23
|
+
if connected?
|
24
|
+
sleep 180
|
25
|
+
online!
|
26
|
+
else
|
27
|
+
connect!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def connect!
|
34
|
+
@jabber.connect
|
35
|
+
@jabber.auth @password
|
36
|
+
online!
|
37
|
+
end
|
38
|
+
|
39
|
+
def online!(&block)
|
40
|
+
packet = Jabber::Presence.new
|
41
|
+
packet.from = @jabber.jid
|
42
|
+
@jabber.send packet, &block
|
43
|
+
end
|
44
|
+
|
45
|
+
def connected?
|
46
|
+
@jabber.is_connected?
|
47
|
+
end
|
48
|
+
|
49
|
+
def online?(jid, timeout=1.5)
|
50
|
+
# Only works if our bot is authorized by the given JID
|
51
|
+
# see Presence with type :subscribe for more details
|
52
|
+
# Also, bot should be online by itself
|
53
|
+
jid = Jabber::JID.new(jid)
|
54
|
+
pinger = Thread.new do
|
55
|
+
pinger[:online] = nil
|
56
|
+
packet = Jabber::Presence.new
|
57
|
+
packet.to = jid
|
58
|
+
packet.from = @jabber.jid
|
59
|
+
packet.type = :probe
|
60
|
+
@jabber.send(packet) do |presence|
|
61
|
+
from = Jabber::JID.new presence.from
|
62
|
+
if from.node == jid.node && from.domain == jid.domain
|
63
|
+
if presence.type.nil?
|
64
|
+
pinger[:online] = true
|
65
|
+
pinger.stop
|
66
|
+
elsif presence.type == :error
|
67
|
+
pinger.stop
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
pinger.join timeout
|
73
|
+
result = pinger[:online]
|
74
|
+
pinger.kill
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
def destroy
|
79
|
+
broken!
|
80
|
+
@pinger.kill
|
81
|
+
@jabber.close
|
82
|
+
end
|
83
|
+
|
84
|
+
def broken!
|
85
|
+
@broken = true
|
86
|
+
end
|
87
|
+
|
88
|
+
def broken?
|
89
|
+
@broken
|
90
|
+
end
|
91
|
+
|
92
|
+
def logger
|
93
|
+
pool.logger
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Jacha
|
2
|
+
class ConnectionPool
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
attr_accessor :jid, :password, :size, :logger
|
6
|
+
|
7
|
+
def pool
|
8
|
+
@connections ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def size
|
12
|
+
@size ||= 3
|
13
|
+
end
|
14
|
+
|
15
|
+
def logger
|
16
|
+
@logger ||= Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_connection
|
20
|
+
pool.sample
|
21
|
+
end
|
22
|
+
|
23
|
+
def spawn(number=nil)
|
24
|
+
(number || size).times do
|
25
|
+
logger.warn "#{Time.now}: Spawning XmppConnection"
|
26
|
+
spawner = Thread.new do
|
27
|
+
begin
|
28
|
+
connection = Connection.new @jid, @password
|
29
|
+
spawner[:connection] = connection
|
30
|
+
rescue => ex
|
31
|
+
logger.warn "#{Time.now}: Error on XmppConnection spawn: #{ex}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
spawner.join 7
|
35
|
+
connection = spawner[:connection]
|
36
|
+
spawner.kill
|
37
|
+
if connection && connection.connected?
|
38
|
+
connection.pool = self
|
39
|
+
pool << connection
|
40
|
+
logger.warn "#{Time.now}: XmppConnection spawned: #{connection}"
|
41
|
+
else
|
42
|
+
logger.warn "#{Time.now}: XmppConnection spawn failed. Retrying in 7 seconds."
|
43
|
+
sleep 7
|
44
|
+
spawn 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def respawn
|
50
|
+
pool.delete_if &:broken?
|
51
|
+
spawn @size - pool.size
|
52
|
+
end
|
53
|
+
|
54
|
+
def destroy
|
55
|
+
pool.map &:destroy
|
56
|
+
pool.clear
|
57
|
+
end
|
58
|
+
|
59
|
+
def fix_charset!
|
60
|
+
require_relative '../xmpp4r_monkeypatch'
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.method_missing(sym, *args, &block)
|
64
|
+
if instance.respond_to? sym
|
65
|
+
instance.send(sym, *args, &block)
|
66
|
+
else
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/jacha/server.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'sinatra'
|
3
|
+
|
4
|
+
module Jacha
|
5
|
+
class Server < Sinatra::Application
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super
|
9
|
+
ConnectionPool.instance.spawn
|
10
|
+
end
|
11
|
+
|
12
|
+
get '/check' do
|
13
|
+
checker = ConnectionPool.instance.get_connection
|
14
|
+
result = checker.online? params['jid']
|
15
|
+
"#{!!result}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/jacha.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
if RUBY_VERSION >= '1.9'
|
2
|
+
# Encoding patch
|
3
|
+
# see https://github.com/ln/xmpp4r/issues/3#issuecomment-1739952
|
4
|
+
require 'socket'
|
5
|
+
class TCPSocket
|
6
|
+
def external_encoding
|
7
|
+
Encoding::BINARY
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'rexml/source'
|
12
|
+
class REXML::IOSource
|
13
|
+
alias_method :encoding_assign, :encoding=
|
14
|
+
def encoding=(value)
|
15
|
+
encoding_assign(value) if value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
begin
|
20
|
+
# OpenSSL is optional and can be missing
|
21
|
+
require 'openssl'
|
22
|
+
class OpenSSL::SSL::SSLSocket
|
23
|
+
def external_encoding
|
24
|
+
Encoding::BINARY
|
25
|
+
end
|
26
|
+
end
|
27
|
+
rescue
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jacha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- AlexanderPavlenko
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: xmpp4r
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
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'
|
30
|
+
description: xmpp4r bot that can be included to project as well as started as a standalone
|
31
|
+
service
|
32
|
+
email:
|
33
|
+
- a.pavlenko@roundlake.ru
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- config.ru
|
43
|
+
- jacha.gemspec
|
44
|
+
- lib/jacha.rb
|
45
|
+
- lib/jacha/connection.rb
|
46
|
+
- lib/jacha/connection_pool.rb
|
47
|
+
- lib/jacha/server.rb
|
48
|
+
- lib/jacha/version.rb
|
49
|
+
- lib/xmpp4r_monkeypatch.rb
|
50
|
+
homepage: http://github.com/roundlake/jacha
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.8.18
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Simple xmpp4r bot
|
74
|
+
test_files: []
|