io_daemonizer 4 → 7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/io_daemonizer.rb +70 -8
  3. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32930632de1bc82574c36effe2665f42e3759f1260142d185dad0deed19f3ded
4
- data.tar.gz: e86887bcd129dc4997febb337779420a5bcd644e17489b6e395a90c19fa91b69
3
+ metadata.gz: 659f573346f478e82593492d57366baa4f704cdad86495f71f9e14d3ab656e53
4
+ data.tar.gz: '028c6285884760b1a2fa0330844128c1f63a713bc6efa1b2e6775f4ae3dcd64d'
5
5
  SHA512:
6
- metadata.gz: 0d45b854ab37c9dfc7bc06ae83ced4c1ef2b82b59fb94f0d5ba8bf5042e96732b5afc9514e982242faf9bcc72ff18bf2b1fc2d695ed83cf39f5986186dbdb1b2
7
- data.tar.gz: 38ad97f6c54e41d057a4d6c0dacb41420b273d8549560fe75da9cf87e443acb513ca0c12044ef260f4d6e9a5dfbe11ed9609620589298b1aff23adcfcd660e1d
6
+ metadata.gz: ebb22484722226e4761a4a29176f9b62f95513f693653c93adc7deb815f491b5b5711579c8ba29cf2810bb9c16f3e8539201cc287607ac4cf4e73074b35e21fc
7
+ data.tar.gz: 3ee8bd1928ca173f3ccd5d9e10e47809bac6224f8e5d2eacece6aaf45d97328d5fcceae3201e3f7dbbe2d8df9059d5cf93dbd2401d117ae2223e224969a53d03
data/io_daemonizer.rb CHANGED
@@ -1,11 +1,12 @@
1
- # io_daemonizer v.4 https://github.com/joeyschoblaska/io_daemonizer
1
+ # io_daemonizer v.7.1 https://github.com/joeyschoblaska/io_daemonizer
2
2
 
3
+ require "json"
3
4
  require "shellwords"
4
5
  require "socket"
5
6
  require "stringio"
6
7
 
7
8
  class IODaemonizer
8
- def self.wrap(port:, setup:, run:)
9
+ def self.wrap(port:, setup:, run:, autostart: true)
9
10
  case ARGV[0]
10
11
  when "start"
11
12
  puts "starting server..."
@@ -14,18 +15,28 @@ class IODaemonizer
14
15
  puts "stopping server..."
15
16
  send_request(port: port, args: ARGV)
16
17
  else
17
- send_request(port: port, args: ARGV)
18
+ begin
19
+ send_request(port: port, args: ARGV)
20
+ rescue Errno::ECONNREFUSED => e
21
+ raise(e) unless autostart
22
+ Daemon.run(port: port, setup: setup, run: run, fork: true)
23
+ sleep 0.1
24
+ send_request(port: port, args: ARGV)
25
+ end
18
26
  end
19
27
  rescue Errno::ECONNREFUSED
20
28
  puts "server not running or not responding"
21
29
  end
22
30
 
23
31
  def self.send_request(port:, args:)
32
+ consumer = LabeledIOConsumer.new
33
+
24
34
  TCPSocket.open("127.0.0.1", port) do |socket|
25
35
  socket.puts args.shelljoin
26
36
  socket.write $stdin.tty? ? "" : $stdin.read
27
37
  socket.close_write
28
- STDOUT.write(socket.read(4096)) until socket.eof?
38
+
39
+ consumer.write(socket.read) until socket.eof?
29
40
  end
30
41
  end
31
42
 
@@ -39,10 +50,10 @@ class IODaemonizer
39
50
  end
40
51
 
41
52
  class Daemon
42
- def self.run(port:, setup:, run:)
53
+ def self.run(port:, setup:, run:, fork: false)
43
54
  daemon = new(port: port, setup: setup, run: run)
44
55
  daemon.setup
45
- daemon.start
56
+ fork ? Kernel.fork { daemon.start } : daemon.start
46
57
  end
47
58
 
48
59
  def initialize(port:, setup:, run:)
@@ -73,14 +84,65 @@ class IODaemonizer
73
84
  else
74
85
  IODaemonizer.redirect(
75
86
  stdin: StringIO.new(body.join),
76
- stdout: socket,
77
- stderr: socket
87
+ stdout: IOLabeler.new(1, socket, "stdout"),
88
+ stderr: IOLabeler.new(2, socket, "stderr")
78
89
  ) { @context.instance_exec args, &@run }
79
90
  end
80
91
  rescue => e
81
92
  socket.write e.inspect
93
+ raise e
82
94
  ensure
95
+ socket.close_write
83
96
  socket.close
84
97
  end
85
98
  end
99
+
100
+ class IOLabeler < IO
101
+ attr_reader :label
102
+
103
+ def initialize(fd, socket, label)
104
+ super(fd)
105
+ @socket = socket
106
+ @label = label
107
+ end
108
+
109
+ def write(chunk)
110
+ @socket.write({ @label => chunk }.to_json)
111
+ end
112
+
113
+ def reopen(io)
114
+ @label = io&.label || @label
115
+ end
116
+ end
117
+
118
+ class LabeledIOConsumer
119
+ def initialize
120
+ @buffer = ""
121
+ end
122
+
123
+ def write(chunk)
124
+ chunk.chars.each do |ch|
125
+ @buffer << ch
126
+ process_buffer if ch == "}"
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ def process_buffer
133
+ parsed = JSON.parse(@buffer)
134
+ key = parsed.keys[0]
135
+ value = parsed.values[0]
136
+
137
+ case key
138
+ when "stdout"
139
+ $stdout.write(value)
140
+ when "stderr"
141
+ $stderr.write(value)
142
+ end
143
+
144
+ @buffer = ""
145
+ rescue JSON::ParserError
146
+ end
147
+ end
86
148
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io_daemonizer
3
3
  version: !ruby/object:Gem::Version
4
- version: '4'
4
+ version: '7.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joey Schoblaska
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-06 00:00:00.000000000 Z
11
+ date: 2022-09-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Wrap a Ruby script that speaks IO in a daemon so that you only pay the
14
- startup overhead once.
13
+ description: Wrap a Ruby script that speaks stdio in a daemon so that you only pay
14
+ the startup overhead once.
15
15
  email: joey.schoblaska@gmail.com
16
16
  executables: []
17
17
  extensions: []