local Luan = require "luan:Luan.luan" local error = Luan.error local type = Luan.type or error() local new_error = Luan.new_error or error() local set_metatable = Luan.set_metatable or error() local ipairs = Luan.ipairs or error() local pairs = Luan.pairs or error() local Table = require "luan:Table.luan" local table_size = Table.size or error() local Number = require "luan:Number.luan" local integer = Number.integer or error() local Io = require "luan:Io.luan" local uri = Io.uri or error() local Http = require "luan:http/Http.luan" local Logging = require "luan:logging/Logging.luan" local logger = Logging.logger "Shared" local Parsers = require "luan:Parsers.luan" local json_parse = Parsers.json_parse or error() local json_string = Parsers.json_string or error() local Shared = {} Shared.is_production = Http.domain == "api.openshipper.com" Shared.time_format = "yyyy-MM-dd HH:mm:ss" local base_url = (Shared.is_production and "https" or "http").."://"..(Http.domain or "localhost:8080") Shared.base_url = base_url local function user_error(msg) local e = new_error(msg) e.error = { okay = false error = msg } e.throw() end Shared.user_error = user_error function Shared.handle_error(fn) type(fn)=="function" or error() return function(...) try return fn(...) catch e return e.error or e.throw() end end end function Shared.read_text(url,options) try return uri(url,options).read_text() catch e local msg = e.get_message() if msg=="Read timed out" or msg=="connect timed out" then logger.info(e) user_error(msg) end e.throw() end end local set_mt = {} function set_mt.__index(table,key) return false end function Shared.list_to_set(list) local set = {} for _, v in ipairs(list) do set[v] = true end set_metatable(set,set_mt) return set end local function is_list(tbl) return #tbl == table_size(tbl) end function Shared.to_list(input) if input == nil then return {} elseif type(input) == "table" and is_list(input) then return input else return {input} end end local function in_what(what) return what and " in '"..what.name.."'"..in_what(what.parent) or "" end local function transform_flat(fields,flat,parent) --print("transform_flat") for field_name, field in pairs(fields) do if field.required then flat[field_name] or user_error("missing required field '"..field_name.."'"..in_what(parent)) end end for key, value in pairs(flat) do local field = fields[key] or user_error("invalid field '"..key.."'"..in_what(parent)) local value_type = type(value) local field_type = field.type local name = field.name or key value_type==field_type or user_error("field '"..key.."'"..in_what(parent).." must be type "..field_type) parent[name] = value end return parent end local function transform_map(fields,map,parent) for field_name, field in pairs(fields) do if field.required then map[field_name] or user_error("missing required field '"..field_name.."'"..in_what(parent)) end end local rtn = {} for key, value in pairs(map) do local field = fields[key] if field == nil then continue -- ignore unrecognized fields end local field_type = field.type local value_type = type(value) local name = field.name or key if field_type == "map" then value_type=="table" and #value==0 or user_error("field '"..key.."'"..in_what(parent).." must be type object") rtn[name] = transform_map( field.child, value, {name=key,parent=parent} ) elseif field_type == "flat" then --print("transform_map flat type") rtn = transform_flat( field.child, value, rtn) elseif field_type == "list" then value_type=="table" and is_list(value) or user_error("field '"..key.."'"..in_what(parent).." must be type array") local children = field.children local this = {name=key,parent=parent} local list = {} for _, entry in ipairs(value) do list[#list+1] = transform_map(children,entry,this) end rtn[name] = list elseif field_type == "integer" then value_type=="number" or user_error("field '"..key.."'"..in_what(parent).." must be an integer") try rtn[name] = integer(value) catch e user_error("field '"..key.."'"..in_what(parent).." must be an integer") end else value_type==field_type or user_error("field '"..key.."'"..in_what(parent).." must be type "..field_type) rtn[name] = value end end return rtn end Shared.transform_map = transform_map local mp_id = Shared.is_production and "abc355c2938fdcb0a55e4e9b7625b30c" or "6cff3705b0e4edf7c5a750059e76af40" local mp_url = "https://api.mixpanel.com/track#live-event" function Shared.call_mixpanel(data) data.properties.token = mp_id local options = { method = "POST" parameters = { data = json_string(data) verbose = "1" } } local result = uri(mp_url,options).read_text() result = json_parse(result) result.error and logger.error("mixpanel: "..result.error) end Shared.rmb_to_usd = 0.15 return Shared