use system thin for native compilation

This commit is contained in:
tdreyno 2009-11-17 15:33:46 -08:00
parent 4692ceff07
commit 83d3456837
1048 changed files with 87367 additions and 43151 deletions

View file

@ -1,9 +1,8 @@
source "http://gemcutter.org"
bin_path "vendor/bin"
disable_rubygems
disable_system_gems
# disable_rubygems
# disable_system_gems
gem "thin"
gem "shotgun"
gem "templater"
gem "sprockets"
@ -14,7 +13,11 @@ gem "yui-compressor"
gem "haml"
gem "compass"
gem "smusher"
gem "compass-slickmap"
gem "maruku"
gem "markaby"
gem "jeweler"
gem "rspec"
gem "rdoc"
gem "sdoc"

View file

@ -13,20 +13,20 @@ begin
gem.rubyforge_project = "middleman"
gem.executables = %w(mm-init mm-build mm-server)
gem.add_dependency("thin")
gem.add_dependency("shotgun")
gem.add_dependency("templater")
gem.add_dependency("sprockets")
gem.add_dependency("sinatra")
gem.add_dependency("sinatra-content-for")
gem.add_dependency("rack-test")
gem.add_dependency("yui-compressor")
gem.add_dependency("smusher")
gem.add_dependency("haml", ">=2.1.0")
gem.add_dependency("compass")
gem.add_development_dependency("rdoc")
gem.add_development_dependency("rspec")
gem.add_development_dependency("sdoc")
gem.add_development_dependency("cucumber")
# gem.add_dependency("shotgun")
# gem.add_dependency("templater")
# gem.add_dependency("sprockets")
# gem.add_dependency("sinatra")
# gem.add_dependency("sinatra-content-for")
# gem.add_dependency("rack-test")
# gem.add_dependency("yui-compressor")
# gem.add_dependency("smusher")
# gem.add_dependency("haml", ">=2.1.0")
# gem.add_dependency("compass")
# gem.add_development_dependency("rdoc")
# gem.add_development_dependency("rspec")
# gem.add_development_dependency("sdoc")
# gem.add_development_dependency("cucumber")
# Ignore vendored files
gem.files = gem.files.exclude("vendor/*")

View file

@ -52,6 +52,7 @@ require 'shotgun'
config = File.join(File.dirname(__FILE__), '..', 'lib', 'middleman', 'config.ru')
app = Shotgun.new(config, lambda { |inner_app| Middleman::Base })
require 'rubygems'
require 'thin'
Thin::Logging.silent = true

3
vendor/bin/jeweler vendored Executable file
View file

@ -0,0 +1,3 @@
#!/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby
require File.join(File.dirname(__FILE__), "../gems/environment")
load File.join(File.dirname(__FILE__), "../gems/gems/jeweler-1.3.0/bin/jeweler")

View file

@ -1,3 +1,3 @@
#!/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby
require File.join(File.dirname(__FILE__), "../gems/environment")
load File.join(File.dirname(__FILE__), "../gems/gems/thin-1.2.5/bin/thin")
load File.join(File.dirname(__FILE__), "../gems/gems/maruku-0.6.0/bin/maruku")

3
vendor/bin/marutex vendored Executable file
View file

@ -0,0 +1,3 @@
#!/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby
require File.join(File.dirname(__FILE__), "../gems/environment")
load File.join(File.dirname(__FILE__), "../gems/gems/maruku-0.6.0/bin/marutex")

3
vendor/bin/rubyforge vendored Executable file
View file

@ -0,0 +1,3 @@
#!/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby
require File.join(File.dirname(__FILE__), "../gems/environment")
load File.join(File.dirname(__FILE__), "../gems/gems/rubyforge-2.0.3/bin/rubyforge")

Binary file not shown.

BIN
vendor/gems/cache/gemcutter-0.1.7.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/git-1.2.5.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/jeweler-1.3.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/json_pure-1.2.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/markaby-0.5.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/maruku-0.6.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/net-scp-1.0.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/net-ssh-2.0.15.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/rubyforge-2.0.3.gem vendored Normal file

Binary file not shown.

BIN
vendor/gems/cache/syntax-1.0.0.gem vendored Normal file

Binary file not shown.

View file

@ -3,37 +3,43 @@ module Bundler
file = File.expand_path(__FILE__)
dir = File.dirname(file)
ENV["GEM_HOME"] = dir
ENV["GEM_PATH"] = dir
ENV["PATH"] = "#{dir}/../bin:#{ENV["PATH"]}"
ENV["RUBYOPT"] = "-r#{file} #{ENV["RUBYOPT"]}"
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/builder-2.1.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/builder-2.1.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/polyglot-0.2.9/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/polyglot-0.2.9/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/treetop-1.4.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/treetop-1.4.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/term-ansicolor-1.0.4/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/term-ansicolor-1.0.4/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/syntax-1.0.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/syntax-1.0.0/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/maruku-0.6.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/maruku-0.6.0/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/extlib-0.9.13/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/extlib-0.9.13/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/highline-1.5.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/highline-1.5.1/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/diff-lcs-1.1.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/diff-lcs-1.1.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/cucumber-0.4.4/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/cucumber-0.4.4/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rspec-1.2.9/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rspec-1.2.9/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/templater-1.0.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/templater-1.0.0/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/eventmachine-0.12.10/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/eventmachine-0.12.10/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/daemons-1.0.10/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/daemons-1.0.10/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/net-ssh-2.0.15/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/net-ssh-2.0.15/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/haml-2.2.13/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/haml-2.2.13/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/net-scp-1.0.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/net-scp-1.0.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/json_pure-1.2.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/json_pure-1.2.0/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/gemcutter-0.1.7/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/gemcutter-0.1.7/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rubyforge-2.0.3/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rubyforge-2.0.3/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/git-1.2.5/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/git-1.2.5/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/jeweler-1.3.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/jeweler-1.3.0/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/json-1.2.0/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/json-1.2.0/ext/json/ext")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/json-1.2.0/ext")
@ -44,12 +50,18 @@ module Bundler
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rake-0.8.7/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sprockets-1.0.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sprockets-1.0.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/builder-2.1.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/builder-2.1.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/cucumber-0.4.4/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/cucumber-0.4.4/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rspec-1.2.9/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rspec-1.2.9/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/markaby-0.5/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/markaby-0.5/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/smusher-0.4.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/smusher-0.4.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rack-1.0.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rack-1.0.1/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/thin-1.2.5/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/thin-1.2.5/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rack-test-0.5.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rack-test-0.5.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/configuration-1.1.0/bin")
@ -64,15 +76,109 @@ module Bundler
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/rdoc-2.4.3/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sdoc-0.2.14.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sdoc-0.2.14.1/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/yui-compressor-0.9.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/yui-compressor-0.9.1/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sinatra-content-for-0.2/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/sinatra-content-for-0.2/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/compass-0.8.17/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/compass-0.8.17/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/yui-compressor-0.9.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/yui-compressor-0.9.1/lib")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/compass-slickmap-0.2.1/bin")
$LOAD_PATH.unshift File.expand_path("#{dir}/gems/compass-slickmap-0.2.1/lib")
@gemfile = "#{dir}/../../Gemfile"
require "rubygems"
@bundled_specs = {}
@bundled_specs["polyglot"] = eval(File.read("#{dir}/specifications/polyglot-0.2.9.gemspec"))
@bundled_specs["polyglot"].loaded_from = "#{dir}/specifications/polyglot-0.2.9.gemspec"
@bundled_specs["treetop"] = eval(File.read("#{dir}/specifications/treetop-1.4.2.gemspec"))
@bundled_specs["treetop"].loaded_from = "#{dir}/specifications/treetop-1.4.2.gemspec"
@bundled_specs["term-ansicolor"] = eval(File.read("#{dir}/specifications/term-ansicolor-1.0.4.gemspec"))
@bundled_specs["term-ansicolor"].loaded_from = "#{dir}/specifications/term-ansicolor-1.0.4.gemspec"
@bundled_specs["syntax"] = eval(File.read("#{dir}/specifications/syntax-1.0.0.gemspec"))
@bundled_specs["syntax"].loaded_from = "#{dir}/specifications/syntax-1.0.0.gemspec"
@bundled_specs["maruku"] = eval(File.read("#{dir}/specifications/maruku-0.6.0.gemspec"))
@bundled_specs["maruku"].loaded_from = "#{dir}/specifications/maruku-0.6.0.gemspec"
@bundled_specs["extlib"] = eval(File.read("#{dir}/specifications/extlib-0.9.13.gemspec"))
@bundled_specs["extlib"].loaded_from = "#{dir}/specifications/extlib-0.9.13.gemspec"
@bundled_specs["highline"] = eval(File.read("#{dir}/specifications/highline-1.5.1.gemspec"))
@bundled_specs["highline"].loaded_from = "#{dir}/specifications/highline-1.5.1.gemspec"
@bundled_specs["diff-lcs"] = eval(File.read("#{dir}/specifications/diff-lcs-1.1.2.gemspec"))
@bundled_specs["diff-lcs"].loaded_from = "#{dir}/specifications/diff-lcs-1.1.2.gemspec"
@bundled_specs["templater"] = eval(File.read("#{dir}/specifications/templater-1.0.0.gemspec"))
@bundled_specs["templater"].loaded_from = "#{dir}/specifications/templater-1.0.0.gemspec"
@bundled_specs["net-ssh"] = eval(File.read("#{dir}/specifications/net-ssh-2.0.15.gemspec"))
@bundled_specs["net-ssh"].loaded_from = "#{dir}/specifications/net-ssh-2.0.15.gemspec"
@bundled_specs["haml"] = eval(File.read("#{dir}/specifications/haml-2.2.13.gemspec"))
@bundled_specs["haml"].loaded_from = "#{dir}/specifications/haml-2.2.13.gemspec"
@bundled_specs["net-scp"] = eval(File.read("#{dir}/specifications/net-scp-1.0.2.gemspec"))
@bundled_specs["net-scp"].loaded_from = "#{dir}/specifications/net-scp-1.0.2.gemspec"
@bundled_specs["json_pure"] = eval(File.read("#{dir}/specifications/json_pure-1.2.0.gemspec"))
@bundled_specs["json_pure"].loaded_from = "#{dir}/specifications/json_pure-1.2.0.gemspec"
@bundled_specs["gemcutter"] = eval(File.read("#{dir}/specifications/gemcutter-0.1.7.gemspec"))
@bundled_specs["gemcutter"].loaded_from = "#{dir}/specifications/gemcutter-0.1.7.gemspec"
@bundled_specs["rubyforge"] = eval(File.read("#{dir}/specifications/rubyforge-2.0.3.gemspec"))
@bundled_specs["rubyforge"].loaded_from = "#{dir}/specifications/rubyforge-2.0.3.gemspec"
@bundled_specs["git"] = eval(File.read("#{dir}/specifications/git-1.2.5.gemspec"))
@bundled_specs["git"].loaded_from = "#{dir}/specifications/git-1.2.5.gemspec"
@bundled_specs["jeweler"] = eval(File.read("#{dir}/specifications/jeweler-1.3.0.gemspec"))
@bundled_specs["jeweler"].loaded_from = "#{dir}/specifications/jeweler-1.3.0.gemspec"
@bundled_specs["json"] = eval(File.read("#{dir}/specifications/json-1.2.0.gemspec"))
@bundled_specs["json"].loaded_from = "#{dir}/specifications/json-1.2.0.gemspec"
@bundled_specs["httpclient"] = eval(File.read("#{dir}/specifications/httpclient-2.1.5.2.gemspec"))
@bundled_specs["httpclient"].loaded_from = "#{dir}/specifications/httpclient-2.1.5.2.gemspec"
@bundled_specs["rake"] = eval(File.read("#{dir}/specifications/rake-0.8.7.gemspec"))
@bundled_specs["rake"].loaded_from = "#{dir}/specifications/rake-0.8.7.gemspec"
@bundled_specs["sprockets"] = eval(File.read("#{dir}/specifications/sprockets-1.0.2.gemspec"))
@bundled_specs["sprockets"].loaded_from = "#{dir}/specifications/sprockets-1.0.2.gemspec"
@bundled_specs["builder"] = eval(File.read("#{dir}/specifications/builder-2.1.2.gemspec"))
@bundled_specs["builder"].loaded_from = "#{dir}/specifications/builder-2.1.2.gemspec"
@bundled_specs["cucumber"] = eval(File.read("#{dir}/specifications/cucumber-0.4.4.gemspec"))
@bundled_specs["cucumber"].loaded_from = "#{dir}/specifications/cucumber-0.4.4.gemspec"
@bundled_specs["rspec"] = eval(File.read("#{dir}/specifications/rspec-1.2.9.gemspec"))
@bundled_specs["rspec"].loaded_from = "#{dir}/specifications/rspec-1.2.9.gemspec"
@bundled_specs["markaby"] = eval(File.read("#{dir}/specifications/markaby-0.5.gemspec"))
@bundled_specs["markaby"].loaded_from = "#{dir}/specifications/markaby-0.5.gemspec"
@bundled_specs["smusher"] = eval(File.read("#{dir}/specifications/smusher-0.4.2.gemspec"))
@bundled_specs["smusher"].loaded_from = "#{dir}/specifications/smusher-0.4.2.gemspec"
@bundled_specs["rack"] = eval(File.read("#{dir}/specifications/rack-1.0.1.gemspec"))
@bundled_specs["rack"].loaded_from = "#{dir}/specifications/rack-1.0.1.gemspec"
@bundled_specs["rack-test"] = eval(File.read("#{dir}/specifications/rack-test-0.5.2.gemspec"))
@bundled_specs["rack-test"].loaded_from = "#{dir}/specifications/rack-test-0.5.2.gemspec"
@bundled_specs["configuration"] = eval(File.read("#{dir}/specifications/configuration-1.1.0.gemspec"))
@bundled_specs["configuration"].loaded_from = "#{dir}/specifications/configuration-1.1.0.gemspec"
@bundled_specs["launchy"] = eval(File.read("#{dir}/specifications/launchy-0.3.3.gemspec"))
@bundled_specs["launchy"].loaded_from = "#{dir}/specifications/launchy-0.3.3.gemspec"
@bundled_specs["shotgun"] = eval(File.read("#{dir}/specifications/shotgun-0.4.gemspec"))
@bundled_specs["shotgun"].loaded_from = "#{dir}/specifications/shotgun-0.4.gemspec"
@bundled_specs["sinatra"] = eval(File.read("#{dir}/specifications/sinatra-0.9.4.gemspec"))
@bundled_specs["sinatra"].loaded_from = "#{dir}/specifications/sinatra-0.9.4.gemspec"
@bundled_specs["rdoc"] = eval(File.read("#{dir}/specifications/rdoc-2.4.3.gemspec"))
@bundled_specs["rdoc"].loaded_from = "#{dir}/specifications/rdoc-2.4.3.gemspec"
@bundled_specs["sdoc"] = eval(File.read("#{dir}/specifications/sdoc-0.2.14.1.gemspec"))
@bundled_specs["sdoc"].loaded_from = "#{dir}/specifications/sdoc-0.2.14.1.gemspec"
@bundled_specs["yui-compressor"] = eval(File.read("#{dir}/specifications/yui-compressor-0.9.1.gemspec"))
@bundled_specs["yui-compressor"].loaded_from = "#{dir}/specifications/yui-compressor-0.9.1.gemspec"
@bundled_specs["sinatra-content-for"] = eval(File.read("#{dir}/specifications/sinatra-content-for-0.2.gemspec"))
@bundled_specs["sinatra-content-for"].loaded_from = "#{dir}/specifications/sinatra-content-for-0.2.gemspec"
@bundled_specs["compass"] = eval(File.read("#{dir}/specifications/compass-0.8.17.gemspec"))
@bundled_specs["compass"].loaded_from = "#{dir}/specifications/compass-0.8.17.gemspec"
@bundled_specs["compass-slickmap"] = eval(File.read("#{dir}/specifications/compass-slickmap-0.2.1.gemspec"))
@bundled_specs["compass-slickmap"].loaded_from = "#{dir}/specifications/compass-slickmap-0.2.1.gemspec"
def self.add_specs_to_loaded_specs
Gem.loaded_specs.merge! @bundled_specs
end
def self.add_specs_to_index
@bundled_specs.each do |name, spec|
Gem.source_index.add_spec spec
end
end
add_specs_to_loaded_specs
add_specs_to_index
def self.require_env(env = nil)
context = Class.new do
@ -129,36 +235,11 @@ module Bundler
end
end
$" << "rubygems.rb"
module Gem
@loaded_stacks = Hash.new { |h,k| h[k] = [] }
module Kernel
def gem(*)
# Silently ignore calls to gem, since, in theory, everything
# is activated correctly already.
def source_index.refresh!
super
Bundler.add_specs_to_index
end
end
# Define all the Gem errors for gems that reference them.
module Gem
def self.ruby ; "/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby" ; end
class LoadError < ::LoadError; end
class Exception < RuntimeError; end
class CommandLineError < Exception; end
class DependencyError < Exception; end
class DependencyRemovalException < Exception; end
class GemNotInHomeException < Exception ; end
class DocumentError < Exception; end
class EndOfYAMLException < Exception; end
class FilePermissionError < Exception; end
class FormatException < Exception; end
class GemNotFoundException < Exception; end
class InstallError < Exception; end
class InvalidSpecificationException < Exception; end
class OperationNotSupportedError < Exception; end
class RemoteError < Exception; end
class RemoteInstallationCancelled < Exception; end
class RemoteInstallationSkipped < Exception; end
class RemoteSourceException < Exception; end
class VerificationError < Exception; end
class SystemExitException < SystemExit; end
end

View file

@ -0,0 +1,3 @@
.DS_Store
pkg
.sass-cache

View file

@ -0,0 +1,20 @@
require 'rubygems'
require 'rake'
begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "compass-slickmap"
gem.summary = %Q{An implementation of SlickmapCSS sitemap in Sass}
gem.email = "tdreyno@gmail.com"
gem.homepage = "http://github.com/tdreyno/compass-slickmap"
gem.authors = ["Thomas Reynolds"]
gem.rubyforge_project = "compassslickmap"
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
gem.add_dependency("compass")
end
Jeweler::RubyforgeTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
end

View file

@ -0,0 +1 @@
0.2.1

View file

@ -0,0 +1,53 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{compass-slickmap}
s.version = "0.2.1"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Thomas Reynolds"]
s.date = %q{2009-10-09}
s.email = %q{tdreyno@gmail.com}
s.files = [
".gitignore",
"Rakefile",
"VERSION",
"compass-slickmap.gemspec",
"lib/slickmap.rb",
"lib/slickmap/compass_plugin.rb",
"sass/_slickmap.sass",
"templates/project/images/L1-center.png",
"templates/project/images/L1-left.png",
"templates/project/images/L1-right.png",
"templates/project/images/L3-bottom.png",
"templates/project/images/L3-center.png",
"templates/project/images/L3-li-top.png",
"templates/project/images/L3-ul-top.png",
"templates/project/images/vertical-line.png",
"templates/project/images/white-highlight.png",
"templates/project/manifest.rb",
"templates/project/sitemap.sass"
]
s.homepage = %q{http://github.com/tdreyno/compass-slickmap}
s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{compassslickmap}
s.rubygems_version = %q{1.3.5}
s.summary = %q{An implementation of SlickmapCSS sitemap in Sass}
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<compass>, [">= 0"])
else
s.add_dependency(%q<compass>, [">= 0"])
end
else
s.add_dependency(%q<compass>, [">= 0"])
end
end

View file

@ -0,0 +1,45 @@
require 'base64'
require File.join(File.dirname(__FILE__), 'slickmap', 'compass_plugin')
module Compass::SlickmapImage
def slickmap_image(path, mime_type = nil)
path = path.value
real_path = File.join(File.dirname(__FILE__), "..", "templates", "project", "images", path)
url = "url('data:#{compute_mime_type(path,mime_type)};base64,#{data(real_path)}')"
Sass::Script::String.new(url)
end
private
def compute_mime_type(path, mime_type)
return mime_type if mime_type
case path
when /\.png$/i
'image/png'
when /\.jpe?g$/i
'image/jpeg'
when /\.gif$/i
'image/gif'
when /\.([a-zA-Z]+)$/
"image/#{Regexp.last_match(1).downcase}"
else
raise Compass::Error, "A mime type could not be determined for #{path}, please specify one explicitly."
end
end
def data(real_path)
if File.readable?(real_path)
Base64.encode64(File.read(real_path)).gsub("\n","")
else
raise Compass::Error, "File not found or cannot be read: #{real_path}"
end
end
end
module ::Sass::Script::Functions
include Compass::SlickmapImage
end
class ::Sass::Script::Functions::EvaluationContext
include ::Sass::Script::Functions
end

View file

@ -0,0 +1,5 @@
options = Hash.new
options[:stylesheets_directory] = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'sass'))
options[:templates_directory] = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'templates'))
Compass::Frameworks.register('slickmap', options)

View file

