Class: QB::IPC::STDIO::Server
- Inherits:
-
Object
- Object
- QB::IPC::STDIO::Server
- Includes:
- NRSER::Log::Mixin
- Defined in:
- lib/qb/ipc/stdio/server.rb
Overview
There is also a InService for STDIN
, but it's is pretty experimental /
broken at this point. That would be nice to fix in the future so that
programs that make use of user interaction work seamlessly through QB.
This will probably require using pseudo-TTY streams or whatever mess.
This feature only works for localhost
. I have no idea what it will do
in other cases. It doesn't seem like it should break anything, but remotely
executing modules definitely won't be able to connect to the sockets on
the host.
Server functionality to make the master QB process' STDIO streams available to external processes, specifically Ansible modules.
Ansible's handling of STDIO in modules is really not suitable for our use case - we want to see what modules and other external process commands are doing in real time, much like invoking them in a Bash script.
This thing is far from perfect, but it's been incredibly helpful for a simple solution.
Basically, OutService instances are created for STDOUT
and STDERR
,
which each create a UNIXServer on a local socket file and spawn a Thread
to listen to it. The socket's path is then made available to the Ansible
child process via ENV vars, and that process in turn carries those ENV vars
to it's module child processes, who can then use an instance of the
corresponding Client class to connect to those sockets and
write output that is passed through to the master QB process' output streams.
The protocol is simply text line-based, and modules - or any other process - written in other languages can easily connect and write as well.
Defined Under Namespace
Classes: InService, LogService, OutService, Service
Instance Attribute Summary collapse
-
#socket_dir ⇒ Pathname
readonly
Where the UNIX socket files get put.
Class Method Summary collapse
-
.clean_up_for(object_id:, services:, socket_dir:) ⇒ nil
Clean up resources for an instance.
-
.finalizer_for(**kwds) ⇒ Proc<() => nil>
Make a Proc to use for finalization.
Instance Method Summary collapse
-
#initialize ⇒ Server
constructor
Instantiate a new
QB::IPC::STDIO::Server
. -
#services ⇒ Array<(InService, OutService, OutService)>
Array of in, out and err services.
-
#start! ⇒ self
Start all the #services by calling Service#open! on them.
-
#stop! ⇒ self
Stop all #services by calling Service#close! on them and clean up the resources.
Constructor Details
#initialize ⇒ Server
Instantiate a new QB::IPC::STDIO::Server
.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/qb/ipc/stdio/server.rb', line 163 def initialize @socket_dir = Dir.mktmpdir( 'qb-ipc-stdio' ).to_pn @in_service = QB::IPC::STDIO::Server::InService.new \ name: :in, socket_dir: socket_dir, src: $stdin @out_service = QB::IPC::STDIO::Server::OutService.new \ name: :out, socket_dir: socket_dir, dest: $stdout @err_service = QB::IPC::STDIO::Server::OutService.new \ name: :err, socket_dir: socket_dir, dest: $stderr @log_service = QB::IPC::STDIO::Server::LogService.new \ name: :log, socket_dir: socket_dir ObjectSpace.define_finalizer \ self, self.class.finalizer_for( object_id: object_id, services: services, socket_dir: socket_dir ) end |
Instance Attribute Details
#socket_dir ⇒ Pathname (readonly)
Where the UNIX socket files get put.
155 156 157 |
# File 'lib/qb/ipc/stdio/server.rb', line 155 def socket_dir @socket_dir end |
Class Method Details
.clean_up_for(object_id:, services:, socket_dir:) ⇒ nil
Clean up resources for an instance. Broken out because I was trying to make it run as a finalizer to remove the directory in all cases, but that does not seem to be triggering. Whatever man...
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/qb/ipc/stdio/server.rb', line 106 def self.clean_up_for object_id:, services:, socket_dir: logger.debug "Cleaning up...", object_id: object_id, socket_dir: socket_dir services.each do |service| logger.catch.warn( "Unable to close service", service: service, ) { service.close! } end FileUtils.rm_rf( socket_dir ) if socket_dir.exist? logger.debug "Clean!", object_id: object_id, socket_dir: socket_dir nil end |
.finalizer_for(**kwds) ⇒ Proc<() => nil>
Make a Proc to use for finalization.
Needs to be done outside instance scope to doesn't close over the instance.
139 140 141 142 143 144 145 |
# File 'lib/qb/ipc/stdio/server.rb', line 139 def self.finalizer_for **kwds -> { logger.debug "Finalizing...", **kwds clean_up_for **kwds logger.debug "Finalized", **kwds } end |
Instance Method Details
#services ⇒ Array<(InService, OutService, OutService)>
Returns Array of in, out and err services.
201 202 203 |
# File 'lib/qb/ipc/stdio/server.rb', line 201 def services [ @in_service, @out_service, @err_service, @log_service ] end |
#start! ⇒ self
Start all the #services by calling QB::IPC::STDIO::Server::Service#open! on them.
210 211 212 213 |
# File 'lib/qb/ipc/stdio/server.rb', line 210 def start! services.each &:open! self end |
#stop! ⇒ self
Stop all #services by calling QB::IPC::STDIO::Server::Service#close! on them and clean up the resources.
221 222 223 224 225 226 227 |
# File 'lib/qb/ipc/stdio/server.rb', line 221 def stop! self.class.clean_up_for \ object_id: object_id, services: services, socket_dir: socket_dir self end |