io_daemonizer 4 → 7.1

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.
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: []