gluon-config-api: cleanup dupplicate files
This commit is contained in:
parent
8d5d7531a8
commit
2e13eadabe
@ -1,137 +0,0 @@
|
|||||||
local json = require 'jsonc'
|
|
||||||
local site = require 'gluon.site'
|
|
||||||
local util = require 'gluon.util'
|
|
||||||
local ubus = require 'ubus'
|
|
||||||
local os = require 'os'
|
|
||||||
local glob = require 'posix.glob'
|
|
||||||
local libgen = require 'posix.libgen'
|
|
||||||
local simpleuci = require 'simple-uci'
|
|
||||||
local schema = dofile('/lib/gluon/config-api/controller/schema.lua')
|
|
||||||
local ucl = require "ucl"
|
|
||||||
|
|
||||||
package 'gluon-config-api'
|
|
||||||
|
|
||||||
function load_parts()
|
|
||||||
local parts = {}
|
|
||||||
for _, f in pairs(glob.glob('/lib/gluon/config-api/parts/*.lua')) do
|
|
||||||
table.insert(parts, dofile(f))
|
|
||||||
end
|
|
||||||
return parts
|
|
||||||
end
|
|
||||||
|
|
||||||
function config_get(parts)
|
|
||||||
local config = {}
|
|
||||||
local uci = simpleuci.cursor()
|
|
||||||
|
|
||||||
for _, part in pairs(parts) do
|
|
||||||
part.get(uci, config)
|
|
||||||
end
|
|
||||||
|
|
||||||
return config
|
|
||||||
end
|
|
||||||
|
|
||||||
function schema_get(parts)
|
|
||||||
local total_schema = {}
|
|
||||||
for _, part in pairs(parts) do
|
|
||||||
total_schema = schema.merge_schemas(total_schema, part.schema(site, nil))
|
|
||||||
end
|
|
||||||
return total_schema
|
|
||||||
end
|
|
||||||
|
|
||||||
function config_set(parts, config)
|
|
||||||
local uci = simpleuci.cursor()
|
|
||||||
|
|
||||||
for _, part in pairs(parts) do
|
|
||||||
part.set(config, uci)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pump(src, snk)
|
|
||||||
while true do
|
|
||||||
local chunk, src_err = src()
|
|
||||||
local ret, snk_err = snk(chunk, src_err)
|
|
||||||
|
|
||||||
if not (chunk and ret) then
|
|
||||||
local err = src_err or snk_err
|
|
||||||
if err then
|
|
||||||
return nil, err
|
|
||||||
else
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local parts = load_parts()
|
|
||||||
|
|
||||||
entry({"v1", "config"}, call(function(http, renderer)
|
|
||||||
if http.request.env.REQUEST_METHOD == 'GET' then
|
|
||||||
http:header('Content-Type', 'application/json; charset=utf-8')
|
|
||||||
http:write(json.stringify(config_get(parts), true))
|
|
||||||
elseif http.request.env.REQUEST_METHOD == 'POST' then
|
|
||||||
local request_body = ""
|
|
||||||
pump(http.input, function (data)
|
|
||||||
if data then
|
|
||||||
request_body = request_body .. data
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- Verify that we really have JSON input. UCL is able to parse other
|
|
||||||
-- config formats as well. Those config formats allow includes and so on.
|
|
||||||
-- This may be a security issue.
|
|
||||||
|
|
||||||
local config = json.parse(request_body)
|
|
||||||
if not config then
|
|
||||||
http:status(400, 'Bad Request')
|
|
||||||
http:header('Content-Type', 'application/json; charset=utf-8')
|
|
||||||
http:write('{ "status": 400, "error": "Bad JSON in Body" }\n')
|
|
||||||
http:close()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Verify schema
|
|
||||||
|
|
||||||
local parser = ucl.parser()
|
|
||||||
local res, err = parser:parse_string(request_body)
|
|
||||||
|
|
||||||
if not res then
|
|
||||||
http:status(500, 'Internal Server Error.')
|
|
||||||
http:header('Content-Type', 'application/json; charset=utf-8')
|
|
||||||
http:write('{ "status": 500, "error": "Internal UCL Parsing Failed. This should not happen at all." }\n')
|
|
||||||
http:close()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
res, err = parser:validate(schema_get(parts))
|
|
||||||
if not res then
|
|
||||||
http:status(400, 'Bad Request')
|
|
||||||
http:header('Content-Type', 'application/json; charset=utf-8')
|
|
||||||
http:write('{ "status": 400, "error": "Schema mismatch" }\n')
|
|
||||||
http:close()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Apply config
|
|
||||||
config_set(parts, config)
|
|
||||||
|
|
||||||
-- Write result
|
|
||||||
|
|
||||||
http:write(json.stringify(res, true))
|
|
||||||
elseif http.request.env.REQUEST_METHOD == 'OPTIONS' then
|
|
||||||
local result = json.stringify({
|
|
||||||
schema = schema_get(parts),
|
|
||||||
allowed_methods = {'GET', 'POST', 'OPTIONS'}
|
|
||||||
}, true)
|
|
||||||
|
|
||||||
-- Content-Length is needed, as the transfer encoding is not chunked for OPTIONS.
|
|
||||||
http:header('Content-Length', tostring(#result))
|
|
||||||
http:header('Content-Type', 'application/json; charset=utf-8')
|
|
||||||
http:write(result)
|
|
||||||
else
|
|
||||||
http:status(501, 'Not Implemented')
|
|
||||||
http:header('Content-Length', '0')
|
|
||||||
http:write('Not Implemented\n')
|
|
||||||
end
|
|
||||||
|
|
||||||
http:close()
|
|
||||||
end))
|
|
@ -1,131 +0,0 @@
|
|||||||
|
|
||||||
local util = require 'gluon.util'
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
local function merge_types(Ta, Tb)
|
|
||||||
-- T == nil means "any" type is allowed
|
|
||||||
|
|
||||||
if not Ta then return Tb end
|
|
||||||
if not Tb then return Ta end
|
|
||||||
|
|
||||||
-- convert scalar types to arrays
|
|
||||||
if type(Ta) ~= 'table' then Ta = { Ta } end
|
|
||||||
if type(Tb) ~= 'table' then Tb = { Tb } end
|
|
||||||
|
|
||||||
local Tnew = {}
|
|
||||||
|
|
||||||
for _, t in pairs(Ta) do
|
|
||||||
if util.contains(Tb, t) then
|
|
||||||
table.insert(Tnew, t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(#Tnew > 0, 'ERROR: The schema does not match anything at all.')
|
|
||||||
|
|
||||||
if #Tnew == 1 then
|
|
||||||
return Tnew[1] -- convert to scalar
|
|
||||||
else
|
|
||||||
return Tnew
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function keys(tab)
|
|
||||||
local keys = {}
|
|
||||||
if tab then
|
|
||||||
for k, _ in pairs(tab) do
|
|
||||||
table.insert(keys, k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return keys
|
|
||||||
end
|
|
||||||
|
|
||||||
local function merge_array(table1, table2)
|
|
||||||
local values = {}
|
|
||||||
if table1 then
|
|
||||||
for _, v in pairs(table1) do
|
|
||||||
table.insert(values, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if table2 then
|
|
||||||
for _, v in pairs(table2) do
|
|
||||||
if not util.contains(values, v) then
|
|
||||||
table.insert(values, v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return values
|
|
||||||
end
|
|
||||||
|
|
||||||
local function deepcopy(o, seen)
|
|
||||||
seen = seen or {}
|
|
||||||
if o == nil then return nil end
|
|
||||||
if seen[o] then return seen[o] end
|
|
||||||
|
|
||||||
local no
|
|
||||||
if type(o) == 'table' then
|
|
||||||
no = {}
|
|
||||||
seen[o] = no
|
|
||||||
|
|
||||||
for k, v in next, o, nil do
|
|
||||||
no[deepcopy(k, seen)] = deepcopy(v, seen)
|
|
||||||
end
|
|
||||||
setmetatable(no, deepcopy(getmetatable(o), seen))
|
|
||||||
else -- number, string, boolean, etc
|
|
||||||
no = o
|
|
||||||
end
|
|
||||||
return no
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.merge_schemas(schema1, schema2)
|
|
||||||
local merged = {}
|
|
||||||
|
|
||||||
merged.type = merge_types(schema1.type, schema2.type)
|
|
||||||
|
|
||||||
function add_property(pkey, pdef)
|
|
||||||
merged.properties = merged.properties or {}
|
|
||||||
merged.properties[pkey] = pdef
|
|
||||||
end
|
|
||||||
|
|
||||||
if not merged.type or merged.type == 'object' then
|
|
||||||
-- generate merged.properties
|
|
||||||
local properties1 = schema1.properties or {}
|
|
||||||
local properties2 = schema2.properties or {}
|
|
||||||
|
|
||||||
for _, pkey in pairs(merge_array(keys(properties1), keys(properties2))) do
|
|
||||||
local pdef1 = properties1[pkey]
|
|
||||||
local pdef2 = properties2[pkey]
|
|
||||||
|
|
||||||
if pdef1 and pdef2 then
|
|
||||||
add_property(pkey, M.merge_schemas(pdef1, pdef2))
|
|
||||||
elseif pdef1 then
|
|
||||||
add_property(pkey, deepcopy(pdef1))
|
|
||||||
elseif pdef2 then
|
|
||||||
add_property(pkey, deepcopy(pdef2))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- generate merged.additionalProperties
|
|
||||||
if schema1.additionalProperties and schema2.additionalProperties then
|
|
||||||
merged.additionalProperties = M.merge_schemas(
|
|
||||||
schema1.additionalProperties, schema2.additionalProperties)
|
|
||||||
else
|
|
||||||
merged.additionalProperties = false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- generate merged.required
|
|
||||||
merged.required = merge_array(schema1.required, schema2.required)
|
|
||||||
if #merged.required == 0 then
|
|
||||||
merged.required = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- TODO: implement array
|
|
||||||
|
|
||||||
-- generate merged.default
|
|
||||||
merged.default = schema2.default or schema1.default
|
|
||||||
|
|
||||||
return merged
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
@ -1,24 +0,0 @@
|
|||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.schema(site, platform)
|
|
||||||
return {
|
|
||||||
type = 'object',
|
|
||||||
properties = {
|
|
||||||
wizard = {
|
|
||||||
type = 'object',
|
|
||||||
additionalProperties = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
additionalProperties = false,
|
|
||||||
required = { 'wizard' }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.set(config, uci)
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.get(uci, config)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/lua
|
|
||||||
|
|
||||||
require 'gluon.web.cgi' {
|
|
||||||
base_path = '/lib/gluon/config-api',
|
|
||||||
|
|
||||||
layout_package = 'gluon-config-api',
|
|
||||||
layout_template = 'theme/layout', -- only used for error pages
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user