libs/core: Reworked some basic libraries to not use package.seeall
authorSteven Barth <steven@midlink.org>
Tue, 26 Aug 2008 00:53:28 +0000 (00:53 +0000)
committerSteven Barth <steven@midlink.org>
Tue, 26 Aug 2008 00:53:28 +0000 (00:53 +0000)
libs/json: Implemented own JSON-Decoder (Encoder will follow)
modules/rpc: Preliminary implemented RPC-Exports for luci.fs, luci.sys and luci.model.uci

libs/core/luasrc/fs.lua
libs/json/luasrc/json.lua
libs/sys/luasrc/sys.lua
libs/uci/luasrc/model/uci.lua
libs/web/luasrc/dispatcher.lua
modules/rpc/luasrc/controller/rpc.lua
modules/rpc/luasrc/controller/rpc/uci.lua [new file with mode: 0644]
modules/rpc/luasrc/jsonrpc.lua

index e089d55dd04bfa1a508dd5b6cbfffdf0b6c2a1a6..56108db953194c958c7edc4bc02e6f7d22c9b8d5 100644 (file)
@@ -24,10 +24,12 @@ limitations under the License.
 
 ]]--
 
---- LuCI filesystem library.
-module("luci.fs", package.seeall)
+local posix = require "posix"
+local io    = require "io"
+local type  = type
 
-require("posix")
+--- LuCI filesystem library.
+module "luci.fs"
 
 --- Test for file access permission on given path.
 -- @class              function
index 85b85e1e890e9e2714116e4d265a64922be66b2e..0d38ed479c792fa0775f25f81906a99638ecc81f 100644 (file)
 --[[
+LuCI - Lua Configuration Interface
 
- JSON Encoder and Parser for Lua 5.1
- Copyright � 2007 Shaun Brown (http://www.chipmunkav.com).
- All Rights Reserved.
- Permission is hereby granted, free of charge, to any person 
- obtaining a copy of this software to deal in the Software without 
- restriction, including without limitation the rights to use, 
- copy, modify, merge, publish, distribute, sublicense, and/or 
- sell copies of the Software, and to permit persons to whom the 
- Software is furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be 
- included in all copies or substantial portions of the Software.
- If you find this software useful please give www.chipmunkav.com a mention.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 
- ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
- CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Usage:
-
- -- Lua script:
- local t = { 
-       ["name1"] = "value1",
-       ["name2"] = {1, false, true, 23.54, "a \021 string"},
-       name3 = Json.Null() 
- }
-
- local json = Json.Encode (t)
- print (json) 
- --> {"name1":"value1","name3":null,"name2":[1,false,true,23.54,"a \u0015 string"]}
-
- local t = Json.Decode(json)
- print(t.name2[4])
- --> 23.54
- Notes:
- 1) Encodable Lua types: string, number, boolean, table, nil
- 2) Use Json.Null() to insert a null value into a Json object
- 3) All control chars are encoded to \uXXXX format eg "\021" encodes to "\u0015"
- 4) All Json \uXXXX chars are decoded to chars (0-255 byte range only)
- 5) Json single line // and /* */ block comments are discarded during decoding
- 6) Numerically indexed Lua arrays are encoded to Json Lists eg [1,2,3]
- 7) Lua dictionary tables are converted to Json objects eg {"one":1,"two":2}
- 8) Json nulls are decoded to Lua nil and treated by Lua in the normal way
-
---]]
-
-local string = string
-local math = math
-local table = table
-local error = error
-local tonumber = tonumber
-local tostring = tostring
-local type = type
-local setmetatable = setmetatable
-local pairs = pairs
-local ipairs = ipairs
-local assert = assert
-local Chipmunk = Chipmunk
-
-module("luci.json")
-
-local StringBuilder = {
-       buffer = {}
-}
-
-function StringBuilder:New()
-       local o = {}
-       setmetatable(o, self)
-       self.__index = self
-       o.buffer = {}
-       return o
-end
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
 
