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
|
-- load asterisk csv cdr file and parse it
module(..., package.seeall)
function new(a)
return cdr:new(a)
end
cdr = {}
cdr.__metatable = "cdr"
function cdr:new(a)
local c = {
path = a:path("/var/log/asterisk/cdr-csv/Master.csv"),
_records = {},
}
setmetatable(c, self)
local res, err = c:_parse()
if not res then
return res, err
end
return c
end
function cdr:len()
return self:__len()
end
function cdr:__len()
return #self._records
end
function cdr:__index(i)
if type(i) == "number" then
return rawget(self, "_records")[i]
end
return rawget(cdr, i)
end
function cdr:ipairs()
return ipairs(self._records)
end
function cdr:records()
local i = 1
local f = function(s)
local r = s._records[i]
i = i + 1
return r
end
return f, self
end
function cdr:_parse()
local f, err = io.open(self.path)
if not f then
return f, err
end
local count = 1
for line in f:lines() do
local r, err = cdr_record:new(line)
if not r then
return r, ("error parsing cdr on line %s (%s)"):format(count, err)
end
table.insert(self._records, r)
count = count + 1
end
return self
end
cdr_record = {}
function cdr_record:new(line)
local r = {
index = {
"accountcode",
"src",
"dst",
"dcontext",
"clid",
"channel",
"dstchannel",
"lastapp",
"lastdata",
"start",
"answer",
"end",
"duration",
"billsec",
"disposition",
"amaflags",
"uniqueid",
"userfield",
},
data = {},
}
setmetatable(r, self)
self._process_index(r)
local res, err = self._parse(r, line)
if not res then
return res, err
end
return r
end
function cdr_record:_parse(line)
-- this algorithm is adapted from Programming in Lua (1st Edition)
-- chapter 20, section 4
line = line .. ',' -- ending comma
local start = 1
repeat
-- next field is quoted? (start with `"'?)
if line:find('^"', start) then
local a, c
local i = start
repeat
-- find closing quote
a, i, c = line:find('"("?),', i+1)
until c ~= '"' -- quote not followed by quote?
if not i then return nil, 'unmatched "' end
local f = line:sub(start+1, i-2)
table.insert(self.data, (f:gsub('""', '"')))
start = i+1
else -- unquoted; find next comma
local nexti = line:find(',', start)
table.insert(self.data, line:sub(start, nexti-1))
start = nexti + 1
end
until start > line:len()
return self.data
end
function cdr_record:_process_index()
for k, v in ipairs(self.index) do
self.index[v] = k
end
end
function cdr_record:__index(i)
if type(i) == "number" then
return rawget(self, "data")[i]
end
return rawget(self, "data")[rawget(self, "index")[i]]
end
-- put cdr in the ast table too
_G.ast.cdr = _G.cdr
|