em-midori 0.1.12 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ad463d2a5c54f9995812d347d0f428752414d77
4
- data.tar.gz: 9a9ea6eb52f59bf540e7dc37d24a6581393a439d
3
+ metadata.gz: d890861f5486fd8c8ecd3dff2a3780a26af42340
4
+ data.tar.gz: 1d6ddf047c3534998eb6637cfbe387d56f1e86f2
5
5
  SHA512:
6
- metadata.gz: bf12420ff582c13a143a872462284f3232472decff29a686286d931eb5fac60371182a313e0327c41281eea5a8a673913dd59eeebf560a8ecc99a4245aeaca9b
7
- data.tar.gz: b40da8f51f4c39e5b9dd46a5944c17b0672425ffa5869a14a5880df85d0ce9bd92c19daa7433131624e4b93308ecf69d09f8c0e5afb3c0edcc3b4111957c3066
6
+ metadata.gz: 2664bb10cda5ab00f264bd91e633315ab2f05fb44218050597fc61c34890fa00bf042d3a476e24711415b9eb8d28e2a4b94f2225bb307f1f1e77c1fffde468d6
7
+ data.tar.gz: 884cce78c3c28f9014823b45d03529082d7ff4c6832be0bfaa490265a08a7a05ad2b3ed7d5447074edbb6d3e06d32a0006004116afece1b442511f417583d33e
data/.editorconfig ADDED
@@ -0,0 +1,9 @@
1
+ root = true
2
+
3
+ [*]
4
+ end_of_line = lf
5
+ insert_final_newline = true
6
+
7
+ [*.rb]
8
+ indent_style = space
9
+ indent_size = 2
@@ -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
+ }
@@ -39,6 +39,8 @@ class Midori::Connection
39
39
  def close_connection
40
40
  EventLoop.deregister @socket
41
41
  @socket.close
42
+ rescue Errno::EBADF
43
+ # Connection finished in advance
42
44
  end
43
45
 
44
46
  def close_connection_after_writing
@@ -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
- monitor = SELECTOR.register(io, interest)
15
- monitor.value = {
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 1 secs
27
- monitor.value[:timer].stop unless monitor.value[:timer].nil?
28
- monitor.value[:callback].call(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
@@ -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
- EventLoop.register(@io.to_io, interest) do
7
- EventLoop.deregister(@io.to_io)
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
- socket = IO::open(conn.socket)
40
- await(Promise.new do |resolve|
41
- EventLoop.register(socket, :w) do
42
- EventLoop.deregister(socket)
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
- EventLoop.register(socket, :r) do
53
- EventLoop.deregister(socket)
54
- resolve.call(conn.async_result)
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
- socket_object = IO.for_fd(socket)
14
- await(Promise.new do |resolve|
15
- EventLoop.register(socket_object, :w) do
16
- unless is_busy
17
- EventLoop.deregister(socket_object)
18
- send_query(sql)
19
- resolve.call
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.error "#{@request.ip} - - Reached an EOF Error".red
46
+ @logger.warn "#{@request.ip} - - Reached an EOF Error".yellow
47
47
  end
48
48
  end)
49
49
  end.call
@@ -1,5 +1,5 @@
1
1
  # Midori Module
2
2
  module Midori
3
3
  # Current Version Code
4
- VERSION = '0.1.12'.freeze
4
+ VERSION = '0.2.0'.freeze
5
5
  end
@@ -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.7
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.7 is now running on 127.0.0.1:8080
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 globally like sinatra to avoid scope pollution, which affects a lot in scaling project.
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.1.12
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-02-25 00:00:00.000000000 Z
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.4'
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.4'
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.8
140
+ rubygems_version: 2.6.10
139
141
  signing_key:
140
142
  specification_version: 4
141
143
  summary: High performance ruby web framework