File: datasource.lua

package info (click to toggle)
ntopng 5.2.1%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 121,832 kB
  • sloc: javascript: 143,431; cpp: 71,175; ansic: 11,108; sh: 4,687; makefile: 911; python: 587; sql: 512; pascal: 234; perl: 118; ruby: 52; exp: 4
file content (155 lines) | stat: -rw-r--r-- 4,788 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
--
-- (C) 2013-22 - ntop.org
--

local dirs = ntop.getDirs()
package.path = dirs.installdir .. "/scripts/lua/modules/?.lua;" .. package.path
package.path = dirs.installdir .. "/scripts/lua/modules/datasources/?.lua;" .. package.path

local json = require "dkjson"
local rest_utils = require "rest_utils"
local template = require "resty.template"
-- Import the classes library.
local classes = require "classes"

-- ##############################################

local datasource = classes.class()

-- ##############################################

-- This is the base REST prefix for all the available datasources
datasource.BASE_REST_PREFIX = "/lua/rest/v1/get/datasource/"

-- ##############################################

-- @brief Base class constructor
function datasource:init()
   self._dataset_params     = {}  -- Holds per-dataset params
   self._datamodel_instance = nil -- Instance of the datamodel holding data for each dataset
end

-- ##############################################

-- @brief Parses params
-- @param params_table A table with submitted params
-- @return True if parameters parsing is successful, false otherwise
function datasource:read_params(params_table)
   if not params_table then
      self.parsed_params = nil
      return false
   end

   self.parsed_params = {}
   for _, param in pairs(self.meta.params or {}) do
      local parsed_param = params_table[param]

      -- Assumes all params mandatory and not empty
      -- May override this behavior in subclasses
      if isEmptyString(parsed_param) then
	 -- Reset any possibly set param
	 self.parsed_params = nil

	 return false
      end

      self.parsed_params[param] = parsed_param
   end

   -- Ok, parsin has been successful
   return true
end

-- ##############################################

-- @brief Parses params submitted along with the REST endpoint request. If parsing fails, a REST error is sent.
-- @param params_table A table with submitted params, either _POST or _GET
-- @return True if parameters parsing is successful, false otherwise
function datasource:_rest_read_params(params_table)
   if not self:read_params(params_table) then
      rest_utils.answer(rest_utils.consts.err.widgets_missing_datasource_params)
      return false
   end

   return true
end

-- ##############################################

-- @brief Send datasource data via REST
function datasource:rest_send_response()
   -- Make sure this is a direct REST request and not just a require() that needs this class
   if not _SERVER -- Not executing a Lua script initiated from the web server (i.e., backend execution)
   or not _SERVER["URI"] -- Cannot reliably determine if this is a REST request
   or not _SERVER["URI"]:starts(datasource.BASE_REST_PREFIX) -- Web Lua script execution but not for this REST endpoint
   then
      -- Don't send any REST response
      return
   end

   if not self:_rest_read_params(_POST) then
      -- Params parsing has failed, error response already sent by the caller
      return
   end

   self:fetch()

   rest_utils.answer(
      rest_utils.consts.success.ok,
      self.datamodel_instance:get_data()
   )
end

-- ##############################################

-- @brief Deserializes REST endpoint response into an internal datamodel
-- @param rest_response_data Response data as obtained from the REST call
function datasource:deserialize(rest_response_data)
   if rest_response_data and rest_response_data.RESPONSE_CODE == 200 then
      local data = json.decode(rest_response_data.CONTENT)
      local when = os.time()

      if data and data.rc == rest_utils.consts.success.ok.rc then
	 self.datamodel_instance = self.meta.datamodel:new(data.rsp.header)

	 for _, row in ipairs(data.rsp.rows) do
	    self.datamodel_instance:appendRow(when, data.rsp.header, row)
	 end
      end
   end
end

-- ##############################################

-- @brief Returns instance metadata, which depends on the current instance and parsed_params
function datasource:get_metadata()
   local res = {}

   -- Render a url with submitted parsed_params
   if self.meta.url then
      local url_func = template.compile(self.meta.url, nil, true)
      local url_rendered = url_func({
	    params = self.parsed_params,
      })

      res["url"] = url_rendered
   end

   return res
end

-- ##############################################

-- @brief Transform data according to the specified transformation
-- @param data The data to be transformed
-- @param transformation The transformation to be applied
-- @return transformed data
function datasource:transform(transformation)
   return self.datamodel_instance:transform(transformation)
end

-- ##############################################

return datasource

-- ##############################################