Last active
February 20, 2020 07:36
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# 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 | |
-- [email protected] | |
-- 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 [email protected] 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