murasaki 0.0.1 → 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 +4 -4
- data/.editorconfig +9 -0
- data/lib/murasaki.rb +7 -0
- data/lib/murasaki/event_loop.rb +118 -0
- data/lib/murasaki/promise.rb +70 -0
- data/lib/murasaki/timer.rb +22 -0
- data/lib/murasaki/version.rb +5 -0
- data/murasaki.gemspec +19 -0
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ecdeb71724f0d1efe13027d3acee86a7575b1f4
|
4
|
+
data.tar.gz: 4523b9a2b5ebb11f93002b3190d360bc8ac667e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed8ca771ea23774b154477690d892ae658861fe929c42511357249468a562a5a598f005ae90f0b6798dc88d292ee6c948e815c2d52a0154b74cb05079bead52a
|
7
|
+
data.tar.gz: 81e4529da54237d5fe8dbe536c86eaca74c99055c60f781fe9aac6247728babeed2ac8ce19dedca4653db62390e59d7ecd88340b5cde2adf3dd4ee4bdb4d20e4
|
data/.editorconfig
ADDED
data/lib/murasaki.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
##
|
2
|
+
# EventLoop Module, providing main loop for events
|
3
|
+
module EventLoop
|
4
|
+
class << self
|
5
|
+
# Config EvnetLoop, call by default if any other methods called
|
6
|
+
# @param [NIO::Selector] selector an event selector
|
7
|
+
def config(selector = NIO::Selector.new)
|
8
|
+
# Raw NIO Selector
|
9
|
+
@selector = selector
|
10
|
+
# Array of active timers
|
11
|
+
@timers = []
|
12
|
+
# Hash of io and its callback
|
13
|
+
@ios = Hash.new
|
14
|
+
# IO queue
|
15
|
+
@queue = Hash.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Add timer in event loop
|
19
|
+
# @param [EventLoop::Timer] timer timer to insert
|
20
|
+
# @return [nil] nil
|
21
|
+
def add_timer(timer)
|
22
|
+
config if @selector.nil?
|
23
|
+
timer.start_time = Time.now.to_f + timer.time
|
24
|
+
@timers << timer
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Register I/O event with queue protection
|
29
|
+
# @param [IO] io io to register
|
30
|
+
# @param [Symbol] interest :r for read only, :w for write only, and :rw for both
|
31
|
+
# @yield what to run when io callbacks
|
32
|
+
# @return [nil] nil
|
33
|
+
def register(io, interest=(:rw), &callback)
|
34
|
+
config if @selector.nil?
|
35
|
+
if @queue[io.to_i].nil?
|
36
|
+
@queue[io.to_i] = Array.new
|
37
|
+
register_raw(io, interest, callback)
|
38
|
+
else
|
39
|
+
@queue[io.to_i] << [io, interest, callback]
|
40
|
+
end
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Register I/O event directly, without any queue protection
|
45
|
+
# @param [IO] io io to register
|
46
|
+
# @param [Symbol] interest :r for read only, :w for write only, and :rw for both
|
47
|
+
# @param [Proc] callback what to run when io callbacks
|
48
|
+
# @return [nil] nil
|
49
|
+
def register_raw(io, interest=(:rw), callback)
|
50
|
+
config if @selector.nil?
|
51
|
+
@selector.register(io, interest)
|
52
|
+
@ios[io] = { callback: callback }
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
# Deregister I/O event
|
57
|
+
# @param [IO] io io to deregister
|
58
|
+
# @return [nil] nil
|
59
|
+
def deregister(io)
|
60
|
+
fd = io.to_i
|
61
|
+
@selector.deregister(io)
|
62
|
+
@ios.delete(io)
|
63
|
+
next_register = @queue[fd].shift
|
64
|
+
next_register.nil? ? @queue.delete(fd) : register_raw(*next_register)
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
# Run I/O selector once
|
69
|
+
# @return [nil] nil
|
70
|
+
def run_once
|
71
|
+
config if @selector.nil?
|
72
|
+
@selector.select(0.2) do |monitor| # Timeout for 0.2 secs
|
73
|
+
@ios[monitor.io][:callback].call(monitor)
|
74
|
+
end
|
75
|
+
timer_once
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# Run timer once
|
80
|
+
# @return [nil] nil
|
81
|
+
def timer_once
|
82
|
+
config if @selector.nil?
|
83
|
+
now_time = Time.now.to_f
|
84
|
+
@timers.delete_if do |timer|
|
85
|
+
if timer.start_time < now_time
|
86
|
+
timer.callback.call
|
87
|
+
true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
# Start the event loop
|
94
|
+
# @return [nil] nil
|
95
|
+
def start
|
96
|
+
return if running?
|
97
|
+
@stop = false
|
98
|
+
until @stop
|
99
|
+
run_once
|
100
|
+
end
|
101
|
+
@stop = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
# Set the stop flag
|
105
|
+
# @return [nil] nil
|
106
|
+
def stop
|
107
|
+
@stop = true
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
# Detect the stop flag
|
112
|
+
# @return [Boolean] return if eventloop is set to be stopped
|
113
|
+
def running?
|
114
|
+
@stop = true if @stop.nil?
|
115
|
+
!@stop
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
##
|
2
|
+
# Meta-programming String for Syntactic Sugars
|
3
|
+
# Referenced from {Qiita}[http://qiita.com/south37/items/99a60345b22ef395d424]
|
4
|
+
class Promise
|
5
|
+
# Init a Promise
|
6
|
+
# @param [Proc] callback an async method
|
7
|
+
def initialize(&callback)
|
8
|
+
@callback = callback
|
9
|
+
end
|
10
|
+
|
11
|
+
# Define what to do after a method callbacks
|
12
|
+
# @param [Proc] resolve what on callback
|
13
|
+
# @return [nil] nil
|
14
|
+
def then(&resolve)
|
15
|
+
@callback.call(resolve)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Kernel
|
20
|
+
# Make fiber as async chain
|
21
|
+
# @param [Fiber] fiber root of async chain
|
22
|
+
def async_fiber(fiber)
|
23
|
+
chain = proc do |result|
|
24
|
+
next unless result.is_a? Promise
|
25
|
+
result.then do |val|
|
26
|
+
chain.call(fiber.resume(val))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
chain.call(fiber.resume)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Define an async method
|
33
|
+
# @param [Symbol] method method name
|
34
|
+
# @yield async method
|
35
|
+
# @example
|
36
|
+
# async :hello do
|
37
|
+
# puts 'Hello'
|
38
|
+
# end
|
39
|
+
def async(method)
|
40
|
+
define_singleton_method method do |*args|
|
41
|
+
async_fiber(Fiber.new {yield(*args)})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Block the I/O to wait for async method response
|
46
|
+
# @param [Promise] promise promise method
|
47
|
+
# @example
|
48
|
+
# result = await SQL.query('SELECT * FROM hello')
|
49
|
+
def await(promise)
|
50
|
+
result = Fiber.yield promise
|
51
|
+
if result.is_a? PromiseException
|
52
|
+
raise result.payload
|
53
|
+
end
|
54
|
+
result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
# Exceptions for Promises
|
61
|
+
# @!attribute [r] payload
|
62
|
+
# @return [Exception] raw execption
|
63
|
+
class PromiseException < Exception
|
64
|
+
attr_reader :payload
|
65
|
+
# Init PromiseException with existed Exception
|
66
|
+
# @param [Exception] payload raw execption
|
67
|
+
def initialize(payload)
|
68
|
+
@payload = payload
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
##
|
2
|
+
# Timer Object in EventLoop
|
3
|
+
# @!attribute [r] time
|
4
|
+
# @return [Float] timeout length
|
5
|
+
# @!attribute [r] callback
|
6
|
+
# @return [Proc] proc to call when callbacks
|
7
|
+
# @!attribute start_time
|
8
|
+
# @return [Float] when timer should callbacks
|
9
|
+
class EventLoop::Timer
|
10
|
+
|
11
|
+
attr_reader :time, :callback
|
12
|
+
attr_accessor :start_time
|
13
|
+
|
14
|
+
# Init a timer with a time period and callback
|
15
|
+
# @param [Float] time timeout length
|
16
|
+
# @yield proc to call when callbacks
|
17
|
+
def initialize(time, &callback)
|
18
|
+
@time = time
|
19
|
+
@callback = callback
|
20
|
+
@start_time = Float::INFINITY
|
21
|
+
end
|
22
|
+
end
|
data/murasaki.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require './lib/murasaki/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'murasaki'
|
5
|
+
s.version = Murasaki::VERSION
|
6
|
+
s.required_ruby_version = '>=2.2.6'
|
7
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
8
|
+
s.summary = 'Event Kernel for Ruby'
|
9
|
+
s.description = 'Event Kernel for Ruby, power for midori project'
|
10
|
+
s.authors = ['HeckPsi Lab']
|
11
|
+
s.email = 'business@heckpsi.com'
|
12
|
+
s.require_paths = ['lib']
|
13
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|.resources)/}) } \
|
14
|
+
- %w(README.md CONTRIBUTOR_COVENANT_CODE_OF_CONDUCT.md Gemfile Rakefile em-midori.gemspec .gitignore .rspec .codeclimate.yml .rubocop.yml .travis.yml logo.png Rakefile Gemfile)
|
15
|
+
s.homepage = 'https://github.com/heckpsi-lab/murasaki'
|
16
|
+
s.metadata = { 'issue_tracker' => 'https://github.com/heckpsi-lab/murasaki/issues' }
|
17
|
+
s.license = 'MIT'
|
18
|
+
s.add_runtime_dependency 'nio4r', '~> 2.0'
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murasaki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- HeckPsi Lab
|
@@ -9,14 +9,35 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2017-06-13 00:00:00.000000000 Z
|
12
|
-
dependencies:
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nio4r
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
13
27
|
description: Event Kernel for Ruby, power for midori project
|
14
28
|
email: business@heckpsi.com
|
15
29
|
executables: []
|
16
30
|
extensions: []
|
17
31
|
extra_rdoc_files: []
|
18
32
|
files:
|
33
|
+
- ".editorconfig"
|
19
34
|
- LICENSE
|
35
|
+
- lib/murasaki.rb
|
36
|
+
- lib/murasaki/event_loop.rb
|
37
|
+
- lib/murasaki/promise.rb
|
38
|
+
- lib/murasaki/timer.rb
|
39
|
+
- lib/murasaki/version.rb
|
40
|
+
- murasaki.gemspec
|
20
41
|
homepage: https://github.com/heckpsi-lab/murasaki
|
21
42
|
licenses:
|
22
43
|
- MIT
|