1 
2 module i3ipc.protocol;
3 
4 import std.exception : enforce;
5 import std.socket : Socket;
6 import std.conv : to;
7 import std.json : JSONValue, parseJSON;
8 
9 import i3ipc.socket;
10 
11 align(1) struct Header
12 {
13 	align (1):
14 	/** Never change this, only on major IPC breakage (don’t do that) */
15     char[6] magic = "i3-ipc";
16     uint payloadSize;
17 	union
18 	{
19 		uint rawType;
20 		RequestType requestType;
21 		ResponseType responseType;
22 		EventType eventType;
23 	}
24 }
25 
26 enum RequestType : uint
27 {
28 	Command = 0,
29 	GetWorkspaces,
30 	Subscribe,
31 	GetOutputs,
32 	GetTree,
33 	GetMarks,
34 	GetBarConfig,
35 	GetVersion
36 }
37 
38 enum ResponseType : uint
39 {
40 	Command = 0,
41 	Workspaces,
42 	Subscribe,
43 	Outputs,
44 	Tree,
45 	Marks,
46 	BarConfig,
47 	Version
48 }
49 
50 enum EventMask = (1 << 31);
51 enum EventType : uint
52 {
53 	Workspace       = (EventMask | 0),
54 	Output          = (EventMask | 1),
55 	Mode            = (EventMask | 2),
56 	Window          = (EventMask | 3),
57 	BarConfigUpdate = (EventMask | 4),
58 	Binding         = (EventMask | 5)
59 }
60 
61 string toString(EventType type)
62 {
63 	switch (type) {
64 		case EventType.Workspace: return "workspace";
65 		case EventType.Output: return "output";
66 		case EventType.Mode: return "mode";
67 		case EventType.Window: return "window";
68 		case EventType.BarConfigUpdate: return "barconfig_update";
69 		case EventType.Binding: return "binding";
70 		default: assert(0);
71 	}
72 }
73 
74 void sendMessage(Socket socket, RequestType type, immutable(void)[] message = [])
75 {
76     Header header;
77     header.payloadSize = to!uint(message.length);
78     header.requestType = type;
79     socket.send((cast(void*) &header)[0 .. Header.sizeof]);
80     if (message.length) socket.send(message);
81 }
82 
83 JSONValue receiveMessage(Socket socket, ResponseType type)
84 {
85 	auto header = socket.receiveExactly!Header;
86 	auto payload = socket.receiveExactly(new ubyte[header.payloadSize]);
87 
88 	enforce(type == header.responseType);
89 	return parseJSON(payload);
90 }