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 +5 -5
- data/bin/xify +1 -1
- data/lib/xify.rb +51 -16
- data/lib/xify/base/rocket_chat.rb +75 -0
- data/lib/xify/input/pipe.rb +10 -8
- data/lib/xify/input/prompt.rb +22 -24
- data/lib/xify/input/rocket_chat.rb +39 -0
- data/lib/xify/input/shell.rb +19 -7
- data/lib/xify/output/rocket_chat.rb +19 -77
- data/lib/xify/output/stdout.rb +7 -5
- metadata +34 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a399f02dbab5c7417063d2d1223487c16887d249
|
4
|
+
data.tar.gz: 86a1847c1f3e928efa7083b100d7b57e26438e5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d35c9c553fa24f87024bb60fbd51490e61a5b0ead5e2db3959fd265f47b15b4c86916deebf875a81de69e0fa9b5406701be40b85302377577bc77c4cdf511e1
|
7
|
+
data.tar.gz: 94b1bb9808f4a56e8b46d54e9a4511038a8fffdfb1a34c6a5c91cf7d0db9d96edd4f6eafea5b7149a9d3ebf847a1fa90e1092f03208b462c9bf71f2907b92d2a
|
data/bin/xify
CHANGED
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
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
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 |
|
24
|
-
|
36
|
+
config.keys.each do |section|
|
37
|
+
type = section[0...-1]
|
38
|
+
config[section].map! do |handler|
|
25
39
|
next unless handler['enabled']
|
26
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
data/lib/xify/input/pipe.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Input
|
2
|
+
class Pipe
|
3
|
+
def initialize(config)
|
4
|
+
@author = config['author']
|
5
|
+
end
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
data/lib/xify/input/prompt.rb
CHANGED
@@ -1,37 +1,35 @@
|
|
1
1
|
require 'xify/event'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module Input
|
4
|
+
class Prompt
|
5
|
+
def initialize(config)
|
6
|
+
@author = config['author']
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def updates
|
10
|
+
loop do
|
11
|
+
begin
|
12
|
+
input = prompt
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
break
|
17
|
-
end
|
14
|
+
unless input
|
15
|
+
raise Interrupt
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
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
|
-
|
27
|
+
private
|
31
28
|
|
32
|
-
|
33
|
-
|
29
|
+
def prompt
|
30
|
+
print '> '
|
34
31
|
|
35
|
-
|
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
|
data/lib/xify/input/shell.rb
CHANGED
@@ -1,10 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
data/lib/xify/output/stdout.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'time'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
module Output
|
4
|
+
class Stdout
|
5
|
+
def initialize(config)
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
-
|
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
|
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-
|
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.
|
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.
|