plux 0.1.3 → 0.1.8
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/Gemfile.lock +3 -1
- data/README.md +33 -8
- data/lib/plux.rb +5 -2
- data/lib/plux/engine.rb +21 -0
- data/lib/plux/reactor.rb +76 -0
- data/lib/plux/server.rb +11 -34
- data/lib/plux/version.rb +1 -1
- data/plux.gemspec +2 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccf41ebecbdaa05e45295b9a3237cf72710d435459c4031b8d19c3ce1806165f
|
4
|
+
data.tar.gz: 61ab35e88507321b06de9c1c4e9fabcfdabfd1c7d5333bcb1cf7b1195b6a9b10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ddb55b3ab4d9a5544ba0ba3780d30a63decab60197cc97ea431d68d313bc6c9a0e91b17dfa9cf54f25848eee10f2ade27e5790d5f454a13bc063759811bf729
|
7
|
+
data.tar.gz: 4cda0ff1be89717a676b5622e221a227d426cbc08ede6bb86faf4bc8a0e12c525965a5eafcb29f90f345ec8f3627946ba5e2f2f0ca09d553926e1ebf80f6e186
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
plux (0.1.
|
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
|
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
|
34
|
+
def process(msg)
|
35
35
|
# @db << parse(msg)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
#
|
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
|
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.
|
data/lib/plux.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/plux/engine.rb
ADDED
@@ -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
|
data/lib/plux/reactor.rb
ADDED
@@ -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
|
data/lib/plux/server.rb
CHANGED
@@ -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(
|
17
|
+
def boot(worker)
|
14
18
|
Plux.lock_pid_file(name) do |file|
|
15
|
-
start_server_if_not_pid(file,
|
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,
|
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
|
43
|
-
|
44
|
-
|
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
|
data/lib/plux/version.rb
CHANGED
data/plux.gemspec
CHANGED
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
|
+
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-
|
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
|