stalkerr 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5e221a6891528b82fcb96f86fd755fc67849b574
4
+ data.tar.gz: c3b563649487135c4c77e4ce77f3f3f3dee32205
5
+ SHA512:
6
+ metadata.gz: 80b0e80f8c158bb4081e9426a25d4381343f40b2bfd604318b73bccc7d10b23cefba63535744500632f21044b3a72e1270b971d8b53daaa03086ca8355dae1fa
7
+ data.tar.gz: 13ae4d63529d31a4e98195f52b5813a6c8b798983ebd2f6561a9fa94fdbf88be2b765df34b88fe10b43701d464796e5c79aa5549bb7b8f95d93fa93bfc6a50ac
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ vendor
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ log
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'net-irc'
4
+ gem 'json'
5
+ gem 'octokit'
6
+ gem 'string-irc'
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 by linyows <linyows@gmail.com>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ Stalkerr
2
+ ========
3
+
4
+ Stalkerr is IRC Gateway, inspired by [agig](https://github.com/hsbt/agig) and [atig](https://github.com/mzp/atig).
5
+
6
+ ![The Shining](http://goo.gl/7JPKQ)
7
+
8
+ Usage
9
+ -----
10
+
11
+ ### Start Stalkerr
12
+
13
+ $ gem install stalkerr
14
+ $ stalkerr --help
15
+ $ stalkerr -D
16
+
17
+ ### Connecting to Stalkerr
18
+
19
+ /join #github <username>:<password>
20
+
21
+ Contributing
22
+ ------------
23
+
24
+ 1. Fork it
25
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
26
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
27
+ 4. Push to the branch (`git push origin my-new-feature`)
28
+ 5. Create new Pull Request
29
+
30
+ Author
31
+ ------
32
+
33
+ - [@linyows](https://github.com/linyows)
34
+
35
+ License
36
+ -------
37
+
38
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'stalkerr'
4
+
5
+ ::Stalkerr::Server.run
@@ -0,0 +1,7 @@
1
+ require 'stalkerr/version'
2
+ require 'stalkerr/optparse'
3
+ require 'stalkerr/const'
4
+ require 'stalkerr/server'
5
+ require 'stalkerr/session'
6
+ require 'stalkerr/target'
7
+ require 'stalkerr/extensions/string'
@@ -0,0 +1,10 @@
1
+ module Stalkerr::Const
2
+
3
+ DEFAULT_HOST = '127.0.0.1'
4
+
5
+ DEFAULT_PORT = 16705
6
+
7
+ ROLLBACK_SEC = 60 * 60
8
+
9
+ FETCH_INTERVAL = 30
10
+ end
@@ -0,0 +1,16 @@
1
+ module Stalkerr::Extensions
2
+ module String
3
+ def constantize
4
+ names = self.split('::')
5
+ names.shift if names.empty? || names.first.empty?
6
+ constant = Object
7
+ names.each do |name|
8
+ constant = constant.const_defined?(name, false) ?
9
+ constant.const_get(name) : constant.const_missing(name)
10
+ end
11
+ constant
12
+ end
13
+ end
14
+ end
15
+
16
+ ::String.__send__(:include, Stalkerr::Extensions::String)
@@ -0,0 +1,47 @@
1
+ require 'optparse'
2
+ require 'stalkerr'
3
+
4
+ module Stalkerr::OptParser
5
+ def self.parse!(argv)
6
+ opts = {
7
+ host: Stalkerr::Const::DEFAULT_HOST,
8
+ port: Stalkerr::Const::DEFAULT_PORT,
9
+ log: nil,
10
+ debug: false,
11
+ daemonize: false,
12
+ }
13
+
14
+ OptionParser.new do |parser|
15
+ parser.instance_eval do
16
+ self.banner = "Usage: #{$0} [opts]"
17
+ separator "Options:"
18
+
19
+ on("-p", "--port [PORT=#{opts[:port]}]",
20
+ "use PORT (default: #{Stalkerr::Const::DEFAULT_PORT})") do |port|
21
+ opts[:port] = port
22
+ end
23
+
24
+ on("-h", "--host [HOST=#{opts[:host]}]",
25
+ "listen HOST (default: #{Stalkerr::Const::DEFAULT_HOST})") do |host|
26
+ opts[:host] = host
27
+ end
28
+
29
+ on("-l", "--log LOG", "log file") do |log|
30
+ opts[:log] = log
31
+ end
32
+
33
+ on("-d", "--debug", "enable debug mode") do
34
+ opts[:log] = $stdout
35
+ opts[:debug] = true
36
+ end
37
+
38
+ on("-D", "--daemonize", "run daemonized in the background") do
39
+ opts[:daemonize] = true
40
+ end
41
+
42
+ parse!(argv)
43
+ end
44
+ end
45
+ opts
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ require 'net/irc'
2
+ require 'logger'
3
+
4
+ module Stalkerr::Server
5
+ def self.run
6
+ opts = Stalkerr::OptParser.parse!(ARGV)
7
+ Process.daemon if opts[:daemonize]
8
+ opts[:logger] = Logger.new(opts[:log], 'daily')
9
+ opts[:logger].level = opts[:debug] ? Logger::DEBUG : Logger::INFO
10
+ Net::IRC::Server.new(opts[:host], opts[:port], Stalkerr::Session, opts).start
11
+ end
12
+ end
@@ -0,0 +1,73 @@
1
+ require 'ostruct'
2
+ require 'time'
3
+ require 'net/irc'
4
+ require 'stalkerr'
5
+ Dir["#{File.dirname(__FILE__)}/target/*.rb"].each { |p| require p }
6
+
7
+ class Stalkerr::Session < Net::IRC::Server::Session
8
+
9
+ def initialize(*args)
10
+ super
11
+ @debug = args.last.debug
12
+ @channels = {}
13
+ Dir["#{File.dirname(__FILE__)}/target/*.rb"].each do |path|
14
+ name = File.basename(path, '.rb')
15
+ @channels.merge!(name.to_sym => "##{name}")
16
+ end
17
+ end
18
+
19
+ def on_disconnected
20
+ @retrieve_thread.kill rescue nil
21
+ end
22
+
23
+ def on_user(m)
24
+ super
25
+ @real, *@opts = @real.split(/\s+/)
26
+ @opts = OpenStruct.new @opts.inject({}) { |r, i|
27
+ key, value = i.split("=", 2)
28
+ r.update key => case value
29
+ when nil then true
30
+ when /\A\d+\z/ then value.to_i
31
+ when /\A(?:\d+\.\d*|\.\d+)\z/ then value.to_f
32
+ else value
33
+ end
34
+ }
35
+ end
36
+
37
+ def on_join(m)
38
+ super
39
+
40
+ matched = m.params[1].match(/(.*?):(.*)/)
41
+ channel = m.params[0]
42
+
43
+ if !@channels.value?(channel) || !matched
44
+ @log.error "#{channel} not found."
45
+ end
46
+
47
+ @class_name = "Stalkerr::Target::#{@channels.invert[channel].capitalize}"
48
+ @username = matched[1]
49
+ @password = matched[2]
50
+ post @username, JOIN, channel
51
+
52
+ @retrieve_thread = Thread.start do
53
+ loop do
54
+ begin
55
+ target.stalking do |prefix, command, *params|
56
+ post(prefix, command, *params)
57
+ end
58
+ sleep Stalkerr::Const::FETCH_INTERVAL
59
+ rescue Exception => e
60
+ @log.error e.inspect
61
+ e.backtrace.each { |l| @log.error "\t#{l}" }
62
+ sleep 10
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def target
71
+ @target ||= @class_name.constantize.new(@username, @password)
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ Dir["#{File.dirname(__FILE__)}/stalkerr/target/*.rb"].each { |p| require p }
@@ -0,0 +1,197 @@
1
+ require 'time'
2
+ require 'net/irc'
3
+ require 'octokit'
4
+ require 'net/http'
5
+ require 'string-irc'
6
+ require 'stalkerr'
7
+
8
+ module Stalkerr::Target
9
+ class Github
10
+ include Net::IRC::Constants
11
+
12
+ HOST = 'https://github.com'
13
+ CHANNEL = '#github'
14
+
15
+ def initialize(username, password)
16
+ @username = username
17
+ @password = password
18
+ @last_event_id = nil
19
+ end
20
+
21
+ def client
22
+ @client ||= Octokit::Client.new(login: @username, password: @password)
23
+ end
24
+
25
+ def stalking(&post)
26
+ @post = post
27
+ client.received_events(@username).reverse_each { |event|
28
+ if @last_event_id.nil?
29
+ next if Time.now.utc - Stalkerr::Const::ROLLBACK_SEC >= Time.parse(event.created_at).utc
30
+ else
31
+ next if @last_event_id >= event.id
32
+ end
33
+ result = parse(event)
34
+ @last_event_id = result if result != false
35
+ }
36
+ end
37
+
38
+ def parse(event)
39
+ obj = event.payload
40
+ header = status = title = link = ''
41
+ body = []
42
+ none_repository = false
43
+ notice_body = false
44
+
45
+ case event.type
46
+ when 'CommitCommentEvent'
47
+ status = "commented on commit"
48
+ title = "#{obj.comment.path}"
49
+ body = body + split_for_comment(obj.comment.body)
50
+ link = obj.comment.html_url
51
+ when 'PullRequestReviewCommentEvent'
52
+ status = "commented on pull request"
53
+ if obj.comment.pull_request_url
54
+ pull_id = obj.comment.pull_request_url.match(/\/pulls\/([0-9]+)/)[1]
55
+ pull = client.pull(event.repo.name, pull_id)
56
+ title = "#{pull.title}: #{obj.comment.path}"
57
+ else
58
+ title = obj.comment.path
59
+ end
60
+ body = body + split_for_comment(obj.comment.body)
61
+ link = obj.comment.html_url
62
+ when 'IssueCommentEvent'
63
+ if obj.action == 'created'
64
+ status = "commented on issue ##{obj.issue.number}"
65
+ title = obj.issue.title
66
+ else
67
+ status = "#{obj.action} issue comment"
68
+ end
69
+ body = body + split_for_comment(obj.comment.body)
70
+ link = obj.comment.html_url
71
+ when 'IssuesEvent'
72
+ status = "#{obj.action} issue ##{obj.issue.number}"
73
+ title = obj.issue.title
74
+ body = body + split_for_comment(obj.issue.body)
75
+ body << "assignee: #{obj.issue.assignee.login}" if obj.issue.assignee
76
+ body << "milestone: #{obj.issue.milestone.title}[#{obj.issue.milestone.state}]" if obj.issue.milestone
77
+ link = obj.issue.html_url
78
+ when 'PullRequestEvent'
79
+ status = "#{obj.action} pull request ##{obj.number}"
80
+ title = obj.pull_request.title
81
+ body = body + split_for_comment(obj.pull_request.body)
82
+ link = obj.pull_request.html_url
83
+ when 'PushEvent'
84
+ notice_body = true
85
+ status = "pushed to #{obj.ref.gsub('refs/heads/', '')}"
86
+ obj.commits.each do |commit|
87
+ verbose_commit = client.commit(event.repo.name, commit.sha)
88
+ name = verbose_commit.author ? verbose_commit.author.login : commit.author.name
89
+ url = "#{HOST}/#{event.repo.name}/commit/#{commit.sha}"
90
+ line = "#{StringIrc.new(name).silver}: #{commit.message}"
91
+ line << " - #{StringIrc.new(shorten url).blue}"
92
+ body = body + split_for_comment(line)
93
+ end
94
+ link = "#{HOST}/#{event.repo.name}"
95
+ when 'CreateEvent'
96
+ if obj.ref_type.eql? 'repository'
97
+ none_repository = true
98
+ status = "created repository"
99
+ title = event.repo.name
100
+ else
101
+ status = "created #{obj.ref_type}:#{obj.ref}"
102
+ end
103
+ title = obj.description
104
+ link = "#{HOST}/#{event.repo.name}"
105
+ when 'DeleteEvent'
106
+ status = "deleted #{obj.ref_type}:#{obj.ref}"
107
+ link = "#{HOST}/#{event.repo.name}"
108
+ when 'DownloadEvent'
109
+ status = "download #{obj.name}"
110
+ title = obj.description
111
+ link = obj.html_url
112
+ when 'ForkEvent'
113
+ status = "forked #{obj.forkee.full_name} [#{obj.forkee.language}]"
114
+ title = obj.forkee.description
115
+ link = obj.forkee.html_url
116
+ when 'TeamAddEvent'
117
+ status = "add team"
118
+ title = obj.team.name
119
+ when 'WatchEvent'
120
+ none_repository = true
121
+ status = "#{obj.action} repository"
122
+ title = event.repo.name
123
+ link = "#{HOST}/#{event.repo.name}"
124
+ when 'FollowEvent'
125
+ none_repository = true
126
+ notice_body = true
127
+ user = obj.target
128
+ status = "followed"
129
+ title = user.login
130
+ title = "#{title} (#{user.name})" if user.name && user.name != ''
131
+ profile = ["#{StringIrc.new('repos').silver}: #{user.public_repos}"]
132
+ profile << "#{StringIrc.new('followers').silver}: #{user.followers}"
133
+ profile << "#{StringIrc.new('following').silver}: #{user.following}"
134
+ profile << "#{StringIrc.new('location').silver}: #{user.location && user.location != '' ? user.location : '-'}"
135
+ profile << "#{StringIrc.new('company').silver}: #{user.company && user.company != '' ? user.company : '-'}"
136
+ profile << "#{StringIrc.new('bio').silver}: #{user.bio && user.bio != '' ? user.bio : '-'}"
137
+ profile << "#{StringIrc.new('blog').silver}: #{user.blog && user.blog != '' ? user.blog : '-'}"
138
+ body << profile.join(', ')
139
+ link = "#{HOST}/#{user.login}"
140
+ when 'MemberEvent'
141
+ user = obj.member
142
+ status = "#{obj.action} member"
143
+ title = user.login
144
+ link = "#{HOST}/#{user.login}"
145
+ when 'GistEvent'
146
+ none_repository = true
147
+ status = "#{obj.action}d gist"
148
+ title = obj.gist.description unless obj.gist.description.eql? ''
149
+ link = obj.gist.html_url
150
+ when 'DownloadEvent',
151
+ 'ForkApplyEvent',
152
+ 'GollumEvent',
153
+ 'PublicEvent'
154
+ return false
155
+ end
156
+
157
+ nick = event.actor.login
158
+ unless status.eql? ''
159
+ color = case
160
+ when status.include?('created') then :pink
161
+ when status.include?('commented') then :yellow
162
+ when status.include?('pushed') then :lime
163
+ when status.include?('forked') then :orange
164
+ when status.include?('closed') then :brown
165
+ when status.include?('deleted') then :red
166
+ when status.include?('started') then :rainbow
167
+ when status.include?('followed') then :seven_eleven
168
+ else :aqua
169
+ end
170
+ header = StringIrc.new(status).send(color)
171
+ header = "(#{event.repo.name}) #{header}" unless none_repository
172
+ end
173
+ header = "#{header} #{title}" unless title.eql? ''
174
+ header = "#{header} - #{StringIrc.new(shorten link).blue}" unless link.eql? ''
175
+
176
+ @post.call nick, NOTICE, CHANNEL, header unless header.eql? ''
177
+ mode = notice_body ? NOTICE : PRIVMSG
178
+ body.each { |b| @post.call nick, mode, CHANNEL, b } unless body.eql? ''
179
+ event.id
180
+ end
181
+
182
+ def split_for_comment(string)
183
+ string.split(/\r\n|\n/).map { |v| v unless v.eql? '' }.compact
184
+ end
185
+
186
+ def shorten(url)
187
+ Net::HTTP.start('git.io', 80) do |http|
188
+ request = Net::HTTP::Post.new '/'
189
+ request.content_type = 'application/x-www-form-urlencoded'
190
+ query = Hash.new.tap { |h| h[:url] = url }
191
+ request.body = URI.encode_www_form(query)
192
+ response = http.request(request)
193
+ response.key?('Location') ? response["Location"] : url
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,3 @@
1
+ module Stalkerr
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../lib/stalkerr/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.authors = ['linyows']
5
+ gem.email = ['linyows@gmail.com']
6
+ gem.description = %q{Stalkerr is IRC Server for stalking :)}
7
+ gem.summary = %q{Stalkerr is IRC Gateway, inspired by agig and atig.}
8
+ gem.homepage = 'https://github.com/linyows/stalkerr'
9
+
10
+ gem.required_ruby_version = Gem::Requirement.new(">= 1.9.3")
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = 'stalkerr'
16
+ gem.require_paths = ['lib']
17
+ gem.version = Stalkerr::VERSION
18
+
19
+ gem.add_dependency 'net-irc'
20
+ gem.add_dependency 'json'
21
+ gem.add_dependency 'octokit'
22
+ gem.add_dependency 'string-irc'
23
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stalkerr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - linyows
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-irc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: json
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: octokit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: string-irc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Stalkerr is IRC Server for stalking :)
70
+ email:
71
+ - linyows@gmail.com
72
+ executables:
73
+ - stalkerr
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - bin/stalkerr
83
+ - lib/stalkerr.rb
84
+ - lib/stalkerr/const.rb
85
+ - lib/stalkerr/extensions/string.rb
86
+ - lib/stalkerr/optparse.rb
87
+ - lib/stalkerr/server.rb
88
+ - lib/stalkerr/session.rb
89
+ - lib/stalkerr/target.rb
90
+ - lib/stalkerr/target/github.rb
91
+ - lib/stalkerr/version.rb
92
+ - stalkerr.gemspec
93
+ homepage: https://github.com/linyows/stalkerr
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: 1.9.3
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.0.0
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: Stalkerr is IRC Gateway, inspired by agig and atig.
116
+ test_files: []