couchwatcher 0.1.0 → 0.1.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/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.rdoc +1 -1
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/couchwatcher.gemspec +8 -2
- data/lib/couchwatcher.rb +28 -5
- data/lib/couchwatcher/database_listener.rb +40 -30
- metadata +48 -16
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -11,7 +11,7 @@ This gem provides a simple library to watch a couchdb database or specific docum
|
|
11
11
|
|
12
12
|
couch_watcher = CouchWatcher::CouchWatcher.new()
|
13
13
|
couch_watcher.add_database_watcher('http://localhost:5984/my_database', true) {|url, id, rev, doc| puts("DATABASE: Changes detected at: #{url} id: #{id} and rev: #{rev}. \n For document: #{doc.inspect}")}
|
14
|
-
couch_watcher.add_document_watcher('http://localhost:5984/my_database
|
14
|
+
couch_watcher.add_document_watcher('http://localhost:5984/my_database/_design/mydocument', true) {|url, id, rev, doc| puts("DOCUMENT: Changes detected at: #{url} id: #{id} and rev: #{rev}. \n For document: #{doc.inspect}")}
|
15
15
|
couch_watcher.start_watching()
|
16
16
|
|
17
17
|
== Contributing to couchwatcher
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/couchwatcher.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{couchwatcher}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kevin Malakoff"]
|
12
|
-
s.date = %q{2011-06-
|
12
|
+
s.date = %q{2011-06-19}
|
13
13
|
s.description = %q{This gem provides a simple library to watch a couchdb database or specific documents and to receieve notifications when they change.}
|
14
14
|
s.email = %q{xmann.intl@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -42,31 +42,37 @@ Gem::Specification.new do |s|
|
|
42
42
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
43
43
|
s.add_runtime_dependency(%q<json>, ["> 1.1.5"])
|
44
44
|
s.add_runtime_dependency(%q<typhoeus>, ["~> 0.2"])
|
45
|
+
s.add_runtime_dependency(%q<thor>, ["~> 0.14.0"])
|
45
46
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
46
47
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
47
48
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
|
48
49
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
49
50
|
s.add_runtime_dependency(%q<json>, ["> 1.1.5"])
|
50
51
|
s.add_runtime_dependency(%q<typhoeus>, ["~> 0.2"])
|
52
|
+
s.add_runtime_dependency(%q<thor>, ["~> 0.14.0"])
|
51
53
|
else
|
52
54
|
s.add_dependency(%q<json>, ["> 1.1.5"])
|
53
55
|
s.add_dependency(%q<typhoeus>, ["~> 0.2"])
|
56
|
+
s.add_dependency(%q<thor>, ["~> 0.14.0"])
|
54
57
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
55
58
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
56
59
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
57
60
|
s.add_dependency(%q<rcov>, [">= 0"])
|
58
61
|
s.add_dependency(%q<json>, ["> 1.1.5"])
|
59
62
|
s.add_dependency(%q<typhoeus>, ["~> 0.2"])
|
63
|
+
s.add_dependency(%q<thor>, ["~> 0.14.0"])
|
60
64
|
end
|
61
65
|
else
|
62
66
|
s.add_dependency(%q<json>, ["> 1.1.5"])
|
63
67
|
s.add_dependency(%q<typhoeus>, ["~> 0.2"])
|
68
|
+
s.add_dependency(%q<thor>, ["~> 0.14.0"])
|
64
69
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
65
70
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
66
71
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
67
72
|
s.add_dependency(%q<rcov>, [">= 0"])
|
68
73
|
s.add_dependency(%q<json>, ["> 1.1.5"])
|
69
74
|
s.add_dependency(%q<typhoeus>, ["~> 0.2"])
|
75
|
+
s.add_dependency(%q<thor>, ["~> 0.14.0"])
|
70
76
|
end
|
71
77
|
end
|
72
78
|
|
data/lib/couchwatcher.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'typhoeus'
|
2
|
-
|
3
2
|
require 'couchwatcher/database_listener'
|
4
3
|
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__))))
|
5
|
+
|
5
6
|
module CouchWatcher
|
6
7
|
|
8
|
+
DEFAULT_POLLING_INTERVAL = 1
|
9
|
+
|
7
10
|
class CouchWatcher
|
8
11
|
def initialize()
|
9
12
|
@database_listeners = {}
|
13
|
+
@verbose = true
|
10
14
|
end
|
11
15
|
|
12
16
|
def add_database_watcher(database_url, include_document, &callback_block)
|
@@ -17,7 +21,8 @@ module CouchWatcher
|
|
17
21
|
database_listener(database_url).remove_database_callback(callback_object)
|
18
22
|
end
|
19
23
|
|
20
|
-
def add_document_watcher(
|
24
|
+
def add_document_watcher(document_url, include_document, &callback_block)
|
25
|
+
database_url, document_id = extract_url_components(document_url)
|
21
26
|
database_listener(database_url).add_document_callback(document_id, callback_block, include_document)
|
22
27
|
end
|
23
28
|
|
@@ -25,12 +30,14 @@ module CouchWatcher
|
|
25
30
|
database_listener(database_url).remove_document_callback(callback_object)
|
26
31
|
end
|
27
32
|
|
28
|
-
def start_watching()
|
29
|
-
|
33
|
+
def start_watching(verbose=true, polling_interval=nil)
|
34
|
+
polling_interval = DEFAULT_POLLING_INTERVAL if (polling_interval.nil? || polling_interval <= 0)
|
35
|
+
@verbose = verbose
|
36
|
+
@database_listeners.each {|database_url, database_listener| database_listener.start_watching(verbose, polling_interval)}
|
30
37
|
end
|
31
38
|
|
32
39
|
def stop_watching()
|
33
|
-
@database_listeners.each {|database_url, database_listener| database_listener.stop_watching()}
|
40
|
+
@database_listeners.each {|database_url, database_listener| database_listener.stop_watching(@verbose)}
|
34
41
|
end
|
35
42
|
|
36
43
|
private
|
@@ -45,6 +52,22 @@ module CouchWatcher
|
|
45
52
|
|
46
53
|
return database_listener
|
47
54
|
end
|
55
|
+
|
56
|
+
def extract_url_components(document_url)
|
57
|
+
url_elements = document_url.split('/')
|
58
|
+
|
59
|
+
# a special design type
|
60
|
+
if url_elements[url_elements.length-2].start_with?("_")
|
61
|
+
document_element = url_elements[url_elements.length-2]
|
62
|
+
|
63
|
+
# a normal document type
|
64
|
+
else
|
65
|
+
document_element = url_elements[url_elements.length-1]
|
66
|
+
end
|
67
|
+
|
68
|
+
url_elements = document_url.split(document_element)
|
69
|
+
return [url_elements[0].chomp("/"), (url_elements[1].nil? ? document_element : document_element + url_elements[1])]
|
70
|
+
end
|
48
71
|
|
49
72
|
end
|
50
73
|
end
|
@@ -1,33 +1,29 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'thor/shell/basic'
|
2
3
|
|
3
4
|
module CouchWatcher
|
4
5
|
|
5
6
|
class DatabaseListener
|
6
7
|
|
7
|
-
|
8
|
+
# shortcut to say
|
9
|
+
def say(message, color=nil)
|
10
|
+
@shell ||= Thor::Shell::Basic.new
|
11
|
+
@shell.say message, color
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(database_url)
|
8
15
|
@database_url = database_url
|
9
|
-
@polling_interval = polling_interval
|
10
16
|
@last_sequence = nil
|
11
|
-
@connection_stopped = false
|
12
17
|
@thread = nil
|
13
18
|
@DatabaseCallback = Struct.new(:callback_proc, :include_document)
|
14
19
|
@database_callbacks = []
|
15
20
|
@DocumentCallback = Struct.new(:document_id, :callback_proc, :include_document)
|
16
21
|
@document_callbacks = []
|
17
|
-
|
18
|
-
data = get_info()
|
19
|
-
if data.nil?
|
20
|
-
puts "Error: the database cannnot be watched: #{@database_url}. Check that the couchdb is running, the database exists, and you have adequate permissions."
|
21
|
-
@connection_stopped = true
|
22
|
-
return
|
23
|
-
end
|
24
|
-
|
25
|
-
@last_sequence = data["update_seq"]
|
26
22
|
end
|
27
23
|
|
28
24
|
def add_database_callback(callback_proc, include_document)
|
29
25
|
if !@thread.nil?
|
30
|
-
|
26
|
+
say "Error: cannot add callbacks to a running listener", :red
|
31
27
|
return nil
|
32
28
|
end
|
33
29
|
|
@@ -38,7 +34,7 @@ module CouchWatcher
|
|
38
34
|
|
39
35
|
def remove_database_callback(database_callback)
|
40
36
|
if !@thread.nil?
|
41
|
-
|
37
|
+
say "Error: cannot remove callbacks from a running listener", :red
|
42
38
|
return
|
43
39
|
end
|
44
40
|
|
@@ -47,7 +43,7 @@ module CouchWatcher
|
|
47
43
|
|
48
44
|
def add_document_callback(document_id, callback_proc, include_document)
|
49
45
|
if !@thread.nil?
|
50
|
-
|
46
|
+
say "Error: cannot add callbacks to a running listener", :red
|
51
47
|
return nil
|
52
48
|
end
|
53
49
|
|
@@ -58,23 +54,38 @@ module CouchWatcher
|
|
58
54
|
|
59
55
|
def remove_document_callback(document_callback)
|
60
56
|
if !@thread.nil?
|
61
|
-
|
57
|
+
say "Error: cannot remove callbacks from a running listener", :red
|
62
58
|
return
|
63
59
|
end
|
64
60
|
|
65
61
|
@document_callbacks.delete(document_callback)
|
66
62
|
end
|
67
63
|
|
68
|
-
def start_watching
|
64
|
+
def start_watching(verbose, polling_interval)
|
69
65
|
if !@thread.nil?
|
70
|
-
|
66
|
+
say "Error: listener is already running listener", :red
|
71
67
|
return
|
72
68
|
end
|
73
69
|
|
74
|
-
|
70
|
+
say "Database watching started for: #{@database_url}", :green if verbose
|
75
71
|
@thread = Thread.new do
|
72
|
+
|
73
|
+
# get the sequence
|
74
|
+
if @last_sequence.nil?
|
75
|
+
data = get_info()
|
76
|
+
if data.nil? || data["update_seq"].nil?
|
77
|
+
say "Error: the database cannnot be watched: #{@database_url}. Check that the couchdb is running, the database exists, and you have adequate permissions.", :red
|
78
|
+
return
|
79
|
+
end
|
80
|
+
|
81
|
+
@last_sequence = data["update_seq"]
|
82
|
+
end
|
83
|
+
|
84
|
+
@connection_stopped = false
|
76
85
|
while true
|
77
86
|
|
87
|
+
#puts "Checking heartbeat: #{@database_url} sequence: #{@last_sequence} connecte"
|
88
|
+
|
78
89
|
# stopped the connection
|
79
90
|
if @connection_stopped
|
80
91
|
return
|
@@ -82,17 +93,18 @@ module CouchWatcher
|
|
82
93
|
# the sequence number has been returned so start polling
|
83
94
|
elsif @last_sequence
|
84
95
|
results = get_changes()
|
85
|
-
|
86
|
-
#
|
87
|
-
|
88
|
-
puts "Change detected in database: #{@database_url}" if (results && !results.empty?)
|
89
|
-
|
96
|
+
|
97
|
+
#puts "Checking heartbeat: #{@database_url} sequence: #{@last_sequence}"
|
98
|
+
|
90
99
|
results.each do |result|
|
91
100
|
|
92
101
|
document_id = result["id"]
|
93
102
|
document_rev = result["changes"][0]["rev"]
|
94
103
|
document = result["doc"]
|
95
104
|
|
105
|
+
# tell a change
|
106
|
+
say "Change detected in database: #{@database_url} document: #{document_id}", :green if verbose
|
107
|
+
|
96
108
|
# call the database watchers
|
97
109
|
@database_callbacks.each do |callback|
|
98
110
|
if callback.include_document
|
@@ -115,24 +127,22 @@ module CouchWatcher
|
|
115
127
|
end
|
116
128
|
end
|
117
129
|
|
118
|
-
sleep
|
130
|
+
sleep polling_interval
|
119
131
|
end
|
120
132
|
end
|
121
133
|
end
|
122
134
|
|
123
|
-
def stop_watching
|
135
|
+
def stop_watching(verbose)
|
124
136
|
if @thread.nil?
|
125
|
-
|
137
|
+
say "Error: cannot stop because listener is is not running", :red
|
126
138
|
return
|
127
139
|
end
|
128
140
|
|
129
141
|
# give the thread time to finish
|
130
142
|
@connection_stopped = true
|
131
|
-
sleep @polling_interval + 2
|
132
|
-
|
133
143
|
@thread.kill
|
134
144
|
@thread = nil
|
135
|
-
|
145
|
+
say "Database watching stopped for: #{@database_url}", :green if verbose
|
136
146
|
end
|
137
147
|
|
138
148
|
private
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchwatcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 1
|
10
|
+
version: 0.1.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kevin Malakoff
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-06-
|
18
|
+
date: 2011-06-19 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -50,8 +50,24 @@ dependencies:
|
|
50
50
|
version_requirements: *id002
|
51
51
|
prerelease: false
|
52
52
|
- !ruby/object:Gem::Dependency
|
53
|
-
type: :
|
53
|
+
type: :runtime
|
54
54
|
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 39
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
- 14
|
63
|
+
- 0
|
64
|
+
version: 0.14.0
|
65
|
+
name: thor
|
66
|
+
version_requirements: *id003
|
67
|
+
prerelease: false
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
type: :development
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
55
71
|
none: false
|
56
72
|
requirements:
|
57
73
|
- - ">="
|
@@ -61,11 +77,11 @@ dependencies:
|
|
61
77
|
- 0
|
62
78
|
version: "0"
|
63
79
|
name: shoulda
|
64
|
-
version_requirements: *
|
80
|
+
version_requirements: *id004
|
65
81
|
prerelease: false
|
66
82
|
- !ruby/object:Gem::Dependency
|
67
83
|
type: :development
|
68
|
-
requirement: &
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
69
85
|
none: false
|
70
86
|
requirements:
|
71
87
|
- - ~>
|
@@ -77,11 +93,11 @@ dependencies:
|
|
77
93
|
- 0
|
78
94
|
version: 1.0.0
|
79
95
|
name: bundler
|
80
|
-
version_requirements: *
|
96
|
+
version_requirements: *id005
|
81
97
|
prerelease: false
|
82
98
|
- !ruby/object:Gem::Dependency
|
83
99
|
type: :development
|
84
|
-
requirement: &
|
100
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
85
101
|
none: false
|
86
102
|
requirements:
|
87
103
|
- - ~>
|
@@ -93,11 +109,11 @@ dependencies:
|
|
93
109
|
- 2
|
94
110
|
version: 1.6.2
|
95
111
|
name: jeweler
|
96
|
-
version_requirements: *
|
112
|
+
version_requirements: *id006
|
97
113
|
prerelease: false
|
98
114
|
- !ruby/object:Gem::Dependency
|
99
115
|
type: :development
|
100
|
-
requirement: &
|
116
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
101
117
|
none: false
|
102
118
|
requirements:
|
103
119
|
- - ">="
|
@@ -107,11 +123,11 @@ dependencies:
|
|
107
123
|
- 0
|
108
124
|
version: "0"
|
109
125
|
name: rcov
|
110
|
-
version_requirements: *
|
126
|
+
version_requirements: *id007
|
111
127
|
prerelease: false
|
112
128
|
- !ruby/object:Gem::Dependency
|
113
129
|
type: :runtime
|
114
|
-
requirement: &
|
130
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
115
131
|
none: false
|
116
132
|
requirements:
|
117
133
|
- - ">"
|
@@ -123,11 +139,11 @@ dependencies:
|
|
123
139
|
- 5
|
124
140
|
version: 1.1.5
|
125
141
|
name: json
|
126
|
-
version_requirements: *
|
142
|
+
version_requirements: *id008
|
127
143
|
prerelease: false
|
128
144
|
- !ruby/object:Gem::Dependency
|
129
145
|
type: :runtime
|
130
|
-
requirement: &
|
146
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
131
147
|
none: false
|
132
148
|
requirements:
|
133
149
|
- - ~>
|
@@ -138,7 +154,23 @@ dependencies:
|
|
138
154
|
- 2
|
139
155
|
version: "0.2"
|
140
156
|
name: typhoeus
|
141
|
-
version_requirements: *
|
157
|
+
version_requirements: *id009
|
158
|
+
prerelease: false
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
type: :runtime
|
161
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
162
|
+
none: false
|
163
|
+
requirements:
|
164
|
+
- - ~>
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
hash: 39
|
167
|
+
segments:
|
168
|
+
- 0
|
169
|
+
- 14
|
170
|
+
- 0
|
171
|
+
version: 0.14.0
|
172
|
+
name: thor
|
173
|
+
version_requirements: *id010
|
142
174
|
prerelease: false
|
143
175
|
description: This gem provides a simple library to watch a couchdb database or specific documents and to receieve notifications when they change.
|
144
176
|
email: xmann.intl@gmail.com
|