em-midori 0.2.0 → 0.2.1
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/lib/midori/api.rb +1 -0
- data/lib/midori/connection.rb +13 -3
- data/lib/midori/const.rb +1 -0
- data/lib/midori/core_ext/configurable.rb +4 -0
- data/lib/midori/core_ext/event_loop.rb +44 -20
- data/lib/midori/core_ext/promise.rb +10 -1
- data/lib/midori/core_ext/safe_require.rb +1 -0
- data/lib/midori/core_ext/timer.rb +14 -2
- data/lib/midori/extension/file.rb +12 -1
- data/lib/midori/extension/hiredis.rb +15 -3
- data/lib/midori/extension/net.rb +6 -1
- data/lib/midori/extension/sequel/mysql2.rb +14 -5
- data/lib/midori/extension/sequel/postgres.rb +24 -23
- data/lib/midori/version.rb +1 -1
- data/tutorial/README.md +1 -1
- data/tutorial/SUMMARY.md +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5a62c03f0e31bd0ea7466d2ddda81f2fbdd8efd
|
4
|
+
data.tar.gz: c16d4d64ce2fd066ccd7bef0546bd07a816a7ac0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8c6e274f821b8f2f4f3ef746e98b1b5efe2d1774d67a55e7083271ab5fb51928e71cdb2df4f19fe2a7e5d7ac62293ce728525b87b3d76ff2ac37e4f6b95d18c
|
7
|
+
data.tar.gz: ce6a571451d2a7647872135c2546fc097fb86667b4888b5ddfe6cd54374989964bcc5530c58d8466401956ed4959bba6634bbb298b32ce63cedf88b852f63c78
|
data/lib/midori/api.rb
CHANGED
@@ -303,6 +303,7 @@ class Midori::API
|
|
303
303
|
|
304
304
|
# Add EVENTSOURCE method as a DSL for route definition
|
305
305
|
# @param [String] path Accepts as part of path in route definition
|
306
|
+
# @yield what to run when route matched
|
306
307
|
# @return [nil] nil
|
307
308
|
# @example String as router
|
308
309
|
# eventsource '/' do
|
data/lib/midori/connection.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
##
|
2
|
+
# States of a connection
|
1
3
|
class Midori::Connection
|
2
4
|
include Midori::Server
|
3
5
|
|
6
|
+
# @!attribute data
|
7
|
+
# @return [String] string buffer of data to send
|
4
8
|
attr_accessor :data
|
5
9
|
|
10
|
+
# Init Connection with socket
|
11
|
+
# @param [IO] socket raw socket
|
6
12
|
def initialize(socket)
|
7
13
|
@registered = false
|
8
14
|
@socket = socket
|
@@ -12,6 +18,8 @@ class Midori::Connection
|
|
12
18
|
listen(socket)
|
13
19
|
end
|
14
20
|
|
21
|
+
# Register events of connection
|
22
|
+
# @param [IO] socket raw socket
|
15
23
|
def listen(socket)
|
16
24
|
EventLoop.register(socket, :rw) do |monitor|
|
17
25
|
@monitor = monitor
|
@@ -32,18 +40,20 @@ class Midori::Connection
|
|
32
40
|
end
|
33
41
|
end
|
34
42
|
|
43
|
+
# Send message to client
|
44
|
+
# @param [String] data data to send
|
35
45
|
def send_data(data)
|
36
46
|
@monitor.writable? ? @socket.write_nonblock(data) : @data << data
|
37
47
|
end
|
38
48
|
|
49
|
+
# Close the connection
|
39
50
|
def close_connection
|
40
51
|
EventLoop.deregister @socket
|
41
52
|
@socket.close
|
42
|
-
rescue Errno::EBADF
|
43
|
-
# Connection finished in advance
|
44
53
|
end
|
45
54
|
|
55
|
+
# Close the connection after writing
|
46
56
|
def close_connection_after_writing
|
47
57
|
@close_flag = true
|
48
58
|
end
|
49
|
-
end
|
59
|
+
end
|
data/lib/midori/const.rb
CHANGED
@@ -6,6 +6,7 @@ module Configurable
|
|
6
6
|
# @param [Symbol] option the name of config
|
7
7
|
# @param [Object] value value to the name
|
8
8
|
# @param [Boolean] read_only Generate option= method or not
|
9
|
+
# @return [nil] nil
|
9
10
|
def set(option, value = (not_set = true), read_only = false)
|
10
11
|
raise ArgumentError if not_set
|
11
12
|
|
@@ -22,6 +23,9 @@ module Configurable
|
|
22
23
|
private
|
23
24
|
|
24
25
|
# Dynamically defines a method on settings.
|
26
|
+
# @param [String] name method name
|
27
|
+
# @param [Proc] content method content
|
28
|
+
# @return [nil] nil
|
25
29
|
def define_singleton(name, content = Proc.new)
|
26
30
|
singleton_class.class_eval do
|
27
31
|
undef_method(name) if method_defined? name
|
@@ -1,59 +1,75 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
##
|
2
|
+
# EventLoop Module, providing main loop for events
|
3
3
|
module EventLoop
|
4
4
|
class << self
|
5
|
+
# Raw NIO Selector
|
5
6
|
SELECTOR = NIO::Selector.new
|
7
|
+
# Array of active timers
|
6
8
|
TIMERS = []
|
9
|
+
# Hash of io and its callback
|
7
10
|
IOS = Hash.new
|
11
|
+
# IO queue
|
8
12
|
QUEUE = Hash.new
|
9
13
|
|
14
|
+
# Add timer in event loop
|
15
|
+
# @param [EventLoop::Timer] timer timer to insert
|
16
|
+
# @return [nil] nil
|
10
17
|
def add_timer(timer)
|
11
18
|
timer.start_time = Time.now.to_f + timer.time
|
12
19
|
TIMERS << timer
|
20
|
+
nil
|
13
21
|
end
|
14
22
|
|
15
|
-
|
23
|
+
# Register I/O event with queue protection
|
24
|
+
# @param [IO] io io to register
|
25
|
+
# @param [Symbol] interest :r for read only, :w for write only, and :rw for both
|
26
|
+
# @yield what to run when io callbacks
|
27
|
+
# @return [nil] nil
|
28
|
+
def register(io, interest=(:rw), &callback)
|
16
29
|
if QUEUE[io.to_i].nil?
|
17
30
|
QUEUE[io.to_i] = Array.new
|
18
|
-
register_raw(io, interest,
|
31
|
+
register_raw(io, interest, callback)
|
19
32
|
else
|
20
|
-
QUEUE[io.to_i] << [io, interest,
|
33
|
+
QUEUE[io.to_i] << [io, interest, callback]
|
21
34
|
end
|
35
|
+
nil
|
22
36
|
end
|
23
37
|
|
24
|
-
|
38
|
+
# Register I/O event directly, without any queue protection
|
39
|
+
# @param [IO] io io to register
|
40
|
+
# @param [Symbol] interest :r for read only, :w for write only, and :rw for both
|
41
|
+
# @param [Proc] callback what to run when io callbacks
|
42
|
+
# @return [nil] nil
|
43
|
+
def register_raw(io, interest=(:rw), callback)
|
25
44
|
SELECTOR.register(io, interest)
|
26
|
-
|
27
|
-
|
28
|
-
timer = EventLoop::Timer.new(timeout) do
|
29
|
-
EventLoop.deregister(io)
|
30
|
-
resolve.call(TimeoutError) unless resolve.nil?
|
31
|
-
end
|
32
|
-
EventLoop.add_timer(timer)
|
33
|
-
end
|
34
|
-
|
35
|
-
IOS[io] = {
|
36
|
-
timer: timer ? timer : nil,
|
37
|
-
callback: callback,
|
38
|
-
}
|
45
|
+
IOS[io] = { callback: callback }
|
46
|
+
nil
|
39
47
|
end
|
40
48
|
|
49
|
+
# Deregister I/O event
|
50
|
+
# @param [IO] io io to deregister
|
51
|
+
# @return [nil] nil
|
41
52
|
def deregister(io)
|
42
53
|
fd = io.to_i
|
43
54
|
SELECTOR.deregister(io)
|
44
55
|
IOS.delete(io)
|
45
56
|
next_register = QUEUE[fd].shift
|
46
57
|
next_register.nil? ? QUEUE.delete(fd) : register_raw(*next_register)
|
58
|
+
nil
|
47
59
|
end
|
48
60
|
|
61
|
+
# Run I/O selector once
|
62
|
+
# @return [nil] nil
|
49
63
|
def run_once
|
50
64
|
SELECTOR.select(0.2) do |monitor| # Timeout for 0.2 secs
|
51
|
-
TIMERS.delete(IOS[monitor.io][:timer]) unless IOS[monitor.io][:timer].nil?
|
52
65
|
IOS[monitor.io][:callback].call(monitor)
|
53
66
|
end
|
54
67
|
EventLoop.timer_once
|
68
|
+
nil
|
55
69
|
end
|
56
70
|
|
71
|
+
# Run timer once
|
72
|
+
# @return [nil] nil
|
57
73
|
def timer_once
|
58
74
|
now_time = Time.now.to_f
|
59
75
|
TIMERS.delete_if do |timer|
|
@@ -62,8 +78,11 @@ module EventLoop
|
|
62
78
|
true
|
63
79
|
end
|
64
80
|
end
|
81
|
+
nil
|
65
82
|
end
|
66
83
|
|
84
|
+
# Start the event loop
|
85
|
+
# @return [nil] nil
|
67
86
|
def start
|
68
87
|
return if running?
|
69
88
|
@stop = false
|
@@ -73,10 +92,15 @@ module EventLoop
|
|
73
92
|
@stop = nil
|
74
93
|
end
|
75
94
|
|
95
|
+
# Set the stop flag
|
96
|
+
# @return [nil] nil
|
76
97
|
def stop
|
77
98
|
@stop = true
|
99
|
+
nil
|
78
100
|
end
|
79
101
|
|
102
|
+
# Detect the stop flag
|
103
|
+
# @return [Boolean] return if eventloop is set to be stopped
|
80
104
|
def running?
|
81
105
|
@stop = true if @stop.nil?
|
82
106
|
!@stop
|
@@ -17,6 +17,8 @@ class Promise
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module Kernel
|
20
|
+
# Make fiber as async chain
|
21
|
+
# @param [Fiber] fiber root of async chain
|
20
22
|
def async_fiber(fiber)
|
21
23
|
chain = proc do |result|
|
22
24
|
next unless result.is_a? Promise
|
@@ -53,9 +55,16 @@ module Kernel
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
58
|
+
|
59
|
+
##
|
60
|
+
# Exceptions for Promises
|
61
|
+
# @!attribute [r] payload
|
62
|
+
# @return [Exception] raw execption
|
56
63
|
class PromiseException < Exception
|
57
64
|
attr_reader :payload
|
65
|
+
# Init PromiseException with existed Exception
|
66
|
+
# @param [Exception] payload raw execption
|
58
67
|
def initialize(payload)
|
59
68
|
@payload = payload
|
60
69
|
end
|
61
|
-
end
|
70
|
+
end
|
@@ -1,10 +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
|
1
9
|
class EventLoop::Timer
|
2
|
-
|
10
|
+
|
11
|
+
attr_reader :time, :callback
|
3
12
|
attr_accessor :start_time
|
4
13
|
|
14
|
+
# Init a timer with a time period and callback
|
15
|
+
# @param [Float] time timeout length
|
16
|
+
# @yield proc to call when callbacks
|
5
17
|
def initialize(time, &callback)
|
6
18
|
@time = time
|
7
19
|
@callback = callback
|
8
20
|
@start_time = Float::INFINITY
|
9
21
|
end
|
10
|
-
end
|
22
|
+
end
|
@@ -1,8 +1,14 @@
|
|
1
|
+
##
|
2
|
+
# Midori Extension of File reading and writing
|
1
3
|
class Midori::File
|
4
|
+
# Init File object
|
5
|
+
# @param [Array] args same args like File.new
|
2
6
|
def initialize(*args)
|
3
7
|
@file = File.new(*args)
|
4
8
|
end
|
5
9
|
|
10
|
+
# read file
|
11
|
+
# @return [String] string readed
|
6
12
|
def read
|
7
13
|
await(Promise.new do |resolve|
|
8
14
|
data = ''
|
@@ -17,6 +23,8 @@ class Midori::File
|
|
17
23
|
end)
|
18
24
|
end
|
19
25
|
|
26
|
+
# write file
|
27
|
+
# @param [String] data string to be written
|
20
28
|
def write(data)
|
21
29
|
await(Promise.new do |resolve|
|
22
30
|
written = 0
|
@@ -30,11 +38,14 @@ class Midori::File
|
|
30
38
|
end)
|
31
39
|
end
|
32
40
|
|
41
|
+
# raw file object
|
42
|
+
# @return [File] file
|
33
43
|
def raw
|
34
44
|
@file
|
35
45
|
end
|
36
46
|
|
47
|
+
# Close the file
|
37
48
|
def close
|
38
49
|
@file.close
|
39
50
|
end
|
40
|
-
end
|
51
|
+
end
|
@@ -1,15 +1,25 @@
|
|
1
|
+
##
|
2
|
+
# Meta-programming hiredis for redis async extension
|
1
3
|
module Hiredis
|
2
4
|
require 'hiredis/connection'
|
3
5
|
# Overwrite with ruby implementation to hook IO
|
4
6
|
require 'hiredis/ruby/connection'
|
5
7
|
require 'hiredis/ruby/reader'
|
8
|
+
# Redis Connection
|
6
9
|
Connection = Ruby::Connection
|
10
|
+
# Redis Result Reader
|
7
11
|
Reader = Ruby::Reader
|
8
|
-
end
|
9
12
|
|
10
|
-
|
13
|
+
##
|
14
|
+
# Meta-programming hiredis for redis async extension
|
11
15
|
module Ruby
|
16
|
+
##
|
17
|
+
# Meta-programming hiredis for redis async extension
|
12
18
|
class Connection
|
19
|
+
# write message directly
|
20
|
+
# @param [IO] _sock raw socket
|
21
|
+
# @param [String] data generated string data
|
22
|
+
# @param [Float] _timeout operation timeout
|
13
23
|
def _write(_sock, data, _timeout)
|
14
24
|
await(Promise.new do |resolve|
|
15
25
|
data.force_encoding('binary') if data.respond_to?(:force_encoding)
|
@@ -24,6 +34,8 @@ module Hiredis
|
|
24
34
|
end)
|
25
35
|
end
|
26
36
|
|
37
|
+
# read from redis socket
|
38
|
+
# @return [String] reply
|
27
39
|
def read
|
28
40
|
raise 'not connected' unless connected?
|
29
41
|
await(Promise.new do |resolve|
|
@@ -44,4 +56,4 @@ module Hiredis
|
|
44
56
|
end
|
45
57
|
end
|
46
58
|
end
|
47
|
-
end
|
59
|
+
end
|
data/lib/midori/extension/net.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'net/protocol'
|
2
2
|
|
3
|
+
##
|
4
|
+
# Meta programming Net class for async HTTP and FTP connection
|
3
5
|
class Net::BufferedIO
|
6
|
+
# Wait till io finishes
|
7
|
+
# @param [Symbol] interest
|
4
8
|
def wait_io(interest)
|
5
9
|
await(Promise.new do |resolve|
|
6
10
|
io = @io.to_io
|
@@ -11,6 +15,7 @@ class Net::BufferedIO
|
|
11
15
|
end)
|
12
16
|
end
|
13
17
|
|
18
|
+
# Fill until the operation finishes
|
14
19
|
def rbuf_fill
|
15
20
|
loop do
|
16
21
|
case rv = @io.read_nonblock(BUFSIZE, exception: false)
|
@@ -34,4 +39,4 @@ class Net::BufferedIO
|
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
37
|
-
end
|
42
|
+
end
|
@@ -1,14 +1,23 @@
|
|
1
1
|
safe_require 'sequel', 'gem install sequel'
|
2
2
|
require 'sequel/adapters/mysql2'
|
3
3
|
|
4
|
+
# Management of MySQL Sockets
|
4
5
|
MYSQL_SOCKETS = {}
|
5
6
|
|
7
|
+
##
|
8
|
+
# Meta-programming Sequel for async extensions
|
6
9
|
module Sequel
|
10
|
+
# Midori Extension of sequel MySQL through meta programming
|
7
11
|
module Mysql2
|
12
|
+
# Midori Extension of sequel MySQL through meta programming
|
8
13
|
class Database
|
9
14
|
# Execute the given SQL on the given connection. If the :type
|
10
15
|
# option is :select, yield the result of the query, otherwise
|
11
16
|
# yield the connection if a block is given.
|
17
|
+
# @param [Mysql2::Client] conn connection to database
|
18
|
+
# @param [String] sql sql query
|
19
|
+
# @param [Hash] opts optional options
|
20
|
+
# @return [Mysql2::Result] MySQL results
|
12
21
|
def _execute(conn, sql, opts) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
13
22
|
begin
|
14
23
|
# :nocov:
|
@@ -44,15 +53,15 @@ module Sequel
|
|
44
53
|
socket = MYSQL_SOCKETS[conn.socket]
|
45
54
|
await(Promise.new do |resolve|
|
46
55
|
count = 0
|
47
|
-
EventLoop.register(socket, :rw
|
56
|
+
EventLoop.register(socket, :rw) do
|
48
57
|
if (count == 0)
|
49
58
|
# Writable
|
50
59
|
count += 1
|
51
60
|
conn.query(sql,
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
database_timezone: timezone,
|
62
|
+
application_timezone: Sequel.application_timezone,
|
63
|
+
stream: stream,
|
64
|
+
async: true)
|
56
65
|
else
|
57
66
|
# Readable
|
58
67
|
begin
|
@@ -1,6 +1,7 @@
|
|
1
1
|
safe_require 'sequel', 'gem install sequel'
|
2
2
|
require 'sequel/adapters/postgres'
|
3
3
|
|
4
|
+
# Management of Postgres Sockets
|
4
5
|
POSTGRES_SOCKETS = {}
|
5
6
|
|
6
7
|
##
|
@@ -11,31 +12,31 @@ class Sequel::Postgres::Adapter
|
|
11
12
|
# @param [Array] args args to send
|
12
13
|
# @return [Array] sql query result
|
13
14
|
def execute_query(sql, args)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
else
|
30
|
-
# Readable
|
31
|
-
EventLoop.deregister(socket_object)
|
32
|
-
resolve.call(get_result)
|
15
|
+
@db.log_connection_yield(sql, self, args) do
|
16
|
+
if POSTGRES_SOCKETS[self].nil?
|
17
|
+
POSTGRES_SOCKETS[self] = IO::open(socket)
|
18
|
+
end
|
19
|
+
socket_object = POSTGRES_SOCKETS[self]
|
20
|
+
await(Promise.new do |resolve|
|
21
|
+
count = 0
|
22
|
+
EventLoop.register(socket_object, :rw) do
|
23
|
+
begin
|
24
|
+
if (count == 0)
|
25
|
+
# Writable
|
26
|
+
unless is_busy
|
27
|
+
send_query(sql)
|
28
|
+
count += 1
|
33
29
|
end
|
34
|
-
|
35
|
-
|
30
|
+
else
|
31
|
+
# Readable
|
32
|
+
EventLoop.deregister(socket_object)
|
33
|
+
resolve.call(get_result)
|
36
34
|
end
|
35
|
+
rescue => e
|
36
|
+
resolve.call(PromiseException.new(e))
|
37
37
|
end
|
38
|
-
end
|
39
|
-
end
|
38
|
+
end
|
39
|
+
end)
|
40
|
+
end
|
40
41
|
end
|
41
42
|
end
|
data/lib/midori/version.rb
CHANGED
data/tutorial/README.md
CHANGED
@@ -8,4 +8,4 @@ If you want to know how midori compares to other libraries/frameworks, checkout
|
|
8
8
|
|
9
9
|
## Note
|
10
10
|
|
11
|
-
The official guide assumes intermediate level knowledge of Ruby and backend development. If you are totally new , it might not be the best idea to jump right into a framework as your first step - grasp the basics then come back! Prior experience with other frameworks like Rails helps, but is not required.
|
11
|
+
The official guide assumes intermediate level knowledge of Ruby and backend development. If you are totally new , it might not be the best idea to jump right into a framework as your first step - grasp the basics then come back! Prior experience with other frameworks like Rails helps, but is not required.
|
data/tutorial/SUMMARY.md
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-midori
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- HeckPsi Lab
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|