#!/usr/bin/env ruby
=begin =======================================================================

# TORK-REMOTE 1 2012-09-26 18.2.3

## NAME

tork-remote - controls tork(1) programs

## SYNOPSIS

`tork-remote` [*OPTION*]... *PROGRAM*

## DESCRIPTION

This program reads lines from its stdin and sends them to the given *PROGRAM*,
which must already be running in the same working directory as this program.
It also prints lines, received in response, from the given *PROGRAM* either
to stdout if they are valid single-line JSON arrays or to stderr otherwise.

## OPTIONS

`-h` [*PATTERN*], `--help` [*PATTERN*]
  Show this help manual and optionally search for *PATTERN* regular expression.

## EXIT STATUS

1
  Could not connect to the *PROGRAM*.

2
  Lost connection to the *PROGRAM*.

## SEE ALSO

tork(1), tork-driver(1), tork-engine(1), tork-master(1)

=end =========================================================================

$0 = File.basename(__FILE__) # for easier identification in ps(1) output

require 'binman'
BinMan.help

require 'socket'
require 'shellwords'
require 'tork/server'

program = ARGV.shift or raise ArgumentError, 'PROGRAM not given'
address = Tork::Server.address(program)

begin
  UNIXSocket.open(address) do |socket|
    # messages to remote from server
    Thread.new do
      while input = socket.gets
        stream =
          begin
            JSON.parse input
            STDOUT
          rescue JSON::ParserError
            STDERR
          end
        stream.puts input
        stream.flush
      end
      warn "#{$0}: lost connection to #{program}"
      exit 2
    end

    # messages from remote to server
    while output = STDIN.gets
      socket.puts output
    end
  end

rescue Errno::ECONNREFUSED
  # the socket file is already there but it's not responding; it's probably
  # a stale socket file left behind by a server that was prematurely killed
  # so it should be safe to delete the socket file and start up a new server
  warn "#{$0}: replacing unresponsive #{program} instance..."
  File.delete address
  exec program, *ARGV

rescue SystemCallError => error
  warn "#{$0}: could not connect to #{program}: #{error}"
  exit 1
end