xify 0.1.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 670138629af686c5ae8d7fe7bd773a6a24ab23e4a1cac1e43ec2c5b1d6a1d6d7
4
- data.tar.gz: ba760cff71020f421c22ec7c100c9bad5193c439fa5af222aeb4f0467a335c35
2
+ SHA1:
3
+ metadata.gz: a399f02dbab5c7417063d2d1223487c16887d249
4
+ data.tar.gz: 86a1847c1f3e928efa7083b100d7b57e26438e5a
5
5
  SHA512:
6
- metadata.gz: e8628de616941c4f2b450739af88d4d60eca6f393babd3f08261b9c178e5a983d332c4ddfa775f6da50f644df3c6a4727c4ea7442d08d70e04a769f7ab172beb
7
- data.tar.gz: 27132224d15386e6e23be525e9e030461643643c2deccfedc3ec2f8a0c4d6f70ac2d5680ff6a2f17279ff3ed718afc3f1e063271576b4e2deacdbc2125cc5dff
6
+ metadata.gz: 0d35c9c553fa24f87024bb60fbd51490e61a5b0ead5e2db3959fd265f47b15b4c86916deebf875a81de69e0fa9b5406701be40b85302377577bc77c4cdf511e1
7
+ data.tar.gz: 94b1bb9808f4a56e8b46d54e9a4511038a8fffdfb1a34c6a5c91cf7d0db9d96edd4f6eafea5b7149a9d3ebf847a1fa90e1092f03208b462c9bf71f2907b92d2a
data/bin/xify CHANGED
@@ -4,4 +4,4 @@ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
4
4
 
5
5
  require 'xify'
6
6
 
7
- Xify.run ARGV
7
+ Xify.run
data/lib/xify.rb CHANGED
@@ -1,42 +1,77 @@
1
+ require 'rufus-scheduler'
1
2
  require 'yaml'
2
3
 
3
4
  require 'xify/input/pipe'
4
5
  require 'xify/input/prompt'
6
+ require 'xify/input/rocket_chat'
5
7
  require 'xify/input/shell'
6
8
  require 'xify/output/stdout'
7
9
  require 'xify/output/rocket_chat'
8
10
 
9
11
  class Xify
10
- def self.run(args)
12
+ @verbose = false
13
+
14
+ def self.run
11
15
  working_dir = "#{ENV['HOME']}/.xify"
12
16
  Dir.mkdir working_dir rescue Errno::EEXIST
13
-
14
17
  config_file = "#{working_dir}/config.yml"
15
- if args.first == '-c'
16
- args.shift
17
- config_file = args.shift
18
+ files = []
19
+
20
+ while arg = ARGV.shift do
21
+ case arg
22
+ when '-c', '--config'
23
+ config_file = ARGV.shift
24
+ when '-v', '--verbose'
25
+ @verbose = true
26
+ else
27
+ files << arg
28
+ end
18
29
  end
19
30
 
20
- puts "Loading config from #{config_file}"
31
+ ARGV.unshift(*files)
32
+
33
+ debug "Loading config from #{config_file}"
21
34
  config = YAML::load_file config_file
22
35
 
23
- config.keys.each do |c|
24
- config[c].map! do |handler|
36
+ config.keys.each do |section|
37
+ type = section[0...-1]
38
+ config[section].map! do |handler|
25
39
  next unless handler['enabled']
26
- Object.const_get(handler['class']).new(handler)
40
+ debug "Setting up #{handler['class']} as #{type}"
41
+ Object.const_get("#{type.capitalize}::#{handler['class']}").new handler
27
42
  end.compact!
28
43
  end
29
44
 
30
- config['inputs'].each do |i|
31
- i.updates do |u|
32
- config['outputs'].each do |o|
33
- begin
34
- o.process u
35
- rescue => e
36
- $stderr.puts e.message
45
+ begin
46
+ config['inputs'].each do |i|
47
+ begin
48
+ i.updates do |u|
49
+ config['outputs'].each do |o|
50
+ begin
51
+ o.process u
52
+ rescue => e
53
+ error e
54
+ end
55
+ end
37
56
  end
