diff options
Diffstat (limited to 'src/tmate/session.vala')
-rw-r--r-- | src/tmate/session.vala | 252 |
1 files changed, 108 insertions, 144 deletions
diff --git a/src/tmate/session.vala b/src/tmate/session.vala index 356aa66..fae55b6 100644 --- a/src/tmate/session.vala +++ b/src/tmate/session.vala @@ -2,122 +2,81 @@ namespace Tmate { public interface SessionInterface : Object { - public abstract signal void address (SessionType session, string address); - - public abstract string? @get(SessionType session); - public abstract bool start(string? config = null); + public abstract signal void started (string socket); + public abstract signal void stopped (); + public abstract signal void address_changed (SessionType session, string address); + public abstract signal void error (string summery, string message = ""); + public abstract signal void joined (string mate, int mates); + public abstract signal void left (string mate, int mates); + + public abstract bool start(Config? 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; - private uint error_count = 0; - - // 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? .+$/; - private Regex r_closed = /^Session closed$/; - private Regex r_note = /^(Note: |Reconnecting)/; - private Regex r_restarted = /^Session shell restarted$/; - private Regex r_netfail= /^[^ ]+ lookup failure\..+ \((.+)\)$/; - - public SessionType flags { get; private set;} - public string? socket { get; private set;} - public bool terminate = true; - - construct { reset(); } - - public virtual signal void started (string socket) - { - info (_("Session: unix://%s"), socket); - } + private IOChannel? stdout = null; + private Pid? pid = null; + private uint error_count = 0; - public virtual signal void network_error(string message) - { - if(error_count ++ > 5) stop(); - } + public bool terminate = true; + public SessionAddress address { get; construct; } + public string? socket { get; private set;} + public Config? config { get; private set;} - public virtual signal void stopped () - { - info (_("Session terminated.")); + construct { + address = new SessionAddress(); reset(); + address.clear(); + error.connect_after(() => { + if(error_count++ < 5) return; + + stop(); + }); } - private void address_set(SessionType session, string address) + private void address_set(SessionType session, string? address) { - info (_("%s address: %s"), session.to_string(), address); - - if (session in SessionType.SSH|SessionType.SSH_READONLY|SessionType.HTTP|SessionType.HTTP_READONLY) { - 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; - default: - warn_if_reached(); - break; - } - - flags |= session; - this.address(session, address); - } else if (session == DISCONNECTED) { - _addr_http = _addr_ssh = _addr_http_ro = _addr_ssh_ro = null; - flags = DISCONNECTED; - this.address(DISCONNECTED, ""); + if (SessionType.SSH in session || SessionType.HTTP in session) { + debug("CALL: %s\t%s", session.to_string(), address); + if(address != null || address != "") + this.address.add(session, address); + + if(this.address[session] != null) + address_changed (session, this.address[session]); } } - 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) + + private void reset() { - info(_("%s left, connected: %d"), mate, mates); + stdout = null; + pid = null; + socket = null; + error_count = 0; + address.clear(); + delete_config(); } - private void reset() + internal void delete_config() { - _addr_ssh = null; - _addr_http = null; - _addr_ssh_ro = null; - _addr_http_ro = null; - stdout = null; - pid = null; - socket = null; - flags = DISCONNECTED; - error_count = 0; + if(null == config) return; + + config.delete(); + config = null; } private bool send(string[] args) { - if(socket == null) + if(pid == null) return false; + var command = new GenericArray<string>(); command.data = { "/usr/bin/tmate", "-S", socket }; + foreach(var arg in args) command.add(arg); @@ -131,50 +90,38 @@ namespace Tmate } - public new string? @get(SessionType session) + private void restart() { - 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; + if(terminate) { + stop(); + return; } - return null; + started(socket); + address_set(SSH, null); + address_set(HTTP, null); + address_set(SSH | READONLY, null); + address_set(HTTP | READONLY, null); } public bool stop() { - return send({"kill-server"}); - } - - private void restart() - { - if(terminate) { - stop(); - return; + debug("stopping!"); + var ret = send({"kill-server"}); + if (! send({"has"})) { + debug("stopped!"); + Idle.add(() => { + stopped(); + return false; + }); } - started(socket); - if((bool)_addr_ssh) address(SSH, _addr_ssh); - if((bool)_addr_ssh_ro) address(SSH_READONLY, _addr_ssh_ro); - if((bool)_addr_http) address(HTTP, _addr_http); - if((bool)_addr_http_ro) address(HTTP_READONLY, _addr_http_ro); + return ret; } - public bool start(string? config = null) + public bool start(Config? config = null) { - if(! (pid == null)) { + if(null != pid) { started(socket); return true; } @@ -183,10 +130,12 @@ namespace Tmate var args = new GenericArray<string>(); args.data = {"/usr/bin/tmate", "-F"}; - if(! (config == null) && FileUtils.test(config, IS_REGULAR)) { + if(null != config) { + this.config = config; args.add("-f"); - args.add(config); + args.add(config.get_path()); } + try { Process.spawn_async_with_pipes( null, args.data, null, @@ -202,29 +151,42 @@ namespace Tmate 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(socket); - else if(r_http.match(line, 0, out info)) - address_set(HTTP, info.fetch(1)); - else if(r_http_ro.match(line, 0, out info)) - address_set(HTTP_READONLY, info.fetch(1)); - else if(r_ssh.match(line, 0, out info)) - address_set(SSH, info.fetch(1)); - else if(r_ssh_ro.match(line, 0, out info)) - address_set(SSH_READONLY, info.fetch(1)); - else if(r_restarted.match(line)) + Stdout.Token token = (new Stdout()).parse(line); + debug(token.to_string()); + + switch(token.class) { + case SOCKET: + socket = token.list[0]; + return true; + case INIT: + started (socket); + delete_config(); + return true; + case ADDRESS: + address_set( + SessionType.from_string( + token.list[0], token.list[1] + ), token.list[2]); + return true; + case RESTART: restart(); - else if(r_closed.match(line)) + return true; + case TERM: + info (_("Session terminated.")); stopped(); - else if(r_netfail.match(line, 0, out info)) - network_error(info.fetch(1)); - else if(r_note.match(line)) unlikely(false); // Ignore line - else - debug("Unprocessed line: \"%s\"", line); + return false; + case ERROR: + this.error(token.list[0], token.list[1]); + return true; + case COMMENT: + return true; // not needed. + case MATES: + return true;// TODO: handle mates join/leave + case UNKNOWN: + debug("%s", token.list[0]); + return true; + } } catch (IOChannelError e) { print ("IOChannelError: %s\n", e.message); return false; @@ -237,13 +199,15 @@ namespace Tmate ChildWatch.add(pid, (pid, status) => { Process.close_pid(pid); - if(flags != DISCONNECTED) - stopped(); + reset(); + stopped(); }); return true; } catch (SpawnError e) { warning("Error: %s", e.message); + this.error(e.message); + reset(); stopped(); return false; } |