gluon-config-api: First working version
Fix bugs, ...
This commit is contained in:
parent
60aa73126e
commit
64ed50c44a
@ -6,7 +6,8 @@ local os = require 'os'
|
|||||||
local glob = require 'posix.glob'
|
local glob = require 'posix.glob'
|
||||||
local libgen = require 'posix.libgen'
|
local libgen = require 'posix.libgen'
|
||||||
local simpleuci = require 'simple-uci'
|
local simpleuci = require 'simple-uci'
|
||||||
local schema = require 'schema'
|
local schema = dofile('../controller/schema.lua') -- pwd is www/
|
||||||
|
local ucl = require "ucl"
|
||||||
|
|
||||||
package 'gluon-config-api'
|
package 'gluon-config-api'
|
||||||
|
|
||||||
@ -29,20 +30,97 @@ function config_get(parts)
|
|||||||
return config
|
return config
|
||||||
end
|
end
|
||||||
|
|
||||||
local parts = load_parts()
|
function schema_get(parts)
|
||||||
|
|
||||||
|
|
||||||
entry({"config"}, call(function(http, renderer)
|
|
||||||
|
|
||||||
http:write(json.stringify(config_get(parts), true))
|
|
||||||
http:close()
|
|
||||||
end))
|
|
||||||
|
|
||||||
entry({"schema"}, call(function(http, renderer)
|
|
||||||
local total_schema = {}
|
local total_schema = {}
|
||||||
for _, part in pairs(parts) do
|
for _, part in pairs(parts) do
|
||||||
total_schema = schema.merge_schemas(total_schema, part.schema())
|
total_schema = schema.merge_schemas(total_schema, part.schema(site, nil))
|
||||||
end
|
end
|
||||||
http:write(json.stringify(total_schema, true))
|
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: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: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: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:write('{ "status": 400, "error": "Schema mismatch" }\n')
|
||||||
|
http:close()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Apply config
|
||||||
|
|
||||||
|
config_set(parts, config)
|
||||||
|
|
||||||
|
http:write(json.stringify(res, true))
|
||||||
|
else
|
||||||
|
http:status(400, 'Bad Request')
|
||||||
|
http:write('Not implemented')
|
||||||
|
end
|
||||||
|
|
||||||
|
http:close()
|
||||||
|
end))
|
||||||
|
|
||||||
|
entry({"v1", "schema"}, call(function(http, renderer)
|
||||||
|
http:write(json.stringify(schema_get(parts), true))
|
||||||
http:close()
|
http:close()
|
||||||
end))
|
end))
|
||||||
|
@ -34,12 +34,12 @@ local function merged_keys(table1, table2)
|
|||||||
local keys = {}
|
local keys = {}
|
||||||
if table1 then
|
if table1 then
|
||||||
for k, _ in pairs(table1) do
|
for k, _ in pairs(table1) do
|
||||||
table.insert(k)
|
table.insert(keys, k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if table2 then
|
if table2 then
|
||||||
for k, _ in pairs(table2) do
|
for k, _ in pairs(table2) do
|
||||||
if not util.contains(k) then
|
if not util.contains(keys, k) then
|
||||||
table.insert(keys, k)
|
table.insert(keys, k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -51,12 +51,12 @@ local function merged_values(table1, table2)
|
|||||||
local values = {}
|
local values = {}
|
||||||
if table1 then
|
if table1 then
|
||||||
for _, v in pairs(table1) do
|
for _, v in pairs(table1) do
|
||||||
table.insert(v)
|
table.insert(values, v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if table2 then
|
if table2 then
|
||||||
for _, v in pairs(table2) do
|
for _, v in pairs(table2) do
|
||||||
if not util.contains(v) then
|
if not util.contains(values, v) then
|
||||||
table.insert(values, v)
|
table.insert(values, v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -105,7 +105,7 @@ function M.merge_schemas(schema1, schema2)
|
|||||||
local pdef2 = properties2[pkey]
|
local pdef2 = properties2[pkey]
|
||||||
|
|
||||||
if pdef1 and pdef2 then
|
if pdef1 and pdef2 then
|
||||||
add_property(pkey, merge_schemas(pdef1, pdef2))
|
add_property(pkey, M.merge_schemas(pdef1, pdef2))
|
||||||
elseif pdef1 then
|
elseif pdef1 then
|
||||||
add_property(pkey, deepcopy(pdef1))
|
add_property(pkey, deepcopy(pdef1))
|
||||||
elseif pdef2 then
|
elseif pdef2 then
|
||||||
@ -115,14 +115,14 @@ function M.merge_schemas(schema1, schema2)
|
|||||||
|
|
||||||
-- generate merged.additionalProperties
|
-- generate merged.additionalProperties
|
||||||
if schema1.additionalProperties and schema2.additionalProperties then
|
if schema1.additionalProperties and schema2.additionalProperties then
|
||||||
merged.additionalProperties = merge_schemas(
|
merged.additionalProperties = M.merge_schemas(
|
||||||
schema1.additionalProperties, schema2.additionalProperties)
|
schema1.additionalProperties, schema2.additionalProperties)
|
||||||
else
|
else
|
||||||
merged.additionalProperties = false
|
merged.additionalProperties = false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- generate merged.required
|
-- generate merged.required
|
||||||
merged.required = merged_values(schema1, schema2)
|
merged.required = merged_values(schema1.required, schema2.required)
|
||||||
if #merged.required == 0 then
|
if #merged.required == 0 then
|
||||||
merged.required = nil
|
merged.required = nil
|
||||||
end
|
end
|
||||||
@ -132,6 +132,8 @@ function M.merge_schemas(schema1, schema2)
|
|||||||
|
|
||||||
-- generate merged.default
|
-- generate merged.default
|
||||||
merged.default = schema2.default or schema1.default
|
merged.default = schema2.default or schema1.default
|
||||||
|
|
||||||
|
return merged
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
@ -13,11 +13,12 @@ function M.schema(site, platform)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
required = { 'wizard' }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.save(config, uci)
|
function M.set(config, uci)
|
||||||
local owner = uci:get_first("gluon-node-info", "owner")
|
local owner = uci:get_first("gluon-node-info", "owner")
|
||||||
|
|
||||||
uci:set("gluon-node-info", owner, "contact", config.wizard.contact)
|
uci:set("gluon-node-info", owner, "contact", config.wizard.contact)
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.schema(site, platform)
|
||||||
|
local altitude = nil
|
||||||
|
|
||||||
|
if site.config_mode.geo_location.show_altitude(false) then
|
||||||
|
altitude = { type = 'number' }
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
type = 'object',
|
||||||
|
properties = {
|
||||||
|
wizard = {
|
||||||
|
type = 'object',
|
||||||
|
properties = {
|
||||||
|
location = {
|
||||||
|
type = 'object',
|
||||||
|
properties = {
|
||||||
|
share_location = { type = 'boolean' },
|
||||||
|
lat = { type = 'number' },
|
||||||
|
lon = { type = 'number' },
|
||||||
|
altitude = altitude
|
||||||
|
},
|
||||||
|
required = { 'lat', 'lon', 'share_location' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
required = { 'wizard' }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.set(config, uci)
|
||||||
|
local location = uci:get_first("gluon-node-info", "location")
|
||||||
|
local config_location = config.wizard.location
|
||||||
|
|
||||||
|
if config_location then
|
||||||
|
uci:set("gluon-node-info", location, "share_location", config_location.share_location)
|
||||||
|
uci:set("gluon-node-info", location, "latitude", config_location.lat)
|
||||||
|
uci:set("gluon-node-info", location, "longitude", config_location.lon)
|
||||||
|
if config_location.altitude then -- altitude is optional
|
||||||
|
uci:set("gluon-node-info", location, "altitude", config_location.altitude) -- TODO: check if the "if" is necessary
|
||||||
|
else
|
||||||
|
uci:delete("gluon-node-info", location, "altitude")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
uci:set("gluon-node-info", location, "share_location", false)
|
||||||
|
uci:delete("gluon-node-info", location, "latitude")
|
||||||
|
uci:delete("gluon-node-info", location, "longitude")
|
||||||
|
uci:delete("gluon-node-info", location, "altitude")
|
||||||
|
end
|
||||||
|
|
||||||
|
uci:save("gluon-node-info")
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.get(uci, config)
|
||||||
|
config.wizard = config.wizard or {}
|
||||||
|
|
||||||
|
local location = uci:get_first("gluon-node-info", "location")
|
||||||
|
local lon = uci:get("gluon-node-info", location, "longitude")
|
||||||
|
|
||||||
|
if lon then
|
||||||
|
config.wizard.location = {
|
||||||
|
share_location = uci:get_bool("gluon-node-info", location, "share_location"),
|
||||||
|
lat = tonumber(uci:get("gluon-node-info", location, "latitude")),
|
||||||
|
lon = tonumber(lon),
|
||||||
|
-- if uci:get() returns nil, then altitude will not be present in the result
|
||||||
|
altitude = tonumber(uci:get("gluon-node-info", location, "altitude"))
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
Loading…
Reference in New Issue
Block a user