Skip to content

Commit 42d9bf0

Browse files
author
Patrick Crosby
committed
added mutex around @running
1 parent 0f4ff71 commit 42d9bf0

File tree

8 files changed

+174
-182
lines changed

8 files changed

+174
-182
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ doc
1414
# jeweler generated
1515
pkg
1616

17-
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
17+
*.gem
18+
19+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
1820
#
1921
# * Create a file at ~/.gitignore
2022
# * Include files you want ignored

Gemfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ source "http://rubygems.org"
77
# Include everything needed to run rake, tests, features, etc.
88
group :development do
99
gem "minitest", ">= 0"
10-
gem "bundler", "~> 1.0.0"
11-
gem "jeweler", "~> 1.5.2"
12-
gem "rcov", ">= 0"
13-
gem "rocco"
10+
# gem "bundler", "~> 1.0.0"
11+
# gem "jeweler", "~> 1.5.2"
12+
# gem "rcov", ">= 0"
13+
# gem "rocco"
1414
end

Gemfile.lock

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
11
GEM
22
remote: http://rubygems.org/
33
specs:
4-
git (1.2.5)
5-
jeweler (1.5.2)
6-
bundler (~> 1.0.0)
7-
git (>= 1.2.5)
8-
rake
94
minitest (2.0.2)
10-
mustache (0.12.0)
11-
rake (0.8.7)
12-
rcov (0.9.9)
13-
rdiscount (1.6.5)
14-
rocco (0.5)
15-
mustache
16-
rdiscount
175

186
PLATFORMS
197
ruby
208

219
DEPENDENCIES
22-
bundler (~> 1.0.0)
23-
jeweler (~> 1.5.2)
2410
minitest
25-
rcov
26-
rocco

Rakefile

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
require 'rubygems'
2-
require 'bundler'
3-
begin
4-
Bundler.setup(:default, :development)
5-
rescue Bundler::BundlerError => e
6-
$stderr.puts e.message
7-
$stderr.puts "Run `bundle install` to install missing gems"
8-
exit e.status_code
9-
end
2+
#require 'bundler'
3+
#begin
4+
# Bundler.setup(:default, :development)
5+
#rescue Bundler::BundlerError => e
6+
# $stderr.puts e.message
7+
# $stderr.puts "Run `bundle install` to install missing gems"
8+
# exit e.status_code
9+
#end
1010
require 'rake'
1111

12-
require 'jeweler'
13-
Jeweler::Tasks.new do |gem|
14-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15-
gem.name = "stathat"
16-
gem.homepage = "http://github.com/patrickxb/stathat"
17-
gem.license = "MIT"
18-
gem.summary = %Q{gem to access StatHat api}
19-
gem.description = %Q{Easily post stats to your StatHat account using this gem. Encapsulates full API.}
20-
gem.email = "[email protected]"
21-
gem.authors = ["Patrick Crosby"]
22-
# Include your dependencies below. Runtime dependencies are required when using your gem,
23-
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24-
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
25-
# gem.add_development_dependency 'rspec', '> 1.2.3'
26-
end
27-
Jeweler::RubygemsDotOrgTasks.new
12+
#require 'jeweler'
13+
#Jeweler::Tasks.new do |gem|
14+
# # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15+
# gem.name = "stathat"
16+
# gem.homepage = "http://github.com/patrickxb/stathat"
17+
# gem.license = "MIT"
18+
# gem.summary = %Q{gem to access StatHat api}
19+
# gem.description = %Q{Easily post stats to your StatHat account using this gem. Encapsulates full API.}
20+
# gem.email = "[email protected]"
21+
# gem.authors = ["Patrick Crosby"]
22+
# # Include your dependencies below. Runtime dependencies are required when using your gem,
23+
# # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24+
# # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25+
# # gem.add_development_dependency 'rspec', '> 1.2.3'
26+
#end
27+
#Jeweler::RubygemsDotOrgTasks.new
2828

2929
require 'rake/testtask'
3030
Rake::TestTask.new(:test) do |test|
@@ -33,28 +33,29 @@ Rake::TestTask.new(:test) do |test|
3333
test.verbose = true
3434
end
3535

36-
require 'rcov/rcovtask'
37-
Rcov::RcovTask.new do |test|
38-
test.libs << 'test'
39-
test.pattern = 'test/**/test_*.rb'
40-
test.verbose = true
41-
end
36+
#require 'rcov/rcovtask'
37+
#Rcov::RcovTask.new do |test|
38+
# test.libs << 'test'
39+
# test.pattern = 'test/**/test_*.rb'
40+
# test.verbose = true
41+
#end
4242

4343
task :default => :test
4444