-function StringBuilder:Append(s)
-       self.buffer[#self.buffer+1] = s
-end
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
 
-function StringBuilder:ToString()
-       return table.concat(self.buffer)
-end
+http://www.apache.org/licenses/LICENSE-2.0
 
-local JsonWriter = {
-       backslashes = {
-               ['\b'] = "\\b",
-               ['\t'] = "\\t", 
-               ['\n'] = "\\n", 
-               ['\f'] = "\\f",
-               ['\r'] = "\\r", 
-               ['"']  = "\\\"", 
-               ['\\'] = "\\\\", 
-               ['/']  = "\\/"
-       }
-}
-
-function JsonWriter:New()
-       local o = {}
-       o.writer = StringBuilder:New()
-       setmetatable(o, self)
-       self.__index = self
-       return o
-end
+$Id$
+]]--
 
-function JsonWriter:Append(s)
-       self.writer:Append(s)
-end
+local util      = require "luci.util"
+local ltn12     = require "luci.ltn12"
+local table     = require "table"
+local coroutine = require "coroutine"
+
+local assert    = assert
+local tonumber  = tonumber
+local error     = error
 
-function JsonWriter:ToString()
-       return self.writer:ToString()
+module "luci.json"
+
+--- Null replacement function
+-- @return null
+function null()
+       return null
 end
 
-function JsonWriter:Write(o)
-       local t = type(o)
-       if t == "nil" then
-               self:WriteNil()
-       elseif t == "boolean" then
-               self:WriteString(o)
-       elseif t == "number" then
-               self:WriteString(o)
-       elseif t == "string" then
-               self:ParseString(o)
-       elseif t == "table" then
-               self:WriteTable(o)
-       elseif t == "function" then
-               self:WriteFunction(o)
-       elseif t == "thread" then
-               self:WriteError(o)
-       elseif t == "userdata" then
-               self:WriteError(o)
+Decoder = util.class()
+
+--- Create an LTN12 sink from the decoder object
+-- @return LTN12 sink
+function Decoder.sink(self)
+       local sink = coroutine.create(self.dispatch)
+       return function(...)
+               return coroutine.resume(sink, self, ...)
        end
 end
 
-function JsonWriter:WriteNil()
-       self:Append("null")
-end
 
-function JsonWriter:WriteString(o)
-       self:Append(tostring(o))
+--- Get the decoded data packets
+-- @return Decoded data
+function Decoder.get(self)
+       return self.data
 end
 
-function JsonWriter:ParseString(s)
-       self:Append('"')
-       self:Append(string.gsub(s, "[%z%c\\\"/]", function(n)
-               local c = self.backslashes[n]
-               if c then return c end
-               return string.format("\\u%.4X", string.byte(n))
-       end))
-       self:Append('"')
-end
 
-function JsonWriter:IsArray(t)
-       local count = 0
-       local isindex = function(k) 
-               if type(k) == "number" and k > 0 then
-                       if math.floor(k) == k then
-                               return true
-                       end
+function Decoder.dispatch(self, chunk, src_err, strict)
+       local robject, object
+        
+       while chunk do
+               if #chunk < 1 then
+                       chunk = self:fetch()
                end
-               return false
-       end
-       for k,v in pairs(t) do
-               if not isindex(k) then
-                       return false, '{', '}'
-               else
-                       count = math.max(count, k)
+               
+               assert(not strict or chunk, "Unexpected EOS")
+               if not chunk then
+                       break
                end
-       end
-       return true, '[', ']', count
-end
-
-function JsonWriter:WriteTable(t)
-       local ba, st, et, n = self:IsArray(t)
-       self:Append(st) 
-       if ba then              
-               for i = 1, n do
-                       self:Write(t[i])
-                       if i < n then
-                               self:Append(',')
-                       end
+               
+               local parser = nil
+               local char   = chunk:sub(1, 1)
+               
+               if char == '"' then
+                       parser = self.parse_string
+               elseif char == 't' then
+                       parser = self.parse_true
+               elseif char == 'f' then
+                       parser = self.parse_false
+               elseif char == 'n' then
+                       parser = self.parse_null
+               elseif char == '[' then
+                       parser = self.parse_array
+               elseif char == '{' then
+                       parser = self.parse_object
+               elseif char:match("%s") then
+                       parser = self.parse_space
+               elseif char:match("[0-9-]") then
+                       parser = self.parse_number
                end
