riser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
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: