slnky 0.3.5 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 511db9f81650717557115069f4f0c506835b6c3f
4
- data.tar.gz: 7be97d4637c490cc2f758c3a464b3fdab7403b85
3
+ metadata.gz: 77b112accb022f9dd0533da6fe381c765d05b91b
4
+ data.tar.gz: 87ed869ce697d6e3a9952804297737fec5f02464
5
5
  SHA512:
6
- metadata.gz: 8b1cd9411c9f2043de755e1eeb4c32675b0a70b638812fc6380f8db349fd6ceaa92ff34a26f793a8ed4d0d7e7557f44b6d904c201c504523beaf690bef148f64
7
- data.tar.gz: c117a14627713d77259a47a39b3fd8504bcd1ff5a7234c6471c76635d2b9b3f004f0fff4aee7b7c0dce72808c979bfd3b249ae81e0f90a5ec0bc925fb6ef202d
6
+ metadata.gz: 8d7a928f9aad0803eed260afdd551b403217c9e8af6dad6ebc3e48380af75d38c164eab540f6fe1450e6022c6681c14f53447c4f7f2056f5769c43cea205aeab
7
+ data.tar.gz: c3b71ab7ec862c1848acef70c172d1d704c0f8275486d606f10ce533e96786aff9b55fffcabdc7bd8df23c71479cb03735f5cec81592118a43586d9d269bc3ad
@@ -4,7 +4,6 @@ module Slnky
4
4
  desc 'service NAME [DIR]', 'generate a service named NAME'
5
5
  def service(name, dir=nil)
6
6
  generator = Slnky::Generator::Service.new(name, dir)
7
- raise Thor::Error, "error: directory '#{generator.dir}' exists" if File.exists?(generator.dir)
8
7
  generator.generate
9
8
  end
10
9
 
data/lib/slnky/cli.rb CHANGED
@@ -11,6 +11,13 @@ end
11
11
  module Slnky
12
12
  module CLI
13
13
  class Main < Thor
14
+ map %w[--version -v] => :__print_version
15
+
16
+ desc "--version, -v", "print the version"
17
+ def __print_version
18
+ puts "Slnky version: #{Slnky::VERSION}"
19
+ end
20
+
14
21
  desc 'init', 'initialize configuration directory'
15
22
  def init
16
23
  dir = "#{ENV['HOME']}/.slnky"
@@ -10,42 +10,82 @@ module Slnky
10
10
 
11
11
  def initialize(name, dir)
12
12
  @name = name
13
- @dir = dir == nil ? "slnky-#{name}" : dir
13
+ @dir = File.expand_path(dir == nil ? "slnky-#{name}" : dir)
14
14
  short = self.class.name.split('::').last.downcase
15
15
  @template = File.expand_path("../template/#{short}", __FILE__)
16
16
  end
17
17
 
18
18
  def generate
19
- # copy dir
20
- puts "creating directory and processing templates..."
21
- FileUtils.cp_r(@template, @dir)
22
- puts "#{@dir}:"
23
- # process templates
24
- Find.find(@dir).each do |f|
25
- next unless File.file?(f) && File.extname(f) == '.erb'
26
- template(f)
27
- end
19
+ puts "generating service #{@name}:"
20
+ puts " from: #{@template}"
21
+ puts " to: #{@dir}"
22
+ process_files
28
23
  # make service executable
29
24
  `chmod 755 #{@dir}/service-slnky-#{@name}`
30
25
  # git init
31
26
  puts "initializing git..."
32
27
  `cd #{@dir} && git init . || true`
28
+ `cd #{@dir} && git add .`
33
29
  end
34
30
 
35
31
  protected
36
32
 