-       else
-               local first = true;
-               for k, v in pairs(t) do
-                       if not first then
-                               self:Append(',')
+               
+               if parser then
+                       chunk, robject = parser(self, chunk)
+                       
+                       if robject ~= nil then
+                               assert(object == nil, "Scope violation: Too many objects")
+                               object = robject
                        end
-                       first = false;                  
-                       self:ParseString(k)
-                       self:Append(':')
-                       self:Write(v)                   
+                       
+                       if strict and object ~= nil then
+                               return chunk, object
+                       end
+               else
+                       error("Unexpected char '%s'" % char)
                end
        end
-       self:Append(et)
+       
+       assert(not src_err, src_err)
+       assert(object ~= nil, "Unexpected EOS")
+       
+       self.data = object
+       return chunk, object
 end
 
-function JsonWriter:WriteError(o)
-       error(string.format(
-               "Encoding of %s unsupported", 
-               tostring(o)))
-end
 
-function JsonWriter:WriteFunction(o)
-       if o == Null then 
-               self:WriteNil()
-       else
-               self:WriteError(o)
-       end
+function Decoder.fetch(self)
+       local tself, chunk, src_err = coroutine.yield()
+       assert(chunk or not src_err, src_err)
+       return chunk
 end
 
-local StringReader = {
-       s = "",
-       i = 0
-}
-
-function StringReader:New(s)
-       local o = {}
-       setmetatable(o, self)
-       self.__index = self
-       o.s = s or o.s
-       return o        
-end
 
-function StringReader:Peek()
-       local i = self.i + 1
-       if i <= #self.s then
-               return string.sub(self.s, i, i)
+function Decoder.fetch_atleast(self, chunk, bytes)
+       while #chunk < bytes do
+               local nchunk = self:fetch()
+               assert(nchunk, "Unexpected EOS")
+               chunk = chunk .. nchunk
        end
-       return nil
+       
+       return chunk
 end
 
-function StringReader:Next()
-       self.i = self.i+1
-       if self.i <= #self.s then
-               return string.sub(self.s, self.i, self.i)
-       end
-       return nil
-end
 
-function StringReader:All()
-       return self.s
-end
-
-local JsonReader = {
-       escapes = {
-               ['t'] = '\t',
-               ['n'] = '\n',
-               ['f'] = '\f',
-               ['r'] = '\r',
-               ['b'] = '\b',
-       }
-}
-
-function JsonReader:New(s)
-       local o = {}
-       o.reader = StringReader:New(s)
-       setmetatable(o, self)
-       self.__index = self
-       return o;
-end
+function Decoder.fetch_until(self, chunk, pattern)
+       local start = chunk:find(pattern)
 
-function JsonReader:Read()
-       self:SkipWhiteSpace()
-       local peek = self:Peek()
-       if peek == nil then
-               error(string.format(
-                       "Nil string: '%s'", 
-                       self:All()))
-       elseif peek == '{' then
-               return self:ReadObject()
-       elseif peek == '[' then
-               return self:ReadArray()
-       elseif peek == '"' then
-               return self:ReadString()
-       elseif string.find(peek, "[%+%-%d]") then
-               return self:ReadNumber()
-       elseif peek == 't' then
-               return self:ReadTrue()
-       elseif peek == 'f' then
-               return self:ReadFalse()
-       elseif peek == 'n' then
-               return self:ReadNull()
-       elseif peek == '/' then
-               self:ReadComment()
-               return self:Read()
-       else
-               error(string.format(
-                       "Invalid input: '%s'", 
-                       self:All()))
+       while not start do
+               local nchunk = self:fetch()
+               assert(nchunk, "Unexpected EOS")
+               chunk = chunk .. nchunk
+               start = chunk:find(pattern)
        end
-end
-               
-function JsonReader:ReadTrue()
-       self:TestReservedWord{'t','r','u','e'}
-       return true
-end
 