@ -0,0 +1,206 @@
@import compass/utilities/general/reset.sass
=slickmap(!body_selector = "body")
+global-reset
#{!body_selector}
+slickmap-body
@if !body_selector != "body"
+slickmap-defaults
@if !body_selector == "body"
+slickmap-defaults
=slickmap-primary-nav
margin: 0
float: left
width: 100%
li
width: 25%
&.col1 li
width: 99.9%
&.col2 li
width: 50.0%
&.col3 li
width: 33.3%
&.col4 li
width: 25.0%
&.col5 li
width: 20.0%
&.col6 li
width: 16.6%
&.col7 li
width: 14.2%
&.col8 li
width: 12.5%
&.col9 li
width: 11.1%
&.col10 li
width: 10.0%
li
ul li
width: 100% !important
a:link:before, a:visited:before
color: #78a9c0
// Second Level
li
width: 100%
clear: left
margin-top: 0
padding: 10px 0 0 0
background= slickmap_image("vertical-line.png") "center" "bottom" "repeat-y"
a
background-color: #cee3ac
border-color: #b8da83
&:hover
border-color: #94b75f
background-color: #e7f1d7
&:first-child
padding-top: 30px
&:last-child
background= slickmap_image("vertical-line.png") "center" "bottom" "repeat-y"
a:link:before, a:visited:before
color: #8faf5c
// Third Level
ul
margin: 10px 0 0 0
width: 100%
float: right
padding: 9px 0 10px 0
background= #fff slickmap_image("L3-ul-top.png") "center" "top" "no-repeat"
li
background= slickmap_image("L3-center.png") "left" "center" "no-repeat"
padding: 5px 0
a
background-color: #fff7aa
border-color: #e3ca4b
font-size: 12px
padding: 5px 0
width: 80%
float: right
&:hover
background-color: #fffce5
border-color: #d1b62c
&:first-child
padding: 15px 0 5px 0
background= slickmap_image("L3-li-top.png") "left" "center" "no-repeat"
&:last-child
background= slickmap_image("L3-bottom.png") "left" "center" "no-repeat"
a:link:before, a:visited:before
color: #ccae14
font-size: 9px
li
float: left
background= slickmap_image("L1-center.png") "center" "top" "no-repeat"
padding: 30px 0
margin-top: -30px
&:last-child
background= slickmap_image("L1-right.png") "center" "top" "no-repeat"
a
margin: 0 20px 0 0
padding: 10px 0
display: block
font-size: 14px
font-weight: bold
text-align: center
color: black
background= #c3eafb slickmap_image("white-highlight.png") "top" "left" "repeat-x"
border: 2px solid #b5d9ea
-moz-border-radius: 5px
-webkit-border-radius: 5px
-webkit-box-shadow: rgba(0,0,0,0.5) 2px 2px 2px
-moz-box-shadow: rgba(0,0,0,0.5) 2px 2px 2px
&:hover
background-color: #e2f4fd
border-color: #97bdcf
=slickmap-primary-nav-home
display: block
float: none
background= #fff slickmap_image("L1-left.png") "center" "bottom" "no-repeat"
position: relative
z-index: 2
padding: 0 0 30px 0
=slickmap-utility-nav
float: right
max-width: 50%
margin-right: 10px
li
float: left
margin-bottom: 10px
a
margin: 0 10px 0 0
padding: 5px 10px
display: block
border: 2px solid #e3ca4b
font-size: 12px
font-weight: bold
text-align: center
color: black
background= #fff7aa slickmap_image("white-highlight.png") "top" "left" "repeat-x"
-moz-border-radius: 5px
-webkit-border-radius: 5px
-webkit-box-shadow: rgba(0,0,0,0.5) 2px 2px 2px
-moz-box-shadow: rgba(0,0,0,0.5) 2px 2px 2px
&:hover
background-color: #fffce5
border-color: #d1b62c
&:link:before, &:visited:before
color: #ccae14
font-size: 9px
margin-bottom: 3px
// General Styles
=slickmap-body
background: white
color: black
padding: 40px
font-family: Gotham, Helvetica, Arial, sans-serif
font-size: 12px
line-height: 1
=slickmap-defaults
.sitemap
margin: 0 0 40px 0
float: left
width: 100%
h1
font-weight: bold
text-transform: uppercase
font-size: 20px
margin: 0 0 5px 0
h2
font-family: "Lucida Grande", Verdana, sans-serif
font-size: 10px
color: #777777
margin: 0 0 20px 0
a
text-decoration: none
&:link:before, &:visited:before
content: " "attr(href)" "
display: block
text-transform: uppercase
font-size: 10px
margin-bottom: 5px
word-wrap: break-word
ol, ul
list-style: none
//
NUMBER OF COLUMNS: Adjust #primaryNav li to set the number
of columns required in your site map. The default is
4 columns (25%). 5 columns would be 20%, 6 columns would
be 16.6%, etc.
#primaryNav
+slickmap-primary-nav
li#home
+slickmap-primary-nav-home
// Utility Navigation
#utilityNav
+slickmap-utility-nav

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 305 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

View file

@ -0,0 +1,10 @@
image 'images/L1-center.png'
image 'images/L1-left.png'
image 'images/L1-right.png'
image 'images/L3-bottom.png'
image 'images/L3-center.png'
image 'images/L3-li-top.png'
image 'images/L3-ul-top.png'
image 'images/vertical-line.png'
image 'images/white-highlight.png'
stylesheet 'sitemap.sass', :media => "screen, projection"

View file

@ -0,0 +1,3 @@
@import slickmap.sass
+slickmap

View file

@ -1,29 +0,0 @@
Copyright (c) 2005-2007 Thomas Uehlinger
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
This license does not apply to daemonize.rb, which is was written by
Travis Whitton und published under the following license:
The Daemonize extension module is copywrited free software by Travis Whitton
<whitton@atlantic.net>. You can redistribute it under the terms specified in
the COPYING file of the Ruby distribution.

View file

@ -1,223 +0,0 @@
= Daemons Version 1.0.10
(See Releases for release-specific information)
== What is Daemons?
Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server)
to be <i>run as a daemon</i> and to be <i>controlled by simple start/stop/restart commands</i>.
If you want, you can also use daemons to <i>run blocks of ruby code in a daemon process</i> and to control
these processes from the main application.
Besides this basic functionality, daemons offers many advanced features like <i>exception backtracing</i>
and logging (in case your ruby script crashes) and <i>monitoring</i> and automatic restarting of your processes
if they crash.
Daemons includes the <tt>daemonize.rb</tt> script written by <i>Travis Whitton</i> to do the daemonization
process.
== Basic Usage
You can use Daemons in four differet ways:
=== 1. Create wrapper scripts for your server scripts or applications
Layout: suppose you have your self-written server <tt>myserver.rb</tt>:
# this is myserver.rb
# it does nothing really useful at the moment
loop do
sleep(5)
end
To use <tt>myserver.rb</tt> in a production environment, you need to be able to
run <tt>myserver.rb</tt> in the _background_ (this means detach it from the console, fork it
in the background, release all directories and file descriptors).
Just create <tt>myserver_control.rb</tt> like this:
# this is myserver_control.rb
require 'rubygems' # if you use RubyGems
require 'daemons'
Daemons.run('myserver.rb')
And use it like this from the console:
$ ruby myserver_control.rb start
(myserver.rb is now running in the background)
$ ruby myserver_control.rb restart
(...)
$ ruby myserver_control.rb stop
For testing purposes you can even run <tt>myserver.rb</tt> <i>without forking</i> in the background:
$ ruby myserver_control.rb run
An additional nice feature of Daemons is that you can pass <i>additional arguments</i> to the script that
should be daemonized by seperating them by two _hyphens_:
$ ruby myserver_control.rb start -- --file=anyfile --a_switch another_argument
=== 2. Create wrapper scripts that include your server procs
Layout: suppose you have some code you want to run in the background and control that background process
from a script:
# this is your code
# it does nothing really useful at the moment
loop do
sleep(5)
end
To run this code as a daemon create <tt>myproc_control.rb</tt> like this and include your code:
# this is myproc_control.rb
require 'rubygems' # if you use RubyGems
require 'daemons'
Daemons.run_proc('myproc.rb') do
loop do
sleep(5)
end
end
And use it like this from the console:
$ ruby myproc_control.rb start
(myproc.rb is now running in the background)
$ ruby myproc_control.rb restart
(...)
$ ruby myproc_control.rb stop
For testing purposes you can even run <tt>myproc.rb</tt> <i>without forking</i> in the background:
$ ruby myproc_control.rb run
=== 3. Control a bunch of daemons from another application
Layout: you have an application <tt>my_app.rb</tt> that wants to run a bunch of
server tasks as daemon processes.
# this is my_app.rb
require 'rubygems' # if you use RubyGems
require 'daemons'
task1 = Daemons.call(:multiple => true) do
# first server task
loop {
conn = accept_conn()
serve(conn)
}
end
task2 = Daemons.call do
# second server task
loop {
something_different()
}
end
# the parent process continues to run
# we can even control our tasks, for example stop them
task1.stop
task2.stop
exit
=== 4. Daemonize the currently running process
Layout: you have an application <tt>my_daemon.rb</tt> that wants to run as a daemon
(but without the ability to be controlled by daemons via start/stop commands)
# this is my_daemons.rb
require 'rubygems' # if you use RubyGems
require 'daemons'
# Initialize the app while we're not a daemon
init()
# Become a daemon
Daemons.daemonize
# The server loop
loop {
conn = accept_conn()
serve(conn)
}
<b>For further documentation, refer to the module documentation of Daemons.</b>
== Download and Installation
*Download*: just go to http://rubyforge.org/projects/daemons/
Installation *with* RubyGems:
$ su
# gem install daemons
Installation *without* RubyGems:
$ tar xfz daemons-x.x.x.tar.gz
$ cd daemons-x.x.x
$ su
# ruby setup.rb
== Documentation
For further documentation, refer to the module documentation of Daemons (click on Daemons).
The RDoc documentation is also online at http://daemons.rubyforge.org
== Author
Written in 2005-2008 by Thomas Uehlinger <mailto:th.uehlinger@gmx.ch>.
== License
Copyright (c) 2005-2008 Thomas Uehlinger
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
This license does not apply to daemonize.rb, which is was written by
Travis Whitton und published under the following license:
The Daemonize extension module is copywrited free software by Travis Whitton
<whitton@atlantic.net>. You can redistribute it under the terms specified in
the COPYING file of the Ruby distribution.
== Feedback and other resources
At http://rubyforge.org/projects/daemons.

View file

@ -1,84 +0,0 @@
require 'rubygems'
Gem::manage_gems
require 'rake/gempackagetask'
#require 'rake/testtask'
require 'rake/packagetask'
require 'rake/rdoctask'
$LOAD_PATH << './lib'
require 'daemons'
PKG_NAME = "daemons"
PKG_FILES = FileList[
"Rakefile", "Releases", "TODO", "README", "LICENSE",
"setup.rb",
"lib/**/*.rb",
#"test/**/*",
"examples/**/*"
]
#PKG_FILES.exclude(%r(^test/tmp/.+))
PKG_FILES.exclude(%r(\.pid$))
PKG_FILES.exclude(%r(\.log$))
spec = Gem::Specification.new do |s|
s.name = PKG_NAME
s.version = Daemons::VERSION
s.author = "Thomas Uehlinger"
s.email = "th.uehlinger@gmx.ch"
s.rubyforge_project = "daemons"
s.homepage = "http://daemons.rubyforge.org"
s.platform = Gem::Platform::RUBY
s.summary = "A toolkit to create and control daemons in different ways"
s.description = <<-EOF
Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server)
to be run as a daemon and to be controlled by simple start/stop/restart commands.
You can also call blocks as daemons and control them from the parent or just daemonize the current
process.
Besides this basic functionality, daemons offers many advanced features like exception
backtracing and logging (in case your ruby script crashes) and monitoring and automatic
restarting of your processes if they crash.
EOF
#s.files = FileList["{test,lib}/**/*"].exclude("rdoc").to_a
s.files = PKG_FILES
s.require_path = "lib"
s.autorequire = "daemons"
s.has_rdoc = true
s.extra_rdoc_files = ["README", "Releases", "TODO"]
end
Rake::GemPackageTask.new(spec) do |pkg|
pkg.need_tar = true
end
#Rake::PackageTask.new("package") do |p|
# p.name = PKG_NAME
# p.version = Daemons::VERSION
# p.need_tar = true
# p.need_zip = true
# p.package_files = PKG_FILES
#end
task :default => [:package]
task :upload do
sh "scp -r html/* uehli@rubyforge.org:/var/www/gforge-projects/daemons"
end
desc "Create the RDOC html files"
rd = Rake::RDocTask.new("rdoc") { |rdoc|
rdoc.rdoc_dir = 'html'
rdoc.title = "Daemons"
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
rdoc.rdoc_files.include('README', 'TODO', 'Releases')
rdoc.rdoc_files.include('lib/**/*.rb')
}

View file

@ -1,126 +0,0 @@
= Daemons Release History
== Release 1.0.10: November 16, 2007
* By default, we now delete stray pid-files (i.e. pid-files which result for
example from a killed daemon) automatically. This function can be deactivated by
passing :keep_pid_files => true as an option.
* All pid files of :multiple daemons new get deleted correctly upon exit of the daemons (reported by Han Holl).
* Use the signal 'KILL' instead of 'TERM' on Windows platforms.
* Use exit! in trap('TERM') instead of exit when option :hard_exit is given (thanks to Han Holl).
* Did some clarification on the exception log.
== Release 1.0.9: October 29, 2007
* fixed a severe bug in the new Pid.running? function: function returned true if the process did not exist (thanks to Jeremy Lawler).
== Release 1.0.8: September 24, 2007
* new Pid.running? function. Checking whether a process exists by sending signal '0' (thanks to Dru Nelson).
== Release 1.0.7: July 7, 2007
* Patch to fix wrong ARGV when using :exec (in def start_exec: Kernel.exec(script(), *(@app_argv || []))) (thanks to Alex McGuire).
== Release 1.0.6: Mai 8, 2007
* New option to pass an ARGV-style array to run and run_proc (thanks to Marc Evans).
* Additional patches for '/var/log' (thanks to Marc Evans).
== Release 1.0.5: February 24, 2007
* Applied patch that makes daemons to use '/var/log' as logfile
directory if you use :dir_mode = :system (thanks to Han Holl).
* Daemons should now work with Ruby 1.9 (at least the basic features).
== Release 1.0.4: January 17, 2007
* Document the :log_output option (thanks to Andrew Kuklewicz).
* Set STDOUT.sync = true when redirecting to a logfile (thanks to Andrew Kuklewicz).
* Should now run also correctly when there is no working 'ps ax' on the system (thanks to Daniel Kehoe).
== Release 1.0.3: November 1, 2006
* Set the app_name correctly also for the monitor process (thanks to Ilya Novoselov).
== Release 1.0.2: September 26, 2006
* Changed the 'ps -ax' call back to 'ps ax'.
* Fixed the documentation for the :normal :dir_mode.
* As a default for Daemons.run_proc, the pid file is now saved in the current directory.
* In :ontop mode for running a proc (this is equal to calling something like 'ruby ctrl_proc.rb run'),
the proc now runs directly in the calling script, not in a forked process anymore (thanks to Paul Butcher).
* Set $0 to app_name in the daemons (thanks to Ilya Novoselov).
== Release 1.0.1: August 30, 2006
* Fixed a regex for parsing the 'ps ax' system call. (thanks to Garance Alistair Drosehn)
== Release 1.0.0: August 29, 2006
* Fix the parsing of the 'ps ax' system call. (thanks to Garance Alistair Drosehn)
== Release 0.4.4: February 14, 2006
* Several fixes that allow us to use the Daemons::Controller
with a proc instead of wrapping a script file. This gives us all the
PID file management, monitoring, command line options, etc. without having
to specify a path to our script which can be tricky, especially when using
RubyGems. (thanks to John-Mason Shackelford)
== Release 0.4.3: November 29, 2005
* New Option: You can specify the name of the application with :app_name
on calling Daemons.run. This will be used to contruct the name of the pid files
and log files. Defaults to the basename of the script. (thanks to Stephen R. Veit)
* Bugfix: Handle the case where no controller options are given when calling Daemons,
just options after "--". (thanks to Stephen R. Veit)
== Release 0.4.2: November 15, 2005
* Bugfix for problem with :normal pid-file directory mode (pid.rb), fixed (thanks to Stephen R. Veit)
== Release 0.4.1: September 11, 2005
* Bugfix for 'run' command line mode: didn't work anymore in 0.4.0, fixed
== Release 0.4.0: July 30, 2005
* Two completely new operation modes:
1. Call a block as a daemon (<tt>Daemons.call { my_daemon_code }</tt>)
and control it from the parent process.
2. Daemonize the currently running process (<tt>Daemons.daemonize</tt>)
plus the already existing mode to control your scripts (<tt>Daemons.run("script.rb")</tt>)
* Improved documentation (for example "How does the daemonization process work?")
* Improved "simulation mode" (<tt>:ontop</tt> option)
* Some minor bugfixes
== Release 0.3.0: April 21, 2005
* New monitor functionality: automatic restarting of your applications if they crash
* 'restart' command fixed
* '--force' command modifier (please refer to the documentation)
* Some more bugfixes and improvements
== Release 0.2.1: Mar 21, 2005
* Bugfix for a problem with the 'status' command
== Release 0.2.0: Mar 21, 2005
* Exception backtrace functionality added
* Exec functionality added
* More examples added
* New commands: status, zap
== Release 0.0.1: Feb 8, 2005
* Initial release

View file

@ -1,6 +0,0 @@
* write the README (2005-02-07) *DONE*
* write some real tests (2005-02-08)
* document the new options (2005-03-14) *DONE*
* start/stop with --force options (2005-04-05)
* option to give some console output on start/stop commands (2005-04-05)

View file

@ -1,56 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
testfile = File.expand_path(__FILE__) + '.log'
# On the first call to <tt<call</tt>, an application group (accessible by <tt>Daemons.group</tt>)
# will be created an the options will be kept within, so you only have to specify
# <tt>:multiple</tt> once.
#
options = {
# :ontop => true,
:multiple => true
}
Daemons.call(options) do
File.open(testfile, 'w') {|f|
f.puts "test"
}
loop { puts "1"; sleep 5 }
end
puts "first task started"
Daemons.call do
loop { puts "2"; sleep 4 }
end
puts "second task started"
# NOTE: this process will exit after 5 seconds
Daemons.call do
puts "3"
sleep 5
end
puts "third task started"
puts "waiting 20 seconds..."
sleep(20)
# This call would result in an exception as it will try to kill the third process
# which has already terminated by that time; but using the 'true' parameter forces the
# stop_all procedure.
puts "trying to stop all tasks..."
Daemons.group.stop_all(true)
puts "done"

View file

@ -1,55 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
testfile = File.expand_path(__FILE__) + '.log'
# On the first call to <tt<call</tt>, an application group (accessible by <tt>Daemons.group</tt>)
# will be created an the options will be kept within, so you only have to specify
# <tt>:multiple</tt> once.
#
options = {
# :ontop => true,
:multiple => true,
:monitor => true
}
Daemons.call(options) do
loop { puts "1"; sleep 20 }
end
puts "first task started"
# NOTE: this process will exit after 5 seconds
Daemons.call do
File.open(testfile, 'a') {|f|
f.puts "started..."
puts "2"
sleep 5
f.puts "...exit"
}
end
puts "second task started"
puts "waiting 100 seconds..."
sleep(100)
# This call would result in an exception as it will try to kill the third process
# which has already terminated by that time; but using the 'true' parameter forces the
# stop_all procedure.
puts "trying to stop all tasks..."
Daemons.group.stop_all(true)
puts "done"

View file

@ -1,20 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
testfile = File.expand_path(__FILE__) + '.log'
Daemons.daemonize
File.open(testfile, 'w') {|f|
f.write("test")
}

View file

@ -1,17 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:log_output => true,
:backtrace => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver_crashing.rb'), options)

View file

@ -1,16 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:mode => :exec
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver.rb'), options)

View file

@ -1,15 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver_exiting.rb'), options)

View file

@ -1,17 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:keep_pid_files => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver.rb'), options)

View file

@ -1,16 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:monitor => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver_crashing.rb'), options)

View file

@ -1,16 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:multiple => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver.rb'), options)

View file

@ -1,12 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
Daemons.run(File.join(File.dirname(__FILE__), 'myserver.rb'))

View file

@ -1,16 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:ontop => true
}
Daemons.run(File.join(File.dirname(__FILE__), 'myserver.rb'), options)

View file

@ -1,43 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
require 'optparse'
require 'logger'
require 'ostruct'
class MyApp < Logger::Application
def initialize(args)
super(self.class)
@options = OpenStruct.new(:daemonize => true)
opts = OptionParser.new do |opts|
opts.banner = 'Usage: myapp [options]'
opts.separator ''
opts.on('-N','--no-daemonize',"Don't run as a daemon") do
@options.daemonize = false
end
end
@args = opts.parse!(args)
end
def run
Daemons.run_proc('myapp',{:ARGV => @args, :ontop => !@options.daemonize}) do
puts "@options.daemonize: #{@options.daemonize}"
STDOUT.sync = true
loop do
print '.'
sleep(2)
end
end
end
end
myapp = MyApp.new(ARGV)
myapp.run

View file

@ -1,25 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:multiple => false,
:ontop => false,
:backtrace => true,
:log_output => true,
:monitor => true
}
Daemons.run_proc('ctrl_proc.rb', options) do
loop do
puts 'ping from proc!'
sleep(3)
end
end

View file

@ -1,101 +0,0 @@
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!
ping from proc!

View file

@ -1,22 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
options = {
:log_output => true,
:multiple => true,
}
Daemons.run_proc('ctrl_proc_multiple.rb', options) do
puts "hello"
sleep(5)
puts "done"
end

View file

@ -1,17 +0,0 @@
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
if File.exist?(File.join(lib_dir, 'daemons.rb'))
$LOAD_PATH.unshift lib_dir
else
begin; require 'rubygems'; rescue ::Exception; end
end
require 'daemons'
Daemons.run_proc('ctrl_proc_simple.rb') do
loop do
puts 'ping from proc!'
sleep(3)
end
end

View file

@ -1,12 +0,0 @@
#!/usr/bin/env ruby
# This is myserver.rb, an example server that is to be controlled by daemons
# and that does nothing really useful at the moment.
#
# Don't run this script by yourself, it can be controlled by the ctrl*.rb scripts.
loop do
puts 'ping from myserver.rb!'
sleep(3)
end

View file

@ -1,14 +0,0 @@
# This is myserver.rb, an example server that is to be controlled by daemons
# and that does nothing really useful at the moment.
#
# Don't run this script by yourself, it can be controlled by the ctrl*.rb scripts.
loop do
puts 'ping from myserver.rb!'
puts 'this example server will crash in 3 seconds...'
sleep(3)
puts 'CRASH!'
raise 'CRASH!'
end

View file

