Module Require With Load (code snippet)

Description

In addition to the standard modules installed with Family Historian Lua has a range of additional modules available.

Several are currently available from Calico Pie using the script below.

    • To load use loadrequire( "luasql", "luasql.sqlite3" )
    • Using sqlite3 requires no other database items so makes a good place for complex data.

If you require additional modules, please contact support@family-historian.co.uk requesting the module to be added to the repository.

Requires: lfs and luacom

Code

require 'lfs'
require 'luacom'
 
local function httpRequest(url)
    local http = luacom.CreateObject("winhttp.winhttprequest.5.1")
    http:Open("GET",url,false)
    http:Send()
    http:WaitForResponse(30)
    return http
end -- local function httpRequest
 
 
function loadrequire(module,extended)
    if not(extended) then extended = module end
    local function installmodule(module,filename,size)
        local bmodule = false
        if not(filename) then
            filename = module..'.mod'
            bmodule = true
        end
        local storein = fhGetContextInfo('CI_APP_DATA_FOLDER')..'\\Plugins\\'
        -- Check if subdirectory needed
        local path = string.match(filename, "(.-)[^/]-[^%.]+$")
        if path ~= "" then
            path = path:gsub('/','\\')
            -- Create sub-directory
            lfs.mkdir(storein..path)
        end
        local attr = lfs.attributes(storein..filename)
        if attr and attr.mode == 'file' and attr.size == size then return true end
        -- Get file down and install it
        local url = "http://www.family-historian.co.uk/lnk/getpluginmodule.php?file="..filename
        local isOK, reply = pcall(httpRequest,url)
        if not isOK then
            fhMessageBox(reply.."\nLoad Require module finds the Internet inaccessible.")
            return false
        end
        local http = reply
        local status = http.StatusText
        if status == 'OK' then
            length = http:GetResponseHeader('Content-Length')
            data = http.ResponseBody
            if bmodule then
                local modlist = loadstring(http.ResponseBody)
                for x,y in pairs(modlist()) do
                    if type(x) == 'number' and type(y) == 'string' then
                        x = y -- revert to original 'filename' ipairs modlist
                        y = 0
                    end -- otherwise use ['filename']=size pairs modlist
                    if not(installmodule(module,x,y)) then
                        break
                    end
                end
            else
                local function OpenFile(strFileName,strMode)
                    local fileHandle, strError = io.open(strFileName,strMode)
                    if not fileHandle then
                        error("\n Unable to open file in \""..strMode.."\" mode. \n "..
                        strFileName.." \n "..tostring(strError).." \n")
                    end
                    return fileHandle
                end -- OpenFile
                local function SaveStringToFile(strString,strFileName)
                    local fileHandle = OpenFile(strFileName,"wb")
                    fileHandle:write(strString)
                    assert(fileHandle:close())
                end -- SaveStringToFile
                SaveStringToFile(data,storein..filename)
            end
            return true
        else
            fhMessageBox('An error occurred in Download please try later')
            return false
        end
    end
    local function requiref(module)
        require(module)
    end
    local res, err = pcall(requiref,extended)
    if err then
     if  err:match("module '"..extended:gsub("(%W)","%%%1").."' not found") then
        local ans = fhMessageBox(
        'This plugin requires '..module..' support, please click OK to download and install the module',
        'MB_OKCANCEL','MB_ICONEXCLAMATION')
        if ans ~= 'OK' then
            return false
        end
        if installmodule(module) then
            package.loaded[extended] = nil -- Reset Failed Load
            require(extended)
        else
            return false
        end
     else
        fhMessageBox('Error from require("'..module..'") command:\n'..(err or ''))
        return false
    end
  end
  return true
  end

Usage

Instead of a simple require statement, use the following and the module will be checked for and installed if required.

--  Standard Modules
if not( loadrequire( 'md5' ) ) then return end
if not( loadrequire( 'zip' ) ) then return end

-- LuaSql and other modules with extensions need the module to load to be specified e.g.
if not( loadrequire( 'luasql', 'luasql.sqlite3' ) ) then return end
if not( loadrequire( 'pl', 'pl.init' ) ) then return end
pl = require 'pl.import_into'()

Section plugins:code_snippets