diff options
Diffstat (limited to 'src/tmate/session.vala')
-rw-r--r-- | src/tmate/session.vala | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/tmate/session.vala b/src/tmate/session.vala new file mode 100644 index 0000000..5571654 --- /dev/null +++ b/src/tmate/session.vala @@ -0,0 +1,207 @@ +namespace Tmate +{ + public interface SessionInterface : Object + { + public abstract string? @get(SessionType session); + public abstract bool start(string? config = null); + public abstract bool stop(); + } + + [SingleInstance] + public class Session: Object, SessionInterface + { + private string? _addr_ssh = null; + private string? _addr_http = null; + private string? _addr_ssh_ro = null; + private string? _addr_http_ro = null; + private IOChannel? stdout = null; + private Pid? pid = null; + + // Regex + private Regex r_connect = /^Connecting to .+\.\.\.$/; + private Regex r_socket = /^To connect.+ tmate -S (.+) attach$/; + private Regex r_http = /^web \w+[:] (.+)$/; + private Regex r_ssh = /^ssh \w+[:] .+ (.+)+$/; + private Regex r_http_ro = /^web \w+ read \w+[:] (.+)$/; + private Regex r_ssh_ro = /^ssh \w+ read \w+[:] .+ (.+)+$/; + private Regex r_joined = /^.+ joined \(([^()]+)\) -- (\d+) clients? .+$/; + private Regex r_left = /^.+ left \(([^()]+)\) -- (\d+) clients? .+$/; + + public SessionType flags { get; private set;} + public string? socket { get; private set;} + + construct { reset(); } + + public virtual signal void started (string socket) + { + info (_("Session: unix://%s"), socket); + } + public virtual signal void stopped () + { + info (_("Session terminated.")); + } + public override signal void address (SessionType session, string address) + { + info (_("%s address: %s"), session.to_string(), address); + switch(session) { + case SSH : + _addr_ssh = address; + break; + case HTTP: + _addr_http = address; + break; + case HTTP_READONLY: + _addr_http_ro = address; + break; + case SSH_READONLY : + _addr_ssh_ro = address; + break; + case DISCONNECTED : + _addr_http = _addr_ssh = _addr_http_ro = _addr_ssh_ro = null; + break; + default: + warn_if_reached(); + break; + } + } + public virtual signal void joined (string mate, int mates) + { + info(_("%s joined, connected: %d"), mate, mates); + } + public virtual signal void left (string mate, int mates) + { + info(_("%s left, connected: %d"), mate, mates); + } + + private void reset() + { + _addr_ssh = null; + _addr_http = null; + _addr_ssh_ro = null; + _addr_http_ro = null; + stdout = null; + pid = null; + socket = null; + flags = DISCONNECTED; + } + + private bool send(string[] args) + { + if(socket == null) + return false; + var command = new GenericArray<string>(); + command.data = { + "/usr/bin/tmate", + "-S", socket + }; + foreach(var arg in args) + command.add(arg); + + try { + return Process.spawn_sync(null, command.data, null, + STDERR_TO_DEV_NULL|STDOUT_TO_DEV_NULL, + null, null, null, null); + } catch (SpawnError e) { + return false; + } + + } + + public new string? @get(SessionType session) + { + switch(session) { + case SSH: + return _addr_ssh; + case HTTP: + return _addr_http; + case SSH_READONLY : + return _addr_ssh_ro; + case HTTP_READONLY: + return _addr_http_ro; + case DISCONNECTED : + warning("No running session."); + break; + default: + warning("Unknown Session Type %s", session.to_string()); + break; + } + + return null; + } + + public bool start(string? config = null) + { + if(! (pid == null)) { + started.emit(socket); + return true; + } + + int out_fd; + var args = new GenericArray<string>(); + args.data = {"/usr/bin/tmate", "-F"}; + + if(! (config == null) && FileUtils.test(config, IS_REGULAR)) { + args.add("-f"); + args.add(config); + } + try { + Process.spawn_async_with_pipes( + null, args.data, null, + STDERR_TO_DEV_NULL | DO_NOT_REAP_CHILD, + null, out pid, null, + out out_fd, null + ); + + stdout = new IOChannel.unix_new(out_fd); + stdout.add_watch(IOCondition.IN | IOCondition.HUP, (channel, condition) => { + if (condition == IOCondition.HUP) + return false; + + try { + string line; + MatchInfo info; + channel.read_line (out line, null, null); + if(r_socket.match(line, 0, out info)) + socket = info.fetch(1); + else if (r_connect.match(line) && socket != null) + started.emit(socket); + else if(r_http.match(line, 0, out info)) + address.emit(HTTP, info.fetch(1)); + else if(r_http_ro.match(line, 0, out info)) + address.emit(HTTP_READONLY, info.fetch(1)); + else if(r_ssh.match(line, 0, out info)) + address.emit(SSH, info.fetch(1)); + else if(r_ssh_ro.match(line, 0, out info)) + address.emit(SSH_READONLY, info.fetch(1)); + else + debug("Unprocessed line: \"%s\"", line); + } catch (IOChannelError e) { + print ("IOChannelError: %s\n", e.message); + return false; + } catch (ConvertError e) { + print ("ConvertError: %s\n", e.message); + return false; + } + return true; + }); + + ChildWatch.add(pid, (pid, status) => { + Process.close_pid(pid); + reset(); + stopped.emit(); + }); + + return true; + } catch (SpawnError e) { + warning("Error: %s", e.message); + reset(); + return false; + } + } + + public bool stop() + { + return false; + } + } +} |