em-midori 0.1.12 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +9 -0
- data/em-midori.sublime-project +16 -0
- data/lib/midori/connection.rb +2 -0
- data/lib/midori/core_ext/event_loop.rb +31 -7
- data/lib/midori/core_ext/promise.rb +12 -1
- data/lib/midori/extension/net.rb +3 -2
- data/lib/midori/extension/sequel/mysql2.rb +26 -15
- data/lib/midori/extension/sequel/postgres.rb +23 -15
- data/lib/midori/runner.rb +4 -0
- data/lib/midori/server.rb +1 -1
- data/lib/midori/version.rb +1 -1
- data/tutorial/essentials/installation.md +2 -2
- data/tutorial/essentials/routing.md +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d890861f5486fd8c8ecd3dff2a3780a26af42340
|
4
|
+
data.tar.gz: 1d6ddf047c3534998eb6637cfbe387d56f1e86f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2664bb10cda5ab00f264bd91e633315ab2f05fb44218050597fc61c34890fa00bf042d3a476e24711415b9eb8d28e2a4b94f2225bb307f1f1e77c1fffde468d6
|
7
|
+
data.tar.gz: 884cce78c3c28f9014823b45d03529082d7ff4c6832be0bfaa490265a08a7a05ad2b3ed7d5447074edbb6d3e06d32a0006004116afece1b442511f417583d33e
|
data/.editorconfig
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
{
|
2
|
+
"folders":
|
3
|
+
[
|
4
|
+
{
|
5
|
+
"path": ".",
|
6
|
+
"folder_exclude_patterns": [".resources", "coverage"],
|
7
|
+
"file_exclude_patterns": ["em-midori-*.gem","*.sublime-workspace","logo.png",".DS_Store","CONTRIBUTOR_COVENANT_CODE_OF_CONDUCT.md"]
|
8
|
+
}
|
9
|
+
],
|
10
|
+
"settings":
|
11
|
+
{
|
12
|
+
"tab_size": 2,
|
13
|
+
"translate_tabs_to_spaces": true,
|
14
|
+
"trim_trailing_white_space_on_save": true
|
15
|
+
}
|
16
|
+
}
|
data/lib/midori/connection.rb
CHANGED
@@ -4,28 +4,52 @@ module EventLoop
|
|
4
4
|
class << self
|
5
5
|
SELECTOR = NIO::Selector.new
|
6
6
|
TIMERS = []
|
7
|
+
IOS = Hash.new
|
8
|
+
QUEUE = Hash.new
|
7
9
|
|
8
10
|
def add_timer(timer)
|
9
11
|
timer.start_time = Time.now.to_f + timer.time
|
10
12
|
TIMERS << timer
|
11
13
|
end
|
12
14
|
|
13
|
-
def register(io, interest=(:rw), &callback)
|
14
|
-
|
15
|
-
|
15
|
+
def register(io, interest=(:rw), timeout=nil, resolve=nil, &callback)
|
16
|
+
if QUEUE[io.to_i].nil?
|
17
|
+
QUEUE[io.to_i] = Array.new
|
18
|
+
register_raw(io, interest, timeout, resolve, callback)
|
19
|
+
else
|
20
|
+
QUEUE[io.to_i] << [io, interest, timeout, resolve, callback]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_raw(io, interest=(:rw), timeout=nil, resolve=nil, callback)
|
25
|
+
SELECTOR.register(io, interest)
|
26
|
+
timer = nil
|
27
|
+
unless timeout.nil?
|
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,
|
16
37
|
callback: callback,
|
17
38
|
}
|
18
|
-
|
19
39
|
end
|
20
40
|
|
21
41
|
def deregister(io)
|
42
|
+
fd = io.to_i
|
22
43
|
SELECTOR.deregister(io)
|
44
|
+
IOS.delete(io)
|
45
|
+
next_register = QUEUE[fd].shift
|
46
|
+
next_register.nil? ? QUEUE.delete(fd) : register_raw(*next_register)
|
23
47
|
end
|
24
48
|
|
25
49
|
def run_once
|
26
|
-
SELECTOR.select(0.2) do |monitor| # Timeout for
|
27
|
-
monitor.
|
28
|
-
monitor.
|
50
|
+
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
|
+
IOS[monitor.io][:callback].call(monitor)
|
29
53
|
end
|
30
54
|
EventLoop.timer_once
|
31
55
|
end
|
@@ -45,6 +45,17 @@ module Kernel
|
|
45
45
|
# @example
|
46
46
|
# result = await SQL.query('SELECT * FROM hello')
|
47
47
|
def await(promise)
|
48
|
-
Fiber.yield promise
|
48
|
+
result = Fiber.yield promise
|
49
|
+
if result.is_a? PromiseException
|
50
|
+
raise result.payload
|
51
|
+
end
|
52
|
+
result
|
49
53
|
end
|
50
54
|
end
|
55
|
+
|
56
|
+
class PromiseException < Exception
|
57
|
+
attr_reader :payload
|
58
|
+
def initialize(payload)
|
59
|
+
@payload = payload
|
60
|
+
end
|
61
|
+
end
|
data/lib/midori/extension/net.rb
CHANGED
@@ -3,8 +3,9 @@ require 'net/protocol'
|
|
3
3
|
class Net::BufferedIO
|
4
4
|
def wait_io(interest)
|
5
5
|
await(Promise.new do |resolve|
|
6
|
-
|
7
|
-
|
6
|
+
io = @io.to_io
|
7
|
+
EventLoop.register(io, interest) do
|
8
|
+
EventLoop.deregister(io)
|
8
9
|
resolve.call(self)
|
9
10
|
end
|
10
11
|
end)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
safe_require 'sequel', 'gem install sequel'
|
2
2
|
require 'sequel/adapters/mysql2'
|
3
3
|
|
4
|
+
MYSQL_SOCKETS = {}
|
5
|
+
|
4
6
|
module Sequel
|
5
7
|
module Mysql2
|
6
8
|
class Database
|
@@ -36,22 +38,31 @@ module Sequel
|
|
36
38
|
stmt.execute(*args)
|
37
39
|
# :nocov:
|
38
40
|
else
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
conn.query(sql,
|
44
|
-
database_timezone: timezone,
|
45
|
-
application_timezone: Sequel.application_timezone,
|
46
|
-
stream: stream,
|
47
|
-
async: true)
|
48
|
-
resolve.call
|
49
|
-
end
|
50
|
-
end)
|
41
|
+
if MYSQL_SOCKETS[conn.socket].nil?
|
42
|
+
MYSQL_SOCKETS[conn.socket] = IO::open(conn.socket)
|
43
|
+
end
|
44
|
+
socket = MYSQL_SOCKETS[conn.socket]
|
51
45
|
await(Promise.new do |resolve|
|
52
|
-
|
53
|
-
|
54
|
-
|
46
|
+
count = 0
|
47
|
+
EventLoop.register(socket, :rw, 2, resolve) do
|
48
|
+
if (count == 0)
|
49
|
+
# Writable
|
50
|
+
count += 1
|
51
|
+
conn.query(sql,
|
52
|
+
database_timezone: timezone,
|
53
|
+
application_timezone: Sequel.application_timezone,
|
54
|
+
stream: stream,
|
55
|
+
async: true)
|
56
|
+
else
|
57
|
+
# Readable
|
58
|
+
begin
|
59
|
+
EventLoop.deregister(socket)
|
60
|
+
resolve.call(conn.async_result)
|
61
|
+
rescue ::Mysql2::Error => e
|
62
|
+
resolve.call(PromiseException.new(e))
|
63
|
+
next
|
64
|
+
end
|
65
|
+
end
|
55
66
|
end
|
56
67
|
end)
|
57
68
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
safe_require 'sequel', 'gem install sequel'
|
2
2
|
require 'sequel/adapters/postgres'
|
3
3
|
|
4
|
+
POSTGRES_SOCKETS = {}
|
5
|
+
|
4
6
|
##
|
5
7
|
# Midori Extension of sequel postgres through meta programming
|
6
8
|
class Sequel::Postgres::Adapter
|
@@ -10,24 +12,30 @@ class Sequel::Postgres::Adapter
|
|
10
12
|
# @return [Array] sql query result
|
11
13
|
def execute_query(sql, args)
|
12
14
|
@db.log_connection_yield(sql, self, args) do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
if POSTGRES_SOCKETS[self].nil?
|
16
|
+
POSTGRES_SOCKETS[self] = IO::open(socket)
|
17
|
+
end
|
18
|
+
socket_object = POSTGRES_SOCKETS[self]
|
19
|
+
result = await(Promise.new do |resolve|
|
20
|
+
count = 0
|
21
|
+
EventLoop.register(socket_object, :rw) do
|
22
|
+
begin
|
23
|
+
if (count == 0)
|
24
|
+
# Writable
|
25
|
+
unless is_busy
|
26
|
+
send_query(sql)
|
27
|
+
count += 1
|
28
|
+
end
|
29
|
+
else
|
30
|
+
# Readable
|
31
|
+
EventLoop.deregister(socket_object)
|
32
|
+
resolve.call(get_result)
|
33
|
+
end
|
34
|
+
rescue => e
|
35
|
+
resolve.call(PromiseException.new(e))
|
20
36
|
end
|
21
37
|
end
|
22
38
|
end)
|
23
|
-
|
24
|
-
await(Promise.new do |resolve|
|
25
|
-
consume_input
|
26
|
-
EventLoop.register(socket_object, :r) do
|
27
|
-
EventLoop.deregister(socket_object)
|
28
|
-
resolve.call(get_result)
|
29
|
-
end
|
30
|
-
end)
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
data/lib/midori/runner.rb
CHANGED
@@ -13,6 +13,7 @@ class Midori::Runner
|
|
13
13
|
@bind = configure.bind
|
14
14
|
@port = configure.port
|
15
15
|
@api = ((api.is_a?Midori::APIEngine) ? api : Midori::APIEngine.new(api, configure.route_type))
|
16
|
+
@before = configure.before
|
16
17
|
end
|
17
18
|
|
18
19
|
# Get Midori server whether running
|
@@ -33,6 +34,9 @@ class Midori::Runner
|
|
33
34
|
connection = Midori::Connection.new(socket)
|
34
35
|
connection.server_initialize(@api, @logger)
|
35
36
|
end
|
37
|
+
async_fiber(Fiber.new do
|
38
|
+
@before.call
|
39
|
+
end)
|
36
40
|
EventLoop.start
|
37
41
|
nil
|
38
42
|
end
|
data/lib/midori/server.rb
CHANGED
@@ -43,7 +43,7 @@ module Midori::Server
|
|
43
43
|
@logger.info "#{@request.ip} - - \"#{@request.method} #{@request.path} HTTP/#{@request.protocol.join('.')}\" #{@response.status} #{(now_time.to_f - start_time.to_f).round(6)}".green
|
44
44
|
rescue
|
45
45
|
close_connection
|
46
|
-
@logger.
|
46
|
+
@logger.warn "#{@request.ip} - - Reached an EOF Error".yellow
|
47
47
|
end
|
48
48
|
end)
|
49
49
|
end.call
|
data/lib/midori/version.rb
CHANGED
@@ -37,7 +37,7 @@ It's hard to say that if it is possible for running on other ruby implementation
|
|
37
37
|
|
38
38
|
```
|
39
39
|
$ gem install em-midori
|
40
|
-
Successfully installed em-midori-0.1.
|
40
|
+
Successfully installed em-midori-0.1.12
|
41
41
|
1 gem installed
|
42
42
|
```
|
43
43
|
|
@@ -50,7 +50,7 @@ $ ruby -r "midori" -e "class A < Midori::API;end;Midori::Runner.new(A).start"
|
|
50
50
|
If you see the following message, then everything now works fine.
|
51
51
|
|
52
52
|
```
|
53
|
-
Midori 0.1.
|
53
|
+
Midori 0.1.12 is now running on 127.0.0.1:8080
|
54
54
|
```
|
55
55
|
|
56
56
|
## Use Bundler
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
## Basic Usage
|
4
4
|
|
5
|
-
Routes should be defined inside a class inherited from `Midori::API`. Midori doesn't support defining routes
|
5
|
+
Routes should be defined inside a class inherited from `Midori::API`. Midori doesn't support defining routes globally like sinatra to avoid scope pollution, which affects a lot in scaling project.
|
6
6
|
|
7
7
|
In midori, a route is an HTTP method with a URL-matching pattern. Each route is associated with a block:
|
8
8
|
|
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.
|
4
|
+
version: 0.2.0
|
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-
|
11
|
+
date: 2017-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nio4r
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0
|
33
|
+
version: '1.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0
|
40
|
+
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: midori_http_parser
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,7 +59,9 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
+
- ".editorconfig"
|
62
63
|
- LICENSE
|
64
|
+
- em-midori.sublime-project
|
63
65
|
- lib/midori.rb
|
64
66
|
- lib/midori/api.rb
|
65
67
|
- lib/midori/api_engine.rb
|
@@ -135,7 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
137
|
version: '0'
|
136
138
|
requirements: []
|
137
139
|
rubyforge_project:
|
138
|
-
rubygems_version: 2.6.
|
140
|
+
rubygems_version: 2.6.10
|
139
141
|
signing_key:
|
140
142
|
specification_version: 4
|
141
143
|
summary: High performance ruby web framework
|