nats 0.3.12
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 +19 -0
- data/README.md +95 -0
- data/Rakefile +31 -0
- data/bin/nats-pub +20 -0
- data/bin/nats-server +5 -0
- data/bin/nats-sub +22 -0
- data/lib/nats/client.rb +424 -0
- data/lib/nats/ext/bytesize.rb +5 -0
- data/lib/nats/ext/em.rb +6 -0
- data/lib/nats/ext/json.rb +7 -0
- data/lib/nats/server.rb +313 -0
- data/lib/nats/server/const.rb +51 -0
- data/lib/nats/server/options.rb +96 -0
- data/lib/nats/server/sublist.rb +116 -0
- data/nats.gemspec +46 -0
- metadata +125 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
#--
|
2
|
+
#
|
3
|
+
# Sublist implementation for a publish-subscribe system.
|
4
|
+
# This container class holds subscriptions and matches
|
5
|
+
# candidate subjects to those subscriptions.
|
6
|
+
# Certain wildcards are supported for subscriptions.
|
7
|
+
# '*' will match any given token at any level.
|
8
|
+
# '>' will match all subsequent tokens.
|
9
|
+
#--
|
10
|
+
# See included test for example usage:
|
11
|
+
##
|
12
|
+
|
13
|
+
class Sublist #:nodoc:
|
14
|
+
PWC = '*'.freeze
|
15
|
+
FWC = '>'.freeze
|
16
|
+
CACHE_SIZE = 4096
|
17
|
+
|
18
|
+
attr_reader :count
|
19
|
+
|
20
|
+
SublistNode = Struct.new(:leaf_nodes, :next_level)
|
21
|
+
SublistLevel = Struct.new(:nodes, :pwc, :fwc)
|
22
|
+
|
23
|
+
def initialize(options = {})
|
24
|
+
@count = 0
|
25
|
+
@results = []
|
26
|
+
@root = SublistLevel.new({})
|
27
|
+
@cache = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
# Ruby is a great language to make selective trade offs of space versus time.
|
31
|
+
# We do that here with a low tech front end cache. The cache holds results
|
32
|
+
# until it is exhausted or if the instance inserts or removes a subscription.
|
33
|
+
# The assumption is that the cache is best suited for high speed matching,
|
34
|
+
# and that once it is cleared out it will naturally fill with the high speed
|
35
|
+
# matches. This can obviously be improved with a smarter LRU structure that
|
36
|
+
# does not need to completely go away when a remove happens..
|
37
|
+
#
|
38
|
+
# front end caching is on by default, but we can turn it off here if needed
|
39
|
+
|
40
|
+
def disable_cache; @cache = nil; end
|
41
|
+
def enable_cache; @cache ||= {}; end
|
42
|
+
def clear_cache; @cache = {} if @cache; end
|
43
|
+
|
44
|
+
# Insert a subscriber into the sublist for the given subject.
|
45
|
+
def insert(subject, subscriber)
|
46
|
+
# TODO - validate subject as correct.
|
47
|
+
level, tokens = @root, subject.split('.')
|
48
|
+
for token in tokens
|
49
|
+
# This is slightly slower than direct if statements, but looks cleaner.
|
50
|
+
case token
|
51
|
+
when FWC then node = (level.fwc || (level.fwc = SublistNode.new([])))
|
52
|
+
when PWC then node = (level.pwc || (level.pwc = SublistNode.new([])))
|
53
|
+
else node = ((level.nodes[token]) || (level.nodes[token] = SublistNode.new([])))
|
54
|
+
end
|
55
|
+
level = (node.next_level || (node.next_level = SublistLevel.new({})))
|
56
|
+
end
|
57
|
+
node.leaf_nodes.push(subscriber)
|
58
|
+
@count += 1
|
59
|
+
clear_cache # Clear the cache
|
60
|
+
end
|
61
|
+
|
62
|
+
# Remove a given subscriber from the sublist for the given subject.
|
63
|
+
def remove(subject, subscriber)
|
64
|
+
# TODO: implement (remember cache and count cleanup if applicable)
|
65
|
+
# Reference counts and GC for long empty tree.
|
66
|
+
level, tokens = @root, subject.split('.')
|
67
|
+
for token in tokens
|
68
|
+
next unless level
|
69
|
+
case token
|
70
|
+
when FWC then node = level.fwc
|
71
|
+
when PWC then node = level.pwc
|
72
|
+
else node = level.nodes[token]
|
73
|
+
end
|
74
|
+
level = node.next_level
|
75
|
+
end
|
76
|
+
# This could be expensize if a large number of subscribers exist.
|
77
|
+
node.leaf_nodes.delete(subscriber) if (node && node.leaf_nodes)
|
78
|
+
clear_cache # Clear the cache
|
79
|
+
end
|
80
|
+
|
81
|
+
# Match a subject to all subscribers, return the array of matches.
|
82
|
+
def match(subject)
|
83
|
+
return @cache[subject] if (@cache && @cache[subject])
|
84
|
+
tokens = subject.split('.')
|
85
|
+
@results.clear
|
86
|
+
matchAll(@root, tokens)
|
87
|
+
# FIXME: This is too low tech, will revisit when needed.
|
88
|
+
if @cache
|
89
|
+
clear_cache if @cache.size > CACHE_SIZE
|
90
|
+
@cache[subject] = Array.new(@results).freeze # Avoid tampering of copy
|
91
|
+
end
|
92
|
+
@results
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def matchAll(level, tokens)
|
98
|
+
node, pwc = nil, nil # Define for scope
|
99
|
+
i, ts = 0, tokens.size
|
100
|
+
while (i < ts) do
|
101
|
+
return if level == nil
|
102
|
+
# Handle a full wildcard here by adding all of the subscribers.
|
103
|
+
@results.concat(level.fwc.leaf_nodes) if level.fwc
|
104
|
+
# Handle an internal partial wildcard by branching recursively
|
105
|
+
lpwc = level.pwc
|
106
|
+
matchAll(lpwc.next_level, tokens[i+1, ts]) if lpwc
|
107
|
+
node, pwc = level.nodes[tokens[i]], lpwc
|
108
|
+
#level = node.next_level if node
|
109
|
+
level = node ? node.next_level : nil
|
110
|
+
i += 1
|
111
|
+
end
|
112
|
+
@results.concat(pwc.leaf_nodes) if pwc
|
113
|
+
@results.concat(node.leaf_nodes) if node
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
data/nats.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib/', __FILE__)
|
4
|
+
$:.unshift lib unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'nats/server/const.rb'
|
7
|
+
|
8
|
+
spec = Gem::Specification.new do |s|
|
9
|
+
s.name = 'nats'
|
10
|
+
s.version = NATSD::VERSION
|
11
|
+
s.date = '2010-11-20'
|
12
|
+
s.summary = 'Simple Publish-Subscribe Messaging System'
|
13
|
+
s.homepage = "http://github.com/derekcollison/nats"
|
14
|
+
s.description = "A lightweight, fast, publish-subscribe messaging system."
|
15
|
+
s.has_rdoc = true
|
16
|
+
|
17
|
+
s.authors = ["Derek Collison"]
|
18
|
+
s.email = ["derek.collison@gmail.com"]
|
19
|
+
|
20
|
+
s.add_dependency('eventmachine', '>= 0.12.10')
|
21
|
+
s.add_dependency('yajl-ruby', '>= 0.7.8')
|
22
|
+
s.add_dependency('daemons', '>= 1.1.0')
|
23
|
+
|
24
|
+
s.require_paths = ['lib']
|
25
|
+
s.bindir = 'bin'
|
26
|
+
s.executables = [NATSD::APP_NAME, 'nats-pub', 'nats-sub']
|
27
|
+
|
28
|
+
s.files = %w[
|
29
|
+
COPYING
|
30
|
+
README.md
|
31
|
+
nats.gemspec
|
32
|
+
Rakefile
|
33
|
+
bin/nats-server
|
34
|
+
bin/nats-sub
|
35
|
+
bin/nats-pub
|
36
|
+
lib/nats/client.rb
|
37
|
+
lib/nats/ext/bytesize.rb
|
38
|
+
lib/nats/ext/em.rb
|
39
|
+
lib/nats/ext/json.rb
|
40
|
+
lib/nats/server.rb
|
41
|
+
lib/nats/server/options.rb
|
42
|
+
lib/nats/server/sublist.rb
|
43
|
+
lib/nats/server/const.rb
|
44
|
+
]
|
45
|
+
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 12
|
9
|
+
version: 0.3.12
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Derek Collison
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-20 00:00:00 -06:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: eventmachine
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 12
|
31
|
+
- 10
|
32
|
+
version: 0.12.10
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: yajl-ruby
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
- 7
|
46
|
+
- 8
|
47
|
+
version: 0.7.8
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: daemons
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 1
|
60
|
+
- 1
|
61
|
+
- 0
|
62
|
+
version: 1.1.0
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
65
|
+
description: A lightweight, fast, publish-subscribe messaging system.
|
66
|
+
email:
|
67
|
+
- derek.collison@gmail.com
|
68
|
+
executables:
|
69
|
+
- nats-server
|
70
|
+
- nats-pub
|
71
|
+
- nats-sub
|
72
|
+
extensions: []
|
73
|
+
|
74
|
+
extra_rdoc_files: []
|
75
|
+
|
76
|
+
files:
|
77
|
+
- COPYING
|
78
|
+
- README.md
|
79
|
+
- nats.gemspec
|
80
|
+
- Rakefile
|
81
|
+
- bin/nats-server
|
82
|
+
- bin/nats-sub
|
83
|
+
- bin/nats-pub
|
84
|
+
- lib/nats/client.rb
|
85
|
+
- lib/nats/ext/bytesize.rb
|
86
|
+
- lib/nats/ext/em.rb
|
87
|
+
- lib/nats/ext/json.rb
|
88
|
+
- lib/nats/server.rb
|
89
|
+
- lib/nats/server/options.rb
|
90
|
+
- lib/nats/server/sublist.rb
|
91
|
+
- lib/nats/server/const.rb
|
92
|
+
has_rdoc: true
|
93
|
+
homepage: http://github.com/derekcollison/nats
|
94
|
+
licenses: []
|
95
|
+
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
requirements: []
|
118
|
+
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.3.7
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Simple Publish-Subscribe Messaging System
|
124
|
+
test_files: []
|
125
|
+
|