crampy 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/bin/cramp +17 -0
- data/lib/cramp/abstract.rb +104 -0
- data/lib/cramp/action.rb +134 -0
- data/lib/cramp/body.rb +48 -0
- data/lib/cramp/callbacks.rb +92 -0
- data/lib/cramp/exception_handler.rb +357 -0
- data/lib/cramp/fiber_pool.rb +47 -0
- data/lib/cramp/generators/application.rb +97 -0
- data/lib/cramp/generators/templates/application/Gemfile +32 -0
- data/lib/cramp/generators/templates/application/app/actions/home_action.rb +11 -0
- data/lib/cramp/generators/templates/application/application.rb +36 -0
- data/lib/cramp/generators/templates/application/config/database.yml +6 -0
- data/lib/cramp/generators/templates/application/config/routes.rb +4 -0
- data/lib/cramp/generators/templates/application/config.ru +25 -0
- data/lib/cramp/keep_connection_alive.rb +19 -0
- data/lib/cramp/long_polling.rb +6 -0
- data/lib/cramp/periodic_timer.rb +56 -0
- data/lib/cramp/rendering.rb +11 -0
- data/lib/cramp/sse.rb +5 -0
- data/lib/cramp/test_case.rb +58 -0
- data/lib/cramp/version.rb +3 -0
- data/lib/cramp/websocket.rb +13 -0
- data/lib/cramp.rb +47 -0
- data/lib/crampy.rb +4 -0
- data/lib/vendor/fiber_pool.rb +85 -0
- metadata +130 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
module Cramp
|
2
|
+
module PeriodicTimer
|
3
|
+
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
# was class_inheritable_accessor
|
8
|
+
class_attribute :periodic_timers, :instance_reader => false
|
9
|
+
self.periodic_timers ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def periodic_timer(method, options = {})
|
14
|
+
self.periodic_timers << [method, options]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(*)
|
19
|
+
super
|
20
|
+
@timers = []
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def continue
|
26
|
+
super
|
27
|
+
start_periodic_timers
|
28
|
+
end
|
29
|
+
|
30
|
+
def init_async_body
|
31
|
+
super
|
32
|
+
|
33
|
+
if self.class.periodic_timers.any?
|
34
|
+
@body.callback { stop_periodic_timers }
|
35
|
+
@body.errback { stop_periodic_timers }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def start_periodic_timers
|
40
|
+
self.class.periodic_timers.each do |method, options|
|
41
|
+
@timers << EventMachine::PeriodicTimer.new(options[:every] || 1) { timer_method_wrapper(method) unless @finished }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def stop_periodic_timers
|
46
|
+
@timers.each {|t| t.cancel }
|
47
|
+
end
|
48
|
+
|
49
|
+
def timer_method_wrapper(method)
|
50
|
+
send(method)
|
51
|
+
rescue StandardError, LoadError, SyntaxError => exception
|
52
|
+
handle_exception(exception)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
data/lib/cramp/sse.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_support/test_case'
|
3
|
+
|
4
|
+
module Cramp
|
5
|
+
class TestCase < ::ActiveSupport::TestCase
|
6
|
+
|
7
|
+
setup :create_request
|
8
|
+
|
9
|
+
def create_request
|
10
|
+
@request = Rack::MockRequest.new(app)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(path, options = {}, headers = {}, &block)
|
14
|
+
callback = options.delete(:callback) || block
|
15
|
+
headers = headers.merge('async.callback' => callback)
|
16
|
+
|
17
|
+
EM.run do
|
18
|
+
catch(:async) { @request.get(path, headers) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_body(path, options = {}, headers = {}, &block)
|
23
|
+
callback = options.delete(:callback) || block
|
24
|
+
response_callback = proc {|response| response[-1].each {|chunk| callback.call(chunk) } }
|
25
|
+
headers = headers.merge('async.callback' => response_callback)
|
26
|
+
|
27
|
+
EM.run do
|
28
|
+
catch(:async) { @request.get(path, headers) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_body_chunks(path, options = {}, headers = {}, &block)
|
33
|
+
callback = options.delete(:callback) || block
|
34
|
+
count = options.delete(:count) || 1
|
35
|
+
|
36
|
+
stopping = false
|
37
|
+
chunks = []
|
38
|
+
|
39
|
+
get_body(path, options, headers) do |body_chunk|
|
40
|
+
chunks << body_chunk unless stopping
|
41
|
+
|
42
|
+
if chunks.count >= count
|
43
|
+
stopping = true
|
44
|
+
callback.call(chunks) if callback
|
45
|
+
EM.next_tick { EM.stop }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def app
|
51
|
+
raise "Please define a method called 'app' returning an async Rack Application"
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop
|
55
|
+
EM.stop
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Cramp
|
2
|
+
class Websocket < Action
|
3
|
+
self.transport = :websocket
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def backend=(backend)
|
7
|
+
raise "Websocket backend #{backend} is unknown" unless [:thin, :rainbows].include?(backend.to_sym)
|
8
|
+
Faye::WebSocket.load_adapter(backend.to_s)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
data/lib/cramp.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
# this shoud be called before reactor start, otherwise EM will silently ignore it
|
3
|
+
EM.epoll
|
4
|
+
|
5
|
+
require 'active_support'
|
6
|
+
require 'active_support/core_ext/class/attribute'
|
7
|
+
#require 'active_support/core_ext/class/inheritable_attributes'
|
8
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
9
|
+
require 'active_support/core_ext/module/aliasing'
|
10
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
11
|
+
require 'active_support/core_ext/kernel/reporting'
|
12
|
+
require 'active_support/concern'
|
13
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
14
|
+
require 'active_support/core_ext/hash/except'
|
15
|
+
require 'active_support/buffered_logger'
|
16
|
+
|
17
|
+
require 'rack'
|
18
|
+
require 'faye/websocket'
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'fiber'
|
22
|
+
require File.join(File.dirname(__FILE__), 'vendor/fiber_pool')
|
23
|
+
rescue LoadError
|
24
|
+
# No fibers available!
|
25
|
+
end
|
26
|
+
|
27
|
+
module Cramp
|
28
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
29
|
+
require "#{Cramp::ROOT}/cramp/version"
|
30
|
+
|
31
|
+
mattr_accessor :logger
|
32
|
+
|
33
|
+
autoload :Action, "cramp/action"
|
34
|
+
autoload :Websocket, "cramp/websocket"
|
35
|
+
autoload :WebsocketExtension, "cramp/websocket/extension"
|
36
|
+
autoload :Protocol10FrameParser, "cramp/websocket/protocol10_frame_parser"
|
37
|
+
autoload :SSE, "cramp/sse"
|
38
|
+
autoload :LongPolling, "cramp/long_polling"
|
39
|
+
autoload :Body, "cramp/body"
|
40
|
+
autoload :PeriodicTimer, "cramp/periodic_timer"
|
41
|
+
autoload :KeepConnectionAlive, "cramp/keep_connection_alive"
|
42
|
+
autoload :Abstract, "cramp/abstract"
|
43
|
+
autoload :Callbacks, "cramp/callbacks"
|
44
|
+
autoload :FiberPool, "cramp/fiber_pool"
|
45
|
+
autoload :ExceptionHandler, "cramp/exception_handler"
|
46
|
+
autoload :TestCase, "cramp/test_case"
|
47
|
+
end
|
data/lib/crampy.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
2
|
+
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
3
|
+
# License:: Distributes under the same terms as Ruby
|
4
|
+
|
5
|
+
require 'fiber'
|
6
|
+
|
7
|
+
class Fiber
|
8
|
+
|
9
|
+
#Attribute Reference--Returns the value of a fiber-local variable, using
|
10
|
+
#either a symbol or a string name. If the specified variable does not exist,
|
11
|
+
#returns nil.
|
12
|
+
def [](key)
|
13
|
+
local_fiber_variables[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
#Attribute Assignment--Sets or creates the value of a fiber-local variable,
|
17
|
+
#using either a symbol or a string. See also Fiber#[].
|
18
|
+
def []=(key,value)
|
19
|
+
local_fiber_variables[key] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def local_fiber_variables
|
25
|
+
@local_fiber_variables ||= {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class FiberPool
|
30
|
+
|
31
|
+
# gives access to the currently free fibers
|
32
|
+
attr_reader :fibers
|
33
|
+
attr_reader :busy_fibers
|
34
|
+
|
35
|
+
# Code can register a proc with this FiberPool to be called
|
36
|
+
# every time a Fiber is finished. Good for releasing resources
|
37
|
+
# like ActiveRecord database connections.
|
38
|
+
attr_accessor :generic_callbacks
|
39
|
+
|
40
|
+
# Prepare a list of fibers that are able to run different blocks of code
|
41
|
+
# every time. Once a fiber is done with its block, it attempts to fetch
|
42
|
+
# another one from the queue
|
43
|
+
def initialize(count = 100)
|
44
|
+
@fibers,@busy_fibers,@queue,@generic_callbacks = [],{},[],[]
|
45
|
+
count.times do |i|
|
46
|
+
fiber = Fiber.new do |block|
|
47
|
+
loop do
|
48
|
+
block.call
|
49
|
+
|
50
|
+
# callbacks are called in a reverse order, much like c++ destructor
|
51
|
+
Fiber.current[:callbacks].pop.call while Fiber.current[:callbacks].length > 0
|
52
|
+
generic_callbacks.each do |cb|
|
53
|
+
cb.call
|
54
|
+
end
|
55
|
+
|
56
|
+
if @queue.any?
|
57
|
+
block = @queue.shift
|
58
|
+
else
|
59
|
+
@busy_fibers.delete(Fiber.current.object_id)
|
60
|
+
@fibers.unshift Fiber.current
|
61
|
+
block = Fiber.yield
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
fiber[:callbacks] = []
|
67
|
+
fiber[:em_keys] = []
|
68
|
+
@fibers << fiber
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# If there is an available fiber use it, otherwise, leave it to linger
|
73
|
+
# in a queue
|
74
|
+
def spawn(&block)
|
75
|
+
if fiber = @fibers.shift
|
76
|
+
fiber[:callbacks] = []
|
77
|
+
@busy_fibers[fiber.object_id] = fiber
|
78
|
+
fiber.resume(block)
|
79
|
+
else
|
80
|
+
@queue << block
|
81
|
+
end
|
82
|
+
self # we are keen on hiding our queue
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crampy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.15.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pratik Naik
|
9
|
+
- Vasily Fedoseyev
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-06-12 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: &70186850572180 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.2'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70186850572180
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rack
|
28
|
+
requirement: &70186850570900 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70186850570900
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: eventmachine
|
39
|
+
requirement: &70186850569540 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.0.0.beta.3
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70186850569540
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: faye-websocket
|
50
|
+
requirement: &70186850567380 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0.3'
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *70186850567380
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: thor
|
61
|
+
requirement: &70186850565720 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ~>
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0.14'
|
67
|
+
type: :runtime
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *70186850565720
|
70
|
+
description: Crampy is a fork of Cramp, a framework for developing asynchronous web
|
71
|
+
applications.
|
72
|
+
email:
|
73
|
+
- vasilyfedoseyev@gmail.com
|
74
|
+
executables:
|
75
|
+
- cramp
|
76
|
+
extensions: []
|
77
|
+
extra_rdoc_files: []
|
78
|
+
files:
|
79
|
+
- MIT-LICENSE
|
80
|
+
- lib/cramp/abstract.rb
|
81
|
+
- lib/cramp/action.rb
|
82
|
+
- lib/cramp/body.rb
|
83
|
+
- lib/cramp/callbacks.rb
|
84
|
+
- lib/cramp/exception_handler.rb
|
85
|
+
- lib/cramp/fiber_pool.rb
|
86
|
+
- lib/cramp/generators/application.rb
|
87
|
+
- lib/cramp/generators/templates/application/app/actions/home_action.rb
|
88
|
+
- lib/cramp/generators/templates/application/application.rb
|
89
|
+
- lib/cramp/generators/templates/application/config/database.yml
|
90
|
+
- lib/cramp/generators/templates/application/config/routes.rb
|
91
|
+
- lib/cramp/generators/templates/application/config.ru
|
92
|
+
- lib/cramp/generators/templates/application/Gemfile
|
93
|
+
- lib/cramp/keep_connection_alive.rb
|
94
|
+
- lib/cramp/long_polling.rb
|
95
|
+
- lib/cramp/periodic_timer.rb
|
96
|
+
- lib/cramp/rendering.rb
|
97
|
+
- lib/cramp/sse.rb
|
98
|
+
- lib/cramp/test_case.rb
|
99
|
+
- lib/cramp/version.rb
|
100
|
+
- lib/cramp/websocket.rb
|
101
|
+
- lib/cramp.rb
|
102
|
+
- lib/crampy.rb
|
103
|
+
- lib/vendor/fiber_pool.rb
|
104
|
+
- bin/cramp
|
105
|
+
homepage: https://github.com/Vasfed/cramp
|
106
|
+
licenses: []
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.15
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Asynchronous web framework.
|
129
|
+
test_files: []
|
130
|
+
has_rdoc: false
|