summaryrefslogtreecommitdiff
path: root/src/tmate/session.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/tmate/session.vala')
-rw-r--r--src/tmate/session.vala207
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;
+ }
+ }
+}