Better CLI messages, better comments, cleaner code.
parent
e2bb0b3122
commit
d9c53342dc
|
@ -2,6 +2,8 @@ shard.lock
|
||||||
bin
|
bin
|
||||||
drop
|
drop
|
||||||
lib
|
lib
|
||||||
|
rules/
|
||||||
|
redirections/
|
||||||
|
|
||||||
pongd
|
pongd
|
||||||
pongc
|
pongc
|
||||||
|
|
126
src/ipcd.cr
126
src/ipcd.cr
|
@ -67,17 +67,33 @@ module IPCd
|
||||||
|
|
||||||
def to_s(io : IO)
|
def to_s(io : IO)
|
||||||
io << "ipcd\n"
|
io << "ipcd\n"
|
||||||
io << @rules.to_s + "\n" + @redirections.to_s
|
@rules.to_s(io)
|
||||||
|
@redirections.to_s(io)
|
||||||
end
|
end
|
||||||
|
|
||||||
# The client asks to ipcd to open a connection to a service
|
# Client => ipcd => Service.
|
||||||
# the service name is used unless there is a redirection that is provided to the client through
|
# ipcd creates a network connection to the remote host,
|
||||||
# a IPC_NETWORK environment variable
|
# then provides a file descriptor to the client.
|
||||||
# This environment variable is sent from the client to ipcd, that's what is parsed here
|
# Besides ipcd configuration, the client shares its IPC_NETWORK
|
||||||
|
# environment variable to ipcd to understand how to contact the service.
|
||||||
|
|
||||||
# parse_lookup_payload extract the right service URI to use from the IPC_NETWORK content
|
# IPC_NETWORK environment variable contains pairs of URIs (redirections).
|
||||||
# sent by the client in the form:
|
# Format: "requested-service new-URI"
|
||||||
# `requested-service-name;service1 uri;service2 uri;...` etc.
|
# Example: "pong tcp://example.com:8000/pong"
|
||||||
|
#
|
||||||
|
# The URI indicates the scheme, the domain (or directly the IP address) and the port
|
||||||
|
# to contact the remote service. The path indicates the remote service to use.
|
||||||
|
#
|
||||||
|
# Several redirections can be put into the IPC_NETWORK variable, using a semi-colon.
|
||||||
|
# Example: "pong tcp://example.com/pong;auth tls://example.com:9000/auth"
|
||||||
|
|
||||||
|
# ipcd prioritises IPC_NETWORK over its own configuration for redirections.
|
||||||
|
# This environment variable is sent from the client to ipcd, that's what is parsed here.
|
||||||
|
|
||||||
|
# parse_lookup_payload extracts the right service URI to use from the message sent by
|
||||||
|
# a client, containing the service to contact and the IPC_NETWORK content.
|
||||||
|
# Format: "requested-service;IPC_NETWORK content"
|
||||||
|
# Example: "pong;pong tcp://example.com:3000/pong-8"
|
||||||
def self.parse_lookup_payload (payload : String) : URI
|
def self.parse_lookup_payload (payload : String) : URI
|
||||||
items = payload.split (";")
|
items = payload.split (";")
|
||||||
requested_service_name = items.delete_at(0).chomp()
|
requested_service_name = items.delete_at(0).chomp()
|
||||||
|
@ -85,30 +101,27 @@ module IPCd
|
||||||
|
|
||||||
services_redirections = {} of String => URI
|
services_redirections = {} of String => URI
|
||||||
|
|
||||||
# from each item (separated by a semicolon), get the service name and the new uri to use
|
# Format: "service-name URI;service-name URI"
|
||||||
# format: `service-name uri;service-name uri`
|
# URI can be:
|
||||||
# uri can be:
|
|
||||||
# * distant service (with protocol to use): https://some.example.com/pong
|
# * distant service (with protocol to use): https://some.example.com/pong
|
||||||
# * local service: "local:newpong" or simply "newpong"
|
# * local service: "local:newpong" or simply "newpong"
|
||||||
items.each do |item|
|
items.each do |item|
|
||||||
x = /([^ ]+) ([^ ]+)/.match(item)
|
case item
|
||||||
unless x.nil?
|
when /(?<origin>[^ ]+) +(?<destination_uri>[^ ]+)/
|
||||||
service, newuri = x.captures()
|
origin, destination_uri = $~["origin"], $~["destination_uri"]
|
||||||
if service.nil?
|
uri = URI.parse destination_uri
|
||||||
next
|
if uri.scheme.nil?
|
||||||
elsif newuri.nil?
|
uri = URI.parse "unix:///#{destination_uri}"
|
||||||
next
|
|
||||||
end
|
end
|
||||||
|
services_redirections[origin] = uri
|
||||||
Baguette::Log.debug "service: #{service} redirection uri: #{newuri}"
|
else
|
||||||
uri = URI.parse newuri
|
Baguette::Log.error "cannot understand configuration #{item}"
|
||||||
services_redirections[service] = uri
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
services_redirections.each do |k, v|
|
services_redirections.each do |k, v|
|
||||||
Baguette::Log.debug "possible redirection (from env. var.): service: #{k} uri: #{v}"
|
|
||||||
if k == requested_service_name
|
if k == requested_service_name
|
||||||
|
Baguette::Log.info "prefered redirection (from IPC_NETWORK): #{k} => #{v}"
|
||||||
requested_service = v
|
requested_service = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -117,50 +130,67 @@ module IPCd
|
||||||
end
|
end
|
||||||
|
|
||||||
# XXX: WIP
|
# XXX: WIP
|
||||||
def service_lookup (message : IPC::Message, fd : Int32)
|
def service_lookup (message : IPC::Message, client_fd : Int32)
|
||||||
payload = String.new message.payload
|
requested_service = IPCd::Service.parse_lookup_payload String.new(message.payload)
|
||||||
|
|
||||||
requested_service = IPCd::Service.parse_lookup_payload payload
|
# Now, we want to get the service used for transport.
|
||||||
|
# Network services used to carry libipc messages are named based on the scheme.
|
||||||
|
# Examples: tcp, udp, ws, etc.
|
||||||
|
network_service_name = requested_service.scheme
|
||||||
|
|
||||||
scheme = requested_service.scheme
|
if network_service_name.nil?
|
||||||
if scheme.nil?
|
raise "no scheme"
|
||||||
raise "no SCHEME in redirection"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
service_name = scheme
|
# In case of "unix", then it's a simple redirection to do, no network required.
|
||||||
if scheme == "unix"
|
if requested_service.scheme == "unix"
|
||||||
# scheme == unix => simple redirection
|
# The URI is "unix:///service" so the path is "/service".
|
||||||
|
# Service to contact is simply the path minus the slash.
|
||||||
# the URI is "unix:///service" so the path is "/service"
|
network_service_name = requested_service.path.lchop
|
||||||
# first, remove its slash prefix
|
end
|
||||||
service_name = requested_service.path.lchop
|
|
||||||
|
Baguette::Log.debug "connecting to #{network_service_name}"
|
||||||
|
|
||||||
|
service = begin
|
||||||
|
IPC::Client.new network_service_name
|
||||||
|
rescue e
|
||||||
|
# Better raise message.
|
||||||
|
raise "cannot contact #{network_service_name}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Will probably never happen in practice.
|
||||||
|
if service.fd.nil?
|
||||||
|
raise "no fd for #{network_service_name}"
|
||||||
end
|
end
|
||||||
|
|
||||||
Baguette::Log.info "service name: #{service_name}"
|
|
||||||
service = IPC::Client.new service_name
|
|
||||||
service_fd = service.fd.not_nil!
|
service_fd = service.fd.not_nil!
|
||||||
|
|
||||||
# TODO: for remote services, we have to connect to communication service
|
# A network service is necessary for remote communications, and it requires an URI.
|
||||||
# these communication services need an URI to work on
|
# TODO: protocol between ipcd and network services.
|
||||||
# The protocol:
|
# The (draft) protocol:
|
||||||
# ipcd sends an URI to the communication service, which responds with a "OK" message
|
# - ipcd sends an URI to the network service
|
||||||
if scheme != "unix"
|
# - network service responds with a "OK" message
|
||||||
service.send service_fd, 1.to_u8, "#{requested_service.to_s}\n"
|
if requested_service.scheme != "unix"
|
||||||
|
service.send service_fd, 1.to_u8, requested_service.to_s
|
||||||
response = service.read
|
response = service.read
|
||||||
payload = String.new response.payload
|
payload = String.new response.payload
|
||||||
if payload.chomp != "OK"
|
if payload.chomp != "OK"
|
||||||
raise "service #{service_name} response was #{payload.chomp}"
|
raise "service #{network_service_name} response was #{payload.chomp}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Then we provide the file descriptor to the client
|
Baguette::Log.debug "providing the fd from #{network_service_name} to the client #{client_fd}"
|
||||||
r = LibIPC.ipc_provide_fd(fd, service_fd)
|
|
||||||
|
# Provide the file descriptor to the client.
|
||||||
|
r = LibIPC.ipc_provide_fd(client_fd, service_fd)
|
||||||
if r.error_code != 0
|
if r.error_code != 0
|
||||||
m = String.new r.error_message.to_slice
|
m = String.new r.error_message.to_slice
|
||||||
raise Exception.new "cannot send the file descriptor of the requested service: #{m}"
|
raise Exception.new "cannot send the file descriptor of the requested service: #{m}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# finally, the service should be closed in ipcd
|
Baguette::Log.debug "everything went well, closing the service fd"
|
||||||
|
|
||||||
|
# Finally, the service should be closed in ipcd.
|
||||||
service.close
|
service.close
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Reference in New Issue