@ -1,30 +0,0 @@
/home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:13: CRASH! (RuntimeError)
from /home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:6:in `loop'
from /home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:6
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:116:in `load'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:116:in `run_via_load'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:90:in `start'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:359:in `run'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:469:in `run'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:468:in `call'
from /home/uehli/Desktop/daemons-current/lib/daemons/cmdline.rb:94:in `catch_exceptions'
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:468:in `run'
from ctrl_crash.rb:17
ping from myserver.rb!
this example server will crash in 3 seconds...
CRASH!
ping from myserver.rb!
this example server will crash in 3 seconds...
CRASH!
/Users/uehli/Projects/daemons-proj/examples/run/myserver_crashing.rb:13: CRASH! (RuntimeError)
from /Users/uehli/Projects/daemons-proj/examples/run/myserver_crashing.rb:6:in `loop'
from /Users/uehli/Projects/daemons-proj/examples/run/myserver_crashing.rb:6
from /Users/uehli/Projects/daemons-proj/lib/daemons/application.rb:176:in `load'
from /Users/uehli/Projects/daemons-proj/lib/daemons/application.rb:176:in `start_load'
from /Users/uehli/Projects/daemons-proj/lib/daemons/application.rb:257:in `start'
from /Users/uehli/Projects/daemons-proj/lib/daemons/controller.rb:69:in `run'
from /Users/uehli/Projects/daemons-proj/lib/daemons.rb:139:in `run'
from /Users/uehli/Projects/daemons-proj/lib/daemons/cmdline.rb:105:in `call'
from /Users/uehli/Projects/daemons-proj/lib/daemons/cmdline.rb:105:in `catch_exceptions'
from /Users/uehli/Projects/daemons-proj/lib/daemons.rb:138:in `run'
from ctrl_crash.rb:17

View file

@ -1,8 +0,0 @@
loop do
puts 'ping from myserver.rb!'
puts 'this example server will exit in 3 seconds...'
sleep(3)
Process.exit
end

View file

@ -1,283 +0,0 @@
require 'optparse'
require 'optparse/time'
require 'daemons/pidfile'
require 'daemons/cmdline'
require 'daemons/exceptions'
require 'daemons/monitor'
require 'daemons/application'
require 'daemons/application_group'
require 'daemons/controller'
# All functions and classes that Daemons provides reside in this module.
#
# Daemons is normally invoked by one of the following four ways:
#
# 1. <tt>Daemons.run(script, options)</tt>:
# This is used in wrapper-scripts that are supposed to control other ruby scripts or
# external applications. Control is completely passed to the daemons library.
# Such wrapper script need to be invoked with command line options like 'start' or 'stop'
# to do anything useful.
#
# 2. <tt>Daemons.run_proc(app_name, options) { (...) }</tt>:
# This is used in wrapper-scripts that are supposed to control a proc.
# Control is completely passed to the daemons library.
# Such wrapper script need to be invoked with command line options like 'start' or 'stop'
# to do anything useful.
#
# 3. <tt>Daemons.call(options) { block }</tt>:
# Execute the block in a new daemon. <tt>Daemons.call</tt> will return immediately
# after spawning the daemon with the new Application object as a return value.
#
# 4. <tt>Daemons.daemonize(options)</tt>:
# Daemonize the currently runnig process, i.e. the calling process will become a daemon.
#
# == What does daemons internally do with my daemons?
# *or*:: why do my daemons crash when they try to open a file?
# *or*:: why can I not see any output from the daemon on the console (when using for example +puts+)?
#
# From a technical aspect of view, daemons does the following when creating a daemon:
#
# 1. Forks a child (and exits the parent process, if needed)
# 2. Becomes a session leader (which detaches the program from
# the controlling terminal).
# 3. Forks another child process and exits first child. This prevents
# the potential of acquiring a controlling terminal.
# 4. Changes the current working directory to "/".
# 5. Clears the file creation mask (sets +umask+ to 0000).
# 6. Closes file descriptors (reopens +STDOUT+ and +STDERR+ to point to a logfile if
# possible).
#
# So what does this mean for your daemons:
# - the current directory is '/'
# - you cannot receive any input from the console (for example no +gets+)
# - you cannot output anything from the daemons with +puts+/+print+ unless a logfile is used
#
# == How do PidFiles work? Where are they stored?
#
# Also, you are maybe interested in reading the documentation for the class PidFile.
# There you can find out about how Daemons works internally and how and where the so
# called <i>PidFiles</i> are stored.
#
module Daemons
VERSION = "1.0.10"
require 'daemons/daemonize'
# Passes control to Daemons.
# This is used in wrapper-scripts that are supposed to control other ruby scripts or
# external applications. Control is completely passed to the daemons library.
# Such wrapper script should be invoked with command line options like 'start' or 'stop'
# to do anything useful.
#
# +script+:: This is the path to the script that should be run as a daemon.
# Please note that Daemons runs this script with <tt>load <script></tt>.
# Also note that Daemons cannot detect the directory in which the controlling
# script resides, so this has to be either an absolute path or you have to run
# the controlling script from the appropriate directory.
#
# +options+:: A hash that may contain one or more of the options listed below
#
# === Options:
# <tt>:app_name</tt>:: The name of the application. This will be
# used to contruct the name of the pid files
# and log files. Defaults to the basename of
# the script.
# <tt>:ARGV</tt>:: An array of strings containing parameters and switches for Daemons.
# This includes both parameters for Daemons itself and the controlled scripted.
# These are assumed to be separated by an array element '--', .e.g.
# ['start', 'f', '--', 'param1_for_script', 'param2_for_script'].
# If not given, ARGV (the parameters given to the Ruby process) will be used.
# <tt>:dir_mode</tt>:: Either <tt>:script</tt> (the directory for writing the pid files to
# given by <tt>:dir</tt> is interpreted relative
# to the script location given by +script+) or <tt>:normal</tt> (the directory given by
# <tt>:dir</tt> is interpreted as a (absolute or relative) path) or <tt>:system</tt>
# (<tt>/var/run</tt> is used as the pid file directory)
#
# <tt>:dir</tt>:: Used in combination with <tt>:dir_mode</tt> (description above)
# <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
# same time
# <tt>:ontop</tt>:: When given (i.e. set to true), stay on top, i.e. do not daemonize the application
# (but the pid-file and other things are written as usual)
# <tt>:mode</tt>:: <tt>:load</tt> Load the script with <tt>Kernel.load</tt>;
# <tt>:exec</tt> Execute the script file with <tt>Kernel.exec</tt>
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
# pid-file directory if the application exits due to an uncaught exception
# <tt>:monitor</tt>:: Monitor the programs and restart crashed instances
# <tt>:log_output</tt>:: When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named '[app_name].output' in the pid-file directory
# <tt>:keep_pid_files</tt>:: When given do not delete lingering pid-files (files for which the process is no longer running).
# <tt>:hard_exit</tt>:: When given use exit! to end a daemons instead of exit (this will for example
# not call at_exit handlers).
# -----
#
# === Example:
# options = {
# :app_name => "my_app",
# :ARGV => ['start', '-f', '--', 'param_for_myscript']
# :dir_mode => :script,
# :dir => 'pids',
# :multiple => true,
# :ontop => true,
# :mode => :exec,
# :backtrace => true,
# :monitor => true
# }
#
# Daemons.run(File.join(File.dirname(__FILE__), 'myscript.rb'), options)
#
def run(script, options = {})
options[:script] = script
@controller = Controller.new(options, options[:ARGV] || ARGV)
@controller.catch_exceptions {
@controller.run
}
# I don't think anybody will ever use @group, as this location should not be reached under non-error conditions
@group = @controller.group
end
module_function :run
# Passes control to Daemons.
# This function does the same as Daemons.run except that not a script but a proc
# will be run as a daemon while this script provides command line options like 'start' or 'stop'
# and the whole pid-file management to control the proc.
#
# +app_name+:: The name of the application. This will be
# used to contruct the name of the pid files
# and log files. Defaults to the basename of
# the script.
#
# +options+:: A hash that may contain one or more of the options listed in the documentation for Daemons.run
#
# A block must be given to this function. The block will be used as the :proc entry in the options hash.
# -----
#
# === Example:
#
# Daemons.run_proc('myproc.rb') do
# loop do
# accept_connection()
# read_request()
# send_response()
# close_connection()
# end
# end
#
def run_proc(app_name, options = {}, &block)
options[:app_name] = app_name
options[:mode] = :proc
options[:proc] = block
# we do not have a script location so the the :script :dir_mode cannot be used, change it to :normal
if [nil, :script].include? options[:dir_mode]
options[:dir_mode] = :normal
options[:dir] = File.expand_path('.')
end
@controller = Controller.new(options, options[:ARGV] || ARGV)
@controller.catch_exceptions {
@controller.run
}
# I don't think anybody will ever use @group, as this location should not be reached under non-error conditions
@group = @controller.group
end
module_function :run_proc
# Execute the block in a new daemon. <tt>Daemons.call</tt> will return immediately
# after spawning the daemon with the new Application object as a return value.
#
# +options+:: A hash that may contain one or more of the options listed below
#
# +block+:: The block to call in the daemon.
#
# === Options:
# <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
# same time
# <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
# pid-file directory if the application exits due to an uncaught exception
# -----
#
# === Example:
# options = {
# :backtrace => true,
# :monitor => true,
# :ontop => true
# }
#
# Daemons.call(options) begin
# # Server loop:
# loop {
# conn = accept_conn()
# serve(conn)
# }
# end
#
def call(options = {}, &block)
unless block_given?
raise "Daemons.call: no block given"
end
options[:proc] = block
options[:mode] = :proc
@group ||= ApplicationGroup.new('proc', options)
new_app = @group.new_application(options)
new_app.start
return new_app
end
module_function :call
# Daemonize the currently runnig process, i.e. the calling process will become a daemon.
#
# +options+:: A hash that may contain one or more of the options listed below
#
# === Options:
# <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
# pid-file directory if the application exits due to an uncaught exception
# -----
#
# === Example:
# options = {
# :backtrace => true,
# :ontop => true
# }
#
# Daemons.daemonize(options)
#
# # Server loop:
# loop {
# conn = accept_conn()
# serve(conn)
# }
#
def daemonize(options = {})
@group ||= ApplicationGroup.new('self', options)
@group.new_application(:mode => :none).start
end
module_function :daemonize
# Return the internal ApplicationGroup instance.
def group; @group; end
module_function :group
# Return the internal Controller instance.
def controller; @controller; end
module_function :controller
end

View file

@ -1,372 +0,0 @@
require 'daemons/pidfile'
require 'daemons/pidmem'
module Daemons
class Application
attr_accessor :app_argv
attr_accessor :controller_argv
# the Pid instance belonging to this application
attr_reader :pid
# the ApplicationGroup the application belongs to
attr_reader :group
# my private options
attr_reader :options
SIGNAL = (RUBY_PLATFORM =~ /win32/ ? 'KILL' : 'TERM')
def initialize(group, add_options = {}, pid = nil)
@group = group
@options = group.options.dup
@options.update(add_options)
@dir_mode = @dir = @script = nil
unless @pid = pid
if dir = pidfile_dir
@pid = PidFile.new(dir, @group.app_name, @group.multiple)
else
@pid = PidMem.new
end
end
end
def script
@script || @group.script
end
def pidfile_dir
Pid.dir(@dir_mode || @group.dir_mode, @dir || @group.dir, @script || @group.script)
end
def output_logfile
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
(options[:log_output] && logdir) ? File.join(logdir, @group.app_name + '.output') : nil
end
def logfile
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
logdir ? File.join(logdir, @group.app_name + '.log') : nil
end
# this function is only used to daemonize the currently running process (Daemons.daemonize)
def start_none
unless options[:ontop]
Daemonize.daemonize(nil, @group.app_name) #(logfile)
else
Daemonize.simulate
end
@pid.pid = Process.pid
# We need this to remove the pid-file if the applications exits by itself.
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
# in your application!
#
at_exit {
begin; @pid.cleanup; rescue ::Exception; end
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
# create a exception log.
if options[:backtrace] and not options[:ontop] and not $daemons_sigterm
begin; exception_log(); rescue ::Exception; end
end
}
# This part is needed to remove the pid-file if the application is killed by
# daemons or manually by the user.
# Note that the applications is not supposed to overwrite the signal handler for
# 'TERM'.
#
trap(SIGNAL) {
begin; @pid.cleanup; rescue ::Exception; end
$daemons_sigterm = true
if options[:hard_exit]
exit!
else
exit
end
}
end
def start_exec
if options[:backtrace]
puts "option :backtrace is not supported with :mode => :exec, ignoring"
end
unless options[:ontop]
Daemonize.daemonize(output_logfile, @group.app_name)
else
Daemonize.simulate(output_logfile)
end
# note that we cannot remove the pid file if we run in :ontop mode (i.e. 'ruby ctrl_exec.rb run')
@pid.pid = Process.pid
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
# haven't tested yet if this is really passed to the exec'd process...
Kernel.exec(script(), *(@app_argv || []))
#Kernel.exec(script(), *ARGV)
end
def start_load
unless options[:ontop]
Daemonize.daemonize(output_logfile, @group.app_name)
else
Daemonize.simulate(output_logfile)
end
@pid.pid = Process.pid
# We need this to remove the pid-file if the applications exits by itself.
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
# in your application!
#
at_exit {
begin; @pid.cleanup; rescue ::Exception; end
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
# create a exception log.
if options[:backtrace] and not options[:ontop] and not $daemons_sigterm
begin; exception_log(); rescue ::Exception; end
end
}
# This part is needed to remove the pid-file if the application is killed by
# daemons or manually by the user.
# Note that the applications is not supposed to overwrite the signal handler for
# 'TERM'.
#
trap(SIGNAL) {
begin; @pid.cleanup; rescue ::Exception; end
$daemons_sigterm = true
if options[:hard_exit]
exit!
else
exit
end
}
# Now we really start the script...
$DAEMONS_ARGV = @controller_argv
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
ARGV.clear
ARGV.concat @app_argv if @app_argv
# TODO: begin - rescue - end around this and exception logging
load script()
end
def start_proc
return unless p = options[:proc]
myproc = proc do
# We need this to remove the pid-file if the applications exits by itself.
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
# in your application!
#
at_exit {
begin; @pid.cleanup; rescue ::Exception; end
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
# create a exception log.
if options[:backtrace] and not options[:ontop] and not $daemons_sigterm
begin; exception_log(); rescue ::Exception; end
end
}
# This part is needed to remove the pid-file if the application is killed by
# daemons or manually by the user.
# Note that the applications is not supposed to overwrite the signal handler for
# 'TERM'.
#
trap(SIGNAL) {
begin; @pid.cleanup; rescue ::Exception; end
$daemons_sigterm = true
if options[:hard_exit]
exit!
else
exit
end
}
p.call()
end
unless options[:ontop]
@pid.pid = Daemonize.call_as_daemon(myproc, output_logfile, @group.app_name)
else
Daemonize.simulate(output_logfile)
@pid.pid = Process.pid
myproc.call
# why did we use this??
# Thread.new(&options[:proc])
# why did we use the code below??
# unless pid = Process.fork
# @pid.pid = pid
# Daemonize.simulate(logfile)
# options[:proc].call
# exit
# else
# Process.detach(@pid.pid)
# end
end
end
def start
@group.create_monitor(@group.applications[0] || self) unless options[:ontop] # we don't monitor applications in the foreground
case options[:mode]
when :none
# this is only used to daemonize the currently running process
start_none
when :exec
start_exec
when :load
start_load
when :proc
start_proc
else
start_load
end
end
# def run
# if @group.controller.options[:exec]
# run_via_exec()
# else
# run_via_load()
# end
# end
#
# def run_via_exec
#
# end
#
# def run_via_load
#
# end
# This is a nice little function for debugging purposes:
# In case a multi-threaded ruby script exits due to an uncaught exception
# it may be difficult to find out where the exception came from because
# one cannot catch exceptions that are thrown in threads other than the main
# thread.
#
# This function searches for all exceptions in memory and outputs them to STDERR
# (if it is connected) and to a log file in the pid-file directory.
#
def exception_log
return unless logfile
require 'logger'
l_file = Logger.new(logfile)
# the code below finds the last exception
e = nil
ObjectSpace.each_object {|o|
if ::Exception === o
e = o
end
}
l_file.info "*** below you find the most recent exception thrown, this will be likely (but not certainly) the exception that made the application exit abnormally ***"
l_file.error e
l_file.info "*** below you find all exception objects found in memory, some of them may have been thrown in your application, others may just be in memory because they are standard exceptions ***"
# this code logs every exception found in memory
ObjectSpace.each_object {|o|
if ::Exception === o
l_file.error o
end
}
l_file.close
end
def stop
if options[:force] and not running?
self.zap
return
end
# Catch errors when trying to kill a process that doesn't
# exist. This happens when the process quits and hasn't been
# restarted by the monitor yet. By catching the error, we allow the
# pid file clean-up to occur.
begin
Process.kill(SIGNAL, @pid.pid)
rescue Errno::ESRCH => e
puts "#{e} #{@pid.pid}"
puts "deleting pid-file."
end
# We try to remove the pid-files by ourselves, in case the application
# didn't clean it up.
begin; @pid.cleanup; rescue ::Exception; end
end
def zap
@pid.cleanup
end
def zap!
begin; @pid.cleanup; rescue ::Exception; end
end
def show_status
running = self.running?
puts "#{self.group.app_name}: #{running ? '' : 'not '}running#{(running and @pid.exist?) ? ' [pid ' + @pid.pid.to_s + ']' : ''}#{(@pid.exist? and not running) ? ' (but pid-file exists: ' + @pid.pid.to_s + ')' : ''}"
end
# This function implements a (probably too simle) method to detect
# whether the program with the pid found in the pid-file is still running.
# It just searches for the pid in the output of <tt>ps ax</tt>, which
# is probably not a good idea in some cases.
# Alternatives would be to use a direct access method the unix process control
# system.
#
def running?
if @pid.exist?
return Pid.running?(@pid.pid)
end
return false
end
end
end

View file

@ -1,152 +0,0 @@
module Daemons
class ApplicationGroup
attr_reader :app_name
attr_reader :script
attr_reader :monitor
#attr_reader :controller
attr_reader :options
attr_reader :applications
attr_accessor :controller_argv
attr_accessor :app_argv
attr_accessor :dir_mode
attr_accessor :dir
# true if the application is supposed to run in multiple instances
attr_reader :multiple
def initialize(app_name, options = {})
@app_name = app_name
@options = options
if options[:script]
@script = File.expand_path(options[:script])
end
#@controller = controller
@monitor = nil
#options = controller.options
@multiple = options[:multiple] || false
@dir_mode = options[:dir_mode] || :script
@dir = options[:dir] || ''
@keep_pid_files = options[:keep_pid_files] || false
#@applications = find_applications(pidfile_dir())
@applications = []
end
# Setup the application group.
# Currently this functions calls <tt>find_applications</tt> which finds
# all running instances of the application and populates the application array.
#
def setup
@applications = find_applications(pidfile_dir())
end
def pidfile_dir
PidFile.dir(@dir_mode, @dir, script)
end
def find_applications(dir)
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
#pp pid_files
@monitor = Monitor.find(dir, app_name + '_monitor')
pid_files.reject! {|f| f =~ /_monitor.pid$/}
return pid_files.map {|f|
app = Application.new(self, {}, PidFile.existing(f))
setup_app(app)
app
}
end
def new_application(add_options = {})
if @applications.size > 0 and not @multiple
if options[:force]
@applications.delete_if {|a|
unless a.running?
a.zap
true
end
}
end
raise RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
end
app = Application.new(self, add_options)
setup_app(app)
@applications << app
return app
end
def setup_app(app)
app.controller_argv = @controller_argv
app.app_argv = @app_argv
end
private :setup_app
def create_monitor(an_app)
return if @monitor
if options[:monitor]
@monitor = Monitor.new(an_app)
@monitor.start(@applications)
end
end
def start_all
@monitor.stop if @monitor
@monitor = nil
@applications.each {|a|
fork {
a.start
}
}
end
def stop_all(force = false)
@monitor.stop if @monitor
@applications.each {|a|
if force
begin; a.stop; rescue ::Exception; end
else
a.stop
end
}
end
def zap_all
@monitor.stop if @monitor
@applications.each {|a| a.zap}
end
def show_status
@applications.each {|a| a.show_status}
end
end
end

View file

@ -1,117 +0,0 @@
module Daemons
class Optparse
attr_reader :usage
def initialize(controller)
@controller = controller
@options = {}
@opts = OptionParser.new do |opts|
#opts.banner = "Usage: example.rb [options]"
opts.banner = ""
# Boolean switch.
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
# @options[:verbose] = v
# end
opts.on("-t", "--ontop", "Stay on top (does not daemonize)") do |t|
@options[:ontop] = t
end
opts.on("-f", "--force", "Force operation") do |t|
@options[:force] = t
end
#opts.separator ""
#opts.separator "Specific options:"
opts.separator ""
opts.separator "Common options:"
# No argument, shows at tail. This will print an options summary.
# Try it and see!
opts.on_tail("-h", "--help", "Show this message") do
#puts opts
#@usage =
controller.print_usage()
exit
end
# Another typical switch to print the version.
opts.on_tail("--version", "Show version") do
puts "daemons version #{Daemons::VERSION}"
exit
end
end
begin
@usage = @opts.to_s
rescue ::Exception # work around a bug in ruby 1.9
@usage = <<END
-t, --ontop Stay on top (does not daemonize)
-f, --force Force operation
Common options:
-h, --help Show this message
--version Show version
END
end
end
#
# Return a hash describing the options.
#
def parse(args)
# The options specified on the command line will be collected in *options*.
# We set default values here.
#options = {}
##pp args
@opts.parse(args)
return @options
end
end
class Controller
def print_usage
puts "Usage: #{@app_name} <command> <options> -- <application options>"
puts
puts "* where <command> is one of:"
puts " start start an instance of the application"
puts " stop stop all instances of the application"
puts " restart stop all instances and restart them afterwards"
puts " run start the application and stay on top"
puts " zap set the application to a stopped state"
puts
puts "* and where <options> may contain several of the following:"
puts @optparse.usage
end
def catch_exceptions(&block)
begin
block.call
rescue CmdException, OptionParser::ParseError => e
puts "ERROR: #{e.to_s}"
puts
print_usage()
rescue RuntimeException => e
puts "ERROR: #{e.to_s}"
end
end
end
end

View file