57
+ rescue => e
58
+ error e
38
59
  end
39
60
  end
61
+
62
+ Rufus::Scheduler.singleton.join
63
+ rescue Interrupt => e
64
+ $stderr.puts "\nExiting."
40
65
  end
41
66
  end
67
+
68
+ def self.debug(str)
69
+ puts str if @verbose
70
+ end
71
+
72
+ def self.error(e)
73
+ return $stderr.puts e.message unless @verbose
74
+
75
+ $stderr.puts "#{e.backtrace.first}: #{e.message} (#{e.class})", e.backtrace.drop(1).map{|s| "\t#{s}"}
76
+ end
42
77
  end
@@ -0,0 +1,75 @@
1
+ require 'json'
2
+ require 'net/https'
3
+ require 'time'
4
+
5
+ module Base
6
+ class RocketChat
7
+ def initialize(config)
8
+ @config = config
9
+
10
+ uri = URI.parse config['uri']
11
+ @http = Net::HTTP.new uri.host, uri.port
12
+ @http.use_ssl = true
13
+
14
+ working_dir = "#{ENV['HOME']}/.xify/RocketChat"
15
+ Dir.mkdir working_dir rescue Errno::EEXIST
16
+ @auth_file = "#{working_dir}/#{@config['user']}.json"
17
+ end
18
+
19
+ def request(method, path, &block)
20
+ login unless @auth_data
21
+
22
+ req = Object.const_get("Net::HTTP::#{method.capitalize}").new path,
23
+ 'X-User-Id' => @auth_data['userId'],
24
+ 'X-Auth-Token' => @auth_data['authToken']
25
+
26
+ yield req if block_given?
27
+
28
+ res = @http.request req
29
+
30
+ case res
31
+ when Net::HTTPUnauthorized
32
+ relogin
33
+ request method, path, &block
34
+ when Net::HTTPSuccess
35
+ # nothing
36
+ else
37
+ $stderr.puts res.body
38
+ raise "Error on #{method.upcase} #{@config['uri']}#{path}: #{res.code} #{res.message}"
39
+ end
40
+
41
+ res
42
+ end
43
+
44
+ private
45
+
46
+ def login
47
+ if File.exists? @auth_file
48
+ @auth_data = JSON.parse File.read @auth_file
49
+ return
50
+ end
51
+
52
+ req = Net::HTTP::Post.new '/api/v1/login',
53
+ 'Content-Type' => 'application/json'
54
+ req.body = {
55
+ username: @config['user'],
56
+ password: @config['pass']
57
+ }.to_json
58
+
59
+ res = @http.request req
60
+
61
+ unless res.is_a? Net::HTTPSuccess
62
+ $stderr.puts res.body
63
+ raise "Error while authenticating to #{@config['uri']}: #{res.code} #{res.message}"
64
+ end
65
+
66
+ @auth_data = JSON.parse(res.body)['data']
67
+ File.write @auth_file, @auth_data.to_json
68
+ end
69
+
70
+ def relogin
71
+ File.delete @auth_file
72
+ login
73
+ end
74
+ end
75
+ end
@@ -1,10 +1,12 @@
1
- class Pipe
2
- def initialize(config)
3
- @author = config['author']
4
- end
1
+ module Input
2
+ class Pipe
3
+ def initialize(config)
4
+ @author = config['author']
5
+ end
5
6
 
6
- def updates
7
- out = ARGF.read.chomp
8
- yield Event.new @author, out if out && out.length != 0
7
+ def updates
8
+ out = ARGF.read.chomp
9
+ yield Event.new @author, out if out && out.length != 0
10
+ end
9
11
  end
10
- end
12
+ end
@@ -1,37 +1,35 @@
1
1
  require 'xify/event'
2
2
 
3
- class Prompt
4
- def initialize(config)
5
- @author = config['author']
6
- end
3
+ module Input
4
+ class Prompt
5
+ def initialize(config)
6
+ @author = config['author']
7
+ end
7
8
 
8
- def updates
9
- loop do
10
- begin
11
- input = prompt
9
+ def updates
10
+ loop do
11
+ begin
12
+ input = prompt
12
13
 
