eventbox 0.1.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.appveyor.yml +28 -0
- data/.gitignore +8 -0
- data/.travis.yml +16 -0
- data/.yardopts +9 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +381 -0
- data/Rakefile +14 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/docs/downloads.md +143 -0
- data/docs/server.md +88 -0
- data/docs/threadpool.md +73 -0
- data/eventbox.gemspec +31 -0
- data/lib/eventbox.rb +270 -0
- data/lib/eventbox/argument_wrapper.rb +76 -0
- data/lib/eventbox/boxable.rb +298 -0
- data/lib/eventbox/event_loop.rb +385 -0
- data/lib/eventbox/object_registry.rb +35 -0
- data/lib/eventbox/sanitizer.rb +342 -0
- data/lib/eventbox/thread_pool.rb +170 -0
- data/lib/eventbox/timer.rb +172 -0
- data/lib/eventbox/version.rb +5 -0
- metadata +156 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
class Eventbox
|
4
|
+
# Simple timer services for Eventboxes
|
5
|
+
#
|
6
|
+
# This module can be included into Eventbox classes to add simple timer functions.
|
7
|
+
#
|
8
|
+
# class MyBox < Eventbox
|
9
|
+
# include Eventbox::Timer
|
10
|
+
#
|
11
|
+
# async_call def init
|
12
|
+
# super # make sure Timer#init is called
|
13
|
+
# timer_after(1) do
|
14
|
+
# puts "one second elapsed"
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The main functions are timer_after and timer_every.
|
20
|
+
# They schedule asynchronous calls to the given block:
|
21
|
+
# timer_after(3) do
|
22
|
+
# # executed once after 3 seconds
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# timer_every(3) do
|
26
|
+
# # executed repeatedly every 3 seconds
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# Both functions return an Alarm object which can be used to cancel the alarm through timer_cancel.
|
30
|
+
#
|
31
|
+
# timer_after, timer_every and timer_cancel can be used within the event scope, in actions and from external scope.
|
32
|
+
#
|
33
|
+
# {Timer} always uses one action thread per Eventbox object, regardless of the number of scheduled timers.
|
34
|
+
module Timer
|
35
|
+
class Reload < RuntimeError
|
36
|
+
end
|
37
|
+
class InternalError < RuntimeError
|
38
|
+
end
|
39
|
+
|
40
|
+
class Alarm
|
41
|
+
# @private
|
42
|
+
def initialize(ts, &block)
|
43
|
+
@timestamp = ts
|
44
|
+
@block = block
|
45
|
+
end
|
46
|
+
|
47
|
+
# @private
|
48
|
+
attr_reader :timestamp
|
49
|
+
end
|
50
|
+
|
51
|
+
class OneTimeAlarm < Alarm
|
52
|
+
# @private
|
53
|
+
def fire_then_repeat?(now=Time.now)
|
54
|
+
@block.call
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class RepeatedAlarm < Alarm
|
60
|
+
# @private
|
61
|
+
def initialize(ts, every_seconds, &block)
|
62
|
+
super(ts, &block)
|
63
|
+
@every_seconds = every_seconds
|
64
|
+
end
|
65
|
+
|
66
|
+
# @private
|
67
|
+
def fire_then_repeat?(now=Time.now)
|
68
|
+
@block.call
|
69
|
+
@timestamp = now + @every_seconds
|
70
|
+
true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
extend Boxable
|
75
|
+
|
76
|
+
# @private
|
77
|
+
private async_call def init(*args)
|
78
|
+
super
|
79
|
+
@timer_alarms = []
|
80
|
+
@timer_action = timer_start_worker
|
81
|
+
end
|
82
|
+
|
83
|
+
# @private
|
84
|
+
private action def timer_start_worker
|
85
|
+
loop do
|
86
|
+
begin
|
87
|
+
interval = timer_next_timestamp&.-(Time.now)
|
88
|
+
Thread.handle_interrupt(Reload => :on_blocking) do
|
89
|
+
if interval.nil?
|
90
|
+
Kernel.sleep
|
91
|
+
elsif interval > 0.0
|
92
|
+
Kernel.sleep(interval)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
rescue Reload
|
96
|
+
else
|
97
|
+
timer_fire
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Schedule a one shot alarm
|
103
|
+
#
|
104
|
+
# Call the given block after half a second:
|
105
|
+
# timer_after(0.5) do
|
106
|
+
# # executed in 0.5 seconds
|
107
|
+
# end
|
108
|
+
sync_call def timer_after(seconds, now=Time.now, &block)
|
109
|
+
a = OneTimeAlarm.new(now + seconds, &block)
|
110
|
+
timer_add_alarm(a)
|
111
|
+
a
|
112
|
+
end
|
113
|
+
|
114
|
+
# Schedule a repeated alarm
|
115
|
+
#
|
116
|
+
# Call the given block in after half a second and then repeatedly every 0.5 seconds:
|
117
|
+
# timer_after(0.5) do
|
118
|
+
# # executed every 0.5 seconds
|
119
|
+
# end
|
120
|
+
sync_call def timer_every(seconds, now=Time.now, &block)
|
121
|
+
a = RepeatedAlarm.new(now + seconds, seconds, &block)
|
122
|
+
timer_add_alarm(a)
|
123
|
+
a
|
124
|
+
end
|
125
|
+
|
126
|
+
# Cancel an alarm previously scheduled per timer_after or timer_every
|
127
|
+
async_call def timer_cancel(alarm)
|
128
|
+
a = @timer_alarms.delete(alarm)
|
129
|
+
if a
|
130
|
+
timer_check_integrity
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @private
|
135
|
+
private def timer_add_alarm(alarm)
|
136
|
+
i = @timer_alarms.bsearch_index {|t| t.timestamp <= alarm.timestamp }
|
137
|
+
if i
|
138
|
+
@timer_alarms[i, 0] = alarm
|
139
|
+
else
|
140
|
+
@timer_alarms << alarm
|
141
|
+
@timer_action.raise(Reload) unless @timer_action.current?
|
142
|
+
end
|
143
|
+
timer_check_integrity
|
144
|
+
end
|
145
|
+
|
146
|
+
# @private
|
147
|
+
private def timer_check_integrity
|
148
|
+
@timer_alarms.inject(nil) do |min, a|
|
149
|
+
raise InternalError, "alarms are not ordered: #{@timer_alarms.inspect}" if min && min < a.timestamp
|
150
|
+
a.timestamp
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# @private
|
155
|
+
private sync_call def timer_next_timestamp
|
156
|
+
@timer_alarms.last&.timestamp
|
157
|
+
end
|
158
|
+
|
159
|
+
# @private
|
160
|
+
private sync_call def timer_fire(now=Time.now)
|
161
|
+
while @timer_alarms.last&.timestamp&.<=(now)
|
162
|
+
a = @timer_alarms.pop
|
163
|
+
if a.fire_then_repeat?(now)
|
164
|
+
timer_add_alarm(a)
|
165
|
+
end
|
166
|
+
timer_check_integrity
|
167
|
+
end
|
168
|
+
# the method result is irrelevant, but sync_call is necessary to yield the timer blocks
|
169
|
+
nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eventbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lars Kanis
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDPDCCAiSgAwIBAgIBBTANBgkqhkiG9w0BAQsFADBEMQ0wCwYDVQQDDARsYXJz
|
14
|
+
MR8wHQYKCZImiZPyLGQBGRYPZ3JlaXotcmVpbnNkb3JmMRIwEAYKCZImiZPyLGQB
|
15
|
+
GRYCZGUwHhcNMTgwOTE0MjE0NjIyWhcNMTkwOTE0MjE0NjIyWjBEMQ0wCwYDVQQD
|
16
|
+
DARsYXJzMR8wHQYKCZImiZPyLGQBGRYPZ3JlaXotcmVpbnNkb3JmMRIwEAYKCZIm
|
17
|
+
iZPyLGQBGRYCZGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZb4Uv
|
18
|
+
RFJfRu/VEWiy3psh2jinETjiuBrL0NeRFGf8H7iU9+gx/DI/FFhfHGLrDeIskrJx
|
19
|
+
YIWDMmEjVO10UUdj7wu4ZhmU++0Cd7Kq9/TyP/shIP3IjqHjVLCnJ3P6f1cl5rxZ
|
20
|
+
gqo+d3BAoDrmPk0rtaf6QopwUw9RBiF8V4HqvpiY+ruJotP5UQDP4/lVOKvA8PI9
|
21
|
+
P0GmVbFBrbc7Zt5h78N3UyOK0u+nvOC23BvyHXzCtcFsXCoEkt+Wwh0RFqVZdnjM
|
22
|
+
LMO2vULHKKHDdX54K/sbVCj9pN9h1aotNzrEyo55zxn0G9PHg/G3P8nMvAXPkUTe
|
23
|
+
brhXrfCwWRvOXA4TAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0G
|
24
|
+
A1UdDgQWBBRAHK81igrXodaDj8a8/BIKsaZrETANBgkqhkiG9w0BAQsFAAOCAQEA
|
25
|
+
ZNTM80Pn9caTOcDYCmJi28qV0H8x6k5zeEd8PckEr9gYCFrUtVvtQPBi364PWo82
|
26
|
+
Img1GQle3nbhYuiNPRsjfr0uaTgUeA7JXw5OCEtgck2w93KzFISBt+jLyoprAJDh
|
27
|
+
uHImSFGzjRwHVi2Kihh1y4VR0ZkofNWaPqhxhxN7JCTVrV8MLqe2ZgHoe1WMGAyT
|
28
|
+
mmzdbSP3kmz9L2eshisCKPSi0qKk4VyBhdeeIf+3xMim/DK1gTz44BwHSCtGkaJT
|
29
|
+
NOQ0Qq2j8NtFfBHqGHBKaqj/Q0AciwGWIMfXJh3fTsRuMonkEu6TgB6M79HzgqQ8
|
30
|
+
sXOGZvvDWUBn5GWztfhdZw==
|
31
|
+
-----END CERTIFICATE-----
|
32
|
+
date: 2018-12-04 00:00:00.000000000 Z
|
33
|
+
dependencies:
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: bundler
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.16'
|
41
|
+
- - "<"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '3'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '1.16'
|
51
|
+
- - "<"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rake
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '10.0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: minitest
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '5.0'
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '5.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: yard
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.9'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0.9'
|
96
|
+
description: |-
|
97
|
+
{Eventbox} objects are event based and single threaded from the inside but thread-safe and blocking from the outside.
|
98
|
+
Eventbox enforces a separation of code for event processing and code running blocking operations.
|
99
|
+
Code inside an {Eventbox} object is executed non-concurrently and hence shouldn't do any blocking operations.
|
100
|
+
This is similar to the typical JavaScript programming style.
|
101
|
+
email:
|
102
|
+
- lars@greiz-reinsdorf.de
|
103
|
+
executables: []
|
104
|
+
extensions: []
|
105
|
+
extra_rdoc_files: []
|
106
|
+
files:
|
107
|
+
- ".appveyor.yml"
|
108
|
+
- ".gitignore"
|
109
|
+
- ".travis.yml"
|
110
|
+
- ".yardopts"
|
111
|
+
- CODE_OF_CONDUCT.md
|
112
|
+
- Gemfile
|
113
|
+
- LICENSE.txt
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- bin/console
|
117
|
+
- bin/setup
|
118
|
+
- docs/downloads.md
|
119
|
+
- docs/server.md
|
120
|
+
- docs/threadpool.md
|
121
|
+
- eventbox.gemspec
|
122
|
+
- lib/eventbox.rb
|
123
|
+
- lib/eventbox/argument_wrapper.rb
|
124
|
+
- lib/eventbox/boxable.rb
|
125
|
+
- lib/eventbox/event_loop.rb
|
126
|
+
- lib/eventbox/object_registry.rb
|
127
|
+
- lib/eventbox/sanitizer.rb
|
128
|
+
- lib/eventbox/thread_pool.rb
|
129
|
+
- lib/eventbox/timer.rb
|
130
|
+
- lib/eventbox/version.rb
|
131
|
+
homepage: https://github.com/larskanis/eventbox
|
132
|
+
licenses:
|
133
|
+
- MIT
|
134
|
+
metadata:
|
135
|
+
yard.run: yri
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - "~>"
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '2.3'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">="
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
requirements: []
|
151
|
+
rubyforge_project:
|
152
|
+
rubygems_version: 2.7.7
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Manage multithreading with the safety of event based programming
|
156
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|