plux 0.1.4 → 0.1.5

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
  SHA256:
3
- metadata.gz: 06c8e6b4eae44651cb3ba6e01503710c25b1746e11ae2c339bbe37225200e5bc
4
- data.tar.gz: 92c320fe5e1c92078bd87d09c78bb0e76224a5ed9e1fc18604056d8ccdb23eea
3
+ metadata.gz: 56011d823e56b1bd06759d5546edc8519338a99392ce980ebc6033b7f458cd0f
4
+ data.tar.gz: 7b3353cbbb07daa6394aceb3fefa830c438c797a455352d6283c6a71942cdb59
5
5
  SHA512:
6
- metadata.gz: 8957056c62d9cc90a236e0bf2eb06d8d38cfd3cb8b1054d812c08741b672c0ebc2e3b545111ea5bf4825b3955e21cb748b1c6df727f2fc8748eb8eaa17c169d9
7
- data.tar.gz: b7aed8c1662ab951728321576bd611bb5d402557e2d01d2b5943b644fec92b9eb0d312612bcdf725162f0647da4a54f7cc01ff3e3dc8e5a9b34c54fb6b1a66b5
6
+ metadata.gz: f2c201408eb9e5d0d2b19d1eabf0908324645ef2b95b922bda8e1ec3f2b39d988b58ebfb50c1fc17ec2e0522900122956b65fd2bdda4285785e42f4b28ff0838
7
+ data.tar.gz: 4ac2ab94501c97a09d3416d3dcf0837a04ecafc12050b0f8346f30a541e088059761ede6b7c674c9c1e720380a95b7bf1adc46d9c0df52c2dfa70a53132bcfb0
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- plux (0.1.4)
4
+ plux (0.1.5)
5
5
  nio4r (~> 2.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -25,7 +25,7 @@ Or install it yourself as:
25
25
  # no matter the code below is called how many times in whatever processes/threads
26
26
  server = Plux.worker(:abc, thread: 2) do
27
27
 
28
- # prepare resources like mq/db, to handle requests
28
+ # prepare thread-safe resources like mq/db, to handle requests
29
29
  def initialize
30
30
  # @db = ...
31
31
  end
@@ -36,11 +36,12 @@ server = Plux.worker(:abc, thread: 2) do
36
36
  end
37
37
  end
38
38
 
39
- # the 2 threads will handle these 5 clients
39
+ # clients connect, send msg, and close concurrently
40
40
  5.times do |n|
41
41
  Thread.new do
42
42
  client = server.connect
43
- client.puts "hello #{n}"
43
+ client.puts "hello"
44
+ client.puts "my name is #{n}"
44
45
  client.close
45
46
  end
46
47
  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.work(@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,5 +1,5 @@
1
1
  require "nio"
2
- require "plux/reactors"
2
+ require "plux/reactor"
3
3
 
4
4
  module Plux
5
5
 
@@ -44,8 +44,8 @@ module Plux
44
44
  UNIXServer.open(Plux.server_file(name)) do |serv|
45
45
  parent.close
46
46
  worker = Class.new(&block).new
47
- reactors = Reactors.new(@thread, worker)
48
- loop{ reactors.register(serv.accept) }
47
+ reactor = Reactor.new(@thread, worker)
48
+ loop{ reactor.register(serv.accept) }
49
49
  end
50
50
  end
51
51
 
@@ -1,3 +1,3 @@
1
1
  module Plux
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  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.4
4
+ version: 0.1.5
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-19 00:00:00.000000000 Z
11
+ date: 2020-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,7 +100,7 @@ files:
100
100
  - lib/plux.rb
101
101
  - lib/plux/client.rb
102
102
  - lib/plux/parser.rb
103
- - lib/plux/reactors.rb
103
+ - lib/plux/reactor.rb
104
104
  - lib/plux/server.rb
105
105
  - lib/plux/version.rb
106
106
  - plux.gemspec
@@ -1,91 +0,0 @@
1
- module Plux
2
- class Reactors
3
- def initialize(count, worker)
4
- @lock = Mutex.new
5
- @reactor_loops = count.times.each_with_object({}) do |r, hash|
6
- hash[Reactor.new(worker, self)] = 0
7
- end
8
- end
9
-
10
- def register(socket)
11
- @lock.synchronize do
12
- reactor = @reactor_loops.sort_by{ |_, v| v }.first.first
13
- reactor.register(socket)
14
- end
15
- end
16
-
17
- def timer(reactor, duration)
18
- @lock.synchronize{ @reactor_loops[reactor] += duration }
19
- end
20
-
21
- class Reactor
22
- def initialize(worker, reactors)
23
- @worker = worker
24
- @reactors = reactors
25
-
26
- @nio = NIO::Selector.new
27
- @newly_accepted = Queue.new
28
- @closed = []
29
-
30
- run
31
- end
32
-
33
- def register(socket)
34
- @newly_accepted << socket
35
- @nio.wakeup
36
- end
37
-
38
- private
39
-
40
- def run
41
- Thread.new do
42
- loop do
43
- @closed.size.times{ @nio.deregister(@closed.pop) }
44
-
45
- @newly_accepted.size.times do
46
- socket = @newly_accepted.pop
47
- mon = @nio.register(socket, :r)
48
- mon.value = Worker.new(socket, @worker)
49
- end
50
-
51
- start = Time.now.to_i
52
-
53
- next unless @nio.select do |m|
54
- next if m.value.process
55
- @closed << m.io
56
- end
57
-
58
- @reactors.timer(self, Time.now.to_i - start)
59
- end
60
- end
61
- end
62
- end
63
-
64
- class Worker
65
- def initialize(socket, worker)
66
- @parser = Parser.new
67
- @socket = socket
68
- @worker = worker
69
- end
70
-
71
- def process
72
- 10.times do
73
- stream = @socket.read_nonblock(Parser::STREAM_MAX_LEN, exception: false)
74
- return true if stream == :wait_readable
75
-
76
- msgs = @parser.decode(stream)
77
- last_msg = msgs.pop
78
-
79
- msgs.each{ |msg| @worker.work(msg) }
80
- if last_msg == Parser::LAST_MSG
81
- @socket.close
82
- return false
83
- end
84
- @worker.work(last_msg)
85
- end
86
- true
87
- end
88
- end
89
-
90
- end
91
- end