-function JsonReader:ReadFalse()
-       self:TestReservedWord{'f','a','l','s','e'}
-       return false
+       return chunk, start
 end
 
-function JsonReader:ReadNull()
-       self:TestReservedWord{'n','u','l','l'}
-       return nil
-end
 
-function JsonReader:TestReservedWord(t)
-       for i, v in ipairs(t) do
-               if self:Next() ~= v then
-                        error(string.format(
-                               "Error reading '%s': %s", 
-                               table.concat(t), 
-                               self:All()))
+function Decoder.parse_space(self, chunk)
+       local start = chunk:find("[^%s]")
+       
+       while not start do
+               chunk = self:fetch()
+               if not chunk then
+                       return nil
                end
+               start = chunk:find("[^%s]")
        end
+       
+       return chunk:sub(start)
 end
 
-function JsonReader:ReadNumber()
-        local result = self:Next()
-        local peek = self:Peek()
-        while peek ~= nil and string.find(
-               peek, 
-               "[%+%-%d%.eE]") do
-            result = result .. self:Next()
-            peek = self:Peek()
-       end
-       result = tonumber(result)
-       if result == nil then
-               error(string.format(
-                       "Invalid number: '%s'", 
-                       result))
-       else
-               return result
-       end
+
+function Decoder.parse_literal(self, chunk, literal, value)
+       chunk = self:fetch_atleast(chunk, #literal)     
+       assert(chunk:sub(1, #literal) == literal, "Invalid character sequence")
+       return chunk:sub(#literal + 1), value
 end
 
-function JsonReader:ReadString()
-       local result = ""
-       assert(self:Next() == '"')
-        while self:Peek() ~= '"' do
-               local ch = self:Next()
-               if ch == '\\' then
-                       ch = self:Next()
-                       if self.escapes[ch] then
-                               ch = self.escapes[ch]
-                       end
-               end
-                result = result .. ch
-       end
-        assert(self:Next() == '"')
-       local fromunicode = function(m)
-               return string.char(tonumber(m, 16))
-       end
-       return string.gsub(
-               result, 
-               "u%x%x(%x%x)", 
-               fromunicode)
+
+function Decoder.parse_null(self, chunk)
+       return self:parse_literal(chunk, "null", null)
 end
 
-function JsonReader:ReadComment()
-        assert(self:Next() == '/')
-        local second = self:Next()
-        if second == '/' then
-            self:ReadSingleLineComment()
-        elseif second == '*' then
-            self:ReadBlockComment()
-        else
-            error(string.format(
-               "Invalid comment: %s", 
-               self:All()))
-       end
+
+function Decoder.parse_true(self, chunk)
+       return self:parse_literal(chunk, "true", true)
 end
 
-function JsonReader:ReadBlockComment()
-       local done = false
-       while not done do
-               local ch = self:Next()          
-               if ch == '*' and self:Peek() == '/' then
-                       done = true
-                end
-               if not done and 
-                       ch == '/' and 
-                       self:Peek() == "*" then
-                    error(string.format(
-                       "Invalid comment: %s, '/*' illegal.",  
-                       self:All()))
-               end
-       end
-       self:Next()
+
+function Decoder.parse_false(self, chunk)
+       return self:parse_literal(chunk, "false", false)
 end
 
-function JsonReader:ReadSingleLineComment()
-       local ch = self:Next()
-       while ch ~= '\r' and ch ~= '\n' do
-               ch = self:Next()
-       end
+
+function Decoder.parse_number(self, chunk)
+       local chunk, start = self:fetch_until(chunk, "[^0-9eE.+-]")
+       local number = tonumber(chunk:sub(1, start - 1))
+       assert(number, "Invalid number specification")
+       return chunk:sub(start), number
 end
 
-function JsonReader:ReadArray()
-       local result = {}
-       assert(self:Next() == '[')
-       self:SkipWhiteSpace()
-       local done = false
-       if self:Peek() == ']' then
-               done = true;
-       end
-       while not done do
-               local item = self:Read()
-               result[#result+1] = item
-               self:SkipWhiteSpace()
-               if self:Peek() == ']' then
-                       done = true
-               end
-               if not done then
-                       local ch = self:Next()
-                       if ch ~= ',' then
-                               error(string.format(
-                                       "Invalid array: '%s' due to: '%s'", 
-                                       self:All(), ch))
+
+function Decoder.parse_string(self, chunk)
+       local str = ""
+       local object = nil
+       assert(chunk:sub(1, 1) == '"', 'Expected "')
+       chunk = chunk:sub(2)
+
+       while true do
+               local spos = chunk:find('[\\"]')
+               if spos then
+                       str = str .. chunk:sub(1, spos - 1)
+                       
+                       local char = chunk:sub(spos, spos)
+                       if char == '"' then                             -- String end
+                               chunk = chunk:sub(spos + 1)
+                               break
+                       elseif char == "\\" then                -- Escape sequence
+                               chunk, object = self:parse_escape(chunk:sub(spos))
+                               str = str .. object
                        end
+               else
+                       str = str .. chunk
+                       chunk = self:fetch()
+                       assert(chunk, "Unexpected EOS while parsing a string")          
                end
        end
-       assert(']' == self:Next())
-       return result
-end
 
-function JsonReader:ReadObject()
-       local result = {}
-       assert(self:Next() == '{')
-       self:SkipWhiteSpace()
-       local done = false
-       if self:Peek() == '}' then
-               done = true
-       end
-       while not done do
-               local key = self:Read()
-               if type(key) ~= "string" then
-                       error(string.format(
-                               "Invalid non-string object key: %s", 
-                               key))
-               end
-               self:SkipWhiteSpace()
-               local ch = self:Next()
-               if ch ~= ':' then
-                       error(string.format(
-                               "Invalid object: '%s' due to: '%s'", 
-                               self:All(), 
-                               ch))
-               end
-               self:SkipWhiteSpace()
-               local val = self:Read()
-               result[key] = val
-               self:SkipWhiteSpace()
-               if self:Peek() == '}' then
-                       done = true
-               end
-               if not done then
-                       ch = self:Next()
-                       if ch ~= ',' then
-                               error(string.format(
-                                       "Invalid array: '%s' near: '%s'", 
-                                       self:All(), 
-                                       ch))
-                       end
-               end
+       return chunk, str
+end
+
+
+function Decoder.parse_escape(self, chunk)
+       local str = ""
+       chunk = self:fetch_atleast(chunk:sub(2), 1)
+       local char = chunk:sub(1, 1)
+       chunk = chunk:sub(2)
+       
+       if char == '"' then
+               return chunk, '"'
+       elseif char == "\\" then
+               return chunk, "\\"
+       elseif char == "/" then
+               return chunk, "/"
+       elseif char == "b" then
+               return chunk, "\b"
+       elseif char == "f" then
+               return chunk, "\f"
+       elseif char == "n" then
+               return chunk, "\n"
+       elseif char == "r" then
+               return chunk, "\r"
+       elseif char == "t" then
+               return chunk, "\t"
+       elseif char == "u" then
+               chunk = self:fetch_atleast(chunk, 4)
+               local s1, s2 = chunk:sub(1, 4):match("^([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])$")
+               assert(s1 and s2, "Invalid Unicode character 'U+%s%s'" % {s1, s2})
+               s1, s2 = tonumber(s1, 16), tonumber(s2, 16)
+               
+               -- ToDo: Unicode support
+               return chunk:sub(5), s1 == 0 and s2 or ""
+       else
+               error("Unexpected escaping sequence '\\%s'" % char)
        end
-       assert(self:Next() == "}")
-       return result
 end
 
-function JsonReader:SkipWhiteSpace()
-       local p = self:Peek()
-       while p ~= nil and string.find(p, "[%s/]") do
-               if p == '/' then
-                       self:ReadComment()
-               else
-                       self:Next()
-               end
-               p = self:Peek()
+
+function Decoder.parse_array(self, chunk)
+       chunk = chunk:sub(2)
+       local array = {}
+       
+       local chunk, object = self:parse_delimiter(chunk, "%]")
+       
+       if object then
+               return chunk, array
        end
-end
+       
+       repeat
+               chunk, object = self:dispatch(chunk, nil, true)
+               table.insert(array, object)
+               
+               chunk, object = self:parse_delimiter(chunk, ",%]")
+               assert(object, "Delimiter expected")
+       until object == "]"
 
-function JsonReader:Peek()
-       return self.reader:Peek()
+       return chunk, array
 end
 
-function JsonReader:Next()
-       return self.reader:Next()
-end
 
-function JsonReader:All()
-       return self.reader:All()
-end
+function Decoder.parse_object(self, chunk)
+       chunk = chunk:sub(2)
+       local array = {}
+       local name
 
-function Encode(o)
-       local writer = JsonWriter:New()
-       writer:Write(o)
-       return writer:ToString()
-end
+       local chunk, object = self:parse_delimiter(chunk, "}")
 
-function Decode(s)
-       local reader = JsonReader:New(s)
-       local object = reader:Read()
-       reader:SkipWhiteSpace()
-       assert(reader:Peek() == nil, "Invalid characters after JSON body")
-       return object
-end
+       if object then
+               return chunk, array
+       end
+
+       repeat
+               chunk = self:parse_space(chunk)
+               assert(chunk, "Unexpected EOS")
+               
+               chunk, name   = self:parse_string(chunk)
+               
+               chunk, object = self:parse_delimiter(chunk, ":")
+               assert(object, "Separator expected")
+               
+               chunk, object = self:dispatch(chunk, nil, true)
+               array[name] = object
+
+               chunk, object = self:parse_delimiter(chunk, ",}")
+               assert(object, "Delimiter expected")
+       until object == "}"
 
-function Null()
-       return Null
+       return chunk, array
 end
+
+
+function Decoder.parse_delimiter(self, chunk, delimiter)
+       while true do
+               chunk = self:fetch_atleast(chunk, 1)
+               local char = chunk:sub(1, 1)
+               if char:match("%s") then
+                       chunk = self:parse_space(chunk)
+                       assert(chunk, "Unexpected EOS")
+               elseif char:match("[%s]" % delimiter) then
+                       return chunk:sub(2), char
+               else
+                       return chunk, nil
+               end
+       end
+end
\ No newline at end of file
index d0dc5acbd879a9ffda17e55763b361388555fbd8..bce4e8a62c12043642b2d0e22762fcac752a10c3 100644 (file)
@@ -24,14 +24,26 @@ limitations under the License.
 
 ]]--
 
+
+local io    = require "io"
+local os    = require "os"
+local posix = require "posix"
+local table = require "table"
+
+local luci  = {}
+luci.util   = require "luci.util"
+luci.fs     = require "luci.fs"
+luci.ip     = require "luci.ip"
+
+local tonumber, ipairs, pairs = tonumber, ipairs, pairs
+
+
 --- LuCI Linux and POSIX system utilities.
-module("luci.sys", package.seeall)
-require("posix")
-require("luci.util")
-require("luci.fs")
-require("luci.ip")
+module "luci.sys"
+
 
 --- Invoke the luci-flash executable to write an image to the flash memory.
+-- @param image                Local path or URL to image file
 -- @param kpattern     Pattern of files to keep over flash process
 -- @return                     Return value of os.execute()
 function flash(image, kpattern)
index e4c5d5db70a3b276da391c79db4abee98d1a1210..6c4ae6ed8b1ce3ca42d4c9e59b89930a3a0ad2ea 100644 (file)
@@ -23,11 +23,13 @@ See the License for the specific language governing permissions and
 limitations under the License.
 
 ]]--
-local uci  = require("uci")
-local util = require("luci.util")
+local uci   = require "uci"
+local util  = require "luci.util"
+local table = require "table"
+
 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
-local table = table
+local require = require
 
 --- LuCI UCI model library.
 module("luci.model.uci", function(m) setmetatable(m, {__index = uci}) end)
@@ -37,6 +39,14 @@ confdir_default = "/etc/config"
 
 savedir_state = "/var/state"
 
+
+--- Applies the new config
+-- @param config               UCI config
+function apply(config)
+       local conf = require "luci.config"
+       return conf.uci_oncommit[config] and os.execute(conf.uci_oncommit[config])
+end
+
 --- Delete all sections of a given type that match certain criteria.
 -- @param config               UCI config
 -- @param type                 UCI section type
@@ -149,7 +159,6 @@ function get_list(config, section, option)
 end
 
 --- Set given values as list.
--- Warning: This function is unsave! You should use save_config or save_state if possible.
 -- @param config       UCI config
 -- @param section      UCI section name
 -- @param option       UCI option
@@ -244,7 +253,6 @@ end
 -- @see unload
 
 --- Set a value or create a named section.
--- Warning: This function is unsave! You should use save_config or save_state if possible.
 -- @class function
 -- @name set
 -- @param config       UCI config
index 3ee42d72bbaca3aa9b524ee9ff426c4c7acbe584..3cfa6c70446097a64aec1cdaa8bf25dbc3a59fcb 100644 (file)
@@ -187,13 +187,15 @@ function dispatch(request)
                
                if not luci.util.contains(accs, user) then
                        if authen then
-                               local user = authen(luci.sys.user.checkpasswd, accs, def)
+                               local user, sess = authen(luci.sys.user.checkpasswd, accs, def)
                                if not user or not luci.util.contains(accs, user) then
                                        return
                                else
-                                       local sid = luci.sys.uniqueid(16)
+                                       local sid = sess or luci.sys.uniqueid(16)
                                        luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path=/")
-                                       luci.sauth.write(sid, user)
+                                       if not sess then
+                                               luci.sauth.write(sid, user)
+                                       end
                                end
                        else
                                luci.http.status(403, "Forbidden")
index a004d0dd9257d2b66fc16888852200cf9e88f438..aa77a8f2485d0248a16302b47bdf570f0235beff 100644 (file)
@@ -12,15 +12,20 @@ You may obtain a copy of the License at
 
 $Id$
 ]]--
-module("luci.controller.rpc", package.seeall)
+
+local require = require
+local pairs = pairs
+local print = print
+
+module "luci.controller.rpc"
 
 function index()
        local function authenticator(validator, accs)
-               local args = luci.dispatcher.context.args
-               if args and #args > 0 then
-                       local user = luci.sauth.read(args[1])
+               local auth = luci.http.formvalue("auth", true)
+               if auth then
+                       local user = luci.sauth.read(auth)
                        if user and luci.util.contains(accs, user) then
-                               return user
+                               return user, auth
                        end
                end
                luci.http.status(403, "Forbidden")
@@ -29,16 +34,25 @@ function index()
        uci = entry({"rpc", "uci"}, call("rpc_uci"))
        uci.sysauth = "root"
        uci.sysauth_authenticator = authenticator
-       uci.leaf = true
+       
+       fs = entry({"rpc", "fs"}, call("rpc_fs"))
+       fs.sysauth = "root"
+       fs.sysauth_authenticator = authenticator
+
+       fs = entry({"rpc", "sys"}, call("rpc_sys"))
+       fs.sysauth = "root"
+       fs.sysauth_authenticator = authenticator
        
        uci = entry({"rpc", "auth"}, call("rpc_auth"))
 end
 
 function rpc_auth()
