flowhook 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 32a9cb67ca6f2fbf7405bb1219511d4efd010600
4
+ data.tar.gz: 3c1f823fa4bca3d5eae463711a349b15758ac101
5
+ SHA512:
6
+ metadata.gz: 6a8bf94bc500f0d3ddff805a2e3660e07e6cdf866b06540155032a671751f29e6c09f2d58892ff2aa554c7813b054b3d2a020a9c1c0ecbfcc64791a3505f8e0c
7
+ data.tar.gz: e0e33f1f09bcd189d0287d0cccdd3e406670d805dddd9c5074f1f1b9c9e1c08c070d1999ece547d434065d96f79b34974aea92d4cd1daa753d348003c8d5e38d
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+
13
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.16.0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in flowhook.gemspec
6
+ gemspec
@@ -0,0 +1,35 @@
1
+ # Flowhook
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/flowhook`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'flowhook'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install flowhook
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/flowhook.
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'flowhook'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'flowhook'
4
+
5
+ Flowhook.start
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'flowhook/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'flowhook'
7
+ spec.version = Flowhook::VERSION
8
+ spec.authors = ['蒼時弦也']
9
+ spec.email = ['elct9620@frost.tw']
10
+
11
+ spec.summary = 'Convert flowdock straming into webhook'
12
+ spec.description = 'Convert flowdock streaming into webhook'
13
+ spec.homepage = 'https://github.com/elct9620/flowhook'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.16'
23
+ spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec', '~> 3.0'
25
+ end
@@ -0,0 +1 @@
1
+ 95962
@@ -0,0 +1,19 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'thread'
4
+ require 'json'
5
+ require 'net/http'
6
+
7
+ require 'flowhook/version'
8
+
9
+ # Flowdock Streaming to Webhook
10
+ module Flowhook
11
+ autoload :Streaming, 'flowhook/streaming'
12
+ autoload :Worker, 'flowhook/worker'
13
+ autoload :Options, 'flowhook/options'
14
+
15
+ def self.start
16
+ options = Options.new.parse!
17
+ Worker.new(options).start
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ module Flowhook
2
+ # rubocop:disable Metrics/LineLength
3
+ # The option parser
4
+ class Options < OptionParser
5
+ attr_reader :options
6
+
7
+ def initialize
8
+ super
9
+
10
+ prepare_options
11
+ setup_options
12
+ end
13
+
14
+ def parse!(args = ARGV)
15
+ super
16
+ options
17
+ end
18
+
19
+ private
20
+
21
+ def setup_options
22
+ %w[url path token flows events daemonize help version].each do |option|
23
+ send("setup_#{option}_option")
24
+ end
25
+ end
26
+
27
+ def setup_url_option
28
+ on('-u', '--url URL', String, 'The webhook url to send event') do |url|
29
+ options.url = url
30
+ end
31
+ end
32
+
33
+ def setup_path_option
34
+ on('-p', '--path PATH', String, 'The path saving pid and logs') do |path|
35
+ options.path = path
36
+ end
37
+ end
38
+
39
+ def setup_token_option
40
+ on('-t', '--token TOKEN', String, 'The personal token to access messages') do |token|
41
+ options.token = token
42
+ end
43
+ end
44
+
45
+ def setup_flows_option
46
+ on('-F', '--flows FLOW1, FLOW2', Array, 'The flows wants to straming') do |flows|
47
+ options.flows = flows
48
+ end
49
+ end
50
+
51
+ def setup_events_option
52
+ on('-E', '--events EVENT1, EVENT2', Array, 'The events want to straming') do |events|
53
+ options.events = events
54
+ end
55
+ end
56
+
57
+ def setup_daemonize_option
58
+ on('-d', '--[no-]daemonize', 'Daemonize the process') do |daemonize|
59
+ options.daemonize = daemonize
60
+ end
61
+ end
62
+
63
+ def setup_help_option
64
+ on_tail('-h', '--help', 'Show this message') do
65
+ puts self
66
+ exit
67
+ end
68
+ end
69
+
70
+ def setup_version_option
71
+ on_tail('--version', 'Show version') do
72
+ puts VERSION
73
+ exit
74
+ end
75
+ end
76
+
77
+ def prepare_options
78
+ @options = OpenStruct.new
79
+ options.path = Dir.pwd
80
+ options.url = nil
81
+ options.token = nil
82
+ options.flows = []
83
+ options.events = []
84
+ options.daemonize = false
85
+ end
86
+ end
87
+ end
88
+ # rubocop:enable Metrics/LineLength
@@ -0,0 +1,65 @@
1
+ module Flowhook
2
+ # The streaming client for Flowdock API
3
+ class Streaming
4
+ STREAMING_URL = 'https://stream.flowdock.com/flows'.freeze
5
+
6
+ def initialize(token, flows = [], events = [])
7
+ @token = token
8
+ @flows = flows
9
+ @events = events
10
+ @queue = Queue.new
11
+ @thread = nil
12
+ @stop = false
13
+ end
14
+
15
+ def stop?
16
+ @stop == true
17
+ end
18
+
19
+ def stop!
20
+ @stop = true
21
+ end
22
+
23
+ def read(&_block)
24
+ ensure_connection
25
+ until stop?
26
+ yield @queue.pop(true) until @queue.empty?
27
+ # NOOP
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def ensure_connection
34
+ return if @thread
35
+ @thread ||= Thread.new { streaming }
36
+ end
37
+
38
+ def queue(chunk)
39
+ chunk.chomp!
40
+ return if chunk.empty?
41
+ event = JSON.parse(chunk)
42
+ @queue.push event if @events.empty? || @events.include?(event['event'])
43
+ end
44
+
45
+ def streaming
46
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
47
+ http.request request do |response|
48
+ response.read_body do |chunk|
49
+ queue chunk
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def request
56
+ @request ||= Net::HTTP::Get.new(uri).tap do |request|
57
+ request.basic_auth @token, nil
58
+ end
59
+ end
60
+
61
+ def uri
62
+ @uri ||= URI("#{STREAMING_URL}?filter=#{@flows.join(',')}")
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module Flowhook
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,111 @@
1
+ require 'pp'
2
+
3
+ module Flowhook
4
+ # The worker to sending webhook
5
+ class Worker
6
+ def initialize(options)
7
+ @options = options
8
+ @pidfile = File.expand_path('flowhook.pid')
9
+
10
+ initialize_stream
11
+ end
12
+
13
+ def start
14
+ check_pid
15
+ daemonize if daemonize?
16
+ write_pid
17
+ trap_signals
18
+
19
+ @stream.read do |event|
20
+ # TODO: Logging response
21
+ Thread.new { send event }
22
+ end
23
+ end
24
+
25
+ def daemonize?
26
+ @options.daemonize
27
+ end
28
+
29
+ def pidfile?
30
+ !@pidfile.nil?
31
+ end
32
+
33
+ private
34
+
35
+ # TODO: Refactor PID manager: https://codeincomplete.com/posts/ruby-daemons/
36
+ def check_pid
37
+ return unless pidfile?
38
+ case pid_status(@pidfile)
39
+ when :running, :not_owned
40
+ puts "Worker is running. Check #{@pidfile}"
41
+ exit 1
42
+ when :dead
43
+ File.delete(@pidfile)
44
+ end
45
+ end
46
+
47
+ def write_pid
48
+ return unless pidfile?
49
+ File.write(@pidfile, Process.pid)
50
+ at_exit { File.delete(@pidfile) if File.exist?(@pidfile) }
51
+ rescue Errno::EEXIST
52
+ check_pid
53
+ retry
54
+ end
55
+
56
+ def pid_status(pidfile)
57
+ return :exited unless File.exist?(pidfile)
58
+ pid = File.read(pidfile).to_i
59
+ return :dead if pid.zero?
60
+ Process.kill(0, pid)
61
+ :running
62
+ rescue Errno::ESRCH
63
+ :dead
64
+ rescue Errno::EPERM
65
+ :not_owned
66
+ end
67
+
68
+ def daemonize
69
+ exit if fork
70
+ Process.setsid
71
+ exit if fork
72
+ Dir.chdir '/'
73
+ end
74
+
75
+ def trap_signals
76
+ trap :QUIT do
77
+ @stream.stop!
78
+ end
79
+
80
+ trap :SIGINT do
81
+ @stream.stop!
82
+ end
83
+ end
84
+
85
+ def send(event)
86
+ use_ssl = uri.scheme == 'https'
87
+ Net::HTTP.start(uri.host, uri.port, use_ssl: use_ssl) do |http|
88
+ http.request make_request(event)
89
+ end
90
+ end
91
+
92
+ def make_request(event)
93
+ Net::HTTP::Post.new(uri).tap do |request|
94
+ request.body = event.to_json
95
+ request.content_type = 'application/json'
96
+ end
97
+ end
98
+
99
+ def uri
100
+ @uri ||= URI(@options.url)
101
+ end
102
+
103
+ def initialize_stream
104
+ @stream = Streaming.new(
105
+ @options.token,
106
+ @options.flows,
107
+ @options.events
108
+ )
109
+ end
110
+ end
111
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flowhook
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - 蒼時弦也
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Convert flowdock streaming into webhook
56
+ email:
57
+ - elct9620@frost.tw
58
+ executables:
59
+ - flowhook
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - README.md
68
+ - Rakefile
69
+ - bin/console
70
+ - bin/setup
71
+ - exe/flowhook
72
+ - flowhook.gemspec
73
+ - flowhook.pid
74
+ - lib/flowhook.rb
75
+ - lib/flowhook/options.rb
76
+ - lib/flowhook/streaming.rb
77
+ - lib/flowhook/version.rb
78
+ - lib/flowhook/worker.rb
79
+ homepage: https://github.com/elct9620/flowhook
80
+ licenses: []
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.6.13
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Convert flowdock straming into webhook
102
+ test_files: []