@ -1,134 +0,0 @@
module Daemons
class Controller
attr_reader :app_name
attr_reader :group
attr_reader :options
COMMANDS = [
'start',
'stop',
'restart',
'run',
'zap',
'status'
]
def initialize(options = {}, argv = [])
@options = options
@argv = argv
# Allow an app_name to be specified. If not specified use the
# basename of the script.
@app_name = options[:app_name]
if options[:script]
@script = File.expand_path(options[:script])
@app_name ||= File.split(@script)[1]
end
@app_name ||= 'unknown_application'
@command, @controller_part, @app_part = Controller.split_argv(argv)
#@options[:dir_mode] ||= :script
@optparse = Optparse.new(self)
end
# This function is used to do a final update of the options passed to the application
# before they are really used.
#
# Note that this function should only update <tt>@options</tt> and no other variables.
#
def setup_options
#@options[:ontop] ||= true
end
def run
@options.update @optparse.parse(@controller_part).delete_if {|k,v| !v}
setup_options()
#pp @options
@group = ApplicationGroup.new(@app_name, @options)
@group.controller_argv = @controller_part
@group.app_argv = @app_part
@group.setup
case @command
when 'start'
@group.new_application.start
when 'run'
@options[:ontop] ||= true
@group.new_application.start
when 'stop'
@group.stop_all
when 'restart'
unless @group.applications.empty?
@group.stop_all
sleep 1
@group.start_all
end
when 'zap'
@group.zap_all
when 'status'
unless @group.applications.empty?
@group.show_status
else
puts "#{@group.app_name}: no instances running"
end
when nil
raise CmdException.new('no command given')
#puts "ERROR: No command given"; puts
#print_usage()
#raise('usage function not implemented')
else
raise Error.new("command '#{@command}' not implemented")
end
end
# Split an _argv_ array.
# +argv+ is assumed to be in the following format:
# ['command', 'controller option 1', 'controller option 2', ..., '--', 'app option 1', ...]
#
# <tt>command</tt> must be one of the commands listed in <tt>COMMANDS</tt>
#
# *Returns*: the command as a string, the controller options as an array, the appliation options
# as an array
#
def Controller.split_argv(argv)
argv = argv.dup
command = nil
controller_part = []
app_part = []
if COMMANDS.include? argv[0]
command = argv.shift
end
if i = argv.index('--')
# Handle the case where no controller options are given, just
# options after "--" as well (i == 0)
controller_part = (i == 0 ? [] : argv[0..i-1])
app_part = argv[i+1..-1]
else
controller_part = argv[0..-1]
end
return command, controller_part, app_part
end
end
end

View file

@ -1,263 +0,0 @@
#--
###############################################################################
# daemonize.rb is a slightly modified version of daemonize.rb was #
# from the Daemonize Library written by Travis Whitton #
# for details, read the notice below #
###############################################################################
#++
#
#
# =Daemonize Library
#
# February. 4, 2005 Travis Whitton <whitton@atlantic.net>
#
# Daemonize allows you to easily modify any existing Ruby program to run
# as a daemon. See README.rdoc for more details.
#
# == How to install
# 1. su to root
# 2. ruby install.rb
# build the docs if you want to
# 3. rdoc --main README.rdoc daemonize.rb README.rdoc
#
# == Copying
# The Daemonize extension module is copywrited free software by Travis Whitton
# <whitton@atlantic.net>. You can redistribute it under the terms specified in
# the COPYING file of the Ruby distribution.
#
# == WARRANTY
# THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
# PURPOSE.
#
#
# ----
#
# == Purpose
#
# Daemonize is a module derived from Perl's Proc::Daemon module. This module
# allows you to easily modify any existing Ruby program to run as a daemon.
# A daemon is a process that runs in the background with no controlling terminal.
# Generally servers (like FTP and HTTP servers) run as daemon processes.
# Note, do not make the mistake that a daemon == server. Converting a program
# to a daemon by hand is a relatively simple process; however, this module will
# save you the effort of repeatedly looking up the procedure, and it will also
# insure that your programs are daemonized in the safest and most corrects
# fashion possible.
#
# == Procedure
#
# The Daemonize module does the following:
#
# Forks a child and exits the parent process.
#
# Becomes a session leader (which detaches the program from
# the controlling terminal).
#
# Forks another child process and exits first child. This prevents
# the potential of acquiring a controlling terminal.
#
# Changes the current working directory to "/".
#
# Clears the file creation mask.
#
# Closes file descriptors.
#
# == Example usage
#
# Using the Daemonize module is extremely simple:
#
# require 'daemonize'
#
# class TestDaemon
# include Daemonize
#
# def initialize
# daemonize()
# loop do
# # do some work here
# end
# end
# end
#
# == Credits
#
# Daemonize was written by Travis Whitton and is based on Perl's
# Proc::Daemonize, which was written by Earl Hood. The above documentation
# is also partially borrowed from the Proc::Daemonize POD documentation.
module Daemonize
VERSION = "0.1.1m"
# Try to fork if at all possible retrying every 5 sec if the
# maximum process limit for the system has been reached
def safefork
tryagain = true
while tryagain
tryagain = false
begin
if pid = fork
return pid
end
rescue Errno::EWOULDBLOCK
sleep 5
tryagain = true
end
end
end
module_function :safefork
def simulate(logfile_name = nil)
# NOTE: STDOUT and STDERR will not be redirected to the logfile, because in :ontop mode, we normally want to see the output
Dir.chdir "/" # Release old working directory
File.umask 0000 # Insure sensible umask
# Make sure all file descriptors are closed
ObjectSpace.each_object(IO) do |io|
unless [STDIN, STDOUT, STDERR].include?(io)
begin
unless io.closed?
io.close
end
rescue ::Exception
end
end
end
# Free file descriptors and
# point them somewhere sensible
# STDOUT/STDERR should go to a logfile
begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
end
module_function :simulate
def call_as_daemon(block, logfile_name = nil, app_name = nil)
rd, wr = IO.pipe
if tmppid = safefork
# parent
wr.close
pid = rd.read.to_i
rd.close
Process.waitpid(tmppid)
return pid
else
# child
rd.close
# Detach from the controlling terminal
unless sess_id = Process.setsid
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
end
# Prevent the possibility of acquiring a controlling terminal
#if oldmode.zero?
trap 'SIGHUP', 'IGNORE'
exit if pid = safefork
#end
wr.write Process.pid
wr.close
$0 = app_name if app_name
Dir.chdir "/" # Release old working directory
File.umask 0000 # Insure sensible umask
# Make sure all file descriptors are closed
ObjectSpace.each_object(IO) do |io|
unless [STDIN, STDOUT, STDERR].include?(io)
begin
unless io.closed?
io.close
end
rescue ::Exception
end
end
end
redirect_io(logfile_name)
block.call
exit
end
end
module_function :call_as_daemon
# This method causes the current running process to become a daemon
def daemonize(logfile_name = nil, app_name = nil)
srand # Split rand streams between spawning and daemonized process
safefork and exit # Fork and exit from the parent
# Detach from the controlling terminal
unless sess_id = Process.setsid
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
end
# Prevent the possibility of acquiring a controlling terminal
#if oldmode.zero?
trap 'SIGHUP', 'IGNORE'
exit if pid = safefork
#end
$0 = app_name if app_name
Dir.chdir "/" # Release old working directory
File.umask 0000 # Insure sensible umask
# Make sure all file descriptors are closed
ObjectSpace.each_object(IO) do |io|
unless [STDIN, STDOUT, STDERR].include?(io)
begin
unless io.closed?
io.close
end
rescue ::Exception
end
end
end
redirect_io(logfile_name)
#return oldmode ? sess_id : 0 # Return value is mostly irrelevant
return sess_id
end
module_function :daemonize
# Free file descriptors and
# point them somewhere sensible
# STDOUT/STDERR should go to a logfile
def redirect_io(logfile_name)
begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
if logfile_name
begin
STDOUT.reopen logfile_name, "a"
STDOUT.sync = true
rescue ::Exception
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
end
else
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
end
begin; STDERR.reopen STDOUT; rescue ::Exception; end
STDERR.sync = true
end
module_function :redirect_io
end

View file

@ -1,28 +0,0 @@
module Daemons
class Exception < ::RuntimeError
end
class RuntimeException < Exception
end
class CmdException < Exception
end
class Error < Exception
end
class SystemError < Error
attr_reader :system_error
def initialize(msg, system_error)
super(msg)
@system_error = system_error
end
end
end

View file

@ -1,127 +0,0 @@
module Daemons
require 'daemons/daemonize'
class Monitor
def self.find(dir, app_name)
pid = PidFile.find_files(dir, app_name, false)[0]
if pid
pid = PidFile.existing(pid)
unless PidFile.running?(pid.pid)
begin; pid.cleanup; rescue ::Exception; end
return
end
monitor = self.allocate
monitor.instance_variable_set(:@pid, pid)
return monitor
end
return nil
end
def initialize(an_app)
@app = an_app
@app_name = an_app.group.app_name + '_monitor'
if an_app.pidfile_dir
@pid = PidFile.new(an_app.pidfile_dir, @app_name, false)
else
@pid = PidMem.new
end
end
def watch(applications)
sleep(30)
loop do
applications.each {|a|
sleep(10)
unless a.running?
a.zap!
Process.detach(fork { a.start })
sleep(10)
end
}
sleep(30)
end
end
private :watch
def start_with_pidfile(applications)
fork do
Daemonize.daemonize(nil, @app_name)
begin
@pid.pid = Process.pid
# at_exit {
# begin; @pid.cleanup; rescue ::Exception; end
# }
# This part is needed to remove the pid-file if the application is killed by
# daemons or manually by the user.
# Note that the applications is not supposed to overwrite the signal handler for
# 'TERM'.
#
# trap('TERM') {
# begin; @pid.cleanup; rescue ::Exception; end
# exit
# }
watch(applications)
rescue ::Exception => e
begin
File.open(@app.logfile, 'a') {|f|
f.puts Time.now
f.puts e
f.puts e.backtrace.inspect
}
ensure
begin; @pid.cleanup; rescue ::Exception; end
exit!
end
end
end
end
private :start_with_pidfile
def start_without_pidfile(applications)
Thread.new { watch(applications) }
end
private :start_without_pidfile
def start(applications)
return if applications.empty?
if @pid.kind_of?(PidFile)
start_with_pidfile(applications)
else
start_without_pidfile(applications)
end
end
def stop
begin; Process.kill(Application::SIGNAL, @pid.pid); rescue ::Exception; end
# We try to remove the pid-files by ourselves, in case the application
# didn't clean it up.
begin; @pid.cleanup; rescue ::Exception; end
end
end
end

View file

@ -1,101 +0,0 @@
require 'open3'
module Daemons
class Pid
def Pid.running?(pid)
# Check if process is in existence
# The simplest way to do this is to send signal '0'
# (which is a single system call) that doesn't actually
# send a signal
begin
Process.kill(0, pid)
return true
rescue Errno::ESRCH
return false
rescue ::Exception # for example on EPERM (process exists but does not belong to us)
return true
#rescue Errno::EPERM
# return false
end
end
# def Pid.running?(pid, additional = nil)
# match_pid = Regexp.new("^\\s*#{pid}\\s")
# got_match = false
#
# #ps_all = IO.popen('ps ax') # the correct syntax is without a dash (-) !
# ps_in, ps_out, ps_err = Open3.popen3('ps ax') # the correct syntax is without a dash (-) !
#
# return true unless ps_out.gets
#
# begin
# ps_out.each { |psline|
# next unless psline =~ match_pid
# got_match = true
# got_match = false if additional and psline !~ /#{additional}/
# break
# }
# ensure
# begin; begin; ps_in.close; rescue ::Exception; end; begin; ps_out.close; rescue ::Exception; end; ps_err.close; rescue ::Exception; end
# end
#
# # an alternative would be to use the code below, but I don't know whether this is portable
# # `ps axo pid=`.split.include? pid.to_s
#
# return got_match
# end
# Returns the directory that should be used to write the pid file to
# depending on the given mode.
#
# Some modes may require an additionaly hint, others may determine
# the directory automatically.
#
# If no valid directory is found, returns nil.
#
def Pid.dir(dir_mode, dir, script)
# nil script parameter is allowed as long as dir_mode is not :script
return nil if dir_mode == :script && script.nil?
case dir_mode
when :normal
return File.expand_path(dir)
when :script
return File.expand_path(File.join(File.dirname(script),dir))
when :system
return '/var/run'
else
raise Error.new("pid file mode '#{dir_mode}' not implemented")
end
end
# Initialization method
def initialize
end
# Get method
def pid
end
# Set method
def pid=(p)
end
# Cleanup method
def cleanup
end
# Exists? method
def exist?
true
end
end
end

View file

@ -1,111 +0,0 @@
require 'daemons/pid'
module Daemons
# === What is a Pid-File?
# A <i>Pid-File</i> is a file containing the <i>process identification number</i>
# (pid) that is stored in a well-defined location of the filesystem thus allowing other
# programs to find out the pid of a running script.
#
# Daemons needs the pid of the scripts that are currently running in the background
# to send them so called _signals_. Daemons uses the +TERM+ signal to tell the script
# to exit when you issue a +stop+ command.
#
# === How does a Pid-File look like?
#
# Pid-Files generated by Daemons have to following format:
# <scriptname>.rb<number>.pid
# (Note that <tt><number></tt> is omitted if only one instance of the script can
# run at any time)
#
# Each file just contains one line with the pid as string (for example <tt>6432</tt>).
#
# === Where are the Pid-Files stored?
#
# Daemons is configurable to store the Pid-Files relative to three different locations:
# 1. in a directory relative to the directory where the script (the one that is supposed to run
# as a daemon) resides (<tt>:script</tt> option for <tt>:dir_mode</tt>)
# 2. in a directory given by <tt>:dir</tt> (<tt>:normal</tt> option for <tt>:dir_mode</tt>)
# 3. in the preconfigured directory <tt>/var/run</tt> (<tt>:system</tt> option for <tt>:dir_mode</tt>)
#
class PidFile < Pid
attr_reader :dir, :progname, :multiple, :number
def PidFile.find_files(dir, progname, delete = false)
files = Dir[File.join(dir, "#{progname}*.pid")]
files.delete_if {|f| not (File.file?(f) and File.readable?(f))}
if delete
files.delete_if do |f|
pid = File.open(f) {|h| h.read}.to_i
rsl = ! Pid.running?(pid)
if rsl
puts "pid-file for killed process #{pid} found (#{f}), deleting."
begin; File.unlink(f); rescue ::Exception; end
end
rsl
end
end
return files
end
def PidFile.existing(path)
new_instance = PidFile.allocate
new_instance.instance_variable_set(:@path, path)
def new_instance.filename
return @path
end
return new_instance
end
def initialize(dir, progname, multiple = false)
@dir = File.expand_path(dir)
@progname = progname
@multiple = multiple
@number = nil
@number = 0 if multiple
if multiple
while File.exist?(filename) and @number < 1024
@number += 1
end
if @number == 1024
raise RuntimeException('cannot run more than 1024 instances of the application')
end
end
end
def filename
File.join(@dir, "#{@progname}#{ @number or '' }.pid")
end
def exist?
File.exist? filename
end
def pid=(p)
File.open(filename, 'w') {|f|
f.puts p #Process.pid
}
end
def cleanup
File.delete(filename)
end
def pid
File.open(filename) {|f|
return f.gets.to_i
}
end
end
end

View file

@ -1,10 +0,0 @@
require 'daemons/pid'
module Daemons
class PidMem < Pid
attr_accessor :pid
end
end

View file

@ -1,14 +0,0 @@
pkg
rdoc
Makefile
*.bundle
*.dll
*.so
*.jar
*.class
*.o
*.log
*.def
*.pdb
java/src/.project

View file

@ -1,82 +0,0 @@
= RUBY/EventMachine
Homepage:: http://rubyeventmachine.com
Rubyforge Page:: http://rubyforge.org/projects/eventmachine
Google Group:: http://groups.google.com/group/eventmachine
Mailing List:: http://rubyforge.org/pipermail/eventmachine-talk
RDoc:: http://eventmachine.rubyforge.org
IRC:: ##eventmachine on irc.freenode.net
Copyright:: (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
Email:: gmail address: garbagecat10
EventMachine is copyrighted free software made available under the terms
of either the GPL or Ruby's License. See the file COPYING for full licensing
information.
See EventMachine and EventMachine::Connection for documentation and
usage examples.
EventMachine implements a fast, single-threaded engine for arbitrary network
communications. It's extremely easy to use in Ruby. EventMachine wraps all
interactions with IP sockets, allowing programs to concentrate on the
implementation of network protocols. It can be used to create both network
servers and clients. To create a server or client, a Ruby program only needs
to specify the IP address and port, and provide a Module that implements the
communications protocol. Implementations of several standard network protocols
are provided with the package, primarily to serve as examples. The real goal
of EventMachine is to enable programs to easily interface with other programs
using TCP/IP, especially if custom protocols are required.
A Ruby program uses EventMachine by registering the addresses and ports of
network servers and clients, and then entering an event-handling loop.
EventMachine contains glue code in Ruby which will execute callbacks to
user-supplied code for all significant events occurring in the clients
and servers. These events include connection acceptance, startup, data-receipt,
shutdown, and timer events. Arbitrary processing can be performed by user code
during event callbacks, including sending data to one or more remote network
peers, startup and shutdown of network connections, and installation of new
event handlers.
The EventMachine implements a very familiar model for network programming.
It emphasizes: 1) the maximum possible isolation of user code from network
objects like sockets; 2) maximum performance and scalability; and 3) extreme
ease-of-use for user code. It attempts to provide a higher-level interface
than similar projects which expose a variety of low-level event-handling
and networking objects to Ruby programs.
The design and implementation of EventMachine grows out of nearly ten years
of experience writing high-performance, high-scaling network server applications.
We have taken particular account of the challenges and lessons described as
the "C10K problem" by Dan Kegel and others.
EventMachine consists of an extension library written in C++ (which can be
accessed from languages other than Ruby), and a Ruby module which can be dropped
into user programs. On most platforms, EventMachine uses the
<tt>select(2)</tt> system call,
so it will run on a large range of Unix-like systems and on Microsoft
Windows with good performance and scalability. On Linux 2.6 kernels, EventMachine
automatically configures itself to use <tt>epoll(4)</tt> instead of
<tt>select(2),</tt> so scalability on that platform can be significantly
improved.
Here's a fully-functional echo server written with EventMachine:
require 'eventmachine'
module EchoServer
def post_init
puts "-- someone connected to the echo server!"
end
def receive_data data
send_data ">>>you sent: #{data}"
close_connection if data =~ /quit/i
end
def unbind
puts "-- someone disconnected from the echo server!"
end
end
EventMachine::run {
EventMachine::start_server "127.0.0.1", 8081, EchoServer
}

View file