37
- def template(file)
33
+ def process_files
34
+ Find.find(@template).each do |path|
35
+ next unless File.file?(path)
36
+ file = path.gsub(/^#{@template}\//, '')
37
+ ext = File.extname(path)
38
+ mkdir(File.dirname("#{@dir}/#{file}"))
39
+ if ext == '.erb'
40
+ tmpl(file)
41
+ else
42
+ file(file)
43
+ end
44
+ end
45
+ end
46
+
47
+ def mkdir(dir)
48
+ return if File.directory?(dir)
49
+ # puts "mkdir: #{dir}"
50
+ FileUtils.mkdir_p(dir)
51
+ end
52
+
53
+ def file(file)
54
+ # puts "file: #{file}"
55
+ FileUtils.cp("#{@template}/#{file}", "#{@dir}/#{file}")
56
+ end
57
+
58
+ def tmpl(file)
59
+ # puts "tmpl: #{file}"
60
+ path = "#{@template}/#{file}"
38
61
  var = {
39
62
  name: @name,
40
63
  dir: @dir
41
64
  }
42
- dest = file.gsub(/\.erb$/, '').gsub('NAME', @name)
43
- puts " #{dest}"
44
- template = Tilt.new(file)
65
+ out = file.gsub(/\.erb$/, '').gsub('NAME', @name)
66
+ dest = "#{@dir}/#{out}"
67
+ # puts " #{dest}"
68
+ template = Tilt.new(path)
45
69
  output = template.render(self, var)
46
70
  File.write(dest, output)
47
- FileUtils.rm(file) if file != dest
48
71
  end
72
+
73
+ # def generate_old
74
+ # # copy dir
75
+ # puts "creating directory and processing templates..."
76
+ # FileUtils.cp_r(@template, @dir)
77
+ # puts "#{@dir}:"
78
+ # # process templates
79
+ # Find.find(@dir).each do |f|
80
+ # next unless File.file?(f) && File.extname(f) == '.erb'
81
+ # template(f)
82
+ # end
83
+ # # make service executable
84
+ # `chmod 755 #{@dir}/service-slnky-#{@name}`
85
+ # # git init
86
+ # puts "initializing git..."
87
+ # `cd #{@dir} && git init . || true`
88
+ # end
49
89
  end
50
90
  end
51
91
  end
@@ -0,0 +1,33 @@
1
+ module Slnky
2
+ module Service
3
+ class Exchanges
4
+ def initialize(channel)
5
+ @channel = channel
6
+ @exchanges = {}
7
+ end
8
+
9
+ def create(name, overrides={})
10
+ options = {
11
+ type: :fanout
12
+ }.merge(overrides)
13
+ @exchanges[name] =
14
+ case options[:type]
15
+ when :fanout
16
+ @channel.fanout("slnky.#{name}")
17
+ else
18
+ raise "unknown exchange type: #{options[:type]}"
19
+ end
20
+ end
21
+
22
+ def [](name)
23
+ @exchanges["slnky.#{name}"] || @exchanges[name] || raise("no exchange found: #{name}")
24
+ end
25
+
26
+ def each
27
+ @exchanges.each do |name, exchange|
28
+ yield name, exchange
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Slnky
2
+ module Service
3
+ class Periodics
4
+ def initialize
5
+ @timers = []
6
+ end
7
+
8
+ def add(seconds, method)
9
+ @timers << {seconds: seconds, method: method}
10
+ end
11
+
12
+ def each
13
+ @timers.each do |timer|
14
+ yield timer['seconds'], timer['method']
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Slnky
2
+ module Service
3
+ class Queues
4
+ def initialize(channel)
5
+ @channel = channel
6
+ @queues = {}
7
+ end
8
+
9
+ def create(name, exchange, overrides={})
10
+ options = {
11
+ durable: true
12
+ }.merge(overrides)
13
+ @queues[name] = @channel.queue("service.#{@name}.events", options).bind(exchange)
14
+ end
15
+
16
+ def [](name)
17
+ @queues["service.#{@name}.events"] || @queues[name] || raise("no queue found: #{name}")
18
+ end
19
+
20
+ def each
21
+ @queues.each do |name, exchange|
22
+ yield name, exchange
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ module Slnky
2
+ module Service
3
+ class Subscriptions
4
+ def initialize
5
+ @subs = []
6
+ end
7
+
8
+ def add(name, method)
9
+ @subs << {name: name, method: method}
10
+ end
11
+
12
+ def each
13
+ @subs.each do |sub|
14
+ yield sub[:name], sub[:method]
15
+ end
16
+ end
17
+
18
+ def for(name)
19
+ @subs.each do |sub|
20
+ if sub[:name] == name || File.fnmatch(sub[:name], name)
21
+ yield sub[:name], sub[:method] if block_given?
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/slnky/service.rb CHANGED
@@ -1,57 +1,66 @@
1
- require 'slnky/version'
2
- require 'slnky/message'
3
1
  require 'amqp'
4
2
  require 'open-uri'
5
3
  require 'json'
4
+ require 'socket'
5
+
6
+ require 'slnky/version'
7
+ require 'slnky/message'
8
+ require 'slnky/service/subscriptions'
9
+ require 'slnky/service/periodics'
10
+ require 'slnky/service/queues'
11
+ require 'slnky/service/exchanges'
6
12
 
7
13
  module Slnky
8
14
  module Service
9
15
  class Base
10
- def initialize(url, env='development')
16
+ attr_reader :config
17
+
18
+ def initialize(url, options={})
11
19
  @server = url
12
- @environment = env
13
20
  @name = self.class.name.split('::').last.downcase
14
- json = open("#{@server}/configs/#{@name}") {|f| f.read }
15
- @config = JSON.parse(json)
16
- @host = @config['rabbit']['host']
17
- @port = @config['rabbit']['port']
18
- @subscriptions = {}
19
- @periodics = []
20
- @exchanges = {}
21
+ @environment = options.delete(:env) || options.delete(:environment) || 'development'
22
+ @config = load_config(options)
23
+
24
+ @subscriptions = self.class.subscriptions || Slnky::Service::Subscriptions.new
25
+ @periodics = self.class.periodics || Slnky::Service::Periodics.new
26
+ @hostname = Socket.gethostname
27
+ @ipaddress = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address
21
28
  end
22
29
 
23
30
  def start
24
- AMQP.start("amqp://#{@host}:#{@port}") do |connection|
31
+ AMQP.start("amqp://#{config.rabbit.host}:#{config.rabbit.port}") do |connection|
25
32
  @channel = AMQP::Channel.new(connection)
26
33
  @channel.on_error do |ch, channel_close|
27
34
  raise "Channel-level exception: #{channel_close.reply_text}"
28
35
  end
29
- @exchanges['events'] = @channel.fanout("slnky.events")
30
- @exchanges['logs'] = @channel.fanout("slnky.logs")
31
36
 
32
- log :info, "slnky.service.#{@name}: running"
37
+ @exchanges = Slnky::Service::Exchanges.new(@channel)
38
+ @exchanges.create('events')
39
+ @exchanges.create('logs')
40
+
41
+ @queues = Slnky::Service::Queues.new(@channel)
42
+ @queues.create(@name, @exchanges['events'])
43
+
44
+ log :info, "running"
33
45
 
34
46
  run
35
47
 
36
- @subscriptions.each do |name, block|
37
- log :info, "slnky.service.#{@name}: subscribed to: #{name}"
48
+ @subscriptions.each do |name, method|
49
+ log :info, "subscribed to: #{name} -> #{self.class.name}.#{method}"
38
50
  end
39
51
 
40
- @channel.queue("service.#{@name}.events", durable: true).bind(@exchanges['events']).subscribe do |raw|
41
- payload = parse(raw)
42
- if @subscriptions[payload.name]
43
- @subscriptions[payload.name].call(payload)
44
- end
45
- # TODO: support this better
46
- if @subscriptions['*']
47
- @subscriptions['*'].call(payload)
52
+ @queues[@name].subscribe do |raw|
53
+ message = parse(raw)
54
+ event = message.name
55
+ data = message.payload
56
+ @subscriptions.for(event) do |name, method|
57
+ self.send(method.to_sym, event, data)
48
58
  end
49
59
  end
50
60
 
51
- @periodics.each do |p|
52
- EventMachine.add_periodic_timer(p[:timer]) do
53
- b = p[:block]
54
- instance_eval &b
61
+ @periodics.each do |seconds, method|
62
+ EventMachine.add_periodic_timer(seconds) do
63
+ self.send(method.to_sym)
55
64
  end
56
65
  end
57
66
 
@@ -69,7 +78,7 @@ module Slnky
69
78
  protected
70
79
 
71
80
  def run
72
- # nothing here
81
+ # nothing here - overridden in subclasses
73
82
  end
74
83
 
75
84
  def msg(data)
@@ -80,16 +89,57 @@ module Slnky
80
89
  Slnky::Message.parse(data)
81
90
  end
82
91
 
83
- def subscribe(name, &block)
84
- @subscriptions[name] = block
92
+ def subscribe(name, method)
93
+ raise "move this to class level, use methods instead of blocks"
94
+ # @subscriptions.add(name, method)
85
95
  end
86
96
 
87
- def periodic(timer, &block)
88
- @periodics << {timer: timer, block: block}
97
+ def periodic(seconds, method)
98
+ raise "move this to class level, use methods instead of blocks"
99
+ # @periodics.add(seconds, method)
89
100
  end
90
101
 
91
102
  def log(level, message)
92
- @exchanges['logs'].publish(msg({service: "#{@name}-#{$$}", level: level, message: message}))
103
+ data = {
104
+ service: "#{@name}-#{$$}",
105
+ level: level,
106
+ hostname: @hostname,
107
+ ipaddress: @ipaddress,
108
+ message: "slnky.service.#{@name}: #{message}"
109
+ }
110
+ @exchanges['logs'].publish(msg(data)) if @exchanges && @exchanges['logs'] # only log to the exchange if it's created
111
+ puts "%s [%6s] %s" % [Time.now, data[:level], data[:message]] if development? # log to the console if in development
112
+ end
113
+
114
+ def development?
115
+ @environment == 'development'
116
+ end
117
+
118
+ def load_config(config)
119
+ # if you specify config, it will not load from server
120
+ # this is useful for testing, so you won't need to be running
121
+ # a server locally or configure your development service to
122
+ # talk to production server
123
+ if !config || config.count == 0
124
+ config = JSON.parse(open("#{@server}/configs/#{@name}") {|f| f.read })
125
+ end
126
+ DeepStruct.new(config)
127
+ end
128
+
129
+ class << self
130
+ attr_reader :subscriptions
131
+ attr_reader :periodics
132
+
133
+ def subscribe(name, method)
134
+ @subscriptions ||= Slnky::Service::Subscriptions.new
135
+ @subscriptions.add(name, method)
136
+ end
137
+
138
+ def periodic(seconds, method)
139
+ @periodics ||= Slnky::Service::Periodics.new
140
+ @periodics.add(seconds, method)
141
+ end
142
+ alias_method :timer, :periodic
93
143
  end
94
144
 
95
145
  # def pub(data)
@@ -8,4 +8,6 @@
8
8
  /tmp/
9
9
  /log/*
10
10
  /.env
11
+ /slnky-cli/lib/slnky/template/service/deploy.env.erb
12
+ /test/config.yaml
11
13
  /deploy.env
@@ -3,12 +3,13 @@ require 'slnky'
3
3
  module Slnky
4
4
  module Service
5
5
  class <%= name.capitalize %> < Base
6
- def run
7
- subscribe 'event.name' do |message|
8
- name = message.name
9
- data = message.payload
10
- # do something
11
- end
6
+ subscribe 'slnky.service.test', :handler
7
+ # you can also subscribe to heirarchies, this gets
8
+ # all events under something.happened
9
+ # subscribe 'something.happened.*', :other_handler
10
+
11
+ def handler(name, data)
12
+ name == 'slnky.service.test' && data.hello == 'world!'
12
13
  end
13
14
  end
14
15
  end
@@ -15,4 +15,4 @@ env = ARGV[1]
15
15
  # Become a daemon
16
16
  Daemons.daemonize if env == 'production'
17
17
 
18
- Slnky::Service::<%= name.capitalize %>.new(ENV['SLNKY_URL'], env).start
18
+ Slnky::Service::<%= name.capitalize %>.new(ENV['SLNKY_URL'], env: env).start
@@ -1,7 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Slnky::Service::<%= name.capitalize %> do
4
- it 'does something useful' do
5
- expect(false).to eq(true)
4
+ subject { described_class.new("http://localhost:3000", test_config) }
5
+ let(:test_event) { event_load('test')}
6
+
7
+ it 'handles event' do
8
+ expect(subject.handler(test_event.name, test_event.payload)).to eq(true)
6
9
  end
7
10
  end
@@ -1,2 +1,28 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'slnky'
2
3
  require 'slnky/service/<%= name %>'
4
+ require 'yaml'
5
+ require 'erb'
6
+ require 'tilt'
7
+
8
+ require 'dotenv'
9
+ @dotenv = Dotenv.load
10
+
11
+ def event_load(name)
12
+ @events ||= {}
13
+ @events[name] ||= begin
14
+ file = File.expand_path("../../test/events/#{name}.json", __FILE__)
15
+ raise "file #{file} not found" unless File.exists?(file)
16
+ Slnky::Message.new(JSON.parse(File.read(file)))
17
+ end
18
+ end
19
+
20
+ def test_config
21
+ @config ||= begin
22
+ file = File.expand_path("../../test/config.yaml", __FILE__)
23
+ template = Tilt.new(file)
24
+ output = template.render(self, @dotenv)
25
+ YAML.load(output)
26
+ end
27
+ end
28
+
@@ -0,0 +1,7 @@
1
+ ---
2
+ # config.yaml for Slnky::Service::Test
3
+ # this file is processed through ERB, you can inject
4
+ # values into the config from the environment, by specifying them
5
+ # in the .env file
6
+ environment: development # should specify this
7
+ service: test # just an example
@@ -0,0 +1,7 @@
1
+ ---
2
+ # config.yaml for Slnky::Service::<%= name.capitalize %>
3
+ # this file is processed through ERB, you can inject
4
+ # values into the config from the environment, by specifying them
5
+ # in the .env file
6
+ environment: development # should specify this
7
+ service: <%= name %> # just an example
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "slnky.service.test",
3
+ "payload": {
4
+ "hello": "world!"
5
+ }
6
+ }
data/lib/slnky/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Slnky
2
- VERSION = "0.3.5"
2
+ VERSION = "0.4.0"
3
3
  end
data/slnky.gemspec CHANGED
@@ -9,9 +9,9 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Shawn Catanzarite"]
10
10
  spec.email = ["me@shawncatz.com"]
11
11
 
12
- spec.summary = %q{core slnky lib}
13
- spec.description = %q{core slnky lib}
14
- spec.homepage = "https://github.com/shawncatz/slnky"
12
+ spec.summary = %q{core slnky lib and command line}
13
+ spec.description = %q{core slnky lib and command line}
14
+ spec.homepage = "https://github.com/slnky/slnky-cli"
15
15
  spec.license = "MIT"
16
16
 
17
17
  # # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slnky
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shawn Catanzarite
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-05 00:00:00.000000000 Z
11
+ date: 2016-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,7 +122,7 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.0.2
125
- description: core slnky lib
125
+ description: core slnky lib and command line
126
126
  email:
127
127
  - me@shawncatz.com
128
128
  executables:
@@ -152,6 +152,10 @@ files:
152
152
  - lib/slnky/generator/service.rb
153
153
  - lib/slnky/message.rb
154
154
  - lib/slnky/service.rb
155
+ - lib/slnky/service/exchanges.rb
156
+ - lib/slnky/service/periodics.rb
157
+ - lib/slnky/service/queues.rb
158
+ - lib/slnky/service/subscriptions.rb
155
159
  - lib/slnky/template/service/.env.sample
156
160
  - lib/slnky/template/service/.gitignore.erb
157
161
  - lib/slnky/template/service/.rspec
@@ -162,16 +166,19 @@ files:
162
166
  - lib/slnky/template/service/config/deploy.rb.erb
163
167
  - lib/slnky/template/service/config/deploy/production.rb
164
168
  - lib/slnky/template/service/config/deploy/staging.rb
165
- - lib/slnky/template/service/deploy.env
169
+ - lib/slnky/template/service/deploy.env.erb
166
170
  - lib/slnky/template/service/lib/capistrano/tasks/NAME.rake.erb
167
171
  - lib/slnky/template/service/lib/slnky/service/NAME.rb.erb
168
172
  - lib/slnky/template/service/log/.keep
169
173
  - lib/slnky/template/service/service-slnky-NAME.erb
170
174
  - lib/slnky/template/service/spec/slnky/service/NAME_spec.rb.erb
171
175
  - lib/slnky/template/service/spec/spec_helper.rb.erb
176
+ - lib/slnky/template/service/test/config.yaml
177
+ - lib/slnky/template/service/test/config.yaml.erb
178
+ - lib/slnky/template/service/test/events/test.json
172
179
  - lib/slnky/version.rb
173
180
  - slnky.gemspec
174
- homepage: https://github.com/shawncatz/slnky
181
+ homepage: https://github.com/slnky/slnky-cli
175
182
  licenses:
176
183
  - MIT
177
184
  metadata: {}
@@ -194,5 +201,5 @@ rubyforge_project:
194
201
  rubygems_version: 2.4.7
195
202
  signing_key:
196
203
  specification_version: 4
197
- summary: core slnky lib
204
+ summary: core slnky lib and command line
198
205
  test_files: []