Skip to content

Instantly share code, notes, and snippets.

@geekhunger
Last active February 20, 2020 07:36
Show Gist options
  • Save geekhunger/50a18c73520422221493ebb5903f3666 to your computer and use it in GitHub Desktop.
Save geekhunger/50a18c73520422221493ebb5903f3666 to your computer and use it in GitHub Desktop.
This is a MySQL Adapter for Codea + demo code. It lets your Codea app talk directly to a MySQL server.
--# Main
-- mysql adapter
--
-- TODO: write higher level API to mysql
-- app should cache inputs and push to mysql when server available
-- also queries should be wrapped in coroutines or something, to be async?
function setup()
-- Config
local config = {
host = "192.168.0.209", -- localhost
port = "3306",
database = "codea-test",
user = "guest",
password = "guest"
}
-- Connect
local function connect()
local db, err = mysql:new()
if not db then print(err) return end
db:set_timeout(1000)
local ok, err, errc, sqlstate = db:connect(config)
if not ok then print(errc, err) return end
print("successfully connected to mysql server at "..config.host..":"..config.port)
return db
end
-- Disconnect
local function disconnect(db)
local ok, err = db:close()
if ok then print("closed mysql server connection") end
end
-- Insert
local function create_user(name)
local db = connect()
if not db then
print("failed to connect to mysql server")
return
end
local res, err, errc, sqlstate = db:query("INSERT INTO users (name) VALUES ('"..name.."')")
if not err then
print("added db record from custom query call...")
pretty(res)
end
disconnect(db)
end
-- Fetch
local function fetch_users()
local db = connect()
if not db then
print("failed to connect to mysql server")
return
end
local res, err, errc, sqlstate = db:query("select * from users")
if not res then
print("could not fetch data from mysql server")
return
end
local numentries = 0
dbquery = "database name: "..config.database.."\ntable name: users\n\n"
for id, row in ipairs(res) do
dbquery = dbquery.."row: "..id.."\n"
for field, value in pairs(row) do
dbquery = dbquery.." "..field..": "..value.."\n"
end
dbquery = dbquery.."\n"
numentries = id
end
print("successfully fetched "..numentries.." entries")
disconnect(db)
end
-- UI
parameter.text("NAME", "yourname")
parameter.action("INSERT", function() create_user(NAME) end)
parameter.action("FETCH", fetch_users)
end
function draw()
background(35, 107, 214, 255)
fill(0, 0, 0, 255)
translate(WIDTH/2, HEIGHT/2)
textMode(CENTER)
text(dbquery or "-no data fetched-")
end
--# sha1
-- SHA-1 secure hash computation, and HMAC-SHA1 signature computation in pure Lua (tested on Lua 5.1)
-- Latest version always at: http://regex.info/blog/lua/sha1
-- Algorithm: http://www.itl.nist.gov/fipspubs/fip180-1.htm
--
-- Copyright 2009 Jeffrey Friedl
-- jfriedl@yahoo.com
-- http://regex.info/blog/
--
-- This file creates four entries in the global namespace:
--
-- local hash_as_hex = sha1(message) -- returns a hex string
-- local hash_as_data = sha1_binary(message) -- returns raw bytes
--
-- local hmac_as_hex = hmac_sha1(key, message) -- hex string
-- local hmac_as_data = hmac_sha1_binary(key, message) -- raw bytes
--
-- Return a W32 object for the number zero
--
local function ZERO()
return {
false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false,
}
end
local hex_to_bits = {
["0"] = { false, false, false, false },
["1"] = { false, false, false, true },
["2"] = { false, false, true, false },
["3"] = { false, false, true, true },
["4"] = { false, true, false, false },
["5"] = { false, true, false, true },
["6"] = { false, true, true, false },
["7"] = { false, true, true, true },
["8"] = { true, false, false, false },
["9"] = { true, false, false, true },
["A"] = { true, false, true, false },
["B"] = { true, false, true, true },
["C"] = { true, true, false, false },
["D"] = { true, true, false, true },
["E"] = { true, true, true, false },
["F"] = { true, true, true, true },
["a"] = { true, false, true, false },
["b"] = { true, false, true, true },
["c"] = { true, true, false, false },
["d"] = { true, true, false, true },
["e"] = { true, true, true, false },
["f"] = { true, true, true, true },
}
--
-- Given a string of 8 hex digits, return a W32 object representing that number
--
local function from_hex(hex)
assert(type(hex) == 'string')
assert(hex:match('^[0123456789abcdefABCDEF]+$'))
assert(#hex == 8)
local W32 = { }
for letter in hex:gmatch('.') do
local b = hex_to_bits[letter]
assert(b)
table.insert(W32, 1, b[1])
table.insert(W32, 1, b[2])
table.insert(W32, 1, b[3])
table.insert(W32, 1, b[4])
end
return W32
end
local function COPY(old)
local W32 = { }
for k,v in pairs(old) do
W32[k] = v
end
return W32
end
local function ADD(first, ...)
local a = COPY(first)
local C, b, sum
for v = 1, select('#', ...) do
b = select(v, ...)
C = 0
for i = 1, #a do
sum = (a[i] and 1 or 0)
+ (b[i] and 1 or 0)
+ C
if sum == 0 then
a[i] = false
C = 0
elseif sum == 1 then
a[i] = true
C = 0
elseif sum == 2 then
a[i] = false
C = 1
else
a[i] = true
C = 1
end
end
-- we drop any ending carry
end
return a
end
local function XOR(first, ...)
local a = COPY(first)
local b
for v = 1, select('#', ...) do
b = select(v, ...)
for i = 1, #a do
a[i] = a[i] ~= b[i]
end
end
return a
end
local function AND(a, b)
local c = ZERO()
for i = 1, #a do
-- only need to set true bits; other bits remain false
if a[i] and b[i] then
c[i] = true
end
end
return c
end
local function OR(a, b)
local c = ZERO()
for i = 1, #a do
-- only need to set true bits; other bits remain false
if a[i] or b[i] then
c[i] = true
end
end
return c
end
local function OR3(a, b, c)
local d = ZERO()
for i = 1, #a do
-- only need to set true bits; other bits remain false
if a[i] or b[i] or c[i] then
d[i] = true
end
end
return d
end
local function NOT(a)
local b = ZERO()
for i = 1, #a do
-- only need to set true bits; other bits remain false
if not a[i] then
b[i] = true
end
end
return b
end
local function ROTATE(bits, a)
local b = COPY(a)
while bits > 0 do
bits = bits - 1
table.insert(b, 1, table.remove(b))
end
return b
end
local binary_to_hex = {
["0000"] = "0",
["0001"] = "1",
["0010"] = "2",
["0011"] = "3",
["0100"] = "4",
["0101"] = "5",
["0110"] = "6",
["0111"] = "7",
["1000"] = "8",
["1001"] = "9",
["1010"] = "a",
["1011"] = "b",
["1100"] = "c",
["1101"] = "d",
["1110"] = "e",
["1111"] = "f",
}
function asHEX(a)
local hex = ""
local i = 1
while i < #a do
local binary = (a[i + 3] and '1' or '0')
..
(a[i + 2] and '1' or '0')
..
(a[i + 1] and '1' or '0')
..
(a[i + 0] and '1' or '0')
hex = binary_to_hex[binary] .. hex
i = i + 4
end
return hex
end
local x67452301 = from_hex("67452301")
local xEFCDAB89 = from_hex("EFCDAB89")
local x98BADCFE = from_hex("98BADCFE")
local x10325476 = from_hex("10325476")
local xC3D2E1F0 = from_hex("C3D2E1F0")
local x5A827999 = from_hex("5A827999")
local x6ED9EBA1 = from_hex("6ED9EBA1")
local x8F1BBCDC = from_hex("8F1BBCDC")
local xCA62C1D6 = from_hex("CA62C1D6")
function sha1(msg)
assert(type(msg) == 'string')
assert(#msg < 0x7FFFFFFF) -- have no idea what would happen if it were large
local H0 = x67452301
local H1 = xEFCDAB89
local H2 = x98BADCFE
local H3 = x10325476
local H4 = xC3D2E1F0
local msg_len_in_bits = #msg * 8
local first_append = string.char(0x80) -- append a '1' bit plus seven '0' bits
local non_zero_message_bytes = #msg +1 +8 -- the +1 is the appended bit 1, the +8 are for the final appended length
local current_mod = non_zero_message_bytes % 64
local second_append = ""
if current_mod ~= 0 then
second_append = string.rep(string.char(0), 64 - current_mod)
end
-- now to append the length as a 64-bit number.
local B1, R1 = math.modf(msg_len_in_bits / 0x01000000)
local B2, R2 = math.modf( 0x01000000 * R1 / 0x00010000)
local B3, R3 = math.modf( 0x00010000 * R2 / 0x00000100)
local B4 = 0x00000100 * R3
local L64 = string.char( 0) .. string.char( 0) .. string.char( 0) .. string.char( 0) -- high 32 bits
.. string.char(B1) .. string.char(B2) .. string.char(B3) .. string.char(B4) -- low 32 bits
msg = msg .. first_append .. second_append .. L64
assert(#msg % 64 == 0)
--local fd = io.open("/tmp/msg", "wb")
--fd:write(msg)
--fd:close()
local chunks = #msg / 64
local W = { }
local start, A, B, C, D, E, f, K, TEMP
local chunk = 0
while chunk < chunks do
--
-- break chunk up into W[0] through W[15]
--
start = chunk * 64 + 1
chunk = chunk + 1
for t = 0, 15 do
W[t] = from_hex(string.format("%02x%02x%02x%02x", msg:byte(start, start + 3)))
start = start + 4
end
--
-- build W[16] through W[79]
--
for t = 16, 79 do
-- For t = 16 to 79 let Wt = S1(Wt-3 XOR Wt-8 XOR Wt-14 XOR Wt-16).
W[t] = ROTATE(1, XOR(W[t-3], W[t-8], W[t-14], W[t-16]))
end
A = H0
B = H1
C = H2
D = H3
E = H4
for t = 0, 79 do
if t <= 19 then
-- (B AND C) OR ((NOT B) AND D)
f = OR(AND(B, C), AND(NOT(B), D))
K = x5A827999
elseif t <= 39 then
-- B XOR C XOR D
f = XOR(B, C, D)
K = x6ED9EBA1
elseif t <= 59 then
-- (B AND C) OR (B AND D) OR (C AND D
f = OR3(AND(B, C), AND(B, D), AND(C, D))
K = x8F1BBCDC
else
-- B XOR C XOR D
f = XOR(B, C, D)
K = xCA62C1D6
end
-- TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;
TEMP = ADD(ROTATE(5, A), f, E, W[t], K)
--E = D;   D = C;    C = S30(B);   B = A;   A = TEMP;
E = D
D = C
C = ROTATE(30, B)
B = A
A = TEMP
--printf("t = %2d: %s %s %s %s %s", t, A:HEX(), B:HEX(), C:HEX(), D:HEX(), E:HEX())
end
-- Let H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.
H0 = ADD(H0, A)
H1 = ADD(H1, B)
H2 = ADD(H2, C)
H3 = ADD(H3, D)
H4 = ADD(H4, E)
end
return asHEX(H0) .. asHEX(H1) .. asHEX(H2) .. asHEX(H3) .. asHEX(H4)
end
local function hex_to_binary(hex)
return hex:gsub('..', function(hexval)
return string.char(tonumber(hexval, 16))
end)
end
function sha1_binary(msg)
return hex_to_binary(sha1(msg))
end
local xor_with_0x5c = {
[string.char( 0)] = string.char( 92), [string.char( 1)] = string.char( 93),
[string.char( 2)] = string.char( 94), [string.char( 3)] = string.char( 95),
[string.char( 4)] = string.char( 88), [string.char( 5)] = string.char( 89),
[string.char( 6)] = string.char( 90), [string.char( 7)] = string.char( 91),
[string.char( 8)] = string.char( 84), [string.char( 9)] = string.char( 85),
[string.char( 10)] = string.char( 86), [string.char( 11)] = string.char( 87),
[string.char( 12)] = string.char( 80), [string.char( 13)] = string.char( 81),
[string.char( 14)] = string.char( 82), [string.char( 15)] = string.char( 83),
[string.char( 16)] = string.char( 76), [string.char( 17)] = string.char( 77),
[string.char( 18)] = string.char( 78), [string.char( 19)] = string.char( 79),
[string.char( 20)] = string.char( 72), [string.char( 21)] = string.char( 73),
[string.char( 22)] = string.char( 74), [string.char( 23)] = string.char( 75),
[string.char( 24)] = string.char( 68), [string.char( 25)] = string.char( 69),
[string.char( 26)] = string.char( 70), [string.char( 27)] = string.char( 71),
[string.char( 28)] = string.char( 64), [string.char( 29)] = string.char( 65),
[string.char( 30)] = string.char( 66), [string.char( 31)] = string.char( 67),
[string.char( 32)] = string.char(124), [string.char( 33)] = string.char(125),
[string.char( 34)] = string.char(126), [string.char( 35)] = string.char(127),
[string.char( 36)] = string.char(120), [string.char( 37)] = string.char(121),
[string.char( 38)] = string.char(122), [string.char( 39)] = string.char(123),
[string.char( 40)] = string.char(116), [string.char( 41)] = string.char(117),
[string.char( 42)] = string.char(118), [string.char( 43)] = string.char(119),
[string.char( 44)] = string.char(112), [string.char( 45)] = string.char(113),
[string.char( 46)] = string.char(114), [string.char( 47)] = string.char(115),
[string.char( 48)] = string.char(108), [string.char( 49)] = string.char(109),
[string.char( 50)] = string.char(110), [string.char( 51)] = string.char(111),
[string.char( 52)] = string.char(104), [string.char( 53)] = string.char(105),
[string.char( 54)] = string.char(106), [string.char( 55)] = string.char(107),
[string.char( 56)] = string.char(100), [string.char( 57)] = string.char(101),
[string.char( 58)] = string.char(102), [string.char( 59)] = string.char(103),
[string.char( 60)] = string.char( 96), [string.char( 61)] = string.char( 97),
[string.char( 62)] = string.char( 98), [string.char( 63)] = string.char( 99),
[string.char( 64)] = string.char( 28), [string.char( 65)] = string.char( 29),
[string.char( 66)] = string.char( 30), [string.char( 67)] = string.char( 31),
[string.char( 68)] = string.char( 24), [string.char( 69)] = string.char( 25),
[string.char( 70)] = string.char( 26), [string.char( 71)] = string.char( 27),
[string.char( 72)] = string.char( 20), [string.char( 73)] = string.char( 21),
[string.char( 74)] = string.char( 22), [string.char( 75)] = string.char( 23),
[string.char( 76)] = string.char( 16), [string.char( 77)] = string.char( 17),
[string.char( 78)] = string.char( 18), [string.char( 79)] = string.char( 19),
[string.char( 80)] = string.char( 12), [string.char( 81)] = string.char( 13),
[string.char( 82)] = string.char( 14), [string.char( 83)] = string.char( 15),
[string.char( 84)] = string.char( 8), [string.char( 85)] = string.char( 9),
[string.char( 86)] = string.char( 10), [string.char( 87)] = string.char( 11),
[string.char( 88)] = string.char( 4), [string.char( 89)] = string.char( 5),
[string.char( 90)] = string.char( 6), [string.char( 91)] = string.char( 7),
[string.char( 92)] = string.char( 0), [string.char( 93)] = string.char( 1),
[string.char( 94)] = string.char( 2), [string.char( 95)] = string.char( 3),
[string.char( 96)] = string.char( 60), [string.char( 97)] = string.char( 61),
[string.char( 98)] = string.char( 62), [string.char( 99)] = string.char( 63),
[string.char(100)] = string.char( 56), [string.char(101)] = string.char( 57),
[string.char(102)] = string.char( 58), [string.char(103)] = string.char( 59),
[string.char(104)] = string.char( 52), [string.char(105)] = string.char( 53),
[string.char(106)] = string.char( 54), [string.char(107)] = string.char( 55),
[string.char(108)] = string.char( 48), [string.char(109)] = string.char( 49),
[string.char(110)] = string.char( 50), [string.char(111)] = string.char( 51),
[string.char(112)] = string.char( 44), [string.char(113)] = string.char( 45),
[string.char(114)] = string.char( 46), [string.char(115)] = string.char( 47),
[string.char(116)] = string.char( 40), [string.char(117)] = string.char( 41),
[string.char(118)] = string.char( 42), [string.char(119)] = string.char( 43),
[string.char(120)] = string.char( 36), [string.char(121)] = string.char( 37),
[string.char(122)] = string.char( 38), [string.char(123)] = string.char( 39),
[string.char(124)] = string.char( 32), [string.char(125)] = string.char( 33),
[string.char(126)] = string.char( 34), [string.char(127)] = string.char( 35),
[string.char(128)] = string.char(220), [string.char(129)] = string.char(221),
[string.char(130)] = string.char(222), [string.char(131)] = string.char(223),
[string.char(132)] = string.char(216), [string.char(133)] = string.char(217),
[string.char(134)] = string.char(218), [string.char(135)] = string.char(219),
[string.char(136)] = string.char(212), [string.char(137)] = string.char(213),
[string.char(138)] = string.char(214), [string.char(139)] = string.char(215),
[string.char(140)] = string.char(208), [string.char(141)] = string.char(209),
[string.char(142)] = string.char(210), [string.char(143)] = string.char(211),
[string.char(144)] = string.char(204), [string.char(145)] = string.char(205),
[string.char(146)] = string.char(206), [string.char(147)] = string.char(207),
[string.char(148)] = string.char(200), [string.char(149)] = string.char(201),
[string.char(150)] = string.char(202), [string.char(151)] = string.char(203),
[string.char(152)] = string.char(196), [string.char(153)] = string.char(197),
[string.char(154)] = string.char(198), [string.char(155)] = string.char(199),
[string.char(156)] = string.char(192), [string.char(157)] = string.char(193),
[string.char(158)] = string.char(194), [string.char(159)] = string.char(195),
[string.char(160)] = string.char(252), [string.char(161)] = string.char(253),
[string.char(162)] = string.char(254), [string.char(163)] = string.char(255),
[string.char(164)] = string.char(248), [string.char(165)] = string.char(249),
[string.char(166)] = string.char(250), [string.char(167)] = string.char(251),
[string.char(168)] = string.char(244), [string.char(169)] = string.char(245),
[string.char(170)] = string.char(246), [string.char(171)] = string.char(247),
[string.char(172)] = string.char(240), [string.char(173)] = string.char(241),
[string.char(174)] = string.char(242), [string.char(175)] = string.char(243),
[string.char(176)] = string.char(236), [string.char(177)] = string.char(237),
[string.char(178)] = string.char(238), [string.char(179)] = string.char(239),
[string.char(180)] = string.char(232), [string.char(181)] = string.char(233),
[string.char(182)] = string.char(234), [string.char(183)] = string.char(235),
[string.char(184)] = string.char(228), [string.char(185)] = string.char(229),
[string.char(186)] = string.char(230), [string.char(187)] = string.char(231),
[string.char(188)] = string.char(224), [string.char(189)] = string.char(225),
[string.char(190)] = string.char(226), [string.char(191)] = string.char(227),
[string.char(192)] = string.char(156), [string.char(193)] = string.char(157),
[string.char(194)] = string.char(158), [string.char(195)] = string.char(159),
[string.char(196)] = string.char(152), [string.char(197)] = string.char(153),
[string.char(198)] = string.char(154), [string.char(199)] = string.char(155),
[string.char(200)] = string.char(148), [string.char(201)] = string.char(149),
[string.char(202)] = string.char(150), [string.char(203)] = string.char(151),
[string.char(204)] = string.char(144), [string.char(205)] = string.char(145),
[string.char(206)] = string.char(146), [string.char(207)] = string.char(147),
[string.char(208)] = string.char(140), [string.char(209)] = string.char(141),
[string.char(210)] = string.char(142), [string.char(211)] = string.char(143),
[string.char(212)] = string.char(136), [string.char(213)] = string.char(137),
[string.char(214)] = string.char(138), [string.char(215)] = string.char(139),
[string.char(216)] = string.char(132), [string.char(217)] = string.char(133),
[string.char(218)] = string.char(134), [string.char(219)] = string.char(135),
[string.char(220)] = string.char(128), [string.char(221)] = string.char(129),
[string.char(222)] = string.char(130), [string.char(223)] = string.char(131),
[string.char(224)] = string.char(188), [string.char(225)] = string.char(189),
[string.char(226)] = string.char(190), [string.char(227)] = string.char(191),
[string.char(228)] = string.char(184), [string.char(229)] = string.char(185),
[string.char(230)] = string.char(186), [string.char(231)] = string.char(187),
[string.char(232)] = string.char(180), [string.char(233)] = string.char(181),
[string.char(234)] = string.char(182), [string.char(235)] = string.char(183),
[string.char(236)] = string.char(176), [string.char(237)] = string.char(177),
[string.char(238)] = string.char(178), [string.char(239)] = string.char(179),
[string.char(240)] = string.char(172), [string.char(241)] = string.char(173),
[string.char(242)] = string.char(174), [string.char(243)] = string.char(175),
[string.char(244)] = string.char(168), [string.char(245)] = string.char(169),
[string.char(246)] = string.char(170), [string.char(247)] = string.char(171),
[string.char(248)] = string.char(164), [string.char(249)] = string.char(165),
[string.char(250)] = string.char(166), [string.char(251)] = string.char(167),
[string.char(252)] = string.char(160), [string.char(253)] = string.char(161),
[string.char(254)] = string.char(162), [string.char(255)] = string.char(163),
}
local xor_with_0x36 = {
[string.char( 0)] = string.char( 54), [string.char( 1)] = string.char( 55),
[string.char( 2)] = string.char( 52), [string.char( 3)] = string.char( 53),
[string.char( 4)] = string.char( 50), [string.char( 5)] = string.char( 51),
[string.char( 6)] = string.char( 48), [string.char( 7)] = string.char( 49),
[string.char( 8)] = string.char( 62), [string.char( 9)] = string.char( 63),
[string.char( 10)] = string.char( 60), [string.char( 11)] = string.char( 61),
[string.char( 12)] = string.char( 58), [string.char( 13)] = string.char( 59),
[string.char( 14)] = string.char( 56), [string.char( 15)] = string.char( 57),
[string.char( 16)] = string.char( 38), [string.char( 17)] = string.char( 39),
[string.char( 18)] = string.char( 36), [string.char( 19)] = string.char( 37),
[string.char( 20)] = string.char( 34), [string.char( 21)] = string.char( 35),
[string.char( 22)] = string.char( 32), [string.char( 23)] = string.char( 33),
[string.char( 24)] = string.char( 46), [string.char( 25)] = string.char( 47),
[string.char( 26)] = string.char( 44), [string.char( 27)] = string.char( 45),
[string.char( 28)] = string.char( 42), [string.char( 29)] = string.char( 43),
[string.char( 30)] = string.char( 40), [string.char( 31)] = string.char( 41),
[string.char( 32)] = string.char( 22), [string.char( 33)] = string.char( 23),
[string.char( 34)] = string.char( 20), [string.char( 35)] = string.char( 21),
[string.char( 36)] = string.char( 18), [string.char( 37)] = string.char( 19),
[string.char( 38)] = string.char( 16), [string.char( 39)] = string.char( 17),
[string.char( 40)] = string.char( 30), [string.char( 41)] = string.char( 31),
[string.char( 42)] = string.char( 28), [string.char( 43)] = string.char( 29),
[string.char( 44)] = string.char( 26), [string.char( 45)] = string.char( 27),
[string.char( 46)] = string.char( 24), [string.char( 47)] = string.char( 25),
[string.char( 48)] = string.char( 6), [string.char( 49)] = string.char( 7),
[string.char( 50)] = string.char( 4), [string.char( 51)] = string.char( 5),
[string.char( 52)] = string.char( 2), [string.char( 53)] = string.char( 3),
[string.char( 54)] = string.char( 0), [string.char( 55)] = string.char( 1),
[string.char( 56)] = string.char( 14), [string.char( 57)] = string.char( 15),
[string.char( 58)] = string.char( 12), [string.char( 59)] = string.char( 13),
[string.char( 60)] = string.char( 10), [string.char( 61)] = string.char( 11),
[string.char( 62)] = string.char( 8), [string.char( 63)] = string.char( 9),
[string.char( 64)] = string.char(118), [string.char( 65)] = string.char(119),
[string.char( 66)] = string.char(116), [string.char( 67)] = string.char(117),
[string.char( 68)] = string.char(114), [string.char( 69)] = string.char(115),
[string.char( 70)] = string.char(112), [string.char( 71)] = string.char(113),
[string.char( 72)] = string.char(126), [string.char( 73)] = string.char(127),
[string.char( 74)] = string.char(124), [string.char( 75)] = string.char(125),
[string.char( 76)] = string.char(122), [string.char( 77)] = string.char(123),
[string.char( 78)] = string.char(120), [string.char( 79)] = string.char(121),
[string.char( 80)] = string.char(102), [string.char( 81)] = string.char(103),
[string.char( 82)] = string.char(100), [string.char( 83)] = string.char(101),
[string.char( 84)] = string.char( 98), [string.char( 85)] = string.char( 99),
[string.char( 86)] = string.char( 96), [string.char( 87)] = string.char( 97),
[string.char( 88)] = string.char(110), [string.char( 89)] = string.char(111),
[string.char( 90)] = string.char(108), [string.char( 91)] = string.char(109),
[string.char( 92)] = string.char(106), [string.char( 93)] = string.char(107),
[string.char( 94)] = string.char(104), [string.char( 95)] = string.char(105),
[string.char( 96)] = string.char( 86), [string.char( 97)] = string.char( 87),
[string.char( 98)] = string.char( 84), [string.char( 99)] = string.char( 85),
[string.char(100)] = string.char( 82), [string.char(101)] = string.char( 83),
[string.char(102)] = string.char( 80), [string.char(103)] = string.char( 81),
[string.char(104)] = string.char( 94), [string.char(105)] = string.char( 95),
[string.char(106)] = string.char( 92), [string.char(107)] = string.char( 93),
[string.char(108)] = string.char( 90), [string.char(109)] = string.char( 91),
[string.char(110)] = string.char( 88), [string.char(111)] = string.char( 89),
[string.char(112)] = string.char( 70), [string.char(113)] = string.char( 71),
[string.char(114)] = string.char( 68), [string.char(115)] = string.char( 69),
[string.char(116)] = string.char( 66), [string.char(117)] = string.char( 67),
[string.char(118)] = string.char( 64), [string.char(119)] = string.char( 65),
[string.char(120)] = string.char( 78), [string.char(121)] = string.char( 79),
[string.char(122)] = string.char( 76), [string.char(123)] = string.char( 77),
[string.char(124)] = string.char( 74), [string.char(125)] = string.char( 75),
[string.char(126)] = string.char( 72), [string.char(127)] = string.char( 73),
[string.char(128)] = string.char(182), [string.char(129)] = string.char(183),
[string.char(130)] = string.char(180), [string.char(131)] = string.char(181),
[string.char(132)] = string.char(178), [string.char(133)] = string.char(179),
[string.char(134)] = string.char(176), [string.char(135)] = string.char(177),
[string.char(136)] = string.char(190), [string.char(137)] = string.char(191),
[string.char(138)] = string.char(188), [string.char(139)] = string.char(189),
[string.char(140)] = string.char(186), [string.char(141)] = string.char(187),
[string.char(142)] = string.char(184), [string.char(143)] = string.char(185),
[string.char(144)] = string.char(166), [string.char(145)] = string.char(167),
[string.char(146)] = string.char(164), [string.char(147)] = string.char(165),
[string.char(148)] = string.char(162), [string.char(149)] = string.char(163),
[string.char(150)] = string.char(160), [string.char(151)] = string.char(161),
[string.char(152)] = string.char(174), [string.char(153)] = string.char(175),
[string.char(154)] = string.char(172), [string.char(155)] = string.char(173),
[string.char(156)] = string.char(170), [string.char(157)] = string.char(171),
[string.char(158)] = string.char(168), [string.char(159)] = string.char(169),
[string.char(160)] = string.char(150), [string.char(161)] = string.char(151),
[string.char(162)] = string.char(148), [string.char(163)] = string.char(149),
[string.char(164)] = string.char(146), [string.char(165)] = string.char(147),
[string.char(166)] = string.char(144), [string.char(167)] = string.char(145),
[string.char(168)] = string.char(158), [string.char(169)] = string.char(159),
[string.char(170)] = string.char(156), [string.char(171)] = string.char(157),
[string.char(172)] = string.char(154), [string.char(173)] = string.char(155),
[string.char(174)] = string.char(152), [string.char(175)] = string.char(153),
[string.char(176)] = string.char(134), [string.char(177)] = string.char(135),
[string.char(178)] = string.char(132), [string.char(179)] = string.char(133),
[string.char(180)] = string.char(130), [string.char(181)] = string.char(131),
[string.char(182)] = string.char(128), [string.char(183)] = string.char(129),
[string.char(184)] = string.char(142), [string.char(185)] = string.char(143),
[string.char(186)] = string.char(140), [string.char(187)] = string.char(141),
[string.char(188)] = string.char(138), [string.char(189)] = string.char(139),
[string.char(190)] = string.char(136), [string.char(191)] = string.char(137),
[string.char(192)] = string.char(246), [string.char(193)] = string.char(247),
[string.char(194)] = string.char(244), [string.char(195)] = string.char(245),
[string.char(196)] = string.char(242), [string.char(197)] = string.char(243),
[string.char(198)] = string.char(240), [string.char(199)] = string.char(241),
[string.char(200)] = string.char(254), [string.char(201)] = string.char(255),
[string.char(202)] = string.char(252), [string.char(203)] = string.char(253),
[string.char(204)] = string.char(250), [string.char(205)] = string.char(251),
[string.char(206)] = string.char(248), [string.char(207)] = string.char(249),
[string.char(208)] = string.char(230), [string.char(209)] = string.char(231),
[string.char(210)] = string.char(228), [string.char(211)] = string.char(229),
[string.char(212)] = string.char(226), [string.char(213)] = string.char(227),
[string.char(214)] = string.char(224), [string.char(215)] = string.char(225),
[string.char(216)] = string.char(238), [string.char(217)] = string.char(239),
[string.char(218)] = string.char(236), [string.char(219)] = string.char(237),
[string.char(220)] = string.char(234), [string.char(221)] = string.char(235),
[string.char(222)] = string.char(232), [string.char(223)] = string.char(233),
[string.char(224)] = string.char(214), [string.char(225)] = string.char(215),
[string.char(226)] = string.char(212), [string.char(227)] = string.char(213),
[string.char(228)] = string.char(210), [string.char(229)] = string.char(211),
[string.char(230)] = string.char(208), [string.char(231)] = string.char(209),
[string.char(232)] = string.char(222), [string.char(233)] = string.char(223),
[string.char(234)] = string.char(220), [string.char(235)] = string.char(221),
[string.char(236)] = string.char(218), [string.char(237)] = string.char(219),
[string.char(238)] = string.char(216), [string.char(239)] = string.char(217),
[string.char(240)] = string.char(198), [string.char(241)] = string.char(199),
[string.char(242)] = string.char(196), [string.char(243)] = string.char(197),
[string.char(244)] = string.char(194), [string.char(245)] = string.char(195),
[string.char(246)] = string.char(192), [string.char(247)] = string.char(193),
[string.char(248)] = string.char(206), [string.char(249)] = string.char(207),
[string.char(250)] = string.char(204), [string.char(251)] = string.char(205),
[string.char(252)] = string.char(202), [string.char(253)] = string.char(203),
[string.char(254)] = string.char(200), [string.char(255)] = string.char(201),
}
local blocksize = 64 -- 512 bits
function hmac_sha1(key, text)
assert(type(key) == 'string', "key passed to hmac_sha1 should be a string")
assert(type(text) == 'string', "text passed to hmac_sha1 should be a string")
if #key > blocksize then
key = sha1_binary(key)
end
local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. string.rep(string.char(0x36), blocksize - #key)
local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. string.rep(string.char(0x5c), blocksize - #key)
return sha1(key_xord_with_0x5c .. sha1_binary(key_xord_with_0x36 .. text))
end
function hmac_sha1_binary(key, text)
return hex_to_binary(hmac_sha1(key, text))
end
--# mysql
-- copyright (c) Yichun Zhang (agentzh)
-- original code available at https://github.com/openresty/lua-resty-mysql
--
-- this version was modified by jack0088@me.com specifically for use in Codea
local socket = require("socket")
local sub = string.sub
local tcp = socket.tcp
local strbyte = string.byte
local strchar = string.char
local strfind = string.find
local format = string.format
local strrep = string.rep
local null = false
local band = function(a, b) return a & b end
local bxor = function(a, b) return a ~ b end
local bor = function(a, b) return a | b end
local lshift = function(a, b) return a << b end
local rshift = function(a, b) return a >> b end
local sha1 = sha1_binary
local concat = table.concat
local unpack = unpack
local setmetatable = setmetatable
local error = error
local tonumber = tonumber
local new_tab = function (narr, nrec) return {} end
mysql = {
_VERSION = '0.17-custom',
_URL = "https://github.com/openresty/lua-resty-mysql",
_DESCRIPTION = [[
This Lua library is a MySQL client driver and takes advantage of luasocket 3.0 API.
Note that this library was modified to work under Codea.
Dependencies are: SHA1, Bit32 and LuaSocket! (Bit32 and LuaSocket 3.0 libraries are available in Codea by default)
]]
}
local mt = { __index = mysql }
-- constants
local COM_QUIT = 0x01
local COM_QUERY = 0x03
local CLIENT_SSL = 0x0800
local SERVER_MORE_RESULTS_EXISTS = 8
-- 16MB - 1, the default max allowed packet size used by libmysqlclient
local FULL_PACKET_SIZE = 16777215
-- mysql field value type converters
local converters = new_tab(0, 8)
for i = 0x01, 0x05 do
-- tiny, short, long, float, double
converters[i] = tonumber
end
-- converters[0x08] = tonumber -- long long
converters[0x09] = tonumber -- int24
converters[0x0d] = tonumber -- year
converters[0xf6] = tonumber -- newdecimal
local function _get_byte2(data, i)
local a, b = strbyte(data, i, i + 1)
return bor(a, lshift(b, 8)), i + 2
end
local function _get_byte3(data, i)
local a, b, c = strbyte(data, i, i + 2)
return bor(a, lshift(b, 8), lshift(c, 16)), i + 3
end
local function _get_byte4(data, i)
local a, b, c, d = strbyte(data, i, i + 3)
return bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24)), i + 4
end
local function _get_byte8(data, i)
local a, b, c, d, e, f, g, h = strbyte(data, i, i + 7)
-- XXX workaround for the lack of 64-bit support in bitop:
local lo = bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24))
local hi = bor(e, lshift(f, 8), lshift(g, 16), lshift(h, 24))
return lo + hi * 4294967296, i + 8
-- return bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24), lshift(e, 32), lshift(f, 40), lshift(g, 48), lshift(h, 56)), i + 8
end
local function _set_byte2(n)
return strchar(band(n, 0xff), band(rshift(n, 8), 0xff))
end
local function _set_byte3(n)
return strchar(band(n, 0xff),
band(rshift(n, 8), 0xff),
band(rshift(n, 16), 0xff))
end
local function _set_byte4(n)
return strchar(band(n, 0xff),
band(rshift(n, 8), 0xff),
band(rshift(n, 16), 0xff),
band(rshift(n, 24), 0xff))
end
local function _from_cstring(data, i)
local last = strfind(data, "\0", i, true)
if not last then
return nil, nil
end
return sub(data, i, last), last + 1
end
local function _to_cstring(data)
return data .. "\0"
end
local function _to_binary_coded_string(data)
return strchar(#data) .. data
end
local function _dump(data)
local len = #data
local bytes = new_tab(len, 0)
for i = 1, len do
bytes[i] = format("%x", strbyte(data, i))
end
return concat(bytes, " ")
end
local function _compute_token(password, scramble)
if password == "" then
return ""
end
local stage1 = sha1(password)
local stage2 = sha1(stage1)
local stage3 = sha1(scramble .. stage2)
local n = #stage1
local bytes = new_tab(n, 0)
for i = 1, n do
bytes[i] = strchar(bxor(strbyte(stage3, i), strbyte(stage1, i)))
end
return concat(bytes)
end
local function _send_packet(self, req, size)
local sock = self.sock
self.packet_no = self.packet_no + 1
-- print("packet no: ", self.packet_no)
local packet = _set_byte3(size) .. strchar(band(self.packet_no, 255)) .. req
--print("sending packet: ", _dump(packet))
-- print("sending packet... of size " .. #packet)
return sock:send(packet)
end
local function _recv_packet(self)
local sock = self.sock
local data, err = sock:receive(4) -- packet header
if not data then
return nil, nil, "failed to receive packet header: " .. err
end
--print("packet header: ", _dump(data))
local len, pos = _get_byte3(data, 1)
--print("packet length: ", len)
if len == 0 then
return nil, nil, "empty packet"
end
if len > self._max_packet_size then
return nil, nil, "packet size too big: " .. len
end
local num = strbyte(data, pos)
--print("recv packet: packet no: ", num)
self.packet_no = num
data, err = sock:receive(len)
--print("receive returned")
if not data then
return nil, nil, "failed to read packet content: " .. err
end
--print("packet content: ", _dump(data))
--print("packet content (ascii): ", data)
local field_count = strbyte(data, 1)
local typ
if field_count == 0x00 then
typ = "OK"
elseif field_count == 0xff then
typ = "ERR"
elseif field_count == 0xfe then
typ = "EOF"
elseif field_count <= 250 then
typ = "DATA"
end
return data, typ
end
local function _from_length_coded_bin(data, pos)
local first = strbyte(data, pos)
--print("LCB: first: ", first)
if not first then
return nil, pos
end
if first >= 0 and first <= 250 then
return first, pos + 1
end
if first == 251 then
return null, pos + 1
end
if first == 252 then
pos = pos + 1
return _get_byte2(data, pos)
end
if first == 253 then
pos = pos + 1
return _get_byte3(data, pos)
end
if first == 254 then
pos = pos + 1
return _get_byte8(data, pos)
end
return nil, pos + 1
end
local function _from_length_coded_str(data, pos)
local len
len, pos = _from_length_coded_bin(data, pos)
if not len or len == null then
return null, pos
end
return sub(data, pos, pos + len - 1), pos + len
end
local function _parse_ok_packet(packet)
local res = new_tab(0, 5)
local pos
res.affected_rows, pos = _from_length_coded_bin(packet, 2)
--print("affected rows: ", res.affected_rows, ", pos:", pos)
res.insert_id, pos = _from_length_coded_bin(packet, pos)
--print("insert id: ", res.insert_id, ", pos:", pos)
res.server_status, pos = _get_byte2(packet, pos)
--print("server status: ", res.server_status, ", pos:", pos)
res.warning_count, pos = _get_byte2(packet, pos)
--print("warning count: ", res.warning_count, ", pos: ", pos)
local message = sub(packet, pos)
if message and message ~= "" then
res.message = message
end
--print("message: ", res.message, ", pos:", pos)
return res
end
local function _parse_eof_packet(packet)
local pos = 2
local warning_count, pos = _get_byte2(packet, pos)
local status_flags = _get_byte2(packet, pos)
return warning_count, status_flags
end
local function _parse_err_packet(packet)
local errno, pos = _get_byte2(packet, 2)
local marker = sub(packet, pos, pos)
local sqlstate
if marker == '#' then
-- with sqlstate
pos = pos + 1
sqlstate = sub(packet, pos, pos + 5 - 1)
pos = pos + 5
end
local message = sub(packet, pos)
return errno, message, sqlstate
end
local function _parse_result_set_header_packet(packet)
local field_count, pos = _from_length_coded_bin(packet, 1)
local extra
extra = _from_length_coded_bin(packet, pos)
return field_count, extra
end
local function _parse_field_packet(data)
local col = new_tab(0, 2)
local catalog, db, table, orig_table, orig_name, charsetnr, length
local pos
catalog, pos = _from_length_coded_str(data, 1)
--print("catalog: ", col.catalog, ", pos:", pos)
db, pos = _from_length_coded_str(data, pos)
table, pos = _from_length_coded_str(data, pos)
orig_table, pos = _from_length_coded_str(data, pos)
col.name, pos = _from_length_coded_str(data, pos)
orig_name, pos = _from_length_coded_str(data, pos)
pos = pos + 1 -- ignore the filler
charsetnr, pos = _get_byte2(data, pos)
length, pos = _get_byte4(data, pos)
col.type = strbyte(data, pos)
--[[
pos = pos + 1
col.flags, pos = _get_byte2(data, pos)
col.decimals = strbyte(data, pos)
pos = pos + 1
local default = sub(data, pos + 2)
if default and default ~= "" then
col.default = default
end
--]]
return col
end
local function _parse_row_data_packet(data, cols, compact)
local pos = 1
local ncols = #cols
local row
if compact then
row = new_tab(ncols, 0)
else
row = new_tab(0, ncols)
end
for i = 1, ncols do
local value
value, pos = _from_length_coded_str(data, pos)
local col = cols[i]
local typ = col.type
local name = col.name
--print("row field value: ", value, ", type: ", typ)
if value ~= null then
local conv = converters[typ]
if conv then
value = conv(value)
end
end
if compact then
row[i] = value
else
row[name] = value
end
end
return row
end
local function _recv_field_packet(self)
local packet, typ, err = _recv_packet(self)
if not packet then
return nil, err
end
if typ == "ERR" then
local errno, msg, sqlstate = _parse_err_packet(packet)
return nil, msg, errno, sqlstate
end
if typ ~= 'DATA' then
return nil, "bad field packet type: " .. typ
end
-- typ == 'DATA'
return _parse_field_packet(packet)
end
-- Global accessors
function mysql.new(self)
local sock, err = tcp()
if not sock then
return nil, err
end
return setmetatable({ sock = sock }, mt)
end
function mysql.set_timeout(self, timeout)
local sock = self.sock
if not sock then
return nil, "not initialized"
end
return sock:settimeout(timeout)
end
function mysql.connect(self, opts)
local sock = self.sock
if not sock then
return nil, "not initialized"
end
local max_packet_size = opts.max_packet_size
if not max_packet_size then
max_packet_size = 1024 * 1024 -- default 1 MB
end
self._max_packet_size = max_packet_size
local ok, err
self.compact = opts.compact_arrays
local database = opts.database or ""
local user = opts.user or "root"
local pool = opts.pool
local host = opts.host
if host then
local port = opts.port or 3306
if not pool then
pool = user .. ":" .. database .. ":" .. host .. ":" .. port
end
ok, err = sock:connect(host, port, { pool = pool })
else
local path = opts.path
if not path then
return nil, 'neither "host" nor "path" options are specified'
end
if not pool then
pool = user .. ":" .. database .. ":" .. path
end
ok, err = sock:connect("unix:" .. path, { pool = pool })
end
if not ok then
return nil, 'failed to connect: ' .. err
end
local packet, typ, err = _recv_packet(self)
if not packet then
return nil, err
end
if typ == "ERR" then
local errno, msg, sqlstate = _parse_err_packet(packet)
return nil, msg, errno, sqlstate
end
self.protocol_ver = strbyte(packet)
--print("protocol version: ", self.protocol_ver)
local server_ver, pos = _from_cstring(packet, 2)
if not server_ver then
return nil, "bad handshake initialization packet: bad server version"
end
--print("server version: ", server_ver)
self._server_ver = server_ver
local thread_id, pos = _get_byte4(packet, pos)
--print("thread id: ", thread_id)
local scramble = sub(packet, pos, pos + 8 - 1)
if not scramble then
return nil, "1st part of scramble not found"
end
pos = pos + 9 -- skip filler
-- two lower bytes
local capabilities -- server capabilities
capabilities, pos = _get_byte2(packet, pos)
-- print(format("server capabilities: %#x", capabilities))
self._server_lang = strbyte(packet, pos)
pos = pos + 1
--print("server lang: ", self._server_lang)
self._server_status, pos = _get_byte2(packet, pos)
--print("server status: ", self._server_status)
local more_capabilities
more_capabilities, pos = _get_byte2(packet, pos)
capabilities = bor(capabilities, lshift(more_capabilities, 16))
--print("server capabilities: ", capabilities)
-- local len = strbyte(packet, pos)
local len = 21 - 8 - 1
--print("scramble len: ", len)
pos = pos + 1 + 10
local scramble_part2 = sub(packet, pos, pos + len - 1)
if not scramble_part2 then
return nil, "2nd part of scramble not found"
end
scramble = scramble .. scramble_part2
--print("scramble: ", _dump(scramble))
local client_flags = 0x3f7cf;
local ssl_verify = opts.ssl_verify
local use_ssl = opts.ssl or ssl_verify
if use_ssl then
if band(capabilities, CLIENT_SSL) == 0 then
return nil, "ssl disabled on server"
end
-- send a SSL Request Packet
local req = _set_byte4(bor(client_flags, CLIENT_SSL))
.. _set_byte4(self._max_packet_size)
.. "\0" -- TODO: add support for charset encoding
.. strrep("\0", 23)
local packet_len = 4 + 4 + 1 + 23
local bytes, err = _send_packet(self, req, packet_len)
if not bytes then
return nil, "failed to send client authentication packet: " .. err
end
local ok, err = sock:sslhandshake(false, nil, ssl_verify)
if not ok then
return nil, "failed to do ssl handshake: " .. (err or "")
end
end
local password = opts.password or ""
local token = _compute_token(password, scramble)
--print("token: ", _dump(token))
local req = _set_byte4(client_flags)
.. _set_byte4(self._max_packet_size)
.. "\0" -- TODO: add support for charset encoding
.. strrep("\0", 23)
.. _to_cstring(user)
.. _to_binary_coded_string(token)
.. _to_cstring(database)
local packet_len = 4 + 4 + 1 + 23 + #user + 1
+ #token + 1 + #database + 1
--print("packet content length: ", packet_len)
--print("packet content: ", _dump(concat(req, "")))
local bytes, err = _send_packet(self, req, packet_len)
if not bytes then
return nil, "failed to send client authentication packet: " .. err
end
--print("packet sent ", bytes, " bytes")
local packet, typ, err = _recv_packet(self)
if not packet then
return nil, "failed to receive the result packet: " .. err
end
if typ == 'ERR' then
local errno, msg, sqlstate = _parse_err_packet(packet)
return nil, msg, errno, sqlstate
end
if typ == 'EOF' then
return nil, "old pre-4.1 authentication protocol not supported"
end
if typ ~= 'OK' then
return nil, "bad packet type: " .. typ
end
return 1
end
function mysql.close(self)
local sock = self.sock
if not sock then
return nil, "not initialized"
end
local bytes, err = _send_packet(self, strchar(COM_QUIT), 1)
if not bytes then
return nil, err
end
return sock:close()
end
function mysql.server_ver(self)
return self._server_ver
end
local function send_query(self, query)
local sock = self.sock
if not sock then
return nil, "not initialized"
end
self.packet_no = -1
local cmd_packet = strchar(COM_QUERY) .. query
local packet_len = 1 + #query
local bytes, err = _send_packet(self, cmd_packet, packet_len)
if not bytes then
return nil, err
end
--print("packet sent ", bytes, " bytes")
return bytes
end
mysql.send_query = send_query
local function read_result(self, est_nrows)
local sock = self.sock
if not sock then
return nil, "not initialized"
end
local packet, typ, err = _recv_packet(self)
if not packet then
return nil, err
end
if typ == "ERR" then
local errno, msg, sqlstate = _parse_err_packet(packet)
return nil, msg, errno, sqlstate
end
if typ == 'OK' then
local res = _parse_ok_packet(packet)
if res and band(res.server_status, SERVER_MORE_RESULTS_EXISTS) ~= 0 then
return res, "again"
end
return res
end
if typ ~= 'DATA' then
return nil, "packet type " .. typ .. " not supported"
end
-- typ == 'DATA'
--print("read the result set header packet")
local field_count, extra = _parse_result_set_header_packet(packet)
--print("field count: ", field_count)
local cols = new_tab(field_count, 0)
for i = 1, field_count do
local col, err, errno, sqlstate = _recv_field_packet(self)
if not col then
return nil, err, errno, sqlstate
end
cols[i] = col
end
local packet, typ, err = _recv_packet(self)
if not packet then
return nil, err
end
if typ ~= 'EOF' then
return nil, "unexpected packet type " .. typ .. " while eof packet is "
.. "expected"
end
-- typ == 'EOF'
local compact = self.compact
local rows = new_tab(est_nrows or 4, 0)
local i = 0
while true do
--print("reading a row")
packet, typ, err = _recv_packet(self)
if not packet then
return nil, err
end
if typ == 'EOF' then
local warning_count, status_flags = _parse_eof_packet(packet)
--print("status flags: ", status_flags)
if band(status_flags, SERVER_MORE_RESULTS_EXISTS) ~= 0 then
return rows, "again"
end
break
end
h
-- if typ ~= 'DATA' then
-- return nil, 'bad row packet type: ' .. typ
-- end
-- typ == 'DATA'
local row = _parse_row_data_packet(packet, cols, compact)
i = i + 1
rows[i] = row
end
return rows
end
mysql.read_result = read_result
function mysql.query(self, query, est_nrows)
local bytes, err = send_query(self, query)
if not bytes then
return nil, "failed to send query: " .. err
end
return read_result(self, est_nrows)
end
function mysql.set_compact_arrays(self, value)
self.compact = value
end
--# io
lfs = {}
local ENV = os.getenv("HOME")
local MIME = {
[".text"] = "text/plain",
[".txt"] = "text/plain",
[".md"] = "text/markdown",
[".markdown"] = "text/markdown",
[".lua"] = "text/x-lua",
[".luac"] = "application/x-lua-bytecode",
[".pdf"] = "application/pdf",
[".jpeg"] = "image/jpeg",
[".jpg"] = "image/jpeg",
[".gif"] = "image/gif",
[".png"] = "image/png",
[".tiff"] = "image/tiff",
[".html"] = "text/html",
[".htm"] = "text/html",
[".css"] = "text/html",
[".js"] = "application/javascript",
[".json"] = "application/json",
}
local function breadcrumbs(path)
return path:gsub(":", "/"):match("(.+)/(.+)(%.[^.]+)$")
end
function lfs.read(file)
local DIR, FILE, EXT = breadcrumbs(file)
local data = io.open(string.format("%s/%s/%s", ENV, DIR, FILE..EXT), "r")
if data then
local content = data:read("*all")
data:close()
return content, MIME[EXT]
end
return false
end
function lfs.write(file, content)
local DIR, FILE, EXT = breadcrumbs(file)
local data = io.open(string.format("%s/%s/%s", ENV, DIR, FILE..EXT), "w")
if data then
wFd:write(td)
wFd:close()
return true
end
return false
end
-- also an example how to read sequentially
function lfs.read_binary(file)
local DIR, FILE, EXT = breadcrumbs(file)
local data = io.open(string.format("%s/%s/%s", ENV, DIR, FILE..EXT), "rb")
if data then
local chunks = 512
local content = ""
while true do
local bytes = data:read(chunks) -- Read only n bytes per iteration
if not bytes then break end
content = content..bytes
break
end
data:close()
return content, MIME[EXT]
end
return false
end
function lfs.write_binary(file, content)
local DIR, FILE, EXT = breadcrumbs(file)
local data = io.open(string.format("%s/%s/%s", ENV, DIR, FILE..EXT), "wb")
if data then
data:write(content) -- You could do it in parts, but oh.
data:close()
return true
end
return false
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment