plux 0.1.3 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 472f8a38bccdb6c63b10b4291c4cd109598e8819222c4061dd673f3491d58344
4
- data.tar.gz: 489ce27db397a3df71058642b8f3dab80ac255cf1ace82f66c12d80980de4efc
3
+ metadata.gz: ccf41ebecbdaa05e45295b9a3237cf72710d435459c4031b8d19c3ce1806165f
4
+ data.tar.gz: 61ab35e88507321b06de9c1c4e9fabcfdabfd1c7d5333bcb1cf7b1195b6a9b10
5
5
  SHA512:
6
- metadata.gz: 565721905d9e193557d56c78a323f35bd41e1650bb7592607534a6da3cf9f961d66801b2a169477f9b3b2019f06d45e1e08bcda6b146d855d5018b11ba5a6231
7
- data.tar.gz: 32d1c59b0a5b169e9ed33302d576dc3d87e42ba376d9f927f61a34d1f5b8bcdf44582fe11a547de0d62c1827158248dfb6293df8fd06cdaa5716f23bcb313741
6
+ metadata.gz: 8ddb55b3ab4d9a5544ba0ba3780d30a63decab60197cc97ea431d68d313bc6c9a0e91b17dfa9cf54f25848eee10f2ade27e5790d5f454a13bc063759811bf729
7
+ data.tar.gz: 4cda0ff1be89717a676b5622e221a227d426cbc08ede6bb86faf4bc8a0e12c525965a5eafcb29f90f345ec8f3627946ba5e2f2f0ca09d553926e1ebf80f6e186
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plux (0.1.3)
4
+ plux (0.1.6)
5
+ nio4r (~> 2.0)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
@@ -9,6 +10,7 @@ GEM
9
10
  coderay (1.1.2)
10
11
  method_source (0.9.2)
11
12
  minitest (5.14.1)
13
+ nio4r (2.5.4)
12
14
  pry (0.12.2)
13
15
  coderay (~> 1.1.0)
14
16
  method_source (~> 0.9.0)
data/README.md CHANGED
@@ -21,32 +21,57 @@ Or install it yourself as:
21
21
  ## Usage
22
22
 
23
23
  ```ruby
24
- # start one and only process named 'abc',
24
+ # start one and only process named 'abc', with 2 threads in it (1 thread if not specified),
25
25
  # no matter the code below is called how many times in whatever processes/threads
26
- server = Plux.worker(:abc) do
26
+ server = Plux.worker(:abc, thread: 2) do
27
27
 
28
- # prepare resources like mq/db, to handle requests
29
- def initialize
28
+ # prepare thread-safe resources like mq/db, to handle requests
29
+ def prepare
30
30
  # @db = ...
31
31
  end
32
32
 
33
33
  # threads call this method to deal with clients' message
34
- def work(msg)
34
+ def process(msg)
35
35
  # @db << parse(msg)
36
36
  end
37
37
  end
38
38
 
39
- # five threads will be started to handle these clients,
40
- # and finished once their counterparts call close
39
+ # clients connect, send msg, and close concurrently
41
40
  5.times do |n|
42
41
  Thread.new do
43
42
  client = server.connect
44
- client.puts "hello #{n}"
43
+ client.puts "hello"
44
+ client.puts "my name is #{n}"
45
45
  client.close
46
46
  end
47
47
  end
48
48
  ```
49
49
 
50
+ Also, you can boot multiple servers(processes) with same logic:
51
+
52
+ ```ruby
53
+ class AwesomeServer < Plux::Engine
54
+ # prepare thread-safe resources like mq/db, to handle requests
55
+ def prepare
56
+ # @db = ...
57
+ end
58
+
59
+ # threads call this method to deal with clients' message
60
+ def process(msg)
61
+ # @db << parse(msg)
62
+ end
63
+ end
64
+
65
+ a = AwesomeServer.new(:a)
66
+ b = AwesomeServer.new(:b)
67
+ c = AwesomeServer.new(:c, thread: 4)
68
+
69
+ a_client = a.connect
70
+ b_client = b.connect
71
+ c_client = c.connect
72
+ c_client_2 = c.connect
73
+ ```
74
+
50
75
  ## Development
51
76
 
52
77
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -4,6 +4,7 @@ require "plux/version"
4
4
  require "plux/server"
5
5
  require "plux/client"
6
6
  require "plux/parser"
7
+ require "plux/engine"
7
8
 
8
9
 
9
10
  module Plux
@@ -32,10 +33,12 @@ module Plux
32
33
  File.join(dir, "#{server_name}.so")
33
34
  end
34
35
 
35
- def worker(name, &block)
36
- Server.new(name).boot(block)
36
+ def worker(name, thread: 1, &block)
37
+ worker = Class.new(&block).new
38
+ Server.new(name, thread: thread).boot(worker)
37
39
  end
38
40
  end
39
41
 
40
42
  FileUtils.mkdir_p(self.dir)
43
+
41
44
  end
@@ -0,0 +1,21 @@
1
+ module Plux
2
+ class Engine
3
+
4
+ attr_reader :name
5
+
6
+ def initialize(name, thread: 1)
7
+ @name = name
8
+ @server = Server.new(name, thread: thread).boot(self)
9
+ end
10
+
11
+ def connect
12
+ @server.connect
13
+ end
14
+
15
+ def prepare
16
+ end
17
+
18
+ def process(msg)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,76 @@
1
+ module Plux
2
+ class Reactor
3
+ def initialize(count, worker)
4
+ @worker = worker
5
+ @msg_q = Queue.new
6
+ @count = count
7
+
8
+ @nio = NIO::Selector.new
9
+ @newly_accepted = Queue.new
10
+ @closed = []
11
+
12
+ receive
13
+ process
14
+ end
15
+
16
+ def register(socket)
17
+ @newly_accepted << socket
18
+ @nio.wakeup
19
+ end
20
+
21
+ private
22
+
23
+ def receive
24
+ Thread.new do
25
+ loop do
26
+ @closed.size.times{ @nio.deregister(@closed.pop) }
27
+
28
+ @newly_accepted.size.times do
29
+ socket = @newly_accepted.pop
30
+ mon = @nio.register(socket, :r)
31
+ mon.value = Worker.new(socket, @msg_q)
32
+ end
33
+
34
+ @nio.select do |m|
35
+ next if m.value.process
36
+ @closed << m.io
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def process
43
+ @count.times.each do
44
+ Thread.new do
45
+ loop{ @worker.process(@msg_q.deq) }
46
+ end
47
+ end
48
+ end
49
+
50
+ class Worker
51
+ def initialize(socket, q)
52
+ @parser = Parser.new
53
+ @socket = socket
54
+ @q = q
55
+ end
56
+
57
+ def process
58
+ stream = @socket.read_nonblock(Parser::STREAM_MAX_LEN, exception: false)
59
+ return true if stream == :wait_readable
60
+
61
+ msgs = @parser.decode(stream)
62
+ last_msg = msgs.pop
63
+
64
+ msgs.each{ |msg| @q << msg }
65
+ if last_msg == Parser::LAST_MSG
66
+ @socket.close
67
+ return false
68
+ end
69
+ @q << last_msg
70
+
71
+ true
72
+ end
73
+ end
74
+
75
+ end
76
+ end
@@ -1,3 +1,6 @@
1
+ require "nio"
2
+ require "plux/reactor"
3
+
1
4
  module Plux
2
5
 
3
6
  class Server
@@ -6,13 +9,14 @@ module Plux
6
9
  Active = {}
7
10
  at_exit{ Active.values.each(&:close) }
8
11
 
9
- def initialize(name)
12
+ def initialize(name, thread: )
10
13
  @name = name
14
+ @thread = thread
11
15
  end
12
16
 
13
- def boot(block)
17
+ def boot(worker)
14
18
  Plux.lock_pid_file(name) do |file|
15
- start_server_if_not_pid(file, block)
19
+ start_server_if_not_pid(file, worker)
16
20
  end
17
21
  self
18
22
  end
@@ -27,7 +31,7 @@ module Plux
27
31
 
28
32
  private
29
33
 
30
- def start_server_if_not_pid(file, block)
34
+ def start_server_if_not_pid(file, worker)
31
35
  @pid = file.read.to_i
32
36
  return unless pid == 0
33
37
 
@@ -39,11 +43,9 @@ module Plux
39
43
  child.close
40
44
  UNIXServer.open(Plux.server_file(name)) do |serv|
41
45
  parent.close
42
- worker = Class.new(&block).new
43
- loop do
44
- socket = serv.accept
45
- Worker.new(socket, worker)
46
- end
46
+ worker.prepare
47
+ reactor = Reactor.new(@thread, worker)
48
+ loop{ reactor.register(serv.accept) }
47
49
  end
48
50
  end
49
51
 
@@ -62,31 +64,6 @@ module Plux
62
64
  File.delete(Plux.send(file, name))
63
65
  end
64
66
  end
65
-
66
- class Worker
67
- def initialize(socket, worker)
68
- par = Parser.new
69
- t = Thread.new do
70
- loop do
71
- begin
72
- stream = socket.read_nonblock(Parser::STREAM_MAX_LEN)
73
- rescue IO::WaitReadable
74
- IO.select([socket])
75
- retry
76
- end
77
-
78
- msgs = par.decode(stream)
79
- last_msg = msgs.pop
80
-
81
- msgs.each{ |msg| worker.work(msg) }
82
- break if last_msg == Parser::LAST_MSG
83
- worker.work(last_msg)
84
- end
85
- socket.close
86
- end
87
- end
88
- end
89
-
90
67
  end
91
68
 
92
69
  end
@@ -1,3 +1,3 @@
1
1
  module Plux
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -23,4 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "minitest", "~> 5.0"
25
25
  spec.add_development_dependency "pry"
26
+
27
+ spec.add_dependency "nio4r", "~> 2.0"
26
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plux
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - ken
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-13 00:00:00.000000000 Z
11
+ date: 2020-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nio4r
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
69
83
  description:
70
84
  email:
71
85
  - block24block@gmail.com
@@ -85,7 +99,9 @@ files:
85
99
  - bin/setup
86
100
  - lib/plux.rb
87
101
  - lib/plux/client.rb
102
+ - lib/plux/engine.rb
88
103
  - lib/plux/parser.rb
104
+ - lib/plux/reactor.rb
89
105
  - lib/plux/server.rb
90
106
  - lib/plux/version.rb
91
107
  - plux.gemspec