riser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +926 -0
- data/Rakefile +31 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/halo.html +18 -0
- data/example/halo.rb +171 -0
- data/example/halo.yml +21 -0
- data/example/local_services.rb +60 -0
- data/example/multiproc_server.rb +21 -0
- data/example/simple_count.rb +52 -0
- data/example/simple_daemon.rb +22 -0
- data/example/simple_key_count.rb +65 -0
- data/example/simple_server.rb +20 -0
- data/example/simple_services.rb +60 -0
- data/example/simple_tls.rb +32 -0
- data/lib/riser/daemon.rb +579 -0
- data/lib/riser/poll.rb +35 -0
- data/lib/riser/resource.rb +386 -0
- data/lib/riser/server.rb +869 -0
- data/lib/riser/services.rb +631 -0
- data/lib/riser/stream.rb +115 -0
- data/lib/riser/temppath.rb +25 -0
- data/lib/riser/test.rb +42 -0
- data/lib/riser/version.rb +10 -0
- data/lib/riser.rb +28 -0
- data/riser.gemspec +35 -0
- metadata +129 -0
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rdoc/task'
|
7
|
+
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
Rake::TestTask.new do |task|
|
11
|
+
if ((ENV.key? 'RUBY_DEBUG') && (! ENV['RUBY_DEBUG'].empty?)) then
|
12
|
+
task.ruby_opts << '-d'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::RDocTask.new do |rd|
|
17
|
+
rd.rdoc_files.include('lib/**/*.rb')
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Build README.html from markdown source.'
|
21
|
+
task :readme => %w[ README.html ]
|
22
|
+
|
23
|
+
file 'README.html' => [ 'README.md' ] do
|
24
|
+
sh "pandoc --from=markdown --to=html5 --standalone --self-contained --css=$HOME/.pandoc/github.css --output=README.html README.md"
|
25
|
+
end
|
26
|
+
CLOBBER.include 'README.html'
|
27
|
+
|
28
|
+
# Local Variables:
|
29
|
+
# mode: Ruby
|
30
|
+
# indent-tabs-mode: nil
|
31
|
+
# End:
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "riser"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/example/halo.html
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta name="generator" content="pandoc">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
7
|
+
<title></title>
|
8
|
+
<style type="text/css">code{white-space: pre;}</style>
|
9
|
+
<link href="data:text/css;charset=utf-8,body%20%7B%0Afont%2Dfamily%3A%20Helvetica%2C%20arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E6%3B%0Apadding%2Dtop%3A%2010px%3B%0Apadding%2Dbottom%3A%2010px%3B%0Abackground%2Dcolor%3A%20white%3B%0Apadding%3A%2030px%3B%20%7D%0Abody%20%3E%20%2A%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%20%21important%3B%20%7D%0Abody%20%3E%20%2A%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%20%21important%3B%20%7D%0Aa%20%7B%0Acolor%3A%20%234183C4%3B%20%7D%0Aa%2Eabsent%20%7B%0Acolor%3A%20%23cc0000%3B%20%7D%0Aa%2Eanchor%20%7B%0Adisplay%3A%20block%3B%0Apadding%2Dleft%3A%2030px%3B%0Amargin%2Dleft%3A%20%2D30px%3B%0Acursor%3A%20pointer%3B%0Aposition%3A%20absolute%3B%0Atop%3A%200%3B%0Aleft%3A%200%3B%0Abottom%3A%200%3B%20%7D%0Ah1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%20%7B%0Amargin%3A%2020px%200%2010px%3B%0Apadding%3A%200%3B%0Afont%2Dweight%3A%20bold%3B%0A%2Dwebkit%2Dfont%2Dsmoothing%3A%20antialiased%3B%0Acursor%3A%20text%3B%0Aposition%3A%20relative%3B%20%7D%0Ah1%3Ahover%20a%2Eanchor%2C%20h2%3Ahover%20a%2Eanchor%2C%20h3%3Ahover%20a%2Eanchor%2C%20h4%3Ahover%20a%2Eanchor%2C%20h5%3Ahover%20a%2Eanchor%2C%20h6%3Ahover%20a%2Eanchor%20%7B%0Abackground%3A%20url%28data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw%2FeHBhY2tldCBiZWdpbj0i77u%2FIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8%2BIDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI%2FPsQhXeAAAABfSURBVHjaYvz%2F%2Fz8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg%3D%3D%29%20no%2Drepeat%2010px%20center%3B%0Atext%2Ddecoration%3A%20none%3B%20%7D%0Ah1%20tt%2C%20h1%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah2%20tt%2C%20h2%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah3%20tt%2C%20h3%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah4%20tt%2C%20h4%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah5%20tt%2C%20h5%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah6%20tt%2C%20h6%20code%20%7B%0Afont%2Dsize%3A%20inherit%3B%20%7D%0Ah1%20%7B%0Afont%2Dsize%3A%2028px%3B%0Acolor%3A%20black%3B%20%7D%0Ah2%20%7B%0Afont%2Dsize%3A%2024px%3B%0Aborder%2Dbottom%3A%201px%20solid%20%23cccccc%3B%0Acolor%3A%20black%3B%20%7D%0Ah3%20%7B%0Afont%2Dsize%3A%2018px%3B%20%7D%0Ah4%20%7B%0Afont%2Dsize%3A%2016px%3B%20%7D%0Ah5%20%7B%0Afont%2Dsize%3A%2014px%3B%20%7D%0Ah6%20%7B%0Acolor%3A%20%23777777%3B%0Afont%2Dsize%3A%2014px%3B%20%7D%0Ap%2C%20blockquote%2C%20ul%2C%20ol%2C%20dl%2C%20li%2C%20table%2C%20pre%20%7B%0Amargin%3A%2015px%200%3B%20%7D%0Ahr%20%7B%0Abackground%3A%20transparent%20url%28data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw%2FeHBhY2tldCBiZWdpbj0i77u%2FIiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8%2BIDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI%2FPqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC%29%20repeat%2Dx%200%200%3B%0Aborder%3A%200%20none%3B%0Acolor%3A%20%23cccccc%3B%0Aheight%3A%204px%3B%0Apadding%3A%200%3B%20%7D%0Abody%20%3E%20h2%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%0Apadding%2Dtop%3A%200%3B%20%7D%0Abody%20%3E%20h1%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%0Apadding%2Dtop%3A%200%3B%20%7D%0Abody%20%3E%20h1%3Afirst%2Dchild%20%2B%20h2%20%7B%0Amargin%2Dtop%3A%200%3B%0Apadding%2Dtop%3A%200%3B%20%7D%0Abody%20%3E%20h3%3Afirst%2Dchild%2C%20body%20%3E%20h4%3Afirst%2Dchild%2C%20body%20%3E%20h5%3Afirst%2Dchild%2C%20body%20%3E%20h6%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%0Apadding%2Dtop%3A%200%3B%20%7D%0Aa%3Afirst%2Dchild%20h1%2C%20a%3Afirst%2Dchild%20h2%2C%20a%3Afirst%2Dchild%20h3%2C%20a%3Afirst%2Dchild%20h4%2C%20a%3Afirst%2Dchild%20h5%2C%20a%3Afirst%2Dchild%20h6%20%7B%0Amargin%2Dtop%3A%200%3B%0Apadding%2Dtop%3A%200%3B%20%7D%0Ah1%20p%2C%20h2%20p%2C%20h3%20p%2C%20h4%20p%2C%20h5%20p%2C%20h6%20p%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Ali%20p%2Efirst%20%7B%0Adisplay%3A%20inline%2Dblock%3B%20%7D%0Aul%2C%20ol%20%7B%0Apadding%2Dleft%3A%2030px%3B%20%7D%0Aul%20%3Afirst%2Dchild%2C%20ol%20%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Aul%20%3Alast%2Dchild%2C%20ol%20%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%20%7D%0Adl%20%7B%0Apadding%3A%200%3B%20%7D%0Adl%20dt%20%7B%0Afont%2Dsize%3A%2014px%3B%0Afont%2Dweight%3A%20bold%3B%0Afont%2Dstyle%3A%20italic%3B%0Apadding%3A%200%3B%0Amargin%3A%2015px%200%205px%3B%20%7D%0Adl%20dt%3Afirst%2Dchild%20%7B%0Apadding%3A%200%3B%20%7D%0Adl%20dt%20%3E%20%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Adl%20dt%20%3E%20%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%20%7D%0Adl%20dd%20%7B%0Amargin%3A%200%200%2015px%3B%0Apadding%3A%200%2015px%3B%20%7D%0Adl%20dd%20%3E%20%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Adl%20dd%20%3E%20%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%20%7D%0Ablockquote%20%7B%0Aborder%2Dleft%3A%204px%20solid%20%23dddddd%3B%0Apadding%3A%200%2015px%3B%0Acolor%3A%20%23777777%3B%20%7D%0Ablockquote%20%3E%20%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Ablockquote%20%3E%20%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%20%7D%0Atable%20%7B%0Apadding%3A%200%3B%20%7D%0Atable%20tr%20%7B%0Aborder%2Dtop%3A%201px%20solid%20%23cccccc%3B%0Abackground%2Dcolor%3A%20white%3B%0Amargin%3A%200%3B%0Apadding%3A%200%3B%20%7D%0Atable%20tr%3Anth%2Dchild%282n%29%20%7B%0Abackground%2Dcolor%3A%20%23f8f8f8%3B%20%7D%0Atable%20tr%20th%20%7B%0Afont%2Dweight%3A%20bold%3B%0Aborder%3A%201px%20solid%20%23cccccc%3B%0Atext%2Dalign%3A%20left%3B%0Amargin%3A%200%3B%0Apadding%3A%206px%2013px%3B%20%7D%0Atable%20tr%20td%20%7B%0Aborder%3A%201px%20solid%20%23cccccc%3B%0Atext%2Dalign%3A%20left%3B%0Amargin%3A%200%3B%0Apadding%3A%206px%2013px%3B%20%7D%0Atable%20tr%20th%20%3Afirst%2Dchild%2C%20table%20tr%20td%20%3Afirst%2Dchild%20%7B%0Amargin%2Dtop%3A%200%3B%20%7D%0Atable%20tr%20th%20%3Alast%2Dchild%2C%20table%20tr%20td%20%3Alast%2Dchild%20%7B%0Amargin%2Dbottom%3A%200%3B%20%7D%0Aimg%20%7B%0Amax%2Dwidth%3A%20100%25%3B%20%7D%0Aspan%2Eframe%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%20%7D%0Aspan%2Eframe%20%3E%20span%20%7B%0Aborder%3A%201px%20solid%20%23dddddd%3B%0Adisplay%3A%20block%3B%0Afloat%3A%20left%3B%0Aoverflow%3A%20hidden%3B%0Amargin%3A%2013px%200%200%3B%0Apadding%3A%207px%3B%0Awidth%3A%20auto%3B%20%7D%0Aspan%2Eframe%20span%20img%20%7B%0Adisplay%3A%20block%3B%0Afloat%3A%20left%3B%20%7D%0Aspan%2Eframe%20span%20span%20%7B%0Aclear%3A%20both%3B%0Acolor%3A%20%23333333%3B%0Adisplay%3A%20block%3B%0Apadding%3A%205px%200%200%3B%20%7D%0Aspan%2Ealign%2Dcenter%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Aclear%3A%20both%3B%20%7D%0Aspan%2Ealign%2Dcenter%20%3E%20span%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Amargin%3A%2013px%20auto%200%3B%0Atext%2Dalign%3A%20center%3B%20%7D%0Aspan%2Ealign%2Dcenter%20span%20img%20%7B%0Amargin%3A%200%20auto%3B%0Atext%2Dalign%3A%20center%3B%20%7D%0Aspan%2Ealign%2Dright%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Aclear%3A%20both%3B%20%7D%0Aspan%2Ealign%2Dright%20%3E%20span%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Amargin%3A%2013px%200%200%3B%0Atext%2Dalign%3A%20right%3B%20%7D%0Aspan%2Ealign%2Dright%20span%20img%20%7B%0Amargin%3A%200%3B%0Atext%2Dalign%3A%20right%3B%20%7D%0Aspan%2Efloat%2Dleft%20%7B%0Adisplay%3A%20block%3B%0Amargin%2Dright%3A%2013px%3B%0Aoverflow%3A%20hidden%3B%0Afloat%3A%20left%3B%20%7D%0Aspan%2Efloat%2Dleft%20span%20%7B%0Amargin%3A%2013px%200%200%3B%20%7D%0Aspan%2Efloat%2Dright%20%7B%0Adisplay%3A%20block%3B%0Amargin%2Dleft%3A%2013px%3B%0Aoverflow%3A%20hidden%3B%0Afloat%3A%20right%3B%20%7D%0Aspan%2Efloat%2Dright%20%3E%20span%20%7B%0Adisplay%3A%20block%3B%0Aoverflow%3A%20hidden%3B%0Amargin%3A%2013px%20auto%200%3B%0Atext%2Dalign%3A%20right%3B%20%7D%0Acode%2C%20tt%20%7B%0Amargin%3A%200%202px%3B%0Apadding%3A%200%205px%3B%0Awhite%2Dspace%3A%20nowrap%3B%0Aborder%3A%201px%20solid%20%23eaeaea%3B%0Abackground%2Dcolor%3A%20%23f8f8f8%3B%0Aborder%2Dradius%3A%203px%3B%20%7D%0Apre%20code%20%7B%0Amargin%3A%200%3B%0Apadding%3A%200%3B%0Awhite%2Dspace%3A%20pre%3B%0Aborder%3A%20none%3B%0Abackground%3A%20transparent%3B%20%7D%0A%2Ehighlight%20pre%20%7B%0Abackground%2Dcolor%3A%20%23f8f8f8%3B%0Aborder%3A%201px%20solid%20%23cccccc%3B%0Afont%2Dsize%3A%2013px%3B%0Aline%2Dheight%3A%2019px%3B%0Aoverflow%3A%20auto%3B%0Apadding%3A%206px%2010px%3B%0Aborder%2Dradius%3A%203px%3B%20%7D%0Apre%20%7B%0Abackground%2Dcolor%3A%20%23f8f8f8%3B%0Aborder%3A%201px%20solid%20%23cccccc%3B%0Afont%2Dsize%3A%2013px%3B%0Aline%2Dheight%3A%2019px%3B%0Aoverflow%3A%20auto%3B%0Apadding%3A%206px%2010px%3B%0Aborder%2Dradius%3A%203px%3B%20%7D%0Apre%20code%2C%20pre%20tt%20%7B%0Abackground%2Dcolor%3A%20transparent%3B%0Aborder%3A%20none%3B%20%7D%0A" rel="stylesheet">
|
10
|
+
<!--[if lt IE 9]>
|
11
|
+
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
12
|
+
<![endif]-->
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
<h1 id="halo">HALO</h1>
|
16
|
+
<p>This is example.</p>
|
17
|
+
</body>
|
18
|
+
</html>
|
data/example/halo.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
require 'optparse'
|
6
|
+
require 'pp'
|
7
|
+
require 'riser'
|
8
|
+
require 'time'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
class ConnectionLimits
|
12
|
+
def initialize(request_max_count, request_timeout_seconds)
|
13
|
+
@mutex = Thread::Mutex.new
|
14
|
+
self.request_max_count = request_max_count
|
15
|
+
self.request_timeout_seconds = request_timeout_seconds
|
16
|
+
end
|
17
|
+
|
18
|
+
def request_max_count
|
19
|
+
@mutex.synchronize{ @request_max_count }
|
20
|
+
end
|
21
|
+
|
22
|
+
def request_max_count=(value)
|
23
|
+
@mutex.synchronize{ @request_max_count = value }
|
24
|
+
end
|
25
|
+
|
26
|
+
def request_timeout_seconds
|
27
|
+
@mutex.synchronize{ @request_timeout_seconds }
|
28
|
+
end
|
29
|
+
|
30
|
+
def request_timeout_seconds=(value)
|
31
|
+
@mutex.synchronize{ @request_timeout_seconds = value }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
options = {
|
36
|
+
daemonize: false,
|
37
|
+
debug: false
|
38
|
+
}
|
39
|
+
|
40
|
+
OptionParser.new{|opts|
|
41
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
42
|
+
opts.on('-d', '--[no-]daemonize', 'Run as daemon') do |value|
|
43
|
+
options[:daemonize] = value
|
44
|
+
end
|
45
|
+
opts.on('-g', '--[no-]debug', 'Run debug') do |value|
|
46
|
+
options[:debug] = value
|
47
|
+
end
|
48
|
+
}.parse!
|
49
|
+
|
50
|
+
name = File.basename($0, '.rb')
|
51
|
+
HALO = IO.read(File.join(File.dirname($0), "#{name}.html"))
|
52
|
+
server_log = File.join(File.dirname($0), "#{name}.log")
|
53
|
+
protocol_log = File.join(File.dirname($0), 'protocol.log')
|
54
|
+
status_file = File.join(File.dirname($0), "#{name}.pid")
|
55
|
+
config_path = File.join(File.dirname($0), "#{name}.yml")
|
56
|
+
|
57
|
+
config = YAML.load_file(config_path)['daemon']
|
58
|
+
|
59
|
+
Riser::Daemon.start_daemon(daemonize: options[:daemonize],
|
60
|
+
daemon_name: name,
|
61
|
+
daemon_debug: options[:debug],
|
62
|
+
status_file: status_file,
|
63
|
+
listen_address: proc{
|
64
|
+
# to reload on server restart
|
65
|
+
YAML.load_file(config_path).dig('server', 'server_listen')
|
66
|
+
},
|
67
|
+
server_polling_interval_seconds: config['server_polling_interval_seconds'],
|
68
|
+
server_restart_overlap_seconds: config['server_restart_overlap_seconds'],
|
69
|
+
server_privileged_user: config['server_privileged_user'],
|
70
|
+
server_privileged_group: config['server_privileged_group']
|
71
|
+
) {|server|
|
72
|
+
|
73
|
+
c = YAML.load_file(config_path)['server']
|
74
|
+
|
75
|
+
logger = Logger.new(server_log)
|
76
|
+
logger.level = c['server_log_level']
|
77
|
+
p_logger = Logger.new(protocol_log)
|
78
|
+
p_logger.level = c['protocol_log_level']
|
79
|
+
|
80
|
+
server.accept_polling_timeout_seconds = c['accept_polling_timeout_seconds']
|
81
|
+
server.process_num = c['process_num']
|
82
|
+
server.process_queue_size = c['process_queue_size']
|
83
|
+
server.process_queue_polling_timeout_seconds = c['process_queue_polling_timeout_seconds']
|
84
|
+
server.process_send_io_polling_timeout_seconds = c['process_send_io_polling_timeout_seconds']
|
85
|
+
server.thread_num = c['thread_num']
|
86
|
+
server.thread_queue_size = c['thread_queue_size']
|
87
|
+
server.thread_queue_polling_timeout_seconds = c['thread_queue_polling_timeout_seconds']
|
88
|
+
|
89
|
+
server.before_start{|socket|
|
90
|
+
logger.info("start HTTP server: listen #{socket.local_address.inspect_sockaddr}")
|
91
|
+
}
|
92
|
+
server.after_stop{
|
93
|
+
logger.info('stop server')
|
94
|
+
}
|
95
|
+
server.at_stat{|info|
|
96
|
+
logger.info("stat: #{info.pretty_inspect}")
|
97
|
+
}
|
98
|
+
|
99
|
+
conn_limits = ConnectionLimits.new(c['request_max_count'], c['request_timeout_seconds'])
|
100
|
+
server.at_stop{|state|
|
101
|
+
logger.info("at stop: #{state}")
|
102
|
+
conn_limits.request_max_count = 1
|
103
|
+
conn_limits.request_timeout_seconds = 0
|
104
|
+
}
|
105
|
+
|
106
|
+
server.at_fork{ logger.info('at fork') }
|
107
|
+
server.preprocess{ logger.info('preprocess') }
|
108
|
+
server.postprocess{ logger.info('postprocess') }
|
109
|
+
|
110
|
+
server.dispatch{|socket|
|
111
|
+
begin
|
112
|
+
read_poll = Riser::ReadPoll.new(socket)
|
113
|
+
stream = Riser::WriteBufferStream.new(socket)
|
114
|
+
stream = Riser::LoggingStream.new(stream, p_logger)
|
115
|
+
|
116
|
+
logger.info("connect from #{socket.remote_address.inspect_sockaddr}")
|
117
|
+
catch(:end_of_connection) {
|
118
|
+
count = 0
|
119
|
+
while (count < conn_limits.request_max_count)
|
120
|
+
count += 1
|
121
|
+
|
122
|
+
until (read_poll.call(1))
|
123
|
+
if (read_poll.interval_seconds >= conn_limits.request_timeout_seconds) then
|
124
|
+
throw(:end_of_connection)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
request_line = stream.gets or throw(:end_of_connection)
|
129
|
+
request_line =~ %r"\A (\S+) \s (\S+) \s (HTTP/\S+) \r\n \z"x or throw(:end_of_connection)
|
130
|
+
method, path, version = $1, $2, $3
|
131
|
+
while (line = stream.gets)
|
132
|
+
if (line == "\r\n") then
|
133
|
+
break
|
134
|
+
end
|
135
|
+
end
|
136
|
+
logger.info("#{method} #{path} #{version}")
|
137
|
+
|
138
|
+
begin
|
139
|
+
t = Time.now
|
140
|
+
case (method)
|
141
|
+
when 'GET', 'HEAD'
|
142
|
+
stream << "HTTP/1.0 200 OK\r\n"
|
143
|
+
stream << "Content-Type: text/html\r\n"
|
144
|
+
stream << "Content-Length: #{HALO.bytesize}\r\n"
|
145
|
+
stream << "Date: #{t.httpdate}\r\n"
|
146
|
+
stream << "\r\n"
|
147
|
+
stream << HALO if (method == 'GET')
|
148
|
+
else
|
149
|
+
stream << "HTTP/1.0 405 Method Not Allowed\r\n"
|
150
|
+
stream << "Content-Type: text/plain\r\n"
|
151
|
+
stream << "Date: #{t.httpdate}\r\n"
|
152
|
+
stream << "\r\n"
|
153
|
+
stream << "#{method} is not allowed.\r\n"
|
154
|
+
throw(:end_of_connection)
|
155
|
+
end
|
156
|
+
ensure
|
157
|
+
stream.flush
|
158
|
+
end
|
159
|
+
end
|
160
|
+
}
|
161
|
+
stream.close
|
162
|
+
rescue
|
163
|
+
logger.error($!)
|
164
|
+
end
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
# Local Variables:
|
169
|
+
# mode: Ruby
|
170
|
+
# indent-tabs-mode: nil
|
171
|
+
# End:
|
data/example/halo.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
daemon:
|
2
|
+
# parameters that will not be reloaded on server restart
|
3
|
+
server_polling_interval_seconds: 3
|
4
|
+
server_restart_overlap_seconds: 0
|
5
|
+
#server_privileged_user: nobody
|
6
|
+
#server_privileged_group: nogroup
|
7
|
+
server:
|
8
|
+
# parameters that will be reloaded on server restart
|
9
|
+
server_listen: localhost:8080
|
10
|
+
server_log_level: info
|
11
|
+
protocol_log_level: info
|
12
|
+
accept_polling_timeout_seconds: 0.1
|
13
|
+
process_num: 4
|
14
|
+
process_queue_size: 20
|
15
|
+
process_queue_polling_timeout_seconds: 0.1
|
16
|
+
process_send_io_polling_timeout_seconds: 0.1
|
17
|
+
thread_num: 4
|
18
|
+
thread_queue_size: 20
|
19
|
+
thread_queue_polling_timeout_seconds: 0.1
|
20
|
+
request_max_count: 100
|
21
|
+
request_timeout_seconds: 10
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'riser'
|
5
|
+
|
6
|
+
Riser::Daemon.start_daemon(daemonize: false,
|
7
|
+
daemon_name: 'local_services',
|
8
|
+
listen_address: 'localhost:8000'
|
9
|
+
) {|server|
|
10
|
+
|
11
|
+
services = Riser::DRbServices.new(0)
|
12
|
+
services.add_any_process_service(:pid_any, proc{ $$ })
|
13
|
+
services.add_single_process_service(:pid_single, proc{ $$ })
|
14
|
+
services.add_sticky_process_service(:pid_stickty, proc{|key| $$ })
|
15
|
+
|
16
|
+
server.process_num = 0
|
17
|
+
server.before_start{|server_socket|
|
18
|
+
services.start_server
|
19
|
+
}
|
20
|
+
server.at_fork{
|
21
|
+
services.detach_server
|
22
|
+
}
|
23
|
+
server.preprocess{
|
24
|
+
services.start_client
|
25
|
+
}
|
26
|
+
server.dispatch{|socket|
|
27
|
+
if (line = socket.gets) then
|
28
|
+
method, uri, _version = line.split
|
29
|
+
while (line = socket.gets)
|
30
|
+
line.strip.empty? and break
|
31
|
+
end
|
32
|
+
if (method == 'GET') then
|
33
|
+
socket << "HTTP/1.0 200 OK\r\n"
|
34
|
+
socket << "Content-Type: text/plain\r\n"
|
35
|
+
socket << "\r\n"
|
36
|
+
|
37
|
+
path, query = uri.split('?', 2)
|
38
|
+
case (path)
|
39
|
+
when '/any'
|
40
|
+
socket << 'pid: ' << services.call_service(:pid_any) << "\n"
|
41
|
+
when '/single'
|
42
|
+
socket << 'pid: ' << services.call_service(:pid_single) << "\n"
|
43
|
+
when '/sticky'
|
44
|
+
key = query || 'default'
|
45
|
+
socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
|
46
|
+
else
|
47
|
+
socket << "unknown path: #{path}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
}
|
52
|
+
server.after_stop{
|
53
|
+
services.stop_server
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
# Local Variables:
|
58
|
+
# mode: Ruby
|
59
|
+
# indent-tabs-mode: nil
|
60
|
+
# End:
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'riser'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
server = Riser::SocketServer.new
|
8
|
+
server.process_num = 2
|
9
|
+
server.dispatch{|socket|
|
10
|
+
while (line = socket.gets)
|
11
|
+
socket.write(line)
|
12
|
+
end
|
13
|
+
}
|
14
|
+
|
15
|
+
server_socket = TCPServer.new('localhost', 5000)
|
16
|
+
server.start(server_socket)
|
17
|
+
|
18
|
+
# Local Variables:
|
19
|
+
# mode: Ruby
|
20
|
+
# indent-tabs-mode: nil
|
21
|
+
# End:
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'pstore'
|
5
|
+
require 'riser'
|
6
|
+
|
7
|
+
Riser::Daemon.start_daemon(daemonize: false,
|
8
|
+
daemon_name: 'simple_count',
|
9
|
+
listen_address: 'localhost:8000'
|
10
|
+
) {|server|
|
11
|
+
|
12
|
+
services = Riser::DRbServices.new(1)
|
13
|
+
services.add_single_process_service(:pstore, PStore.new('simple_count.pstore', true))
|
14
|
+
|
15
|
+
server.process_num = 2
|
16
|
+
server.before_start{|server_socket|
|
17
|
+
services.start_server
|
18
|
+
}
|
19
|
+
server.at_fork{
|
20
|
+
services.detach_server
|
21
|
+
}
|
22
|
+
server.preprocess{
|
23
|
+
services.start_client
|
24
|
+
}
|
25
|
+
server.dispatch{|socket|
|
26
|
+
if (line = socket.gets) then
|
27
|
+
method, _uri, _version = line.split
|
28
|
+
while (line = socket.gets)
|
29
|
+
line.strip.empty? and break
|
30
|
+
end
|
31
|
+
if (method == 'GET') then
|
32
|
+
socket << "HTTP/1.0 200 OK\r\n"
|
33
|
+
socket << "Content-Type: text/plain\r\n"
|
34
|
+
socket << "\r\n"
|
35
|
+
|
36
|
+
services.get_service(:pstore).transaction do |pstore|
|
37
|
+
pstore[:count] ||= 0
|
38
|
+
pstore[:count] += 1
|
39
|
+
socket << 'count: ' << pstore[:count] << "\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
}
|
44
|
+
server.after_stop{
|
45
|
+
services.stop_server
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
# Local Variables:
|
50
|
+
# mode: Ruby
|
51
|
+
# indent-tabs-mode: nil
|
52
|
+
# End:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'riser'
|
5
|
+
|
6
|
+
Riser::Daemon.start_daemon(daemonize: true,
|
7
|
+
daemon_name: 'simple_daemon',
|
8
|
+
status_file: 'simple_daemon.pid',
|
9
|
+
listen_address: 'localhost:5000'
|
10
|
+
) {|server|
|
11
|
+
|
12
|
+
server.dispatch{|socket|
|
13
|
+
while (line = socket.gets)
|
14
|
+
socket.write(line)
|
15
|
+
end
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
# Local Variables:
|
20
|
+
# mode: Ruby
|
21
|
+
# indent-tabs-mode: nil
|
22
|
+
# End:
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'pstore'
|
5
|
+
require 'riser'
|
6
|
+
|
7
|
+
Riser::Daemon.start_daemon(daemonize: false,
|
8
|
+
daemon_name: 'simple_key_count',
|
9
|
+
listen_address: 'localhost:8000'
|
10
|
+
) {|server|
|
11
|
+
|
12
|
+
services = Riser::DRbServices.new(4)
|
13
|
+
services.add_sticky_process_service(:pstore,
|
14
|
+
Riser::ResourceSet.build{|builder|
|
15
|
+
builder.at_create{|key|
|
16
|
+
PStore.new("simple_key_count-#{key}.pstore", true)
|
17
|
+
}
|
18
|
+
builder.at_destroy{
|
19
|
+
# nothing to do.
|
20
|
+
}
|
21
|
+
})
|
22
|
+
|
23
|
+
server.process_num = 2
|
24
|
+
server.before_start{|server_socket|
|
25
|
+
services.start_server
|
26
|
+
}
|
27
|
+
server.at_fork{
|
28
|
+
services.detach_server
|
29
|
+
}
|
30
|
+
server.preprocess{
|
31
|
+
services.start_client
|
32
|
+
}
|
33
|
+
server.dispatch{|socket|
|
34
|
+
if (line = socket.gets) then
|
35
|
+
method, uri, _version = line.split
|
36
|
+
while (line = socket.gets)
|
37
|
+
line.strip.empty? and break
|
38
|
+
end
|
39
|
+
if (method == 'GET') then
|
40
|
+
socket << "HTTP/1.0 200 OK\r\n"
|
41
|
+
socket << "Content-Type: text/plain\r\n"
|
42
|
+
socket << "\r\n"
|
43
|
+
|
44
|
+
_path, query = uri.split('?', 2)
|
45
|
+
key = query || 'default'
|
46
|
+
services.call_service(:pstore, key) {|pstore|
|
47
|
+
pstore.transaction do
|
48
|
+
pstore[:count] ||= 0
|
49
|
+
pstore[:count] += 1
|
50
|
+
socket << 'key: ' << key << "\n"
|
51
|
+
socket << 'count: ' << pstore[:count] << "\n"
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
}
|
57
|
+
server.after_stop{
|
58
|
+
services.stop_server
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
# Local Variables:
|
63
|
+
# mode: Ruby
|
64
|
+
# indent-tabs-mode: nil
|
65
|
+
# End:
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'riser'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
server = Riser::SocketServer.new
|
8
|
+
server.dispatch{|socket|
|
9
|
+
while (line = socket.gets)
|
10
|
+
socket.write(line)
|
11
|
+
end
|
12
|
+
}
|
13
|
+
|
14
|
+
server_socket = TCPServer.new('localhost', 5000)
|
15
|
+
server.start(server_socket)
|
16
|
+
|
17
|
+
# Local Variables:
|
18
|
+
# mode: Ruby
|
19
|
+
# indent-tabs-mode: nil
|
20
|
+
# End:
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'riser'
|
5
|
+
|
6
|
+
Riser::Daemon.start_daemon(daemonize: false,
|
7
|
+
daemon_name: 'simple_services',
|
8
|
+
listen_address: 'localhost:8000'
|
9
|
+
) {|server|
|
10
|
+
|
11
|
+
services = Riser::DRbServices.new(4)
|
12
|
+
services.add_any_process_service(:pid_any, proc{ $$ })
|
13
|
+
services.add_single_process_service(:pid_single, proc{ $$ })
|
14
|
+
services.add_sticky_process_service(:pid_stickty, proc{|key| $$ })
|
15
|
+
|
16
|
+
server.process_num = 2
|
17
|
+
server.before_start{|server_socket|
|
18
|
+
services.start_server
|
19
|
+
}
|
20
|
+
server.at_fork{
|
21
|
+
services.detach_server
|
22
|
+
}
|
23
|
+
server.preprocess{
|
24
|
+
services.start_client
|
25
|
+
}
|
26
|
+
server.dispatch{|socket|
|
27
|
+
if (line = socket.gets) then
|
28
|
+
method, uri, _version = line.split
|
29
|
+
while (line = socket.gets)
|
30
|
+
line.strip.empty? and break
|
31
|
+
end
|
32
|
+
if (method == 'GET') then
|
33
|
+
socket << "HTTP/1.0 200 OK\r\n"
|
34
|
+
socket << "Content-Type: text/plain\r\n"
|
35
|
+
socket << "\r\n"
|
36
|
+
|
37
|
+
path, query = uri.split('?', 2)
|
38
|
+
case (path)
|
39
|
+
when '/any'
|
40
|
+
socket << 'pid: ' << services.call_service(:pid_any) << "\n"
|
41
|
+
when '/single'
|
42
|
+
socket << 'pid: ' << services.call_service(:pid_single) << "\n"
|
43
|
+
when '/sticky'
|
44
|
+
key = query || 'default'
|
45
|
+
socket << 'key: ' << key << ', pid: ' << services.call_service(:pid_stickty, key) << "\n"
|
46
|
+
else
|
47
|
+
socket << "unknown path: #{path}\n"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
}
|
52
|
+
server.after_stop{
|
53
|
+
services.stop_server
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
# Local Variables:
|
58
|
+
# mode: Ruby
|
59
|
+
# indent-tabs-mode: nil
|
60
|
+
# End:
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
require 'openssl'
|
5
|
+
require 'riser'
|
6
|
+
|
7
|
+
cert_path = ARGV.shift or abort('need for server certificate file')
|
8
|
+
pkey_path = ARGV.shift or abort('need for server private key file')
|
9
|
+
|
10
|
+
Riser::Daemon.start_daemon(daemonize: false,
|
11
|
+
daemon_name: 'simple_tls',
|
12
|
+
listen_address: 'localhost:5000'
|
13
|
+
) {|server|
|
14
|
+
|
15
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
16
|
+
ssl_context.cert = OpenSSL::X509::Certificate.new(File.read(cert_path))
|
17
|
+
ssl_context.key = OpenSSL::PKey::RSA.new(File.read(pkey_path))
|
18
|
+
|
19
|
+
server.dispatch{|socket|
|
20
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
|
21
|
+
ssl_socket.accept
|
22
|
+
while (line = ssl_socket.gets)
|
23
|
+
ssl_socket.write(line)
|
24
|
+
end
|
25
|
+
ssl_socket.close
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
# Local Variables:
|
30
|
+
# mode: Ruby
|
31
|
+
# indent-tabs-mode: nil
|
32
|
+
# End:
|