13
- unless input
14
- # Stop on CTRL+D
15
- puts
16
- break
17
- end
14
+ unless input
15
+ raise Interrupt
16
+ end
18
17
 
19
- if input.length != 1
20
- yield Event.new @author, input.chomp
18
+ if input.length != 1
19
+ yield Event.new @author, input.chomp
20
+ end
21
+ rescue Interrupt
22
+ raise
21
23
  end
22
- rescue Interrupt
23
- # Stop on CTRL+C
24
- puts
25
- break
26
24
  end
27
25
  end
28
- end
29
26
 
30
- private
27
+ private
31
28
 
32
- def prompt
33
- print '> '
29
+ def prompt
30
+ print '> '
34
31
 
35
- gets
32
+ gets
33
+ end
36
34
  end
37
35
  end
@@ -0,0 +1,39 @@
1
+ require 'eventmachine'
2
+ require 'json'
3
+ require 'metybur'
4
+ require 'net/https'
5
+ require 'time'
6
+
7
+ require 'xify/base/rocket_chat'
8
+
9
+ module Input
10
+ class RocketChat < Base::RocketChat
11
+ def updates
12
+ login
13
+
14
+ EM.run do
15
+ config = @config
16
+ uri = URI.parse config['uri']
17
+ meteor = Metybur.connect "wss://#{uri.host}:#{uri.port}/websocket"
18
+ meteor.login resume: @auth_data['authToken'] do
19
+ meteor.subscribe 'stream-notify-user', "#{result[:id]}/rooms-changed", false
20
+ messages = meteor.collection 'stream-notify-user'
21
+ messages.on(:changed) do |id, attributes|
22
+ event = attributes[:args].last
23
+ room = event[:name]
24
+ message = event[:lastMessage]
25
+
26
+ next if message[:editedAt] || room != config['channel'][1..-1]
27
+
28
+ author = message[:u][:name]
29
+ text = message[:msg]
30
+ time = message[:ts][:'$date']
31
+ type = event[:t] == 'p' ? 'group' : 'channel'
32
+
33
+ yield Event.new author, text, parent: "##{room}", parent_link: "#{config['uri']}/#{type}/#{room}", time: Time.at(time / 1000)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,10 +1,22 @@
1
- class Shell
2
- def initialize(config)
3
- @config = config
4
- end
1
+ module Input
2
+ class Shell
3
+ def initialize(config)
4
+ @config = config
5
+ end
6
+
7
+ def run
8
+ out = `#{@config['shell']}`.chomp
9
+ yield Event.new @config['author'], out, parent: @config['shell'] if out && out.length != 0
10
+ end
11
+
12
+ def updates(&block)
13
+ return run(&block) unless @config['trigger']
5
14
 
6
- def updates
7
- out = `#{@config['shell']}`.chomp
8
- yield Event.new @config['author'], out, parent: @config['shell'] if out && out.length != 0
15
+ opts = {}
16
+ opts[:first] = :now if @config['trigger']['now']
17
+ Rufus::Scheduler.singleton.repeat @config['trigger']['schedule'], opts do
18
+ run(&block)
19
+ end
20
+ end
9
21
  end
10
22
  end
@@ -2,83 +2,25 @@ require 'json'
2
2
  require 'net/https'
3
3
  require 'time'
4
4
 