@ -1,374 +0,0 @@
#!/usr/bin/env rake
#--
# Ruby/EventMachine
# http://rubyeventmachine.com
# Copyright (C) 2006-07 by Francis Cianfrocca
#
# This program is copyrighted free software. You may use it under
# the terms of either the GPL or Ruby's License. See the file
# COPYING in the EventMachine distribution for full licensing
# information.
#
# $Id$
#++
### OLD RAKE: ###
# # The tasks and external gemspecs we used to generate binary gems are now
# # obsolete. Use Patrick Hurley's gembuilder to build binary gems for any
# # desired platform.
# # To build a binary gem on Win32, ensure that the include and lib paths
# # both contain the proper references to OPENSSL. Use the static version
# # of the libraries, not the dynamic, otherwise we expose the user to a
# # runtime dependency.
#
# # To build a binary gem for win32, first build rubyeventmachine.so
# # using VC6 outside of the build tree (the normal way: ruby extconf.rb,
# # and then nmake). Then copy rubyeventmachine.so into the lib directory,
# # and run rake gemwin32.
#
require 'rubygems' unless defined?(Gem)
require 'rake' unless defined?(Rake)
Package = false # Build zips and tarballs?
Dir.glob('tasks/*.rake').each { |r| Rake.application.add_import r }
# e.g. rake EVENTMACHINE_LIBRARY=java for forcing java build tasks as defaults!
$eventmachine_library = :java if RUBY_PLATFORM =~ /java/ || ENV['EVENTMACHINE_LIBRARY'] == 'java'
$eventmachine_library = :pure_ruby if ENV['EVENTMACHINE_LIBRARY'] == 'pure_ruby'
MAKE = ENV['MAKE'] || if RUBY_PLATFORM =~ /mswin/ # mingw uses make.
'nmake'
else
'make'
end
desc "Build gemspec, then build eventmachine, then run tests."
task :default => [:build, :test]
desc "Build extension (or EVENTMACHINE_LIBRARY) and place in lib"
build_task = 'ext:build'
build_task = 'java:build' if $eventmachine_library == :java
build_task = :dummy_build if $eventmachine_library == :pure_ruby
task :build => build_task do |t|
Dir.glob('{ext,java/src,ext/fastfilereader}/*.{so,bundle,dll,jar}').each do |f|
mv f, "lib"
end
end
task :dummy_build
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.pattern = 'tests/**/test_*.rb'
t.warning = true
end
# Basic clean definition, this is enhanced by imports aswell.
task :clean do
chdir 'ext' do
sh "#{MAKE} clean" if test ?e, 'Makefile'
end
chdir 'ext/fastfilereader' do
sh "#{MAKE} clean" if test ?e, 'Makefile'
end
Dir.glob('**/Makefile').each { |file| rm file }
Dir.glob('**/*.{o,so,bundle,class,jar,dll,log}').each { |file| rm file }
Dir.glob('ext/**/conftest.dSYM').each{ |file| rm_rf file }
end
Spec = Gem::Specification.new do |s|
s.name = "eventmachine"
s.summary = "Ruby/EventMachine library"
s.platform = Gem::Platform::RUBY
s.has_rdoc = true
s.rdoc_options = %w(--title EventMachine --main README --line-numbers -x lib/em/version -x lib/emva -x lib/evma/ -x lib/pr_eventmachine -x lib/jeventmachine)
s.extra_rdoc_files = Dir['README,docs/*']
s.files = `git ls-files`.split("\n")
s.require_path = 'lib'
# TODO / XXX - should we enable this? rubygems fails the install if anything
# is broken. What we could do is CI submission, though, and always terminate
# with a positive code...
# s.test_file = "tests/testem.rb"
# XXX Using rake to compile extensions breaks when you have multiple ruby installations
# and your path isn't set. We can switch back to this once the Gem.exec patch is merged.
# s.extensions = "Rakefile"
s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
s.author = "Francis Cianfrocca"
s.email = "garbagecat10@gmail.com"
s.rubyforge_project = 'eventmachine'
s.homepage = "http://rubyeventmachine.com"
# Pulled in from readme, as code to pull from readme was not working!
# Might be worth removing as no one seems to use gem info anyway.
s.description = <<-EOD
EventMachine implements a fast, single-threaded engine for arbitrary network
communications. It's extremely easy to use in Ruby. EventMachine wraps all
interactions with IP sockets, allowing programs to concentrate on the
implementation of network protocols. It can be used to create both network
servers and clients. To create a server or client, a Ruby program only needs
to specify the IP address and port, and provide a Module that implements the
communications protocol. Implementations of several standard network protocols
are provided with the package, primarily to serve as examples. The real goal
of EventMachine is to enable programs to easily interface with other programs
using TCP/IP, especially if custom protocols are required.
EOD
require 'lib/em/version'
s.version = EventMachine::VERSION
end
if RUBY_PLATFORM =~ /mswin/
Spec.platform = 'x86-mswin32-60'
Spec.files += %w[ lib/rubyeventmachine.so lib/fastfilereaderext.so ]
Spec.extensions = nil
elsif RUBY_PLATFORM =~ /java/
Spec.platform = 'java'
Spec.files += %w[ lib/em_reactor.jar ]
Spec.extensions = nil
end
# this is a hack right now, it requires installing msysgit in the global path so it can use tar/curl/etc.
namespace :win32 do
task :check_git do
unless `git` =~ /rebase/
raise 'git not found, install msys git into the GLOBAL PATH: http://msysgit.googlecode.com/files/Git-1.6.2-preview20090308.exe'
end
end
task :check_vc6 do
begin
raise unless `nmake 2>&1` =~ /Microsoft/
rescue
raise 'VC6 not found, please run c:\vc\setvc.bat vc6'
end
end
task :check_perl do
unless `perl --version` =~ /ActiveState/
raise 'ActiveState perl required to build OpenSSL: http://downloads.activestate.com/ActivePerl/Windows/5.10/ActivePerl-5.10.0.1004-MSWin32-x86-287188.msi'
end
end
task :build_openssl => [:check_git, :check_perl, :check_vc6] do
mkdir_p 'build'
chdir 'build' do
unless File.exists?('openssl-0.9.8j')
sh 'curl http://www.openssl.org/source/openssl-0.9.8j.tar.gz > openssl.tar.gz'
sh 'tar zxvf openssl.tar.gz' rescue nil # fails because of symlinks
end
mkdir_p 'local'
chdir 'openssl-0.9.8j' do
sh "perl Configure VC-WIN32 --prefix=\"../local/\""
sh 'ms\do_ms.bat'
sh 'nmake -f ms\nt.mak install'
end
chdir '../ext' do
sh 'git clean -fd .'
end
mv 'local/include/openssl', '../ext/'
mv 'local/lib/ssleay32.lib', '../ext/'
mv 'local/lib/libeay32.lib', '../ext/'
end
end
desc "build binary win32 gem"
task :gem => :build_openssl do
Rake::Task['build'].invoke
Rake::Task['gem'].invoke
end
end
namespace :ext do
ext_sources = FileList['ext/*.{h,cpp,rb,c}']
ffr_sources = FileList['ext/fastfilereader/*.{h,cpp,rb}']
file ext_extconf = 'ext/extconf.rb'
file ffr_extconf = 'ext/fastfilereader/extconf.rb'
ext_libname = "lib/rubyeventmachine.#{Config::CONFIG['DLEXT']}"
ffr_libname = "lib/fastfilereaderext.#{Config::CONFIG['DLEXT']}"
file ext_libname => ext_sources + ['ext/Makefile'] do
chdir('ext') { sh MAKE }
end
file ffr_libname => ffr_sources + ['ext/fastfilereader/Makefile'] do
chdir('ext/fastfilereader') { sh MAKE }
end
desc "Build C++ extension"
task :build => [:make]
task :make => ext_libname
task :make => ffr_libname
file 'ext/Makefile' => ext_extconf do
chdir 'ext' do
ruby 'extconf.rb'
end
end
file 'ext/fastfilereader/Makefile' => ffr_extconf do
chdir 'ext/fastfilereader' do
ruby 'extconf.rb'
end
end
end
namespace :java do
# This task creates the JRuby JAR file and leaves it in the lib directory.
# This step is required before executing the jgem task.
desc "Build java extension"
task :build => [:jar] do |t|
mv 'java/em_reactor.jar', 'lib/'
end
task :compile do
chdir('java') do
mkdir_p "build"
sh 'javac src/com/rubyeventmachine/*.java -d build'
end
end
task :jar => [:compile] do
chdir('java/build') do
sh "jar -cf ../em_reactor.jar com/rubyeventmachine/*.class"
end
end
desc "build a java binary gem"
task :gem => :build do
Spec.platform = 'java'
Spec.files += %w[ lib/em_reactor.jar ]
Spec.extensions = nil
Rake::Task['gem'].invoke
end
end
namespace :osx do
desc "Build OSX binary gem"
task :gem do
Spec.platform = RUBY_PLATFORM.sub(/darwin.+$/, 'darwin')
Spec.files += %w[ lib/rubyeventmachine.bundle lib/fastfilereaderext.bundle ]
Spec.extensions = nil
Rake::Task['build'].invoke
Rake::Task['gem'].invoke
end
# XXX gcc will still prefer the shared libssl on the system, so we need to hack the extconf
# XXX to use the static library to make this actually work
task :static_gem => [:build_openssl, :gem]
task :build_openssl do
mkdir_p 'build'
chdir 'build' do
unless File.exists?('openssl-0.9.8j')
sh 'curl http://www.openssl.org/source/openssl-0.9.8j.tar.gz > openssl-0.9.8j.tar.gz'
sh 'tar zxvf openssl-0.9.8j.tar.gz'
end
mkdir_p 'local'
chdir 'openssl-0.9.8j' do
local_dir = File.expand_path(File.join(File.dirname(__FILE__),'build','local'))
sh "./config --prefix=#{local_dir}"
sh 'make'
sh 'make install'
end
chdir '../ext' do
sh 'git clean -fd .'
end
mv 'local/include/openssl', '../ext/'
mv 'local/lib/libssl.a', '../ext/'
mv 'local/lib/libcrypto.a', '../ext/'
end
end
end
require 'rake/clean'
rdoc_task_type = begin
require 'rdoc/task'
RDoc::Task
rescue LoadError
require 'rake/rdoctask'
Rake::RDocTask
end
df = begin; require 'rdoc/generator/darkfish'; true; rescue LoadError; end
rdtask = rdoc_task_type.new do |rd|
rd.title = Spec.name
rd.rdoc_dir = 'rdoc'
rd.main = "README"
rd.rdoc_files.include("lib/**/*.rb", *Spec.extra_rdoc_files)
rd.rdoc_files.exclude(*%w(lib/em/version lib/emva lib/evma/ lib/pr_eventmachine lib/jeventmachine))
rd.template = 'darkfish' if df
end
Rake::Task[:clean].enhance [:clobber_rdoc]
desc 'Generate and open documentation'
task :docs => :rdoc do
case RUBY_PLATFORM
when /darwin/ ; sh 'open rdoc/index.html'
when /mswin|mingw/ ; sh 'start rdoc\index.html'
else
sh 'firefox rdoc/index.html'
end
end
def windows?; RUBY_PLATFORM =~ /mswin|mingw/; end
def sudo(cmd)
if windows? || (require 'etc'; Etc.getpwuid.uid == 0)
sh cmd
else
sh "sudo #{cmd}"
end
end
def gem_cmd(action, name, *args)
rb = Gem.ruby rescue nil
rb ||= (require 'rbconfig'; File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']))
sudo "#{rb} -r rubygems -e 'require %{rubygems/gem_runner}; Gem::GemRunner.new.run(%w{#{action} #{name} #{args.join(' ')}})'"
end
begin
require 'rubygems/package_task'
Gem::PackageTask
rescue LoadError
require 'rake/gempackagetask'
Rake::GemPackageTask
end.new(Spec) do |pkg|
pkg.need_tar, pkg.need_tar_gz, pkg.need_zip = true, true, true if Package
pkg.gem_spec = Spec
end
Rake::Task[:clean].enhance [:clobber_package]
namespace :gem do
desc 'Install gem (and sudo if required)'
task :install => :package do
gem_cmd(:install, "pkg/#{Spec.name}-#{Spec.version}.gem")
end
desc 'Uninstall gem (and sudo if required)'
task :uninstall do
gem_cmd(:uninstall, "#{Spec.name}", "-v=#{Spec.version}")
end
desc "Generate new gemspec"
task :spec => :clobber do
open("eventmachine.gemspec", 'w') { |f| f.write Spec.to_ruby }
end
end
task :clobber => :clean
task :test => :build

View file

@ -1,60 +0,0 @@
EventMachine is copyrighted free software owned by Francis Cianfrocca
(blackhedd ... gmail.com). The Owner of this software permits you to
redistribute and/or modify the software under either the terms of the GPL
version 2 (see the file GPL), or the conditions below ("Ruby License"):
1. You may make and give away verbatim copies of the source form of this
software without restriction, provided that you retain ALL of the
original copyright notices and associated disclaimers.
2. You may modify your copy of the software in any way, provided that
you do at least ONE of the following:
a) place your modifications in the Public Domain or otherwise
make them Freely Available, such as by posting said
modifications to Usenet or an equivalent medium, or by allowing
the author to include your modifications in the software.
b) use the modified software only within your corporation or
organization.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the Owner.
3. You may distribute the software in object code or binary form,
provided that you do at least ONE of the following:
a) distribute the binaries and library files of the software,
together with instructions (in a manual page or equivalent)
on where to get the original distribution.
b) accompany the distribution with the machine-readable source of
the software.
c) give non-standard binaries non-standard names, with
instructions on where to get the original software distribution.
d) make other distribution arrangements with the Owner.
4. You may modify and include parts of the software into any other
software (possibly commercial), provided you comply with the terms in
Sections 1, 2, and 3 above. But some files in the distribution
are not written by the Owner, so they may be made available to you
under different terms.
For the list of those files and their copying conditions, see the
file LEGAL.
5. The scripts and library files supplied as input to or produced as
output from the software do not automatically fall under the
copyright of the software, but belong to whoever generated them,
and may be sold commercially, and may be aggregated with this
software.
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.

View file

@ -1,211 +0,0 @@
01Oct06: Replaced EventMachine#open_datagram_server with a version that can
take a Class or a Module, instead of just a Module. Thanks to Tobias
Gustafsson for pointing out the missing case.
04Oct06: Supported subsecond timer resolutions, per request by Jason Roelofs.
05Oct06: Added EventMachine#set_quantum, which sets the timer resolution.
15Nov06: Added Connection#set_comm_inactivity_timeout.
15Nov06: Checked in a Line-and-Text Protocol Handler.
18Nov06: Checked in a Header-and-Body Protocol Handler.
22Nov06: Changed EventMachine#reconnect: no longer excepts when called on an
already-connected handler.
28Nov06: Supported a binary-unix gem.
19Dec06: Added EventMachine#set_effective_user.
05Jan07: Upped max outstanding timers to 1000.
15May07: Applied Solaris patches from Brett Eisenberg
22May07: Cleaned up the license text in all the source files.
22May07: Released version 0.7.2
23May07: Per suggestion from Bill Kelly, fixed a bug with the initialization
of the network libraries under Windows. The goal is to enable EM to
be used without Ruby.
28May07: Applied patch from Bill Kelly, refactors the declarations of
event names to make EM easier to use from C programs without Ruby.
31May07: Added a preliminary implementation of EventMachine#popen.
01Jun07: Added EM, a "pseudo-alias" for EventMachine.
01Jun07: Added EM#next_tick.
01Jun07: Added EM::Connection#get_outbound_data_size
05Jun07: Removed the code which loads a pure-Ruby EM library in case the
compiled extension is unavailable. Suggested by Moshe Litvin.
06Jun07: Preliminary epoll implementation.
12Jun07: Added an evented popen implementation that, like Ruby's, is
full-duplex and makes the subprocess PID available to the caller.
06Jul07: Performance-tweaked the callback dispatcher in eventmachine.rb.
10Jul07: Released version 0.8.0.
12Jul07: Applied patches from Tim Pease to fix Solaris build problems.
15Jul07: Created a new provisional source branch, experiments/jruby-1.
This is a preliminary implementation of the EM reactor in Java,
suitable for use with JRuby.
17Jul07: Added EventMachine#stop_server, per request from Kirk Haines,
and associated unit tests.
22Jul07: Added EventMachine#stream_file_data. This is a very fast and scalable
way of sending data from static files over network connections. It
has separate implementations for small files and large file, and
has tunings to minimize memory consumption.
26Jul07: Added some patches by Kirk Haines to improve the behavior of
EM::Connection#send_file_data_to_connection.
26Jul07: Added a C++ module for directly integrating EM into C++ programs
with no Ruby dependencies. Needs example code.
29Jul07: Added EventMachine::Protocols::LineText2.
29Jul07: Added EventMachine::Protocols::Stomp.
30Jul07: Added sys/stat.h to project.h to fix compilation bug on Darwin.
13Aug07: Added EventMachine#reactor_running?
15Aug07: Added parameters for EventMachine::Connection:start_tls that can be
used to specify client-side private keys and certificates.
17Aug07: Added EventMachine#run_block, a sugaring for a common use case.
24Aug07: Added a preliminary keyboard handler. Needs docs and testing on
windows.
26Aug07: Created EventMachine::Spawnable, an implementation of Erlang-like
processes.
27Aug07: Silenced some -w warnings, requested by James Edward Gray II.
30Aug07: Added cookies to EM::HttpClient#request.
04Sep07: Added an initial implementation of an evented SMTP client.
04Sep07: Added an initial implementation of an evented SMTP server.
10Sep07: Changed EM#spawn to run spawned blocks in the context of the
SpawnedProcess object, not of whatever was the active object at the
time of the spawn.
14Sep07: Heartbeats weren't working with EPOLL. Noticed by Brian Candler.
15Sep07: Added some features, tests and documents to Deferrable.
16Sep07: Added [:content] parameter to EM::Protocols::SmtpClient#send.
16Sep07: Bumped version to 0.9.0 in anticipation of a release.
18Sep07: Released version 0.9.0.
19Sep07: Added #receive_reset to EM::Protocols::SmtpServer.
19Sep07: User overrides of EM::Protocols::SmtpServer#receive_recipient can now
return a Deferrable. Also fixed bug: SmtpClient now raises a protocol
error if none of its RCPT TO: commands are accepted by the server.
26Sep07: Fixed missing keyboard support for Windows.
03Oct07: Added a default handler for RuntimeErrors emitted from user-written
code. Suggested by Brian Candler.
19Oct07: Set the SO_BROADCAST option automatically on all UDP sockets.
10Nov07: Forced integer conversion of send_datagram's port parameter.
Suggested by Matthieu Riou.
12Nov07: Added saslauth.rb, a protocol module to replace the Cyrus SASL
daemons saslauthd and pwcheck.
15Nov07: Fixed bug reported by Mark Zvillius. We were failing to dispatch
zero-length datagrams under certain conditions.
19Nov07: Added EventMachine#set_max_timers. Requested by Matthieu Riou and
others.
19Nov07: Fixed bug with EM::Connection#start_tls. Was not working with server
connections. Reported by Michael S. Fischer.
26Nov07: Supported a hack for EventMachine#popen so it can return an exit
status from subprocesses. Requested by Michael S. Fischer.
30Nov07: Changed Pipe descriptors so that the child-side of the socketpair is
NOT set nonblocking. Suggested by Duane Johnson.
05Dec07: Re-enabled the pure-Ruby implementation.
06Dec07: Released Version 0.10.0.
13Dec07: Added EM::DeferrableChildProcess
24Dec07: Added a SASL client for simple password authentication.
27Dec07: Removed the hookable error handler. No one was using it and it significantly
degraded performance.
30Dec07: Implemented Kqueue support for OSX and BSD.
04Jan08: Fixed bug in epoll ("Bad file descriptor"), patch supplied by Chris
Heath.
04Jan08: Fixed bug reported by Michael S. Fischer. We were terminating
SSL connections that sent data before the handshake was complete.
08Jan08: Added an OpenBSD branch for extconf.rb, contributed by Guillaume
Sellier.
19Jan08: Added EM::Connection::get_sockname per request by Michael Fischer.
19Jan08: Supported IPv6 addresses.
30Apr08: Set the NODELAY option on sockets that we connect to other servers.
Omission noted by Roger Pack.
14May08: Generated a 0.12 release.
15May08: Supported EM#get_sockname for acceptors (TCP server sockets).
Requested by Roger Pack.
15May08; Accepted a patch from Dan Aquino that allows the interval of a
PeriodicTimer to be changed on the fly.
15Jun08: Supported nested calls to EM#run. Many people contributed ideas to
this, notably raggi and tmm1.
20Jul08: Accepted patch from tmm1 for EM#fork_reactor.
28Jul08: Added a Postgres3 implementation, written by FCianfrocca.
14Aug08: Added a patch by Mike Murphy to support basic auth in the http
client.
28Aug08: Added a patch by tmm1 to fix a longstanding problem with Java
data-sends.
13Sep08: Added LineText2#set_binary_mode, a back-compatibility alias.
13Sep08: Modified the load order of protocol libraries in eventmachine.rb
to permit a modification of HeaderAndContentProtocol.
13Sep08: Modified HeaderAndContent to use LineText2, which is less buggy
than LineAndTextProtocol. This change may be reversed if we can fix
the bugs in buftok.
13Sep08: Improved the password handling in the Postgres protocol handler.
15Sep08: Added attach/detach, contributed by Aman Gupta (tmm1) and Riham Aldakkak,
to support working with file descriptors not created in the reactor.
16Sep08: Added an optional version string to the HTTP client. This is a hack
that allows a client to specify a version 1.0 request, which
keeps the server from sending a chunked response. The right way to
solve this, of course, is to support chunked responses.
23Sep08: ChangeLog Summary for Merge of branches/raggi
Most notable work and patches by Aman Gupta, Roger Pack, and James Tucker.
Patches / Tickets also submitted by: Jeremy Evans, aanand, darix, mmmurf,
danielaquino, macournoyer.
- Moved docs into docs/ dir
- Major refactor of rakefile, added generic rakefile helpers in tasks
- Added example CPP build rakefile in tasks/cpp.rake
- Moved rake tests out to tasks/tests.rake
- Added svn ignores where appropriate
- Fixed jruby build on older java platforms
- Gem now builds from Rakefile rather than directly via extconf
- Gem unified for jruby, C++ and pure ruby.
- Correction for pure C++ build, removing ruby dependency
- Fix for CYGWIN builds on ipv6
- Major refactor for extconf.rb
- Working mingw builds
- extconf optionally uses pkg_config over manual configuration
- extconf builds for 1.9 on any system that has 1.9
- extconf no longer links pthread explicitly
- looks for kqueue on all *nix systems
- better error output on std::runtime_error, now says where it came from
- Fixed some tests on jruby
- Added test for general send_data flaw, required for a bugfix in jruby build
- Added timeout to epoll tests
- Added fixes for java reactor ruby api
- Small addition of some docs in httpclient.rb and httpcli2.rb
- Some refactor and fixes in smtpserver.rb
- Added parenthesis where possible to avoid excess ruby warnings
- Refactor of $eventmachine_library logic for accuracy and maintenance, jruby
- EM::start_server now supports unix sockets
- EM::connect now supports unix sockets
- EM::defer @threadqueue now handled more gracefully
- Added better messages on exceptions raised
- Fix edge case in timer fires
- Explicitly require buftok.rb
- Add protocols to autoload, rather than require them all immediately
- Fix a bug in pr_eventmachine for outbound_q
- Refactors to take some of the use of defer out of tests.
- Fixes in EM.defer under start/stop conditions. Reduced scope of threads.
23Sep08: Added patch from tmm1 to avoid popen errors on exit.
30Sep08: Added File.exists? checks in the args for start_tls, as suggested by
Brian Lopez (brianmario).
10Nov08: ruby 1.9 compatibility enhancements
28Nov08: Allow for older ruby builds where RARRAY_LEN is not defined
03Dec08: allow passing arguments to popen handlers
13Jan09: SSL support for httpclient2 (David Smalley)
22Jan09: Fixed errors on OSX with the kqueue reactor, fixed errors in the pure
ruby reactor. Added EM.current_time. Added EM.epoll? and EM.kqueue?
27Jan09: Reactor errors are now raised as ruby RuntimeErrors.
28Jan09: Documentation patch from alloy
29Jan09: (Late sign-off) Use a longer timeout for connect_server (Ilya
Grigorik)
07Feb09: Fix signal handling issues with threads+epoll
07Feb09: Use rb_thread_schedule in the epoll reactor
07Feb09: Use TRAP_BEG/END and rb_thread_schedule in kqueue reactor
08Feb09: Added fastfilereader from swiftiply
08Feb09: 1.9 fix for rb_trap_immediate
08Feb09: Enable rb_thread_blocking_region for 1.9.0 and 1.9.1
10Feb09: Support win32 builds for fastfilereader
10Feb09: Added a new event to indicate completion of SSL handshake on TCP
connections
10Feb09: Working get_peer_cert method. Returns the certificate as a Ruby
String in PEM format. (Jake Douglas)
10Feb09: Added EM.get_max_timers
11Feb09: Fix compile options for sun compiler (Alasdairrr)
11Feb09: get_status returns a Process::Status object
12Feb09: Add EM::Protocols::Memcache with simple get/set functionality
19Feb09: Add catch-all EM.error_handler
20Feb09: Support miniunit (1.9)
20Feb09: Return success on content-length = 0 instead of start waiting forever
(Ugo Riboni)
25Feb09: Allow next_tick to be used to pre-schedule reactor operations before
EM.run
26Feb09: Added EM.get_connection_count
01Mar09: Switch back to extconf for compiling gem extensions
01Mar09: fixed a small bug with basic auth (mmmurf)

View file