-       require "luci.jsonrpc"
-       require "luci.sauth"
+       local jsonrpc = require "luci.jsonrpc"
+       local sauth   = require "luci.sauth"
+       local http    = require "luci.http"
+       local sys     = require "luci.sys"
        
-       luci.http.setfilehandler()
+       http.setfilehandler()
        
        local loginstat
        
@@ -46,21 +60,45 @@ function rpc_auth()
        server.login = function(user, pass)
                local sid
                
-               if luci.sys.user.checkpasswd(user, pass) then
-                       sid = luci.sys.uniqueid(16)
-                       luci.http.header("Set-Cookie", "sysauth=" .. sid.."; path=/")
-                       luci.sauth.write(sid, user)
+               if sys.user.checkpasswd(user, pass) then
+                       sid = sys.uniqueid(16)
+                       http.header("Set-Cookie", "sysauth=" .. sid.."; path=/")
+                       sauth.write(sid, user)
                end
                
                return sid
        end
        
-       luci.http.prepare_content("application/json")
-       luci.http.write(luci.jsonrpc.handle(server, luci.http.content()))
-       
-       return loginstat
+       http.prepare_content("application/json")
+       http.write(jsonrpc.handle(server, http.content()))
 end
 
 function rpc_uci()
+       local uci     = require "luci.controller.rpc.uci"
+       local jsonrpc = require "luci.jsonrpc"
+       local http    = require "luci.http"
+       
+       http.setfilehandler()
+       http.prepare_content("application/json")
+       http.write(jsonrpc.handle(uci, http.content()))
+end
+
+function rpc_fs()
+       local fs      = require "luci.fs"
+       local jsonrpc = require "luci.jsonrpc"
+       local http    = require "luci.http"
+       
+       http.setfilehandler()
+       http.prepare_content("application/json")
+       http.write(jsonrpc.handle(fs, http.content()))
+end
+
+function rpc_sys()
+       local sys     = require "luci.sys"
+       local jsonrpc = require "luci.jsonrpc"
+       local http    = require "luci.http"
        
