joggle 0.1.0
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/COPYING +20 -0
- data/README +212 -0
- data/Rakefile +120 -0
- data/TODO +36 -0
- data/bin/joggle +6 -0
- data/lib/joggle/Session.vim +1223 -0
- data/lib/joggle/cli/option-parser.rb +139 -0
- data/lib/joggle/cli/runner.rb +47 -0
- data/lib/joggle/commands.rb +163 -0
- data/lib/joggle/config-parser.rb +37 -0
- data/lib/joggle/engine.rb +276 -0
- data/lib/joggle/jabber/client.rb +82 -0
- data/lib/joggle/pablotron/cache.rb +131 -0
- data/lib/joggle/pablotron/observable.rb +104 -0
- data/lib/joggle/runner/pstore.rb +252 -0
- data/lib/joggle/store/pstore/all.rb +26 -0
- data/lib/joggle/store/pstore/cache.rb +65 -0
- data/lib/joggle/store/pstore/message.rb +54 -0
- data/lib/joggle/store/pstore/user.rb +96 -0
- data/lib/joggle/twitter/engine.rb +186 -0
- data/lib/joggle/twitter/fetcher.rb +123 -0
- data/lib/joggle/version.rb +6 -0
- data/setup.rb +1596 -0
- data/test/test_cli.rb +10 -0
- data/test/test_runner.rb +10 -0
- metadata +131 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'joggle/pablotron/observable'
|
2
|
+
require 'xmpp4r'
|
3
|
+
require 'xmpp4r/roster'
|
4
|
+
|
5
|
+
module Joggle
|
6
|
+
module Jabber
|
7
|
+
#
|
8
|
+
# Simple XMPP client.
|
9
|
+
#
|
10
|
+
class Client
|
11
|
+
include Joggle::Pablotron::Observable
|
12
|
+
|
13
|
+
DEFAULTS = {
|
14
|
+
'jabber.client.debug' => false,
|
15
|
+
}
|
16
|
+
|
17
|
+
#
|
18
|
+
# Create a new Jabber::Client object.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
#
|
22
|
+
# # create new client object
|
23
|
+
# client = Client.new('foo@example.com', 'mysekretpassword')
|
24
|
+
#
|
25
|
+
def initialize(user, pass, opt = {})
|
26
|
+
# parse options
|
27
|
+
@opt = DEFAULTS.merge(opt || {})
|
28
|
+
|
29
|
+
# enable debugging to stdout
|
30
|
+
if @opt['jabber.client.debug']
|
31
|
+
::Jabber.debug = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# FIXME: this belongs elsewhere
|
35
|
+
Thread.abort_on_exception = false
|
36
|
+
|
37
|
+
# create new jid and client
|
38
|
+
jid = ::Jabber::JID.new(user)
|
39
|
+
available = ::Jabber::Presence.new.set_type(:available)
|
40
|
+
@client = ::Jabber::Client.new(jid)
|
41
|
+
@client.connect
|
42
|
+
|
43
|
+
@client.auth(pass)
|
44
|
+
@client.send(available)
|
45
|
+
|
46
|
+
roster = ::Jabber::Roster::Helper.new(@client)
|
47
|
+
|
48
|
+
@client.add_message_callback do |msg|
|
49
|
+
next unless msg.type == :chat
|
50
|
+
fire('jabber_client_message', msg)
|
51
|
+
end
|
52
|
+
|
53
|
+
@client.add_presence_callback do |old_p, new_p|
|
54
|
+
fire('jabber_client_presence', old_p, new_p)
|
55
|
+
end
|
56
|
+
|
57
|
+
roster.add_subscription_request_callback do |item, presence|
|
58
|
+
from = presence.from
|
59
|
+
|
60
|
+
if fire('before_jabber_client_accept_subscription', from)
|
61
|
+
roster.accept_subscription(from)
|
62
|
+
fire('jabber_client_accept_subscription', from)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Deliver jabber message to user.
|
69
|
+
#
|
70
|
+
# Example:
|
71
|
+
#
|
72
|
+
# # send message
|
73
|
+
# client.deliver('foo@example.com', 'hey there!')
|
74
|
+
#
|
75
|
+
def deliver(who, body, type = :chat)
|
76
|
+
msg = ::Jabber::Message.new(who, body)
|
77
|
+
msg.type = type
|
78
|
+
@client.send(msg)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'pp' # debug
|
2
|
+
require 'cgi'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'joggle/pablotron/observable'
|
5
|
+
|
6
|
+
module Joggle
|
7
|
+
module Pablotron
|
8
|
+
class Cache
|
9
|
+
include Joggle::Pablotron::Observable
|
10
|
+
|
11
|
+
DEFAULTS = {
|
12
|
+
'user-agent' => "Pablotron-Cacher/0.0.0",
|
13
|
+
}
|
14
|
+
|
15
|
+
def initialize(cache_store, extra_headers = nil)
|
16
|
+
@extras = extra_headers
|
17
|
+
@store = cache_store
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.urlify(base, args = nil, hash = nil)
|
21
|
+
ret = base
|
22
|
+
|
23
|
+
if args && args.size > 0
|
24
|
+
ret = base + '?' + args.map { |k, v|
|
25
|
+
[k, v].map { |s| CGI.escape(s.to_s) }.join('=')
|
26
|
+
}.join('&')
|
27
|
+
end
|
28
|
+
|
29
|
+
if hash
|
30
|
+
ret << '#' + hash
|
31
|
+
end
|
32
|
+
|
33
|
+
# return result
|
34
|
+
ret
|
35
|
+
end
|
36
|
+
|
37
|
+
# delimiter for appending header string to url
|
38
|
+
# (chosen because it won't appear in a valid url)
|
39
|
+
HEADER_DELIM = '://?&#'
|
40
|
+
|
41
|
+
def url_key(url, headers = nil)
|
42
|
+
ret = url
|
43
|
+
|
44
|
+
# append header fragment
|
45
|
+
if headers && headers.size > 0
|
46
|
+
# sort, concatenate, and append headers to url
|
47
|
+
ret += HEADER_DELIM + headers.keys.map { |key|
|
48
|
+
key.downcase
|
49
|
+
}.sort.map { |k|
|
50
|
+
"#{k}:#{headers[k]}"
|
51
|
+
}.join(',')
|
52
|
+
end
|
53
|
+
|
54
|
+
# return results
|
55
|
+
ret
|
56
|
+
end
|
57
|
+
|
58
|
+
def get(url, headers = nil)
|
59
|
+
ret = nil
|
60
|
+
|
61
|
+
# create store key
|
62
|
+
key = url_key(url, headers)
|
63
|
+
|
64
|
+
# build headers
|
65
|
+
opt = expand_headers(headers)
|
66
|
+
|
67
|
+
# if we have an existing cache entry for this url,
|
68
|
+
# then use the last-modified and etag headers
|
69
|
+
if entry = @store.get_cached(key)
|
70
|
+
opt.update({
|
71
|
+
'if-modified-since' => entry['last'].to_s,
|
72
|
+
'if-none-match' => entry['etag'],
|
73
|
+
})
|
74
|
+
end
|
75
|
+
|
76
|
+
# fetch url and handle result
|
77
|
+
begin
|
78
|
+
open(url, opt) do |fh|
|
79
|
+
ret = fh.read
|
80
|
+
|
81
|
+
# update store
|
82
|
+
@store.add_cached(key, {
|
83
|
+
'last' => fh.last_modified.to_s || fh.meta['date'],
|
84
|
+
'etag' => fh.meta['etag'],
|
85
|
+
'data' => ret.to_s.dup,
|
86
|
+
})
|
87
|
+
|
88
|
+
fire('cache_updated', url, ret)
|
89
|
+
end
|
90
|
+
rescue OpenURI::HTTPError => err
|
91
|
+
case err.io.status.first
|
92
|
+
when /^304/
|
93
|
+
# not modified
|
94
|
+
ret = entry['data']
|
95
|
+
fire('cache_not_modified', url)
|
96
|
+
else
|
97
|
+
# unknown status code
|
98
|
+
fire('cache_http_error', url, err.io.status.first, err.io.status.last)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# return result
|
103
|
+
ret
|
104
|
+
end
|
105
|
+
|
106
|
+
def has?(url, headers = nil)
|
107
|
+
key = url_key(url, headers)
|
108
|
+
@store.has_cached?(key)
|
109
|
+
end
|
110
|
+
|
111
|
+
def delete(url, headers = nil)
|
112
|
+
key = url_key(url, headers)
|
113
|
+
@store.delete_cached(key)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def expand_headers(headers = nil)
|
119
|
+
[DEFAULTS, @extras, headers].inject({}) do |ret, hash|
|
120
|
+
if hash && hash.size > 0
|
121
|
+
hash.keys.each do |key|
|
122
|
+
ret[key.downcase] = hash[key]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
ret
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Joggle
|
2
|
+
module Pablotron
|
3
|
+
module Observable
|
4
|
+
class StopEvent < Exception; end
|
5
|
+
|
6
|
+
def on(ev, &block)
|
7
|
+
d = lazy_observable_init
|
8
|
+
|
9
|
+
# get next id and create new handler
|
10
|
+
ret = (d[:next_id] += 1)
|
11
|
+
h = { :id => ret }
|
12
|
+
|
13
|
+
# set handler type
|
14
|
+
if ev.kind_of?(String) && block
|
15
|
+
h[:fn] = block
|
16
|
+
|
17
|
+
# add handler to handler list and id to id lut
|
18
|
+
d[:handlers][ev] << h
|
19
|
+
d[:id_lut][ret] = ev
|
20
|
+
|
21
|
+
elsif !ev.kind_of?(String) && !block
|
22
|
+
h[:obj] = ev
|
23
|
+
d[:object_handlers] << h
|
24
|
+
else
|
25
|
+
raise "missing listener block"
|
26
|
+
end
|
27
|
+
|
28
|
+
# return id
|
29
|
+
ret
|
30
|
+
end
|
31
|
+
|
32
|
+
def fire(ev, *args)
|
33
|
+
d = lazy_observable_init
|
34
|
+
ret = true
|
35
|
+
|
36
|
+
# get handlers for this event
|
37
|
+
handlers = d[:handlers][ev]
|
38
|
+
|
39
|
+
begin
|
40
|
+
if handlers.size > 0
|
41
|
+
handlers.each do |handler|
|
42
|
+
if fn = handler[:fn]
|
43
|
+
# run handler
|
44
|
+
fn.call(self, ev, *args)
|
45
|
+
else
|
46
|
+
# FIXME: do nothing, is this an error?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# get object handlers
|
52
|
+
handlers = d[:object_handlers]
|
53
|
+
|
54
|
+
if handlers.size > 0
|
55
|
+
handlers.each do |handler|
|
56
|
+
if o = handler[:obj]
|
57
|
+
# build method symbol
|
58
|
+
meth = "on_#{ev}".intern
|
59
|
+
|
60
|
+
# check for method
|
61
|
+
if o.respond_to?(meth)
|
62
|
+
o.send(meth, self, *args)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
# FIXME: do nothing, is this an error?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
rescue StopEvent => err
|
70
|
+
fire(ev + '_stopped', err, *args)
|
71
|
+
ret = false
|
72
|
+
end
|
73
|
+
|
74
|
+
# return result
|
75
|
+
ret
|
76
|
+
end
|
77
|
+
|
78
|
+
def un(id)
|
79
|
+
d = lazy_observable_init
|
80
|
+
|
81
|
+
# look in event handlers
|
82
|
+
if ev = d[:id_lut][id]
|
83
|
+
d[:handlers][ev].reject! { |fn| fn[:id] == id }
|
84
|
+
end
|
85
|
+
|
86
|
+
# check object handlers
|
87
|
+
d[:object_handlers].reject! { |o| o[:id] == id }
|
88
|
+
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def lazy_observable_init
|
95
|
+
@__observable_data ||= {
|
96
|
+
:next_id => 0,
|
97
|
+
:handlers => Hash.new { |h, k| h[k] = [] },
|
98
|
+
:object_handlers => [],
|
99
|
+
:id_lut => {},
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
rescue LoadError
|
4
|
+
# ignore missing rubygems
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'pstore'
|
8
|
+
require 'logger'
|
9
|
+
require 'fileutils'
|
10
|
+
require 'joggle/pablotron/cache'
|
11
|
+
require 'joggle/version'
|
12
|
+
require 'joggle/store/pstore/all'
|
13
|
+
require 'joggle/jabber/client'
|
14
|
+
require 'joggle/twitter/fetcher'
|
15
|
+
require 'joggle/twitter/engine'
|
16
|
+
require 'joggle/engine'
|
17
|
+
|
18
|
+
module Joggle
|
19
|
+
module Runner
|
20
|
+
#
|
21
|
+
# Basic PStore-backed runner. Creates all necessary objects from
|
22
|
+
# given config and binds them together.
|
23
|
+
#
|
24
|
+
class PStore
|
25
|
+
PATHS = {
|
26
|
+
'store' => ENV['JOGGLE_STORE_PATH'] || '~/.joggle/joggle.pstore',
|
27
|
+
'log' => ENV['JOGGLE_LOG_PATH'] || '~/.joggle/joggle.log',
|
28
|
+
}
|
29
|
+
|
30
|
+
DEFAULTS = {
|
31
|
+
# store configuration
|
32
|
+
'runner.store.path' => File.expand_path(PATHS['store']),
|
33
|
+
|
34
|
+
# log configuration
|
35
|
+
'runner.log.path' => File.expand_path(PATHS['log']),
|
36
|
+
# FIXME: change to INFO
|
37
|
+
'runner.log.level' => 'INFO',
|
38
|
+
'runner.log.format' => '%Y-%m-%dT%H:%M:%S',
|
39
|
+
|
40
|
+
# cache configuration
|
41
|
+
'runner.cache.headers' => {
|
42
|
+
'user-agent' => "Joggle/#{Joggle::VERSION}",
|
43
|
+
},
|
44
|
+
}
|
45
|
+
|
46
|
+
attr_reader :log, :store, :cache, :fetcher, :tweeter, :client, :engine
|
47
|
+
|
48
|
+
#
|
49
|
+
# Create and run PStore runner object.
|
50
|
+
#
|
51
|
+
def self.run(opt = nil)
|
52
|
+
new(opt).run
|
53
|
+
end
|
54
|
+
|
55
|
+
PATH_KEYS = %w{store log}
|
56
|
+
|
57
|
+
#
|
58
|
+
# Create new PStore runner object from the given options.
|
59
|
+
#
|
60
|
+
def initialize(opt = nil)
|
61
|
+
@opt = DEFAULTS.merge(opt || {})
|
62
|
+
|
63
|
+
# make sure paths exist
|
64
|
+
PATH_KEYS.each do |key|
|
65
|
+
FileUtils.mkdir_p(File.dirname(@opt["runner.#{key}.path"]), {
|
66
|
+
# restict access to owner
|
67
|
+
:mode => 0700
|
68
|
+
})
|
69
|
+
end
|
70
|
+
|
71
|
+
# create logger
|
72
|
+
@log = Logger.new(@opt['runner.log.path'])
|
73
|
+
@log.level = Logger.const_get(@opt['runner.log.level'].upcase)
|
74
|
+
@log.datetime_format = @opt['runner.log.format']
|
75
|
+
@log.info('Log started.')
|
76
|
+
|
77
|
+
# create backing store
|
78
|
+
path = @opt['runner.store.path']
|
79
|
+
@log.debug("Creating backing store \"#{path}\".")
|
80
|
+
pstore = ::PStore.new(path)
|
81
|
+
@store = Store::PStore::All.new(pstore)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Run this runner.
|
86
|
+
#
|
87
|
+
def run
|
88
|
+
# create cache
|
89
|
+
@log.debug('Creating cache.')
|
90
|
+
@cache = Joggle::Pablotron::Cache.new(@store, @opt['runner.cache.headers'])
|
91
|
+
|
92
|
+
# create fetcher
|
93
|
+
@log.debug('Creating twitter fetcher.')
|
94
|
+
@fetcher = Twitter::Fetcher.new(@store, @cache, @opt)
|
95
|
+
|
96
|
+
# create twitter engine
|
97
|
+
@log.debug('Creating twitter engine.')
|
98
|
+
@tweeter = Twitter::Engine.new(@store, @fetcher, @opt)
|
99
|
+
@tweeter.on(self)
|
100
|
+
|
101
|
+
# create jabber client
|
102
|
+
@log.debug('Creating jabber client.')
|
103
|
+
@client = Jabber::Client.new(@opt['jabber.user'], @opt['jabber.pass'], @opt)
|
104
|
+
@client.on(self)
|
105
|
+
|
106
|
+
# create new joggle engine
|
107
|
+
@log.debug('Creating engine.')
|
108
|
+
@engine = Engine.new(@client, @tweeter)
|
109
|
+
@engine.on(self)
|
110
|
+
|
111
|
+
@log.debug('Running engine.')
|
112
|
+
@engine.run
|
113
|
+
end
|
114
|
+
|
115
|
+
#################
|
116
|
+
# log listeners #
|
117
|
+
#################
|
118
|
+
|
119
|
+
#
|
120
|
+
# Log twitter_engine_register_user events.
|
121
|
+
#
|
122
|
+
# Note: This method is a listener for Twitter::Engine objects; you
|
123
|
+
# should never call it directly.
|
124
|
+
#
|
125
|
+
def on_twitter_engine_register_user(e, who, user, pass)
|
126
|
+
pre = '<Twitter::Engine>'
|
127
|
+
@log.info("#{pre} Registering user: #{who} (xmpp) => #{user} (twitter).")
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Log twitter_engine_unregister_user events.
|
132
|
+
#
|
133
|
+
# Note: This method is a listener for Twitter::Engine objects; you
|
134
|
+
# should never call it directly.
|
135
|
+
#
|
136
|
+
def on_twitter_engine_unregister_user(e, who)
|
137
|
+
pre = '<Twitter::Engine>'
|
138
|
+
@log.info("#{pre} Unregistering user: #{who} (xmpp).")
|
139
|
+
end
|
140
|
+
|
141
|
+
#
|
142
|
+
# Log twitter_engine_tweet events.
|
143
|
+
#
|
144
|
+
# Note: This method is a listener for Twitter::Engine objects; you
|
145
|
+
# should never call it directly.
|
146
|
+
#
|
147
|
+
def on_twitter_engine_tweet(e, who, msg)
|
148
|
+
pre = '<Twitter::Engine>'
|
149
|
+
@log.info("#{pre} Tweet: #{who}: #{msg}.")
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Log twitter_engine_update events.
|
154
|
+
#
|
155
|
+
# Note: This method is a listener for Twitter::Engine objects; you
|
156
|
+
# should never call it directly.
|
157
|
+
#
|
158
|
+
def on_twitter_engine_update(e, user)
|
159
|
+
pre = '<Twitter::Engine>'
|
160
|
+
@log.info("#{pre} Updating: #{user['who']}.")
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Log engine_update_error events.
|
165
|
+
#
|
166
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
167
|
+
# should never call it directly.
|
168
|
+
#
|
169
|
+
def on_engine_update_error(e, err)
|
170
|
+
pre = '<Engine>'
|
171
|
+
@log.warn("#{pre} Twitter update failed: #{err}.")
|
172
|
+
end
|
173
|
+
|
174
|
+
#
|
175
|
+
# Log engine_reply events.
|
176
|
+
#
|
177
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
178
|
+
# should never call it directly.
|
179
|
+
#
|
180
|
+
def on_engine_reply(e, who, msg)
|
181
|
+
pre = '<Engine>'
|
182
|
+
@log.info("#{pre} Reply: #{who}: #{msg}.")
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
# Log engine_reply_error events.
|
187
|
+
#
|
188
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
189
|
+
# should never call it directly.
|
190
|
+
#
|
191
|
+
def on_engine_reply_error(e, who, msg, err)
|
192
|
+
pre = '<Engine>'
|
193
|
+
@log.warn("#{pre} Reply Error: Couldn't send reply \"#{msg}\" to #{who}: #{err}.")
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Log engine_idle events (debugging only).
|
198
|
+
#
|
199
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
200
|
+
# should never call it directly.
|
201
|
+
#
|
202
|
+
def on_engine_command(e, who, cmd, arg)
|
203
|
+
pre = '<Engine>'
|
204
|
+
@log.debug("#{pre} Command: #{who}: cmd = #{cmd}, arg = #{arg}.")
|
205
|
+
end
|
206
|
+
|
207
|
+
#
|
208
|
+
# Log engine_command events.
|
209
|
+
#
|
210
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
211
|
+
# should never call it directly.
|
212
|
+
#
|
213
|
+
def on_engine_command(e, who, cmd, arg)
|
214
|
+
pre = '<Engine>'
|
215
|
+
@log.info("#{pre} Command: #{who}: cmd = #{cmd}, arg = #{arg}.")
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# Log engine_message events.
|
220
|
+
#
|
221
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
222
|
+
# should never call it directly.
|
223
|
+
#
|
224
|
+
def on_engine_message(e, who, msg)
|
225
|
+
pre = '<Engine>'
|
226
|
+
@log.info("#{pre} Message: #{who}: #{msg}.")
|
227
|
+
end
|
228
|
+
|
229
|
+
#
|
230
|
+
# Log engine_ignored_message events.
|
231
|
+
#
|
232
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
233
|
+
# should never call it directly.
|
234
|
+
#
|
235
|
+
def on_engine_ignored_message(e, who, msg)
|
236
|
+
pre = '<Engine>'
|
237
|
+
@log.info("#{pre} IGNORED: #{who}: #{msg}.")
|
238
|
+
end
|
239
|
+
|
240
|
+
#
|
241
|
+
# Log engine_ignored_subscription events.
|
242
|
+
#
|
243
|
+
# Note: This method is a listener for Joggle::Engine objects; you
|
244
|
+
# should never call it directly.
|
245
|
+
#
|
246
|
+
def on_engine_ignored_subscription(e, who)
|
247
|
+
pre = '<Engine>'
|
248
|
+
@log.info("#{pre} IGNORED: #{who} (subscription)")
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'joggle/store/pstore/cache'
|
2
|
+
require 'joggle/store/pstore/message'
|
3
|
+
require 'joggle/store/pstore/user'
|
4
|
+
|
5
|
+
module Joggle
|
6
|
+
module Store
|
7
|
+
module PStore
|
8
|
+
#
|
9
|
+
# Wrap all store backends into one object.
|
10
|
+
#
|
11
|
+
class All
|
12
|
+
include Cache
|
13
|
+
include Message
|
14
|
+
include User
|
15
|
+
|
16
|
+
#
|
17
|
+
# Create new Joggle::Store::PStore::All object from given
|
18
|
+
# ::PStore object.
|
19
|
+
#
|
20
|
+
def initialize(store)
|
21
|
+
@store = store
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Joggle
|
4
|
+
module Store
|
5
|
+
module PStore
|
6
|
+
#
|
7
|
+
# Mixin that implements cache store methods for PStore backend.
|
8
|
+
#
|
9
|
+
# Note: You're probably looking for Joggle::Store::PStore::All
|
10
|
+
#
|
11
|
+
module Cache
|
12
|
+
#
|
13
|
+
# Add cache entry.
|
14
|
+
#
|
15
|
+
def add_cached(key, row)
|
16
|
+
key = cache_store_key(key)
|
17
|
+
|
18
|
+
@store.transaction do |s|
|
19
|
+
s[key] = {}.merge(row)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Get cache entry.
|
25
|
+
#
|
26
|
+
def get_cached(key)
|
27
|
+
key = cache_store_key(key)
|
28
|
+
|
29
|
+
@store.transaction(true) do |s|
|
30
|
+
s[key]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Does the given entry exist?
|
36
|
+
#
|
37
|
+
def has_cached?(key)
|
38
|
+
key = cache_store_key(key)
|
39
|
+
|
40
|
+
@store.transaction(true) do |s|
|
41
|
+
s.root?(key)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Delete the given entry.
|
47
|
+
#
|
48
|
+
def delete_cached(key)
|
49
|
+
key = cache_store_key(key)
|
50
|
+
|
51
|
+
@store.transaction do |s|
|
52
|
+
s.delete(key)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Map the given key to a pstore root key.
|
58
|
+
#
|
59
|
+
def cache_store_key(key)
|
60
|
+
'cache-' << Digest::MD5.hexdigest(key)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Joggle
|
4
|
+
module Store
|
5
|
+
module PStore
|
6
|
+
#
|
7
|
+
# Mixin that implements message store methods for pstore objects
|
8
|
+
#
|
9
|
+
# Note: You're probably looking for Joggle::Store::PStore::All
|
10
|
+
#
|
11
|
+
module Message
|
12
|
+
#
|
13
|
+
# Add message to store.
|
14
|
+
#
|
15
|
+
def add_message(key, row)
|
16
|
+
key = message_store_key(key)
|
17
|
+
|
18
|
+
@store.transaction do |s|
|
19
|
+
s[key] = row
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Does the given message exist in this store?
|
25
|
+
#
|
26
|
+
def has_message?(key)
|
27
|
+
key = message_store_key(key)
|
28
|
+
|
29
|
+
@store.transaction(true) do |s|
|
30
|
+
s.root?(key)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Delete the given message.
|
36
|
+
#
|
37
|
+
def delete_message(key)
|
38
|
+
key = message_store_key(key)
|
39
|
+
|
40
|
+
@store.transaction do |s|
|
41
|
+
s.delete(key)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Map given key to PStore root key.
|
47
|
+
#
|
48
|
+
def message_store_key(key)
|
49
|
+
'message-' << Digest::MD5.hexdigest(key.to_s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|