45-
require 'rake/rdoctask'
46-
Rake::RDocTask.new do |rdoc|
47-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
48-
49-
rdoc.rdoc_dir = 'rdoc'
50-
rdoc.title = "stathat #{version}"
51-
rdoc.rdoc_files.include('README*')
52-
rdoc.rdoc_files.include('lib/**/*.rb')
53-
end
45+
require 'rdoc/task'
46+
#require 'rake/rdoctask'
47+
#Rake::RDocTask.new do |rdoc|
48+
# version = File.exist?('VERSION') ? File.read('VERSION') : ""
49+
#
50+
# rdoc.rdoc_dir = 'rdoc'
51+
# rdoc.title = "stathat #{version}"
52+
# rdoc.rdoc_files.include('README*')
53+
# rdoc.rdoc_files.include('lib/**/*.rb')
54+
#end
5455

55-
namespace :doc do
56-
desc "build literate documentation"
57-
task :build do
58-
sh "rocco -o doc lib/*.rb"
59-
end
60-
end
56+
#namespace :doc do
57+
# desc "build literate documentation"
58+
# task :build do
59+
# sh "rocco -o doc lib/*.rb"
60+
# end
61+
#end

lib/stathat.rb

Lines changed: 84 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,100 +2,126 @@
22
require 'uri'
33
require 'json'
44
require 'thread'
5+
require 'singleton'
56

67
module StatHat
78
class API
8-
CLASSIC_VALUE_URL = "http://api.stathat.com/v"
9-
CLASSIC_COUNT_URL = "http://api.stathat.com/c"
10-
EZ_URL = "http://api.stathat.com/ez"
11-
12-
REPORTER = self.new()
9+
class << self
10+
def ez_post_value(stat_name, ezkey, value, &block)
11+
Reporter.instance.ez_post_value(stat_name, ezkey, value, block)
12+
end
1313

14-
def initialize()
15-
@Q = Queue.new
16-
run_pool()
17-
end
14+
def ez_post_count(stat_name, ezkey, count, &block)
15+
Reporter.instance.ez_post_count(stat_name, ezkey, count, block)
16+
end
1817

19-
def enqueue(url, args)
20-
point = {:url => url, :args => args}
21-
@Q << point
22-
end
18+
def post_count(stat_key, user_key, count, &block)
19+
Reporter.instance.post_count(stat_key, user_key, count, block)
20+
end
2321

24-
def run_pool()
25-
@running = true
26-
@pool = []
27-
5.times do |i|
28-
pool[i] = Thread.new do
29-
while @running do
30-
point = @Q.pop
31-
# XXX check for error?
32-
send_to_stathat(point[:url], point[:args])
33-
end
34-
end
22+
def post_value(stat_key, user_key, value, &block)
23+
Reporter.instance.post_value(stat_key, user_key, value, block)
3524
end
3625
end
26+
end
3727

38-
def stop_pool()
39-
@running = false
40-
@pool.each do |th|
41-
th.join
42-
end
28+
class Reporter
29+
include Singleton
30+
31+
CLASSIC_VALUE_URL = "http://api.stathat.com/v"
32+
CLASSIC_COUNT_URL = "http://api.stathat.com/c"
33+
EZ_URL = "http://api.stathat.com/ez"
34+
35+
36+
def initialize
37+
@que = Queue.new
38+
@runlock = Mutex.new
39+
run_pool()
4340
end
4441

4542
def finish()
4643
stop_pool
4744
# XXX serialize queue?
4845
end
4946

50-
def send_to_stathat(url, args)
51-
uri = URI.parse(url)
52-
uri.query = URI.encode_www_form(args)
53-
resp = Net::HTTP.get(uri)
54-
return Response.new(resp)
55-
end
56-
57-
def post_value(stat_key, user_key, value)
47+
def post_value(stat_key, user_key, value, cb)
5848
args = { :key => stat_key,
5949
:ukey => user_key,
6050
:value => value }
61-
enqueue(CLASSIC_VALUE_URL, args)
62-
end
63-
64-
def self.post_value(stat_key, user_key, value)
65-
REPORTER.post_value(stat_key, user_key, value)
51+
enqueue(CLASSIC_VALUE_URL, args, cb)
6652
end
6753

68-
def post_count(stat_key, user_key, count)
54+
def post_count(stat_key, user_key, count, cb)
6955
args = { :key => stat_key,
7056
:ukey => user_key,
7157
:count => count }
72-
enqueue(CLASSIC_COUNT_URL, args)
73-
end
74-
75-
def self.post_count(stat_key, user_key, count)
76-
REPORTER.post_count(stat_key, user_key, count)
58+
enqueue(CLASSIC_COUNT_URL, args, cb)
7759
end
7860