5
- class RocketChat
6
- def initialize(config)
7
- @channel = config['channel']
8
- uri = URI.parse config['uri']
9
- @http = Net::HTTP.new uri.host, uri.port
10
- @http.use_ssl = true
11
-
12
- @user = config['user']
13
- @pass = config['pass']
14
-
15
- working_dir = "#{ENV['HOME']}/.xify/RocketChat"
16
- Dir.mkdir working_dir rescue Errno::EEXIST
17
- @auth_file = "#{working_dir}/#{@user}.json"
18
- end
19
-
20
- def login
21
- if File.exists? @auth_file
22
- @auth_data = JSON.parse File.read @auth_file
23
- return
24
- end
25
-
26
- req = Net::HTTP::Post.new '/api/v1/login',
27
- 'Content-Type' => 'application/json'
28
- req.body = {
29
- username: @user,
30
- password: @pass
31
- }.to_json
32
-
33
- res = @http.request req
34
-
35
- raise "Error: #{res.code} #{res.message}\n#{res.body}" unless res.is_a? Net::HTTPSuccess
36
-
37
- @auth_data = JSON.parse(res.body)['data']
38
- File.write @auth_file, @auth_data.to_json
39
- end
40
-
41
- def reset_auth
42
- @auth_data = nil
43
- File.delete @auth_file
44
- end
45
-
46
- def authenticated_request
47
- login unless @auth_data
48
-
49
- req = Net::HTTP::Post.new '/api/v1/chat.postMessage',
50
- 'Content-Type' => 'application/json',
51
- 'X-User-Id' => @auth_data['userId'],
52
- 'X-Auth-Token' => @auth_data['authToken']
53
-
54
- yield req
55
-
56
- req
57
- end
58
-
59
- def process(event)
60
- res = @http.request(authenticated_request do |req|
61
- req.body = {
62
- channel: @channel,
63
- alias: event.author,
64
- attachments: [
65
- {
66
- title: event.args[:parent],
67
- title_link: event.args[:parent_link],
68
- text: event.args[:link] ? "#{event.message.chomp} ([more](#{event.args[:link]}))" : event.message.chomp
69
- }
70
- ]
71
- }.to_json
72
- end)
73
-
74
- case res
75
- when Net::HTTPUnauthorized
76
- reset_auth
77
- process event
78
- when Net::HTTPSuccess
79
- # nothing
80
- else
81
- $stderr.puts "Error: #{res.code} #{res.message}\n#{res.body}"
5
+ require 'xify/base/rocket_chat'
6
+
7
+ module Output
8
+ class RocketChat < Base::RocketChat
9
+ def process(event)
10
+ request :post, '/api/v1/chat.postMessage' do |req|
11
+ req['Content-Type'] = 'application/json'
12
+ req.body = {
13
+ channel: @config['channel'],
14
+ alias: event.author,
15
+ attachments: [
16
+ {
17
+ title: event.args[:parent],
18
+ title_link: event.args[:parent_link],
19
+ text: event.args[:link] ? "#{event.message.chomp} ([more](#{event.args[:link]}))" : event.message.chomp
20
+ }
21
+ ]
22
+ }.to_json
23
+ end
82
24
  end
83
25
  end
84
26
  end
@@ -1,10 +1,12 @@
1
1
  require 'time'
2
2
 
3
- class Stdout
4
- def initialize(config)
5
- end
3
+ module Output
4
+ class Stdout
5
+ def initialize(config)
6
+ end
6
7
 
7
- def process(event)
8
- puts "[#{event.args[:time] || Time.now.iso8601}] #{event.author}:\n#{event.message}"
8
+ def process(event)
9
+ puts "[#{(event.args[:time] || Time.now).iso8601}] #{event.author}:\n#{event.message}"
10
+ end
9
11
  end
10
12
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Finn Glöe
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-11 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2018-05-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: metybur
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rufus-scheduler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.4'
13
41
  description: Cross-post content from one service to another.
14
42
  email: fgloee@united-internet.de
15
43
  executables:
@@ -19,9 +47,11 @@ extra_rdoc_files: []
19
47
  files:
20
48
  - bin/xify
21
49
  - lib/xify.rb
50
+ - lib/xify/base/rocket_chat.rb
22
51
  - lib/xify/event.rb
23
52
  - lib/xify/input/pipe.rb
24
53
  - lib/xify/input/prompt.rb
54
+ - lib/xify/input/rocket_chat.rb
25
55
  - lib/xify/input/shell.rb
26
56
  - lib/xify/output/rocket_chat.rb
27
57
  - lib/xify/output/stdout.rb
@@ -44,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
74
  version: '0'
45
75
  requirements: []
46
76
  rubyforge_project:
47
- rubygems_version: 2.7.6
77
+ rubygems_version: 2.6.11
48
78
  signing_key:
49
79
  specification_version: 4
50
80
  summary: Cross-post content from one service to another.