@ -1,133 +0,0 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency to the Ruby programmer's toolbox: spawned processes and deferrables. This note will show you how to use deferrables. For more information, see the separate document LIGHTWEIGHT_CONCURRENCY.
=== What are Deferrables?
EventMachine's Deferrable borrows heavily from the "deferred" object in Python's "Twisted" event-handling framework. Here's a minimal example that illustrates Deferrable:
require 'eventmachine'
class MyClass
include EM::Deferrable
def print_value x
puts "MyClass instance received #{x}"
end
end
EM.run {
df = MyClass.new
df.callback {|x|
df.print_value(x)
EM.stop
}
EM::Timer.new(2) {
df.set_deferred_status :succeeded, 100
}
}
This program will spin for two seconds, print out the string "MyClass instance received 100" and then exit. The Deferrable pattern relies on an unusual metaphor that may be unfamiliar to you, unless you've used Python's Twisted. You may need to read the following material through more than once before you get the idea.
EventMachine::Deferrable is simply a Ruby Module that you can include in your own classes. (There also is a class named EventMachine::DefaultDeferrable for when you want to create one without including it in code of your own.)
An object that includes EventMachine::Deferrable is like any other Ruby object: it can be created whenever you want, returned from your functions, or passed as an argument to other functions.
The Deferrable pattern allows you to specify any number of Ruby code blocks (callbacks or errbacks) that will be executed at some future time when the status of the Deferrable object changes.
How might that be useful? Well, imagine that you're implementing an HTTP server, but you need to make a call to some other server in order to fulfill a client request.
When you receive a request from one of your clients, you can create and return a Deferrable object. Some other section of your program can add a callback to the Deferrable that will cause the client's request to be fulfilled. Simultaneously, you initiate an event-driven or threaded client request to some different server. And then your EM program will continue to process other events and service other client requests.
When your client request to the other server completes some time later, you will call the #set_deferred_status method on the Deferrable object, passing either a success or failure status, and an arbitrary number of parameters (which might include the data you received from the other server).
At that point, the status of the Deferrable object becomes known, and its callback or errback methods are immediately executed. Callbacks and errbacks are code blocks that are attached to Deferrable objects at any time through the methods #callback and #errback.
The deep beauty of this pattern is that it decouples the disposition of one operation (such as a client request to an outboard server) from the subsequent operations that depend on that disposition (which may include responding to a different client or any other operation).
The code which invokes the deferred operation (that will eventually result in a success or failure status together with associated data) is completely separate from the code which depends on that status and data. This achieves one of the primary goals for which threading is typically used in sophisticated applications, with none of the nondeterminacy or debugging difficulties of threads.
As soon as the deferred status of a Deferrable becomes known by way of a call to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its callbacks or errbacks in the order in which they were added to the Deferrable.
Callbacks and errbacks can be added to a Deferrable object at any time, not just when the object is created. They can even be added after the status of the object has been determined! (In this case, they will be executed immediately when they are added.)
A call to Deferrable#set_deferred_status takes :succeeded or :failed as its first argument. (This determines whether the object will call its callbacks or its errbacks.) #set_deferred_status also takes zero or more additional parameters, that will in turn be passed as parameters to the callbacks or errbacks.
In general, you can only call #set_deferred_status ONCE on a Deferrable object. A call to #set_deferred_status will not return until all of the associated callbacks or errbacks have been called. If you add callbacks or errbacks AFTER making a call to #set_deferred_status, those additional callbacks or errbacks will execute IMMEDIATELY. Any given callback or errback will be executed AT MOST once.
It's possible to call #set_deferred_status AGAIN, during the execution a callback or errback. This makes it possible to change the parameters which will be sent to the callbacks or errbacks farther down the chain, enabling some extremely elegant use-cases. You can transform the data returned from a deferred operation in arbitrary ways as needed by subsequent users, without changing any of the code that generated the original data.
A call to #set_deferred_status will not return until all of the associated callbacks or errbacks have been called. If you add callbacks or errbacks AFTER making a call to #set_deferred_status, those additional callbacks or errbacks will execute IMMEDIATELY.
Let's look at some more sample code. It turns out that many of the internal protocol implementations in the EventMachine package rely on Deferrable. One of these is EM::Protocols::HttpClient.
To make an evented HTTP request, use the module function EM::Protocols::HttpClient#request, which returns a Deferrable object. Here's how:
require 'eventmachine'
EM.run {
df = EM::Protocols::HttpClient.request( :host=>"www.example.com", :request=>"/index.html" )
df.callback {|response|
puts "Succeeded: #{response[:content]}"
EM.stop
}
df.errback {|response|
puts "ERROR: #{response[:status]}"
EM.stop
}
}
(See the documentation of EventMachine::Protocols::HttpClient for information on the object returned by #request.)
In this code, we make a call to HttpClient#request, which immediately returns a Deferrable object. In the background, an HTTP client request is being made to www.example.com, although your code will continue to run concurrently.
At some future point, the HTTP client request will complete, and the code in EM::Protocols::HttpClient will process either a valid HTTP response (including returned content), or an error.
At that point, EM::Protocols::HttpClient will call EM::Deferrable#set_deferred_status on the Deferrable object that was returned to your program, as the return value from EM::Protocols::HttpClient.request. You don't have to do anything to make this happen. All you have to do is tell the Deferrable what to do in case of either success, failure, or both.
In our code sample, we set one callback and one errback. The former will be called if the HTTP call succeeds, and the latter if it fails. (For simplicity, we have both of them calling EM#stop to end the program, although real programs would be very unlikely to do this.)
Setting callbacks and errbacks is optional. They are handlers to defined events in the lifecycle of the Deferrable event. It's not an error if you fail to set either a callback, an errback, or both. But of course your program will then fail to receive those notifications.
If through some bug it turns out that #set_deferred_status is never called on a Deferrable object, then that object's callbacks or errbacks will NEVER be called. It's also possible to set a timeout on a Deferrable. If the timeout elapses before any other call to #set_deferred_status, the Deferrable object will behave as is you had called set_deferred_status(:failed) on it.
Now let's modify the example to illustrate some additional points:
require 'eventmachine'
EM.run {
df = EM::Protocols::HttpClient.request( :host=>"www.example.com", :request=>"/index.html" )
df.callback {|response|
df.set_deferred_status :succeeded, response[:content]
}
df.callback {|string|
puts "Succeeded: #{string}"
EM.stop
}
df.errback {|response|
puts "ERROR: #{response[:status]}"
EM.stop
}
}
Just for the sake of illustration, we've now set two callbacks instead of one. If the deferrable operation (the HTTP client-request) succeeds, then both of the callbacks will be executed in order.
But notice that we've also made our own call to #set_deferred_status in the first callback. This isn't required, because the HttpClient implementation already made a call to #set_deferred_status. (Otherwise, of course, the callback would not be executing.)
But we used #set_deferred_status in the first callback in order to change the parameters that will be sent to subsequent callbacks in the chain. In this way, you can construct powerful sequences of layered functionality. If you want, you can even change the status of the Deferrable from :succeeded to :failed, which would abort the chain of callback calls, and invoke the chain of errbacks instead.
Now of course it's somewhat trivial to define two callbacks in the same method, even with the parameter-changing effect we just described. It would be much more interesting to pass the Deferrable to some other function (for example, a function defined in another module or a different gem), that would in turn add callbacks and/or errbacks of its own. That would illustrate the true power of the Deferrable pattern: to isolate the HTTP client-request from other functions that use the data that it returns without caring where those data came from.
Remember that you can add a callback or an errback to a Deferrable at any point in time, regardless of whether the status of the deferred operation is known (more precisely, regardless of when #set_deferred_status is called on the object). Even hours or days later.
When you add a callback or errback to a Deferrable object on which #set_deferred_status has not yet been called, the callback/errback is queued up for future execution, inside the Deferrable object. When you add a callback or errback to a Deferrable on which #set_deferred_status has already been called, the callback/errback will be executed immediately. Your code doesn't have to worry about the ordering, and there are no timing issues, as there would be with a threaded approach.
For more information on Deferrables and their typical usage patterns, look in the EM unit tests. There are also quite a few sugarings (including EM::Deferrable#future) that make typical Deferrable usages syntactically easier to work with.

View file

@ -1,141 +0,0 @@
EventMachine now supports epoll, bringing large increases in performance and scalability to Ruby programs.
Epoll(7) is a alternative mechanism for multiplexed I/O that is available in Linux 2.6 kernels.
It features significantly greater performance than the standard select(2) mechanism, when used in
applications that require very large numbers of open I/O descriptors.
EventMachine has always used select(2) because its behavior is well standardized and broadly supported.
But select becomes unreasonably slow when a program has a
very large number of file descriptors or sockets. Ruby's version of select hardcodes a limit
of 1024 descriptors per process, but heavily loaded processes will start to show performance
degradation even after only a few hundred descriptors are in use.
Epoll is an extended version of the poll(2) call, and it solves the problems with select. Programs
based on epoll can easily scale past Ruby's 1024-descriptor limit, potentially to tens of thousands
of connectors, with no significant impact on performance.
(Another alternative which is very similar to epoll in principle is kqueue, supplied on BSD and its
variants.)
This note shows you how to use epoll in your programs.
=== Compiling EventMachine to use epoll.
You don't have to do anything to get epoll support in EventMachine.
When you compile EventMachine on a platform that supports epoll, EM will
automatically generate a Makefile that includes epoll. (At this writing, this will only work
on Linux 2.6 kernels.) If you compile EM on a platform without epoll, then epoll support will
be omitted from the Makefile, and EM will work just as it always has.
=== Using epoll in your programs.
First, you need to tell EventMachine to use epoll instead of select (but see below, as this requirement
will be removed in a future EventMachine version). Second, you need to prepare your program to use
more than 1024 descriptors, an operation that generally requires superuser privileges. Third, you will probably
want your process to drop the superuser privileges after you increase your process's descriptor limit.
=== Using EventMachine#epoll
Call the method EventMachine#epoll anytime before you call EventMachine#run, and your program will
automatically use epoll, if available. It's safe to call EventMachine#epoll on any platform because
it compiles to a no-op on platforms that don't support epoll.
require 'rubygems'
require 'eventmachine'
EM.epoll
EM.run {
...
}
EventMachine#epoll was included in this initial release only to avoid changing the behavior of existing
programs. However, it's expected that a future release of EM will convert EventMachine#epoll to a no-op,
and run epoll by default on platforms that support it.
=== Using EventMachine#set_descriptor_table_size
In Linux (as in every Unix-like platform), every process has a internal table that determines the maximum
number of file and socket descriptors you may have open at any given time. The size of this table is
generally fixed at 1024, although it may be increased within certain system-defined hard and soft limits.
If you want your EventMachine program to support more than 1024 total descriptors, you must use
EventMachine#set_descriptor_table_size, as follows:
require 'rubygems'
require 'eventmachine'
new_size = EM.set_descriptor_table_size( 60000 )
$>.puts "New descriptor-table size is #{new_size}"
EM.run {
...
}
If successful, this example will increase the maximum number of descriptors that epoll can use to 60,000.
Call EventMachine#set_descriptor_table_size without an argument at any time to find out the current
size of the descriptor table.
Using EventMachine#set_descriptor_table_size ONLY affects the number of descriptors that can be used
by epoll. It has no useful effect on platforms that don't support epoll, and it does NOT increase the
number of descriptors that Ruby's own I/O functions can use.
#set_descriptor_table_size can fail if your process is not running as superuser, or if you try to set a
table size that exceeds the hard limits imposed by your system. In the latter case, try a smaller number.
=== Using EventMachine#set_effective_user
In general, you must run your program with elevated or superuser privileges if you want to increase
your descriptor-table size beyond 1024 descriptors. This is easy enough to verify. Try running the
sample program given above, that increases the descriptor limit to 60,000. You will probably find that
the table size will not be increased if you don't run your program as root or with elevated privileges.
But of course network servers, especially long-running ones, should not run with elevated privileges.
You will want to drop superuser privileges as soon as possible after initialization. To do this,
use EventMachine#set_effective_user:
require 'rubygems'
require 'eventmachine'
# (Here, program is running as superuser)
EM.set_descriptor_table_size( 60000 )
EM.set_effective_user( "nobody" )
# (Here, program is running as nobody)
EM.run {
...
}
Of course, you will need to replace "nobody" in the example with the name of an unprivileged user
that is valid on your system. What if you want to drop privileges after opening a server socket
on a privileged (low-numbered) port? Easy, just call #set_effective_user after opening your sockets:
require 'rubygems'
require 'eventmachine'
# (Here, program is running as superuser)
EM.set_descriptor_table_size( 60000 )
EM.run {
EM.start_server( "0.0.0.0", 80, MyHttpServer )
EM.start_server( "0.0.0.0", 443, MyEncryptedHttpServer )
EM.set_effective_user( "nobody" )
# (Here, program is running as nobody)
...
}
Because EventMachine#set_effective_user is used to enforce security
requirements, it has no nonfatal errors. If you try to set a nonexistent or invalid effective user,
#set_effective_user will abort your program, rather than continue to run with elevated privileges.
EventMachine#set_effective_user is a silent no-op on platforms that don't support it, such as Windows.

View file

@ -1,281 +0,0 @@
.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

View file

@ -1,13 +0,0 @@
If you have obtained an EventMachine source-tarball (.tar.gz):
unzip and untar the tarball, and enter the directory that is
created. In that directory, say:
ruby setup.rb
(You may need to be root to execute this command.)
To create documentation for EventMachine, simply type:
rake rdoc
in the distro directory. Rdocs will be created in subdirectory rdoc.
If you have obtained a gem version of EventMachine, install it in the
usual way (gem install eventmachine). You may need superuser privileges
to execute this command.

View file

@ -1,38 +0,0 @@
EventMachine (EM) can respond to keyboard events. This gives your event-driven programs the ability to respond to input from local users.
Programming EM to handle keyboard input in Ruby is simplicity itself. Just use EventMachine#open_keyboard, and supply the name of a Ruby module or class that will receive the input:
require 'rubygems'
require 'eventmachine'
module MyKeyboardHandler
def receive_data keystrokes
puts "I received the following data from the keyboard: #{keystrokes}"
end
end
EM.run {
EM.open_keyboard(MyKeyboardHandler)
}
If you want EM to send line-buffered keyboard input to your program, just include the LineText2 protocol module in your handler class or module:
require 'rubygems'
require 'eventmachine'
module MyKeyboardHandler
include EM::Protocols::LineText2
def receive_line data
puts "I received the following line from the keyboard: #{data}"
end
end
EM.run {
EM.open_keyboard(MyKeyboardHandler)
}
As we said, simplicity itself. You can call EventMachine#open_keyboard at any time while the EM reactor loop is running. In other words, the method invocation may appear anywhere in an EventMachine#run block, or in any code invoked in the #run block.

View file

@ -1,25 +0,0 @@
LEGAL NOTICE INFORMATION
------------------------
EventMachine is Copyright (C) 2006-07 by Francis Cianfrocca.
EventMachine is copyrighted software owned by Francis Cianfrocca
(blackhedd ... gmail.com). You may redistribute and/or modify this
software as long as you comply with either the terms of the GPL
(see the file GPL), or Ruby's license (see the file COPYING).
Your use of all the files in this distribution is controlled by these
license terms, except for those files specifically mentioned below:
setup.rb
This file is Copyright (C) 2000-2005 by Minero Aoki
You can distribute/modify this file under the terms of
the GNU LGPL, Lesser General Public License version 2.1.
lib/em/buftok.rb
This file is Copyright (C) 2007 by Tony Arcieri. This file is
covered by the terms of Ruby's License (see the file COPYING).

View file

@ -1,70 +0,0 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency to the Ruby programmer's toolbox: spawned processes and deferrables. This note will show you how to use them.
=== What is Lightweight Concurrency?
We use the term "Lightweight Concurrency" (LC) to refer to concurrency mechanisms that are lighter than Ruby threads. By "lighter," we mean: less resource-intensive in one or more dimensions, usually including memory and CPU usage. In general, you turn to LC in the hope of improving the performance and scalability of your programs.
In addition to the two EventMachine mechanisms we will discuss here, Ruby has at least one other LC construct: Fibers, which are currently under development in Ruby 1.9.
The technical feature that makes all of these LC mechanisms different from standard Ruby threads is that they are not scheduled automatically.
When you create and run Ruby threads, you can assume (within certain constraints) that your threads will all be scheduled fairly by Ruby's runtime. Ruby itself is responsible for giving each of your threads its own share of the total runtime.
But with LC, your program is responsible for causing different execution paths to run. In effect, your program has to act as a "thread scheduler." Scheduled entities in LC run to completion and are never preempted. The runtime system has far less work to do since it has no need to interrupt threads or to schedule them fairly. This is what makes LC lighter and faster.
You'll learn exactly how LC scheduling works in practice as we work through specific examples.
=== EventMachine Lightweight Concurrency
Recall that EM provides a reactor loop that must be running in order for your programs to perform event-driven logic. An EM program typically has a structure like this:
require 'eventmachine'
# your initializations
EM.run {
# perform event-driven I/O here, including network clients,
# servers, timers, and thread-pool operations.
}
# your cleanup
# end of the program
EventMachine#run executes the reactor loop, which causes your code to be called as events of interest to your program occur. The block you pass to EventMachine#run is executed right after the reactor loop starts, and is the right place to start socket acceptors, etc.
Because the reactor loop runs constantly in an EM program (until it is stopped by a call to EventMachine#stop), it has the ability to schedule blocks of code for asynchronous execution. Unlike a pre-emptive thread scheduler, it's NOT able to interrupt code blocks while they execute. But the scheduling capability it does have is enough to enable lightweight concurrency.
For information on Spawned Processes, see the separate document SPAWNED_PROCESSES.
For information on Deferrables, see the separate document DEFERRABLES.
=== [SIDEBAR]: I Heard That EventMachine Doesn't Work With Ruby Threads.
This is incorrect. EM is fully interoperable with all versions of Ruby threads, and has been since its earliest releases.
It's very true that EM encourages an "evented" (non-threaded) programming style. The specific benefits of event-driven programming are far better performance and scalabiity for well-written programs, and far easier debugging.
The benefit of using threads for similar applications is a possibly more intuitive programming model, as well as the fact that threads are already familiar to most programmers. Also, bugs in threaded programs often fail to show up until programs go into production. These factors create the illusion that threaded programs are easier to write.
However, some operations that occur frequently in professional-caliber applications simply can't be done without threads. (The classic example is making calls to database client-libraries that block on network I/O until they complete.)
EventMachine not only allows the use of Ruby threads in these cases, but it even provides a built-in thread-pool object to make them easier to work with.
You may have heard a persistent criticism that evented I/O is fundamentally incompatible with Ruby threads. It is true that some well-publicized attempts to incorporate event-handling libraries into Ruby were not successful. But EventMachine was designed from the ground up with Ruby compatibility in mind, so EM never suffered from the problems that defeated the earlier attempts.
=== [SIDEBAR]: I Heard That EventMachine Doesn't Work Very Well On Windows.
This too is incorrect. EventMachine is an extension written in C++ and Java, and therefore it requires compilation. Many Windows computers (and some Unix computers, especially in production environments) don't have a build stack. Attempting to install EventMachine on a machine without a compiler usually produces a confusing error.
In addition, Ruby has a much-debated issue with Windows compiler versions. Ruby on Windows works best with Visual Studio 6, a compiler version that is long out-of-print, no longer supported by Microsoft, and difficult to obtain. (This problem is not specific to EventMachine.)
Shortly after EventMachine was first released, the compiler issues led to criticism that EM was incompatible with Windows. Since that time, every EventMachine release has been supplied in a precompiled binary form for Windows users, that does not require you to compile the code yourself. EM binary Gems for Windows are compiled using Visual Studio 6.
EventMachine does supply some advanced features (such as Linux EPOLL support, reduced-privilege operation, UNIX-domain sockets, etc.) that have no meaningful implementation on Windows. Apart from these special cases, all EM functionality (including lightweight concurrency) works perfectly well on Windows.

View file

@ -1,75 +0,0 @@
EventMachine is supplied in three alternative versions.
1) A version that includes a Ruby extension written in C++. This version requires compilation;
2) A version for JRuby that contains a precompiled JAR file written in Java;
3) A pure Ruby version that has no external dependencies and can run in any Ruby environment.
The Java version of EventMachine is packaged in a distinct manner and must be installed using a
special procedure. This version is described fully in a different document, and not considered
further here.
The C++ and pure-Ruby versions, however, are shipped in the same distribution. You use the same
files (either tarball or Ruby gem) to install both of these versions.
If you intend to use the C++ version, you must successfully compile EventMachine after you install it.
(The gem installation attempts to perform this step automatically.)
If you choose not to compile the EventMachine C++ extension, or if your compilation fails for any
reason, you still have a fully-functional installation of the pure-Ruby version of EM.
However, for technical reasons, a default EM installation (whether or not the compilation succeeds)
will always assume that the compiled ("extension") implementation should be used.
If you want your EM program to use the pure Ruby version, you must specifically request it. There
are two ways to do this: by setting either a Ruby global variable, or an environment string.
The following code will invoke the pure-Ruby implementation of EM:
$eventmachine_library = :pure_ruby
require 'eventmachine'
EM.library_type #=> "pure_ruby"
Notice that this requires a code change and is not the preferred way to select pure Ruby, unless
for some reason you are absolutely sure you will never want the compiled implementation.
Setting the following environment string has the same effect:
export EVENTMACHINE_LIBRARY="pure_ruby"
This technique gives you the flexibility to select either version at runtime with no code changes.
Support
The EventMachine development team has committed to support precisely the same APIs for all the
various implementations of EM.
This means that you can expect any EM program to behave identically, whether you use pure Ruby,
the compiled C++ extension, or JRuby. Deviations from this behavior are to be considered bugs
and should be reported as such.
There is a small number of exceptions to this rule, which arise from underlying platform
distinctions. Notably, EM#epoll is a silent no-op in the pure Ruby implementation.
When Should You Use the Pure-Ruby Implementation of EM?
Use the pure Ruby implementation of EM when you must support a platform for which no C++ compiler
is available, or on which the standard EM C++ code can't be compiled.
Keep in mind that you don't need a C++ compiler in order to deploy EM applications that rely on
the compiled version, so long as appropriate C++ runtime libraries are available on the target platform.
In extreme cases, you may find that you can develop software with the compiled EM version, but are
not allowed to install required runtime libraries on the deployment system(s). This would be another
case in which the pure Ruby implementation can be useful.
In general you should avoid the pure Ruby version of EM when performance and scalability are important.
EM in pure Ruby will necessarily run slower than the compiled version. Depending on your application
this may or may not be a key issue.
Also, since EPOLL is not supported in pure Ruby, your applications will be affected by Ruby's built-in
limit of 1024 file and socket descriptors that may be open in a single process. For maximum scalability
and performance, always use EPOLL if possible.

View file

@ -1,94 +0,0 @@
RUBY/EventMachine RELEASE NOTES
--------------------------------------------------
Version: 0.9.0, released xxXXX07
Added Erlang-like distributed-computing features
--------------------------------------------------
Version: 0.8.0, released 23Jun07
Added an epoll implementation for Linux 2.6 kernels.
Added evented #popen.
--------------------------------------------------
Version: 0.7.3, released 22May07
Added a large variety of small features. See the ChangeLog.
--------------------------------------------------
Version: 0.7.1, released xxNov06
Added protocol handlers for line-oriented protocols.
Various bug fixes.
--------------------------------------------------
Version: 0.7.0, released 20Nov06
Added a fix in em.cpp/ConnectToServer to fix a fatal exception that
occurred in FreeBSD when connecting successfully to a remote server.
--------------------------------------------------
Version: 0.6.0, released xxJul06
Added deferred operations, suggested by Don Stocks, amillionhitpoints@yahoo.com.
--------------------------------------------------
Version: 0.5.4, released xxJun06
Added get_peername support for streams and datagrams.
--------------------------------------------------
Version: 0.5.3, released 17May06
Fixed bugs in extconf.rb, thanks to Daniel Harple, dharple@generalconsumption.org.
Added proper setup.rb and rake tasks, thanks to Austin Ziegler.
Fixed a handful of reported problems with builds on various platforms.
--------------------------------------------------
Version: 0.5.2, released 05May06
Made several nonvisible improvements to the Windows
implementation.
Added an exception-handling patch contributed by Jeff Rose, jeff@rosejn.net.
Added a dir-config patch contributed anonymously.
Supported builds on Solaris.
--------------------------------------------------
Version: 0.5.1, released 05May06
Made it possible to pass a Class rather than a Module
to a protocol handler.
Added Windows port.
--------------------------------------------------
Version: 0.5.0, released 30Apr06
Added a preliminary SSL/TLS extension. This will probably
change over the next few releases.
--------------------------------------------------
Version: 0.4.5, released 29Apr06
Changed ext files so the ruby.h is installed after unistd.h
otherwise it doesn't compile on gcc 4.1
--------------------------------------------------
Version: 0.4.2, released 19Apr06
Changed the Ruby-glue so the extension will play nicer
in the sandbox with Ruby threads.
Added an EventMachine::run_without_threads API to
switch off the thread-awareness for better performance
in programs that do not spin any Ruby threads.
--------------------------------------------------
Version: 0.4.1, released 15Apr06
Reworked the shared-object interface to make it easier to
use EventMachine from languages other than Ruby.
--------------------------------------------------
Version: 0.3.2, released 12Apr06
Added support for a user-supplied block in EventMachine#connect.
--------------------------------------------------
Version: 0.3.1, released 11Apr06
Fixed bug that prevented EventMachine from being run multiple
times in a single process.
--------------------------------------------------
Version: 0.3.0, released 10Apr06
Added method EventHandler::Connection::post_init
--------------------------------------------------
Version: 0.2.0, released 10Apr06
Added method EventHandler::stop

View file

@ -1,2 +0,0 @@
This note details the usage of EventMachine's built-in support for SMTP. EM supports both client and server connections, which will be described in separate sections.

View file

@ -1,89 +0,0 @@
EventMachine (EM) adds two different formalisms for lightweight concurrency to the Ruby programmer's toolbox: spawned processes and deferrables. This note will show you how to use spawned processes. For more information, see the separate document LIGHTWEIGHT_CONCURRENCY.
=== What are Spawned Processes?
Spawned Processes in EventMachine are inspired directly by the "processes" found in the Erlang programming language. EM deliberately borrows much (but not all) of Erlang's terminology. However, EM's spawned processes differ from Erlang's in ways that reflect not only Ruby style, but also the fact that Ruby is not a functional language like Erlang.
Let's proceed with a complete, working code sample that we will analyze line by line. Here's an EM implementation of the "ping-pong" program that also appears in the Erlang tutorial:
require 'eventmachine'
EM.run {
pong = EM.spawn {|x, ping|
puts "Pong received #{x}"
ping.notify( x-1 )
}
ping = EM.spawn {|x|
if x > 0
puts "Pinging #{x}"
pong.notify x, self
else
EM.stop
end
}
ping.notify 3
}
If you run this program, you'll see the following output:
Pinging 3
Pong received 3
Pinging 2
Pong received 2
Pinging 1
Pong received 1
Let's take it step by step.
EventMachine#spawn works very much like the built-in function spawn in Erlang. It returns a reference to a Ruby object of class EventMachine::SpawnedProcess, which is actually a schedulable entity. In Erlang, the value returned from spawn is called a "process identifier" or "pid." But we'll refer to the Ruby object returned from EM#spawn simply as a "spawned process."
You pass a Ruby block with zero or more parameters to EventMachine#spawn. Like all Ruby blocks, this one is a closure, so it can refer to variables defined in the local context when you call EM#spawn.
However, the code block passed to EM#spawn does NOT execute immediately by default. Rather, it will execute only when the Spawned Object is "notified." In Erlang, this process is called "message passing," and is done with the operator !, but in Ruby it's done simply by calling the #notify method of a spawned-process object. The parameters you pass to #notify must match those defined in the block that was originally passed to EM#spawn.
When you call the #notify method of a spawned-process object, EM's reactor core will execute the code block originally passed to EM#spawn, at some point in the future. (#notify itself merely adds a notification to the object's message queue and ALWAYS returns immediately.)
When a SpawnedProcess object executes a notification, it does so in the context of the SpawnedProcess object itself. The notified code block can see local context from the point at which EM#spawn was called. However, the value of "self" inside the notified code block is a reference to the SpawnedProcesss object itself.
An EM spawned process is nothing more than a Ruby object with a message queue attached to it. You can have any number of spawned processes in your program without compromising scalability. You can notify a spawned process any number of times, and each notification will cause a "message" to be placed in the queue of the spawned process. Spawned processes with non-empty message queues are scheduled for execution automatically by the EM reactor. Spawned processes with no visible references are garbage-collected like any other Ruby object.
Back to our code sample:
pong = EM.spawn {|x, ping|
puts "Pong received #{x}"
ping.notify( x-1 )
}
This simply creates a spawned process and assigns it to the local variable pong. You can see that the spawned code block takes a numeric parameter and a reference to another spawned process. When pong is notified, it expects to receive arguments corresponding to these two parameters. It simply prints out the number it receives as the first argument. Then it notifies the spawned process referenced by the second argument, passing it the first argument minus 1.
And then the block ends, which is crucial because otherwise nothing else can run. (Remember that in LC, scheduled entities run to completion and are never preempted.)
On to the next bit of the code sample:
ping = EM.spawn {|x|
if x > 0
puts "Pinging #{x}"
pong.notify x, self
else
EM.stop
end
}
Here, we're spawning a process that takes a single (numeric) parameter. If the parameter is greater than zero, the block writes it to the console. It then notifies the spawned process referenced by the pong local variable, passing as arguments its number argument, and a reference to itself. The latter reference, as you saw above, is used by pong to send a return notification.
If the ping process receives a zero value, it will stop the reactor loop and end the program.
Now we've created a pair of spawned processes, but nothing else has happened. If we stop now, the program will spin in the EM reactor loop, doing nothing at all. Our spawned processes will never be scheduled for execution.
But look at the next line in the code sample:
ping.notify 3
This line gets the ping-pong ball rolling. We call ping's #notify method, passing the argument 3. This causes a message to be sent to the ping spawned process. The message contains the single argument, and it causes the EM reactor to schedule the ping process. And this in turn results in the execution of the Ruby code block passed to EM#spawn when ping was created. Everything else proceeds as a result of the messages that are subsequently passed to each other by the spawned processes.
[TODO, present the outbound network i/o use case, and clarify that spawned processes are interleaved with normal i/o operations and don't interfere with them at all. Also, blame Erlang for the confusing term "process"]

View file

@ -1,8 +0,0 @@
TODO List:
12Aug06: Noticed by Don Stocks. A TCP connect-request that results
in a failed DNS resolution fires a fatal error back to user code.
Uuuuuugly. We should probably cause an unbind event to get fired
instead, and add some parameterization so the caller can detect
the nature of the failure.

View file

@ -1,40 +0,0 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{eventmachine}
s.version = "0.12.10"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Francis Cianfrocca"]
s.date = %q{2009-10-24}
s.description = %q{EventMachine implements a fast, single-threaded engine for arbitrary network
communications. It's extremely easy to use in Ruby. EventMachine wraps all
interactions with IP sockets, allowing programs to concentrate on the
implementation of network protocols. It can be used to create both network
servers and clients. To create a server or client, a Ruby program only needs
to specify the IP address and port, and provide a Module that implements the
communications protocol. Implementations of several standard network protocols
are provided with the package, primarily to serve as examples. The real goal
of EventMachine is to enable programs to easily interface with other programs
using TCP/IP, especially if custom protocols are required.
}
s.email = %q{garbagecat10@gmail.com}
s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
s.files = [".gitignore", "README", "Rakefile", "docs/COPYING", "docs/ChangeLog", "docs/DEFERRABLES", "docs/EPOLL", "docs/GNU", "docs/INSTALL", "docs/KEYBOARD", "docs/LEGAL", "docs/LIGHTWEIGHT_CONCURRENCY", "docs/PURE_RUBY", "docs/RELEASE_NOTES", "docs/SMTP", "docs/SPAWNED_PROCESSES", "docs/TODO", "eventmachine.gemspec", "examples/ex_channel.rb", "examples/ex_queue.rb", "examples/helper.rb", "ext/binder.cpp", "ext/binder.h", "ext/cmain.cpp", "ext/cplusplus.cpp", "ext/ed.cpp", "ext/ed.h", "ext/em.cpp", "ext/em.h", "ext/emwin.cpp", "ext/emwin.h", "ext/epoll.cpp", "ext/epoll.h", "ext/eventmachine.h", "ext/eventmachine_cpp.h", "ext/extconf.rb", "ext/fastfilereader/extconf.rb", "ext/fastfilereader/mapper.cpp", "ext/fastfilereader/mapper.h", "ext/fastfilereader/rubymain.cpp", "ext/files.cpp", "ext/files.h", "ext/kb.cpp", "ext/page.cpp", "ext/page.h", "ext/pipe.cpp", "ext/project.h", "ext/rubymain.cpp", "ext/sigs.cpp", "ext/sigs.h", "ext/ssl.cpp", "ext/ssl.h", "java/.classpath", "java/.project", "java/src/com/rubyeventmachine/EmReactor.java", "java/src/com/rubyeventmachine/EmReactorException.java", "java/src/com/rubyeventmachine/EventableChannel.java", "java/src/com/rubyeventmachine/EventableDatagramChannel.java", "java/src/com/rubyeventmachine/EventableSocketChannel.java", "java/src/com/rubyeventmachine/application/Application.java", "java/src/com/rubyeventmachine/application/Connection.java", "java/src/com/rubyeventmachine/application/ConnectionFactory.java", "java/src/com/rubyeventmachine/application/DefaultConnectionFactory.java", "java/src/com/rubyeventmachine/application/PeriodicTimer.java", "java/src/com/rubyeventmachine/application/Timer.java", "java/src/com/rubyeventmachine/tests/ApplicationTest.java", "java/src/com/rubyeventmachine/tests/ConnectTest.java", "java/src/com/rubyeventmachine/tests/EMTest.java", "java/src/com/rubyeventmachine/tests/TestDatagrams.java", "java/src/com/rubyeventmachine/tests/TestServers.java", "java/src/com/rubyeventmachine/tests/TestTimers.java", "lib/em/buftok.rb", "lib/em/callback.rb", "lib/em/channel.rb", "lib/em/connection.rb", "lib/em/deferrable.rb", "lib/em/file_watch.rb", "lib/em/future.rb", "lib/em/messages.rb", "lib/em/process_watch.rb", "lib/em/processes.rb", "lib/em/protocols.rb", "lib/em/protocols/header_and_content.rb", "lib/em/protocols/httpclient.rb", "lib/em/protocols/httpclient2.rb", "lib/em/protocols/line_and_text.rb", "lib/em/protocols/linetext2.rb", "lib/em/protocols/memcache.rb", "lib/em/protocols/object_protocol.rb", "lib/em/protocols/postgres3.rb", "lib/em/protocols/saslauth.rb", "lib/em/protocols/smtpclient.rb", "lib/em/protocols/smtpserver.rb", "lib/em/protocols/socks4.rb", "lib/em/protocols/stomp.rb", "lib/em/protocols/tcptest.rb", "lib/em/queue.rb", "lib/em/spawnable.rb", "lib/em/streamer.rb", "lib/em/timers.rb", "lib/em/version.rb", "lib/eventmachine.rb", "lib/evma.rb", "lib/evma/callback.rb", "lib/evma/container.rb", "lib/evma/factory.rb", "lib/evma/protocol.rb", "lib/evma/reactor.rb", "lib/jeventmachine.rb", "lib/pr_eventmachine.rb", "setup.rb", "tasks/cpp.rake_example", "tests/client.crt", "tests/client.key", "tests/test_attach.rb", "tests/test_basic.rb", "tests/test_channel.rb", "tests/test_connection_count.rb", "tests/test_defer.rb", "tests/test_epoll.rb", "tests/test_error_handler.rb", "tests/test_errors.rb", "tests/test_exc.rb", "tests/test_file_watch.rb", "tests/test_futures.rb", "tests/test_get_sock_opt.rb", "tests/test_handler_check.rb", "tests/test_hc.rb", "tests/test_httpclient.rb", "tests/test_httpclient2.rb", "tests/test_inactivity_timeout.rb", "tests/test_kb.rb", "tests/test_ltp.rb", "tests/test_ltp2.rb", "tests/test_next_tick.rb", "tests/test_object_protocol.rb", "tests/test_pause.rb", "tests/test_pending_connect_timeout.rb", "tests/test_process_watch.rb", "tests/test_processes.rb", "tests/test_proxy_connection.rb", "tests/test_pure.rb", "tests/test_queue.rb", "tests/test_running.rb", "tests/test_sasl.rb", "tests/test_send_file.rb", "tests/test_servers.rb", "tests/test_smtpclient.rb", "tests/test_smtpserver.rb", "tests/test_spawn.rb", "tests/test_ssl_args.rb", "tests/test_ssl_methods.rb", "tests/test_ssl_verify.rb", "tests/test_timers.rb", "tests/test_ud.rb", "tests/testem.rb", "web/whatis"]
s.homepage = %q{http://rubyeventmachine.com}
s.rdoc_options = ["--title", "EventMachine", "--main", "README", "--line-numbers", "-x", "lib/em/version", "-x", "lib/emva", "-x", "lib/evma/", "-x", "lib/pr_eventmachine", "-x", "lib/jeventmachine"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{eventmachine}
s.rubygems_version = %q{1.3.5}
s.summary = %q{Ruby/EventMachine library}
if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
else
end
else
end
end

View file

@ -1,43 +0,0 @@
require File.dirname(__FILE__) + '/helper'
EM.run do
# Create a channel to push data to, this could be stocks...
RandChannel = EM::Channel.new
# The server simply subscribes client connections to the channel on connect,
# and unsubscribes them on disconnect.
class Server < EM::Connection
def self.start(host = '127.0.0.1', port = 8000)
EM.start_server(host, port, self)
end
def post_init
@sid = RandChannel.subscribe { |m| send_data "#{m.inspect}\n" }
end
def unbind
RandChannel.unsubscribe @sid
end
end
Server.start
# Two client connections, that just print what they receive.
2.times do
EM.connect('127.0.0.1', 8000) do |c|
c.extend EM::P::LineText2
def c.receive_line(line)
puts "Subscriber: #{signature} got #{line}"
end
EM.add_timer(2) { c.close_connection }
end
end
# This part of the example is more fake, but imagine sleep was in fact a
# long running calculation to achieve the value.
40.times do
EM.defer lambda { v = sleep(rand * 2); RandChannel << [Time.now, v] }
end
EM.add_timer(5) { EM.stop }
end

View file

@ -1,2 +0,0 @@
require File.dirname(__FILE__) + '/helper'

View file

@ -1,2 +0,0 @@
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
require 'eventmachine'

View file

@ -1,181 +0,0 @@
SHELL = /bin/sh
#### Start of system configuration section. ####
srcdir = .
topdir = /Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/include/ruby-1.9.1
hdrdir = /Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/include/ruby-1.9.1
arch_hdrdir = /Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/include/ruby-1.9.1/$(arch)
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
prefix = $(DESTDIR)/Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243
exec_prefix = $(prefix)
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
sitehdrdir = $(rubyhdrdir)/site_ruby
rubyhdrdir = $(includedir)/$(RUBY_INSTALL_NAME)-$(ruby_version)
vendordir = $(libdir)/$(RUBY_INSTALL_NAME)/vendor_ruby
sitedir = $(libdir)/$(RUBY_INSTALL_NAME)/site_ruby
mandir = $(datarootdir)/man
localedir = $(datarootdir)/locale
libdir = $(exec_prefix)/lib
psdir = $(docdir)
pdfdir = $(docdir)
dvidir = $(docdir)
htmldir = $(docdir)
infodir = $(datarootdir)/info
docdir = $(datarootdir)/doc/$(PACKAGE)
oldincludedir = $(DESTDIR)/usr/include
includedir = $(prefix)/include
localstatedir = $(prefix)/var
sharedstatedir = $(prefix)/com
sysconfdir = $(prefix)/etc
datadir = $(datarootdir)
datarootdir = $(prefix)/share
libexecdir = $(exec_prefix)/libexec
sbindir = $(exec_prefix)/sbin
bindir = $(exec_prefix)/bin
rubylibdir = $(libdir)/$(ruby_install_name)/$(ruby_version)
archdir = $(rubylibdir)/$(arch)
sitelibdir = $(sitedir)/$(ruby_version)
sitearchdir = $(sitelibdir)/$(sitearch)
vendorlibdir = $(vendordir)/$(ruby_version)
vendorarchdir = $(vendorlibdir)/$(sitearch)
CC = gcc
CXX = g++
LIBRUBY = $(LIBRUBY_SO)
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
OUTFLAG = -o
COUTFLAG = -o
RUBY_EXTCONF_H =
cflags = $(optflags) $(debugflags) $(warnflags)
optflags = -O2
debugflags = -g
warnflags = -Wall -Wno-parentheses
CFLAGS = -fno-common -O3 -march=core2 -m64 -mmmx -msse4.1 -w -pipe -fomit-frame-pointer -mmacosx-version-min=10.6 $(cflags) -fno-common -pipe -fno-common
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
DEFS =
CPPFLAGS = -DBUILD_FOR_RUBY -DHAVE_RB_THREAD_BLOCKING_REGION -DHAVE_TBR -DHAVE_WRITEV -DHAVE_WRITEV -DHAVE_RB_THREAD_CHECK_INTS -DHAVE_RB_TIME_NEW -DOS_UNIX -DHAVE_SYS_EVENT_H -DHAVE_SYS_QUEUE_H -DHAVE_KQUEUE -DHAVE_OPENSSL_SSL_H -DHAVE_OPENSSL_ERR_H -DWITH_SSL -DHAVE_MAKE_PAIR -I/Users/tdreyno/homebrew/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
CXXFLAGS = $(CFLAGS) -O3 -march=core2 -m64 -mmmx -msse4.1 -w -pipe -fomit-frame-pointer -mmacosx-version-min=10.6 $(cxxflags)
ldflags = -L. -L/Users/tdreyno/homebrew/lib -L/usr/local/lib
dldflags =
archflag =
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
LDSHARED = $(CXX) -dynamic -bundle -undefined suppress -flat_namespace
LDSHAREDXX = $(LDSHARED)
AR = ar
EXEEXT =
RUBY_INSTALL_NAME = ruby
RUBY_SO_NAME = ruby
arch = i386-darwin10.0.0
sitearch = i386-darwin10.0.0
ruby_version = 1.9.1
ruby = /Users/tdreyno/homebrew/Cellar/ruby/1.9.1-p243/bin/ruby
RUBY = $(ruby)
RM = rm -f
RM_RF = $(RUBY) -run -e rm -- -rf
RMDIRS = $(RUBY) -run -e rmdir -- -p
MAKEDIRS = mkdir -p
INSTALL = /usr/bin/install -c
INSTALL_PROG = $(INSTALL) -m 0755
INSTALL_DATA = $(INSTALL) -m 644
COPY = cp
#### End of system configuration section. ####
preload =
libpath = . $(libdir)
LIBPATH = -L. -L$(libdir)
DEFFILE =
CLEANFILES = mkmf.log
DISTCLEANFILES =
DISTCLEANDIRS =
extout =
extout_prefix =
target_prefix =
LOCAL_LIBS =
LIBS = $(LIBRUBYARG_SHARED) -lC -lcrypto -lssl -lpthread -ldl -lobjc
SRCS = binder.cpp cmain.cpp cplusplus.cpp ed.cpp em.cpp emwin.cpp epoll.cpp files.cpp kb.cpp page.cpp pipe.cpp rubymain.cpp sigs.cpp ssl.cpp
OBJS = binder.o cmain.o cplusplus.o ed.o em.o emwin.o epoll.o files.o kb.o page.o pipe.o rubymain.o sigs.o ssl.o
TARGET = rubyeventmachine
DLLIB = $(TARGET).bundle
EXTSTATIC =
STATIC_LIB =
BINDIR = $(bindir)
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
RUBYLIBDIR = /Users/tdreyno/Dropbox/Sites/middleman/vendor/gems/gems/eventmachine-0.12.10/lib$(target_prefix)
RUBYARCHDIR = /Users/tdreyno/Dropbox/Sites/middleman/vendor/gems/gems/eventmachine-0.12.10/lib$(target_prefix)
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
TARGET_SO = $(DLLIB)
CLEANLIBS = $(TARGET).bundle
CLEANOBJS = *.o *.bak
all: $(DLLIB)
static: $(STATIC_LIB)
clean-rb-default::
clean-rb::
clean-so::
clean: clean-so clean-rb-default clean-rb
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
distclean-rb-default::
distclean-rb::
distclean-so::
distclean: clean distclean-so distclean-rb-default distclean-rb
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
@-$(RMDIRS) $(DISTCLEANDIRS)
realclean: distclean
install: install-so install-rb
install-so: $(RUBYARCHDIR)
install-so: $(RUBYARCHDIR)/$(DLLIB)
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
install-rb: pre-install-rb install-rb-default
install-rb-default: pre-install-rb-default
pre-install-rb: Makefile
pre-install-rb-default: Makefile
$(RUBYARCHDIR):
$(MAKEDIRS) $@
site-install: site-install-so site-install-rb
site-install-so: install-so
site-install-rb: install-rb
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
.cc.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
.cxx.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
.cpp.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
.C.o:
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
.c.o:
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
$(DLLIB): $(OBJS) Makefile
@-$(RM) $(@)
$(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h

View file

@ -1,125 +0,0 @@
/*****************************************************************************
$Id$
File: binder.cpp
Date: 07Apr06
Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
Gmail: blackhedd
This program is free software; you can redistribute it and/or modify
it under the terms of either: 1) the GNU General Public License
as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version; or 2) Ruby's License.
See the file COPYING for complete licensing information.
*****************************************************************************/
#include "project.h"
#define DEV_URANDOM "/dev/urandom"
map<unsigned long, Bindable_t*> Bindable_t::BindingBag;
/********************************
STATIC Bindable_t::CreateBinding
********************************/
unsigned long Bindable_t::CreateBinding()
{
// XXX use atomic_t to prevent thread-safety issues
static unsigned long num = 0;
while(BindingBag[++num]);
return num;
}
#if 0
string Bindable_t::CreateBinding()
{
static int index = 0;
static string seed;
if ((index >= 1000000) || (seed.length() == 0)) {
#ifdef OS_UNIX
int fd = open (DEV_URANDOM, O_RDONLY);
if (fd < 0)
throw std::runtime_error ("No entropy device");
unsigned char u[16];
size_t r = read (fd, u, sizeof(u));
if (r < sizeof(u))
throw std::runtime_error ("Unable to read entropy device");
unsigned char *u1 = (unsigned char*)u;
char u2 [sizeof(u) * 2 + 1];
for (size_t i=0; i < sizeof(u); i++)
sprintf (u2 + (i * 2), "%02x", u1[i]);
seed = string (u2);
#endif
#ifdef OS_WIN32
UUID uuid;
UuidCreate (&uuid);
unsigned char *uuidstring = NULL;
UuidToString (&uuid, &uuidstring);
if (!uuidstring)
throw std::runtime_error ("Unable to read uuid");
seed = string ((const char*)uuidstring);
RpcStringFree (&uuidstring);
#endif
index = 0;
}
stringstream ss;
ss << seed << (++index);
return ss.str();
}
#endif
/*****************************
STATIC: Bindable_t::GetObject
*****************************/
Bindable_t *Bindable_t::GetObject (const unsigned long binding)
{
map<unsigned long, Bindable_t*>::const_iterator i = BindingBag.find (binding);
if (i != BindingBag.end())
return i->second;
else
return NULL;
}
/**********************
Bindable_t::Bindable_t
**********************/
Bindable_t::Bindable_t()
{
Binding = Bindable_t::CreateBinding();
BindingBag [Binding] = this;
}
/***********************
Bindable_t::~Bindable_t
***********************/
Bindable_t::~Bindable_t()
{
BindingBag.erase (Binding);
}

View file

@ -1,46 +0,0 @@
/*****************************************************************************
$Id$
File: binder.h
Date: 07Apr06
Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
Gmail: blackhedd
This program is free software; you can redistribute it and/or modify
it under the terms of either: 1) the GNU General Public License
as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version; or 2) Ruby's License.
See the file COPYING for complete licensing information.
*****************************************************************************/
#ifndef __ObjectBindings__H_
#define __ObjectBindings__H_
class Bindable_t
{
public:
static unsigned long CreateBinding();
static Bindable_t *GetObject (const unsigned long);
static map<unsigned long, Bindable_t*> BindingBag;
public:
Bindable_t();
virtual ~Bindable_t();
const unsigned long GetBinding() {return Binding;}
private:
unsigned long Binding;
};
#endif // __ObjectBindings__H_

View file

@ -1,827 +0,0 @@
/*****************************************************************************
$Id$
File: cmain.cpp
Date: 06Apr06
Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
Gmail: blackhedd
This program is free software; you can redistribute it and/or modify
it under the terms of either: 1) the GNU General Public License
as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version; or 2) Ruby's License.
See the file COPYING for complete licensing information.
*****************************************************************************/
#include "project.h"
/* 21Sep09: ruby 1.9 defines macros for common i/o functions that point to rb_w32_* implementations.
We need to undef the stat to fix a build failure in evma_send_file_data_to_connection.
See http://groups.google.com/group/eventmachine/browse_thread/thread/fc60d9bb738ffc71
*/
#if defined(BUILD_FOR_RUBY) && defined(OS_WIN32)
#undef stat
#endif
static EventMachine_t *EventMachine;
static int bUseEpoll = 0;
static int bUseKqueue = 0;
extern "C" void ensure_eventmachine (const char *caller = "unknown caller")
{
if (!EventMachine) {
const int err_size = 128;
char err_string[err_size];
snprintf (err_string, err_size, "eventmachine not initialized: %s", caller);
#ifdef BUILD_FOR_RUBY
rb_raise(rb_eRuntimeError, "%s", err_string);
#else
throw std::runtime_error (err_string);
#endif
}
}
/***********************
evma_initialize_library
***********************/
extern "C" void evma_initialize_library (void(*cb)(const unsigned long, int, const char*, const unsigned long))
{
// Probably a bad idea to mess with the signal mask of a process
// we're just being linked into.
//InstallSignalHandlers();
if (EventMachine)
#ifdef BUILD_FOR_RUBY
rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_initialize_library");
#else
throw std::runtime_error ("eventmachine already initialized: evma_initialize_library");
#endif
EventMachine = new EventMachine_t (cb);
if (bUseEpoll)
EventMachine->_UseEpoll();
if (bUseKqueue)
EventMachine->_UseKqueue();
}
/********************
evma_release_library
********************/
extern "C" void evma_release_library()
{
ensure_eventmachine("evma_release_library");
delete EventMachine;
EventMachine = NULL;
}
/****************
evma_run_machine
****************/
extern "C" void evma_run_machine()
{
ensure_eventmachine("evma_run_machine");
EventMachine->Run();
}
/**************************
evma_install_oneshot_timer
**************************/
extern "C" const unsigned long evma_install_oneshot_timer (int seconds)
{
ensure_eventmachine("evma_install_oneshot_timer");
return EventMachine->InstallOneshotTimer (seconds);
}
/**********************
evma_connect_to_server
**********************/
extern "C" const unsigned long evma_connect_to_server (const char *bind_addr, int bind_port, const char *server, int port)
{
ensure_eventmachine("evma_connect_to_server");
return EventMachine->ConnectToServer (bind_addr, bind_port, server, port);
}
/***************************
evma_connect_to_unix_server
***************************/
extern "C" const unsigned long evma_connect_to_unix_server (const char *server)
{
ensure_eventmachine("evma_connect_to_unix_server");
return EventMachine->ConnectToUnixServer (server);
}
/**************
evma_attach_fd
**************/
extern "C" const unsigned long evma_attach_fd (int file_descriptor, int watch_mode)
{
ensure_eventmachine("evma_attach_fd");
return EventMachine->AttachFD (file_descriptor, watch_mode ? true : false);
}
/**************
evma_detach_fd
**************/
extern "C" int evma_detach_fd (const unsigned long binding)
{
ensure_eventmachine("evma_detach_fd");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed)
return EventMachine->DetachFD (ed);
else
#ifdef BUILD_FOR_RUBY
rb_raise(rb_eRuntimeError, "invalid binding to detach");
#else
throw std::runtime_error ("invalid binding to detach");
#endif
}
/************************
evma_get_file_descriptor
************************/
extern "C" int evma_get_file_descriptor (const unsigned long binding)
{
ensure_eventmachine("evma_get_file_descriptor");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed)
return ed->GetSocket();
else
#ifdef BUILD_FOR_RUBY
rb_raise(rb_eRuntimeError, "invalid binding to get_fd");
#else
throw std::runtime_error ("invalid binding to get_fd");
#endif
}
/***********************
evma_is_notify_readable
***********************/
extern "C" int evma_is_notify_readable (const unsigned long binding)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
return cd->IsNotifyReadable() ? 1 : 0;
return -1;
}
/************************
evma_set_notify_readable
************************/
extern "C" void evma_set_notify_readable (const unsigned long binding, int mode)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
cd->SetNotifyReadable (mode ? true : false);
}
/***********************
evma_is_notify_writable
***********************/
extern "C" int evma_is_notify_writable (const unsigned long binding)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
return cd->IsNotifyWritable() ? 1 : 0;
return -1;
}
/************************
evma_set_notify_writable
************************/
extern "C" void evma_set_notify_writable (const unsigned long binding, int mode)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
cd->SetNotifyWritable (mode ? true : false);
}
/**********
evma_pause
**********/
extern "C" int evma_pause (const unsigned long binding)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
return cd->Pause() ? 1 : 0;
return 0;
}
/***********
evma_resume
***********/
extern "C" int evma_resume (const unsigned long binding)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
return cd->Resume() ? 1 : 0;
return 0;
}
/**************
evma_is_paused
**************/
extern "C" int evma_is_paused (const unsigned long binding)
{
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
return cd->IsPaused() ? 1 : 0;
return 0;
}
/**********************
evma_create_tcp_server
**********************/
extern "C" const unsigned long evma_create_tcp_server (const char *address, int port)
{
ensure_eventmachine("evma_create_tcp_server");
return EventMachine->CreateTcpServer (address, port);
}
/******************************
evma_create_unix_domain_server
******************************/
extern "C" const unsigned long evma_create_unix_domain_server (const char *filename)
{
ensure_eventmachine("evma_create_unix_domain_server");
return EventMachine->CreateUnixDomainServer (filename);
}
/*************************
evma_open_datagram_socket
*************************/
extern "C" const unsigned long evma_open_datagram_socket (const char *address, int port)
{
ensure_eventmachine("evma_open_datagram_socket");
return EventMachine->OpenDatagramSocket (address, port);
}
/******************
evma_open_keyboard
******************/
extern "C" const unsigned long evma_open_keyboard()
{
ensure_eventmachine("evma_open_keyboard");
return EventMachine->OpenKeyboard();
}
/*******************
evma_watch_filename
*******************/
extern "C" const unsigned long evma_watch_filename (const char *fname)
{
ensure_eventmachine("evma_watch_filename");
return EventMachine->WatchFile(fname);
}
/*********************
evma_unwatch_filename
*********************/
extern "C" void evma_unwatch_filename (const unsigned long sig)
{
ensure_eventmachine("evma_unwatch_file");
EventMachine->UnwatchFile(sig);
}
/**************
evma_watch_pid
**************/
extern "C" const unsigned long evma_watch_pid (int pid)
{
ensure_eventmachine("evma_watch_pid");
return EventMachine->WatchPid(pid);
}
/****************
evma_unwatch_pid
****************/
extern "C" void evma_unwatch_pid (const unsigned long sig)
{
ensure_eventmachine("evma_unwatch_pid");
EventMachine->UnwatchPid(sig);
}
/****************************
evma_send_data_to_connection
****************************/
extern "C" int evma_send_data_to_connection (const unsigned long binding, const char *data, int data_length)
{
ensure_eventmachine("evma_send_data_to_connection");
return ConnectionDescriptor::SendDataToConnection (binding, data, data_length);
}
/******************
evma_send_datagram
******************/
extern "C" int evma_send_datagram (const unsigned long binding, const char *data, int data_length, const char *address, int port)
{
ensure_eventmachine("evma_send_datagram");
return DatagramDescriptor::SendDatagram (binding, data, data_length, address, port);
}
/*********************
evma_close_connection
*********************/
extern "C" void evma_close_connection (const unsigned long binding, int after_writing)
{
ensure_eventmachine("evma_close_connection");
ConnectionDescriptor::CloseConnection (binding, (after_writing ? true : false));
}
/***********************************
evma_report_connection_error_status
***********************************/
extern "C" int evma_report_connection_error_status (const unsigned long binding)
{
ensure_eventmachine("evma_report_connection_error_status");
return ConnectionDescriptor::ReportErrorStatus (binding);
}
/********************
evma_stop_tcp_server
********************/
extern "C" void evma_stop_tcp_server (const unsigned long binding)
{
ensure_eventmachine("evma_stop_tcp_server");
AcceptorDescriptor::StopAcceptor (binding);
}
/*****************
evma_stop_machine
*****************/
extern "C" void evma_stop_machine()
{
ensure_eventmachine("evma_stop_machine");
EventMachine->ScheduleHalt();
}
/**************
evma_start_tls
**************/
extern "C" void evma_start_tls (const unsigned long binding)
{
ensure_eventmachine("evma_start_tls");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed)
ed->StartTls();
}
/******************
evma_set_tls_parms
******************/
extern "C" void evma_set_tls_parms (const unsigned long binding, const char *privatekey_filename, const char *certchain_filename, int verify_peer)
{
ensure_eventmachine("evma_set_tls_parms");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed)
ed->SetTlsParms (privatekey_filename, certchain_filename, (verify_peer == 1 ? true : false));
}
/******************
evma_get_peer_cert
******************/
#ifdef WITH_SSL
extern "C" X509 *evma_get_peer_cert (const unsigned long binding)
{
ensure_eventmachine("evma_get_peer_cert");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed)
return ed->GetPeerCert();
return NULL;
}
#endif
/********************
evma_accept_ssl_peer
********************/
#ifdef WITH_SSL
extern "C" void evma_accept_ssl_peer (const unsigned long binding)
{
ensure_eventmachine("evma_accept_ssl_peer");
ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject (binding));
if (cd)
cd->AcceptSslPeer();
}
#endif
/*****************
evma_get_peername
*****************/
extern "C" int evma_get_peername (const unsigned long binding, struct sockaddr *sa)
{
ensure_eventmachine("evma_get_peername");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->GetPeername (sa) ? 1 : 0;
}
else
return 0;
}
/*****************
evma_get_sockname
*****************/
extern "C" int evma_get_sockname (const unsigned long binding, struct sockaddr *sa)
{
ensure_eventmachine("evma_get_sockname");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->GetSockname (sa) ? 1 : 0;
}
else
return 0;
}
/***********************
evma_get_subprocess_pid
***********************/
extern "C" int evma_get_subprocess_pid (const unsigned long binding, pid_t *pid)
{
ensure_eventmachine("evma_get_subprocess_pid");
#ifdef OS_UNIX
PipeDescriptor *pd = dynamic_cast <PipeDescriptor*> (Bindable_t::GetObject (binding));
if (pd) {
return pd->GetSubprocessPid (pid) ? 1 : 0;
}
else if (pid && EventMachine->SubprocessPid) {
*pid = EventMachine->SubprocessPid;
return 1;
}
else
return 0;
#else
return 0;
#endif
}
/**************************
evma_get_subprocess_status
**************************/
extern "C" int evma_get_subprocess_status (const unsigned long binding, int *status)
{
ensure_eventmachine("evma_get_subprocess_status");
if (status) {
*status = EventMachine->SubprocessExitStatus;
return 1;
}
else
return 0;
}
/*************************
evma_get_connection_count
*************************/
extern "C" int evma_get_connection_count()
{
ensure_eventmachine("evma_get_connection_count");
return EventMachine->GetConnectionCount();
}
/*********************
evma_signal_loopbreak
*********************/
extern "C" void evma_signal_loopbreak()
{
ensure_eventmachine("evma_signal_loopbreak");
EventMachine->SignalLoopBreaker();
}
/****************
evma__write_file
****************/
extern "C" const unsigned long evma__write_file (const char *filename)
{
ensure_eventmachine("evma__write_file");
return EventMachine->_OpenFileForWriting (filename);
}
/********************************
evma_get_comm_inactivity_timeout
********************************/
extern "C" float evma_get_comm_inactivity_timeout (const unsigned long binding)
{
ensure_eventmachine("evma_get_comm_inactivity_timeout");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->GetCommInactivityTimeout();
}
else
return 0.0; //Perhaps this should be an exception. Access to an unknown binding.
}
/********************************
evma_set_comm_inactivity_timeout
********************************/
extern "C" int evma_set_comm_inactivity_timeout (const unsigned long binding, float value)
{
ensure_eventmachine("evma_set_comm_inactivity_timeout");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->SetCommInactivityTimeout (value);
}
else
return 0; //Perhaps this should be an exception. Access to an unknown binding.
}
/********************************
evma_get_pending_connect_timeout
********************************/
extern "C" float evma_get_pending_connect_timeout (const unsigned long binding)
{
ensure_eventmachine("evma_get_pending_connect_timeout");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->GetPendingConnectTimeout();
}
else
return 0.0;
}
/********************************
evma_set_pending_connect_timeout
********************************/
extern "C" int evma_set_pending_connect_timeout (const unsigned long binding, float value)
{
ensure_eventmachine("evma_set_pending_connect_timeout");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
if (ed) {
return ed->SetPendingConnectTimeout (value);
}
else
return 0;
}
/**********************
evma_set_timer_quantum
**********************/
extern "C" void evma_set_timer_quantum (int interval)
{
ensure_eventmachine("evma_set_timer_quantum");
EventMachine->SetTimerQuantum (interval);
}
/************************
evma_get_max_timer_count
************************/
extern "C" int evma_get_max_timer_count()
{
return EventMachine_t::GetMaxTimerCount();
}
/************************
evma_set_max_timer_count
************************/
extern "C" void evma_set_max_timer_count (int ct)
{
// This may only be called if the reactor is not running.
if (EventMachine)
#ifdef BUILD_FOR_RUBY
rb_raise(rb_eRuntimeError, "eventmachine already initialized: evma_set_max_timer_count");
#else
throw std::runtime_error ("eventmachine already initialized: evma_set_max_timer_count");
#endif
EventMachine_t::SetMaxTimerCount (ct);
}
/******************
evma_setuid_string
******************/
extern "C" void evma_setuid_string (const char *username)
{
// We do NOT need to be running an EM instance because this method is static.
EventMachine_t::SetuidString (username);
}
/**********
evma_popen
**********/
extern "C" const unsigned long evma_popen (char * const*cmd_strings)
{
ensure_eventmachine("evma_popen");
return EventMachine->Socketpair (cmd_strings);
}
/***************************
evma_get_outbound_data_size
***************************/
extern "C" int evma_get_outbound_data_size (const unsigned long binding)
{
ensure_eventmachine("evma_get_outbound_data_size");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (binding));
return ed ? ed->GetOutboundDataSize() : 0;
}
/**************
evma_set_epoll
**************/
extern "C" void evma_set_epoll (int use)
{
bUseEpoll = !!use;
}
/***************
evma_set_kqueue
***************/
extern "C" void evma_set_kqueue (int use)
{
bUseKqueue = !!use;
}
/**********************
evma_set_rlimit_nofile
**********************/
extern "C" int evma_set_rlimit_nofile (int nofiles)
{
return EventMachine_t::SetRlimitNofile (nofiles);
}
/*********************************
evma_send_file_data_to_connection
*********************************/
extern "C" int evma_send_file_data_to_connection (const unsigned long binding, const char *filename)
{
/* This is a sugaring over send_data_to_connection that reads a file into a
* locally-allocated buffer, and sends the file data to the remote peer.
* Return the number of bytes written to the caller.
* TODO, needs to impose a limit on the file size. This is intended only for
* small files. (I don't know, maybe 8K or less.) For larger files, use interleaved
* I/O to avoid slowing the rest of the system down.
* TODO: we should return a code rather than barf, in case of file-not-found.
* TODO, does this compile on Windows?
* TODO, given that we want this to work only with small files, how about allocating
* the buffer on the stack rather than the heap?
*
* Modified 25Jul07. This now returns -1 on file-too-large; 0 for success, and a positive
* errno in case of other errors.
*
* Contributed by Kirk Haines.
*/
char data[32*1024];
int r;
ensure_eventmachine("evma_send_file_data_to_connection");
int Fd = open (filename, O_RDONLY);
if (Fd < 0)
return errno;
// From here on, all early returns MUST close Fd.
struct stat st;
if (fstat (Fd, &st)) {
int e = errno;
close (Fd);
return e;
}
off_t filesize = st.st_size;
if (filesize <= 0) {
close (Fd);
return 0;
}
else if (filesize > (off_t) sizeof(data)) {
close (Fd);
return -1;
}
r = read (Fd, data, filesize);
if (r != filesize) {
int e = errno;
close (Fd);
return e;
}
evma_send_data_to_connection (binding, data, r);
close (Fd);
return 0;
}
/****************
evma_start_proxy
*****************/
extern "C" void evma_start_proxy (const unsigned long from, const unsigned long to, const unsigned long bufsize)
{
ensure_eventmachine("evma_start_proxy");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
if (ed)
ed->StartProxy(to, bufsize);
}
/***************
evma_stop_proxy
****************/
extern "C" void evma_stop_proxy (const unsigned long from)
{
ensure_eventmachine("evma_stop_proxy");
EventableDescriptor *ed = dynamic_cast <EventableDescriptor*> (Bindable_t::GetObject (from));
if (ed)
ed->StopProxy();
}
/***************************
evma_get_heartbeat_interval
****************************/
extern "C" float evma_get_heartbeat_interval()
{
ensure_eventmachine("evma_get_heartbeat_interval");
return EventMachine->GetHeartbeatInterval();
}
/***************************
evma_set_heartbeat_interval
****************************/
extern "C" int evma_set_heartbeat_interval(float interval)
{
ensure_eventmachine("evma_set_heartbeat_interval");
return EventMachine->SetHeartbeatInterval(interval);
}

Some files were not shown because too many files have changed in this diff Show more