79-
def ez_post_value(stat_name, ezkey, value)
61+
def ez_post_value(stat_name, ezkey, value, cb)
62+
puts "ezval cb: #{cb}"
8063
args = { :stat => stat_name,
8164
:ezkey => ezkey,
8265
:value => value }
83-
enqueue(EZ_URL, args)
66+
enqueue(EZ_URL, args, cb)
8467
end
8568

86-
def self.ez_post_value(stat_name, ezkey, value)
87-
REPORTER.ez_post_value(stat_name, ezkey, value)
88-
end
89-
90-
def ez_post_count(stat_name, ezkey, count)
69+
def ez_post_count(stat_name, ezkey, count, cb)
9170
args = { :stat => stat_name,
9271
:ezkey => ezkey,
9372
:count => count }
94-
enqueue(EZ_URL, args)
73+
enqueue(EZ_URL, args, cb)
74+
end
75+
76+
private
77+
def run_pool
78+
@runlock.synchronize { @running = true }
79+
@pool = []
80+
5.times do |i|
81+
@pool[i] = Thread.new do
82+
puts "thread #{i} started"
83+
while true do
84+
point = @que.pop
85+
# XXX check for error?
86+
begin
87+
puts "thread #{i}: sending"
88+
resp = send_to_stathat(point[:url], point[:args])
89+
if point[:cb]
90+
point[:cb].call(resp)
91+
end
92+
rescue
93+
pp $!
94+
end
95+
@runlock.synchronize {
96+
break unless @running
97+
}
98+
end
99+
puts "reporter thread #{i} finished"
100+
end
101+
end
102+
end
103+
104+
def stop_pool()
105+
@runlock.synchronize {
106+
@running = false
107+
}
108+
@pool.each do |th|
109+
th.join if th && th.alive?
110+
end
95111
end
96112

97-
def self.ez_post_count(stat_name, ezkey, count)
98-
REPORTER.ez_post_count(stat_name, ezkey, count)
113+
def enqueue(url, args, cb=nil)
114+
return false unless @running
115+
point = {:url => url, :args => args, :cb => cb}
116+
@que << point
117+
true
118+
end
119+
120+
def send_to_stathat(url, args)
121+
uri = URI.parse(url)
122+
uri.query = URI.encode_www_form(args)
123+
resp = Net::HTTP.get(uri)
124+
return Response.new(resp)
99125
end
100126
end
101127

stathat.gemspec

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
1-
# Generated by jeweler
2-
# DO NOT EDIT THIS FILE DIRECTLY
3-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
41
# -*- encoding: utf-8 -*-
52

63
Gem::Specification.new do |s|
74
s.name = %q{stathat}
8-
s.version = "0.0.4"
9-
10-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11-
s.authors = ["Patrick Crosby"]
12-
s.date = %q{2012-05-17}
5+
s.version = "0.1.3"
6+
s.authors = ["StatHat"]
137
s.description = %q{Easily post stats to your StatHat account using this gem. Encapsulates full API.}
14-
s.email = %q{patrick@xblabs.com}
8+
s.email = %q{info@stathat.com}
159
s.extra_rdoc_files = [
1610
"LICENSE.txt",
1711
"README.rdoc"
@@ -32,35 +26,10 @@ Gem::Specification.new do |s|
3226
s.homepage = %q{http://github.com/patrickxb/stathat}
3327
s.licenses = ["MIT"]
3428
s.require_paths = ["lib"]
35-
s.rubygems_version = %q{1.5.0}
3629
s.summary = %q{gem to access StatHat api}
3730
s.test_files = [
3831
"test/helper.rb",
3932
"test/test_stathat.rb"
4033
]
41-
42-
if s.respond_to? :specification_version then
43-
s.specification_version = 3
44-
45-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46-
s.add_development_dependency(%q<minitest>, [">= 0"])
47-
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48-
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
49-
s.add_development_dependency(%q<rcov>, [">= 0"])
50-
s.add_development_dependency(%q<rocco>, [">= 0"])
51-
else
52-
s.add_dependency(%q<minitest>, [">= 0"])
53-
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
54-
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
55-
s.add_dependency(%q<rcov>, [">= 0"])
56-
s.add_dependency(%q<rocco>, [">= 0"])
57-
end
58-
else
59-
s.add_dependency(%q<minitest>, [">= 0"])
60-
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
61-
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
62-
s.add_dependency(%q<rcov>, [">= 0"])
63-
s.add_dependency(%q<rocco>, [">= 0"])
64-
end
6534
end
6635

0 commit comments

Comments
 (0)