304 lines
7.7 KiB
Lua
304 lines
7.7 KiB
Lua
local version = "1.0.0"
|
|
local bin = require("bin")
|
|
local multi = require("multi")
|
|
local function merge(t1, t2)
|
|
for k,v in pairs(t2) do
|
|
if type(v) == 'table' then
|
|
if type(t1[k] or false) == 'table' then
|
|
merge(t1[k] or {}, t2[k] or {})
|
|
else
|
|
t1[k] = v
|
|
end
|
|
else
|
|
t1[k] = v
|
|
end
|
|
end
|
|
return t1
|
|
end
|
|
local function getOS()
|
|
if package.config:sub(1,1)=='\\' then
|
|
return 'windows'
|
|
else
|
|
return 'unix'
|
|
end
|
|
end
|
|
local function mkDir(dirname)
|
|
os.execute('mkdir "' .. dirname..'"')
|
|
end
|
|
local function capture(cmd, raw)
|
|
local f = assert(io.popen(cmd, 'r'))
|
|
local s = assert(f:read('*a'))
|
|
f:close()
|
|
if raw then return s end
|
|
s = string.gsub(s, '^%s+', '')
|
|
s = string.gsub(s, '%s+$', '')
|
|
s = string.gsub(s, '[\n\r]+', ' ')
|
|
return s
|
|
end
|
|
local function getWorkingDir()
|
|
return io.popen'cd':read'*l'
|
|
end
|
|
function getDir(dir)
|
|
if not dir then return getWorkingDir() end
|
|
if getOS()=='unix' then
|
|
return capture('cd '..dir..' ; cd')
|
|
else
|
|
return capture('cd '..dir..' & cd')
|
|
end
|
|
end
|
|
function dirExists(strFolderName)
|
|
strFolderName = strFolderName or getDir()
|
|
local fileHandle, strError = io.open(strFolderName..'\\*.*','r')
|
|
if fileHandle ~= nil then
|
|
io.close(fileHandle)
|
|
return true
|
|
else
|
|
if string.match(strError,'No such file or directory') then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
function scandir(directory)
|
|
if not dirExists(directory) then error("Must enter a valid location for scanning a directory!") end
|
|
local i, t, popen = 0, {}, io.popen
|
|
if getOS()=='unix' then
|
|
for filename in popen('ls -a "'..directory..'"'):lines() do
|
|
i = i + 1
|
|
t[i] = filename
|
|
end
|
|
else
|
|
for filename in popen('dir "'..directory..'" /b'):lines() do
|
|
i = i + 1
|
|
t[i] = filename
|
|
end
|
|
end
|
|
return t
|
|
end
|
|
local function split(str)
|
|
local tab = {}
|
|
for word in string.gmatch(str, '([^,]+)') do
|
|
table.insert(tab,word)
|
|
end
|
|
return tab
|
|
end
|
|
local pluginLocation
|
|
local protection = true
|
|
local exposed = {}
|
|
local function _setPluginFolder(path)
|
|
if not dirExists(path) then
|
|
mkDir(path)
|
|
end
|
|
pluginLocation = path
|
|
end
|
|
local function _setProtection(bool)
|
|
protection = bool
|
|
end
|
|
local function _expose(tab,readonly)
|
|
if type(tab)=="string" then
|
|
if tab=="*" or tab:match("*") then
|
|
merge(exposed,_G)
|
|
return
|
|
elseif tab=="std" then
|
|
tab = [[_VERSION,assert,collectgarbage,error,getfenv,getmetatable,ipairs,loadstring,module,next,pairs,pcall,print,rawequal,rawget,rawset,select,setfenv,setmetatable,tonumber,tostring,type,unpack,xpcall,math,coroutine,string,table]]
|
|
_expose({
|
|
io = {tmpfile = io.tmpfile,write = io.write},
|
|
os = {clock = os.clock,date = os.date,difftime = os.difftime,getenv = os.getenv,setlocale = os.setlocale,time = os.time,tmpname = os.tmpname},
|
|
_G = exposed
|
|
},readonly)
|
|
end
|
|
local tab = split(tab)
|
|
for i = 1,#tab do
|
|
exposed[tab[i]] = _G[tab[i]]
|
|
end
|
|
elseif type(tab)=="table" then
|
|
merge(exposed,tab)
|
|
if readonly then
|
|
setmetatable(exposed,{
|
|
__index = _G
|
|
})
|
|
end
|
|
else
|
|
if readonly then
|
|
setmetatable(exposed,{
|
|
__index = _G
|
|
})
|
|
end
|
|
end
|
|
end
|
|
local function file_exists(name)
|
|
local f=io.open(name,"r")
|
|
if f~=nil then io.close(f) return true else return false end
|
|
end
|
|
local function _import(name,data)
|
|
__imports[name] = data
|
|
end
|
|
local GLOBAL = {__PluginList={},vars = {}}
|
|
local conn = multi:newConnection(true)
|
|
local conn2 = multi:newConnection(true)
|
|
local conn3 = multi:newConnection(true)
|
|
local conn4 = multi:newConnection(true) -- Cleanup
|
|
local conn5 = multi:newConnection(true) -- Cleanup
|
|
-- And yes these names are really bad, doesn't matter
|
|
local plugs = {}
|
|
local function cleanTab(tab)
|
|
for i,v in pairs(tab) do
|
|
tab[i]=nil
|
|
end
|
|
end
|
|
local __imports = {}
|
|
local function load_(path)
|
|
if not file_exists(pluginLocation..package.config:sub(1,1)..path) then return end
|
|
local chunk = loadfile(pluginLocation..package.config:sub(1,1)..path)
|
|
if not chunk then error("Could not load plugin: "..path) end
|
|
local temp = {}
|
|
merge(temp,exposed)
|
|
merge(temp,{
|
|
import = function(name)
|
|
return __imports[name]
|
|
end,
|
|
plugin = {
|
|
version = version,
|
|
OnLoaded = conn,
|
|
OnPreload = conn3,
|
|
OnReboot = conn4,
|
|
init = function(version)
|
|
local name = path:sub(1,-5):lower() -- Plugin name is equal to filename
|
|
temp["PLUGIN_NAME"]=name
|
|
GLOBAL[name] = {version = version or "1.0.0"}
|
|
table.insert(GLOBAL.__PluginList,name)
|
|
if not dirExists(pluginLocation..package.config:sub(1,1)..name) then
|
|
mkDir(pluginLocation..package.config:sub(1,1)..name)
|
|
end
|
|
end,
|
|
request = function(method,err)
|
|
local met
|
|
if type(method) == "string" then
|
|
met = split(method)
|
|
elseif type(method) == "table" then
|
|
met = method
|
|
end
|
|
local count = 0
|
|
local max = #met
|
|
local missing = {}
|
|
for ii = 1,#met do
|
|
if temp[met[ii]] then
|
|
count = count + 1
|
|
else
|
|
table.insert(missing,met[ii])
|
|
end
|
|
end
|
|
if err and count ~= max then
|
|
print((temp["PLUGIN_NAME"] or "Unnamed Plugin").." is missing some resources to be able to function properly! Try granting these features to the plugin if you trust it: ")
|
|
for i = 1,#missing do
|
|
print("> "..missing[i])
|
|
end
|
|
elseif count ~= max then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
openFreshFile = function(path)
|
|
local t = package.config:sub(1,1)
|
|
return bin.freshStream(pluginLocation..t..temp["PLUGIN_NAME"]..t..path)
|
|
end,
|
|
openFile = function(path)
|
|
local t = package.config:sub(1,1)
|
|
return bin.stream(pluginLocation..t..temp["PLUGIN_NAME"]..t..path,false)
|
|
end,
|
|
deleteFile = function(path)
|
|
local t = package.config:sub(1,1)
|
|
os.remove(pluginLocation..t..temp["PLUGIN_NAME"]..t..path,false)
|
|
end,
|
|
fileExists = function(path)
|
|
local t = package.config:sub(1,1)
|
|
return file_exists(pluginLocation..t..temp["PLUGIN_NAME"]..t..path)
|
|
end,
|
|
setGlobal = function(var,val)
|
|
GLOBAL.vars[var]=val
|
|
end,
|
|
getGlobal = function(var)
|
|
return GLOBAL.vars[var]
|
|
end,
|
|
getPluginList = function()
|
|
return GLOBAL.__PluginList
|
|
end,
|
|
getPluginRef = function(name)
|
|
local meh = {}
|
|
local link = GLOBAL[name:lower()]
|
|
setmetatable(meh,{
|
|
__index = link -- Cannot alter a plugin's created domain but can read from it
|
|
})
|
|
return meh
|
|
end,
|
|
register = function(name,value)
|
|
GLOBAL[temp["PLUGIN_NAME"]][name] = value
|
|
end,
|
|
expose = function()
|
|
return GLOBAL[temp["PLUGIN_NAME"]]
|
|
end,
|
|
getName = function()
|
|
return temp["PLUGIN_NAME"]
|
|
end,
|
|
}
|
|
})
|
|
conn2:Fire(temp,path)
|
|
setfenv(chunk, temp)
|
|
chunk()
|
|
table.insert(plugs,{chunk,temp,GLOBAL,path})
|
|
conn5(function()
|
|
cleanTab(GLOBAL)
|
|
GLOBAL.__PluginList={}
|
|
GLOBAL.vars = {}
|
|
end)
|
|
if not temp["PLUGIN_NAME"] then
|
|
temp.plugin.init(path:sub(1,-5))
|
|
end
|
|
end
|
|
local granted = {}
|
|
conn2(function(tab,path)
|
|
if granted[path] then
|
|
merge(tab,granted[path])
|
|
end
|
|
end)
|
|
local function _grant(path,tab)
|
|
granted[path] = tab
|
|
end
|
|
local function _load()
|
|
local files = scandir(pluginLocation)
|
|
for i = 1,#files do
|
|
if protection then
|
|
a,b = pcall(load_,files[i])
|
|
if not a then print(b) end
|
|
else
|
|
load_(files[i])
|
|
end
|
|
end
|
|
conn3:Fire()
|
|
conn:Fire(#files)
|
|
end
|
|
local function _reload()
|
|
conn:Bind({}) -- bind to a new connection space
|
|
conn3:Bind({}) -- this in turn removes all references that are connected to the connection obj
|
|
conn4:Fire() -- allow the plugin to clean up some stuff
|
|
conn5:Fire() -- resets all the GLOBAL namespace that is exposed to all plugins
|
|
collectgarbage()
|
|
for i=1,#plugs do
|
|
plugs[i][1]() -- reload the plugins
|
|
end
|
|
conn3:Fire()
|
|
end
|
|
local plugin = {}
|
|
plugin.version = version
|
|
plugin.setPluginFolder = _setPluginFolder
|
|
plugin.setProtection =_setProtection
|
|
plugin.expose =_expose
|
|
plugin.load =_load
|
|
plugin.setImport = _import
|
|
plugin.grant = _grant
|
|
-- plugin.reloadPlugins = _reload
|
|
return plugin
|