+       http.setfilehandler()
+       http.prepare_content("application/json")
+       http.write(jsonrpc.handle(sys, http.content()))
 end
\ No newline at end of file
diff --git a/modules/rpc/luasrc/controller/rpc/uci.lua b/modules/rpc/luasrc/controller/rpc/uci.lua
new file mode 100644 (file)
index 0000000..2dab4e0
--- /dev/null
@@ -0,0 +1,93 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local uci   = require "luci.model.uci"
+local table = require "table"
+
+
+module "luci.controller.rpc.uci"
+_M, _PACKAGE, _NAME = nil, nil, nil
+
+function add(config, ...)
+       uci.load_config(config)
+       local stat = uci.add(config, ...)
+       return uci.save_config(config) and stat
+end
+
+function apply(config)
+       return uci.apply(config)
+end
+
+function changes(...)
+       return uci.changes(...)
+end
+
+function commit(config)
+       return uci.load(config) and uci.commit(config)
+end
+
+function delete(config, ...)
+       uci.load(config) 
+       return uci.delete(config, ...) and uci.save(config) 
+end
+
+function delete_all(config, ...)
+       uci.load(config)
+       return uci.delete_all(config, ...) and uci.save(config) 
+end
+
+function foreach(config, stype)
+       uci.load_config(config)
+       local sections = {}
+       
+       return uci.foreach(config, stype, function(section)
+               table.insert(sections, section)
+       end) and sections
+end
+
+function get(config, ...)
+       uci.load_config(config)
+       return uci.get(config, ...)
+end
+
+function get_all(config, ...)
+       uci.load_config(config)
+       return uci.get_all(config, ...)
+end
+
+function get_state(config, ...)
+       uci.load_state(config)
+       return uci.get(config, ...)
+end
+
+function revert(config)
+       return uci.load(config) and uci.revert(config)
+end
+
+function section(config, ...)
+       uci.load_config(config)
+       return uci.section(config, ...) and uci.save_config(config)
+end
+
+function set(config, ...)
+       uci.load_config(config)
+       return uci.set(config, ...) and uci.save_config(config)
+end
+
+function tset(config, ...)
+       uci.load_config(config)
+       return uci.tset(config, ...) and uci.save_config(config)
+end
+
index 84a7f7056c6525e1c53f71c639d2fbe5be293cec..c4fed2accb816b1ef1416ff9422a5af83dd69413 100644 (file)
@@ -23,12 +23,12 @@ function resolve(mod, method)
                if not type(mod) == "table" then
                        break
                end
-               mod = mod[path[j]]
+               mod = rawget(mod, path[j])
                if not mod then
                        break
                end
        end
-       mod = type(mod) == "table" and mod[path[#path]] or nil
+       mod = type(mod) == "table" and rawget(mod, path[#path]) or nil
        if type(mod) == "function" then
                return mod
        end