-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathironbar.lua
153 lines (146 loc) · 3.12 KB
/
ironbar.lua
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
local packets, argpackets = require("packets")()
local json = require("json")
local ffi = require("cdefs")
local runtimedir = os.getenv("XDG_RUNTIME_DIR") or "/tmp"
local sockpath = runtimedir.."/ironbar-ipc.sock"
--Generic function for connecting to the socket
local function connect()
local fd = ffi.C.socket(1, 1, 0)
if fd == -1 then
return nil, "socket"
end
local addr = ffi.new("struct sockaddr_un")
addr.sun_family = 1
ffi.copy(addr.sun_path, sockpath)
if ffi.C.connect(fd, ffi.cast("struct sockaddr *", addr), ffi.sizeof(addr)) == -1 then
ffi.C.close(fd)
return nil, "connect"
end
return fd
end
--[[
local function format_packet(_type,...)
if argpackets[_type] then
local packet = packets[_type]
for k,v in pairs(argpackets[_type]) do
if v.arg then
packet[k] = select(v.arg,...)
else
packet[k] = v
end
end
return packet
end
return packets[_type]
end
--]]
--Do the above, but ensure types are correct
local function format_packet(_type,...)
if argpackets[_type] then
--Validate types first
local packet = packets[_type]
for k,v in pairs(argpackets[_type]) do
if v.arg then
local arg = select(v.arg,...)
if type(arg) ~= v.type then
return nil, "invalid type"
end
packet[k] = arg
else
packet[k] = v
end
end
return packet
elseif packets[_type] then
return packets[_type]
else
return nil, "invalid packet type"
end
end
--Sending and receiving packets
local function send_packet(fd,enc_packet)
local len = #enc_packet
local sent = ffi.C.write(fd,enc_packet,len)
if sent == -1 then
return nil, "write"
end
if sent ~= len then
return nil, "short write"
end
return true
end
local function read_response(fd)
local buf = ffi.new("char[?]", 4096)
local len = ffi.C.read(fd, buf, 4096)
if len == -1 then
return nil, "read"
end
return ffi.string(buf,len)
end
--Helper to do both
local function send_receive(fd,packet)
local ok,err = send_packet(fd,json.encode(packet))
local send_err = false
if not ok then
send_err = err
end
local response,err = read_response(fd)
if not response then
return nil, err, send_err
end
local packet = json.decode(response)
if not packet then
return nil, "decode"
end
return packet
end
local ironbar = {}
local sock = nil
local function init()
sock = connect()
if not sock then
return nil, "connect"
end
return true
end
local function dispatch(socket,_type,...)
if not packets[_type] then
return nil, "invalid packet type"
end
local packet = format_packet(_type,...)
local packet_or_nil, err, send_err = send_receive(socket,packet)
if type(packet_or_nil) == "table" then
return true, packet_or_nil
else
return false, err, send_err
end
end
local mt = {
__index = function(t,k)
if packets[k] then
init()
return function(...)
return dispatch(sock,k,...)
end
else
error("invalid packet type")
end
end,
__call = function(t,k,...)
if packets[k] then
init()
local ok,packet,err = dispatch(sock,k,...)
if ok then
return ok,packet
else
error(err)
end
else
error("invalid packet type")
end
end
}
setmetatable(ironbar,mt)
return function()
return ironbar,json
end