summaryrefslogtreecommitdiff
path: root/lib/sway/ipc.vala
blob: b4ee15df35899aec91698990da646002cfb1f033 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
namespace AstalSway {
private const string IPC_MAGIC = "i3-ipc";

private struct IpcReponse {
    public PayloadType type;
    public string payload;
}

// Basic interface to send and receive data through Sway IPjC
private class Ipc : Object {
    private string SWAYSOCK = GLib.Environment.get_variable("SWAYSOCK");

    internal void init() throws Error {
        SWAYSOCK = GLib.Environment.get_variable("SWAYSOCK");
        
        if (SWAYSOCK == null) {
            critical("Unable to detect Sway");
            return;
        }
    }
    
    internal SocketConnection connection() throws Error {
        return new SocketClient().connect(new UnixSocketAddress(SWAYSOCK), null);
    }

    internal void send(OutputStream stream, PayloadType type, string payload) throws Error {
        Array<uint8> message = new Array<uint8> ();

        uint8[] magic_str = IPC_MAGIC.data;
        uint32 pl_length = (uint32) payload.length; 
        uint32 pl_type = (uint32) type;
        uint8[] pl_data = payload.data;

        message.append_vals(magic_str, magic_str.length);
        message.append_vals((uint8 *)&pl_length, 4);
        message.append_vals((uint8 *)&pl_type, 4);
        message.append_vals(pl_data, pl_data.length);
        
        stream.write(message.data);
    }

    internal IpcReponse? receive(InputStream stream) {
        try {
            var header = stream.read_bytes(14);
            uint8 data[14] = header.get_data();
            uint32 pl_length = *(uint32 *)&data[IPC_MAGIC.length];
            PayloadType pl_type = *(uint32 *)&data[IPC_MAGIC.length+4];
             
            var payload = stream.read_bytes(pl_length);
            
            var result = payload.get_data();
            result += '\0';
            
            return {pl_type, (string)result};
        } catch (Error err) {
            critical("could not receive message: %s", err.message);
            return null;
        }
    }

    internal async IpcReponse? receive_async(InputStream stream) {
        try {
            var header = yield stream.read_bytes_async(14, Priority.DEFAULT, null);
            uint8 data[14] = header.get_data();
            if (data == null) {
                    return null;
            }
            uint32 pl_length = *(uint32 *)&data[IPC_MAGIC.length];
            PayloadType pl_type = *(uint32 *)&data[IPC_MAGIC.length+4];
             
            var payload = yield stream.read_bytes_async(pl_length, Priority.DEFAULT, null);
            
            var result = payload.get_data();
            result += '\0';

            return {pl_type, (string)result};
        } catch (Error err) {
            critical("could not receive message: %s", err.message);
            return null;
        }
    }

    public string message(PayloadType type, string payload) {
        try {
            SocketConnection conn = connection();
            if (conn == null) {
                return "";
            }
            
            send(conn.output_stream, type, payload);
            var result = receive(conn.input_stream);
            conn.close(null);
            
            if (result == null) {
                return "";
            }
         
            return result.payload;
        } catch (Error err) {
           critical("message failed: %s", err.message);
           return "";
        }
    }
    
    public async string message_async(PayloadType type, string payload) {
        try {
            SocketConnection conn = connection();
            if (conn == null) {
                return "";
            }
            
            send(conn.output_stream, type, payload);
            var result = yield receive_async(conn.input_stream);
            conn.close(null);
            
            if (result == null) {
                return "";
            }
         
            return result.payload;
        } catch (Error err) {
           critical("message failed: %s", err.message);
           return "";
        }
    }
}
}