systemFunc.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. package agi
  2. import (
  3. "encoding/csv"
  4. "encoding/json"
  5. "errors"
  6. "io/ioutil"
  7. "log"
  8. "os/exec"
  9. "path/filepath"
  10. "strings"
  11. "time"
  12. "github.com/robertkrimen/otto"
  13. )
  14. //Inject aroz online custom functions into the virtual machine
  15. func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptScope string) {
  16. //Define system core modules and definations
  17. sysdb := g.Option.UserHandler.GetDatabase()
  18. //Define VM global variables
  19. vm.Set("BUILD_VERSION", g.Option.BuildVersion)
  20. vm.Set("INTERNVAL_VERSION", g.Option.InternalVersion)
  21. vm.Set("LOADED_MODULES", g.Option.LoadedModule)
  22. vm.Set("LOADED_STORAGES", g.Option.UserHandler.GetStoragePool())
  23. vm.Set("HTTP_RESP", "")
  24. vm.Set("HTTP_HEADER", "text/plain")
  25. //Response related
  26. vm.Set("sendResp", func(call otto.FunctionCall) otto.Value {
  27. argString, _ := call.Argument(0).ToString()
  28. vm.Set("HTTP_RESP", argString)
  29. return otto.Value{}
  30. })
  31. vm.Set("sendOK", func(call otto.FunctionCall) otto.Value {
  32. vm.Set("HTTP_RESP", "ok")
  33. return otto.Value{}
  34. })
  35. vm.Set("_sendJSONResp", func(call otto.FunctionCall) otto.Value {
  36. argString, _ := call.Argument(0).ToString()
  37. vm.Set("HTTP_HEADER", "application/json")
  38. vm.Set("HTTP_RESP", argString)
  39. return otto.Value{}
  40. })
  41. vm.Run(`
  42. sendJSONResp = function(object){
  43. if (typeof(object) === "object"){
  44. _sendJSONResp(JSON.stringify(object));
  45. }else{
  46. _sendJSONResp(object);
  47. }
  48. }
  49. `)
  50. vm.Set("addNightlyTask", func(call otto.FunctionCall) otto.Value {
  51. scriptPath, _ := call.Argument(0).ToString() //From web directory
  52. if isValidAGIScript(scriptPath) {
  53. g.NightlyScripts = append(g.NightlyScripts, scriptPath)
  54. } else {
  55. return otto.FalseValue()
  56. }
  57. return otto.TrueValue()
  58. })
  59. //Database related
  60. //newDBTableIfNotExists(tableName)
  61. vm.Set("newDBTableIfNotExists", func(call otto.FunctionCall) otto.Value {
  62. tableName, err := call.Argument(0).ToString()
  63. if err != nil {
  64. g.raiseError(err)
  65. reply, _ := vm.ToValue(false)
  66. return reply
  67. }
  68. //Create the table with given tableName
  69. if g.filterDBTable(tableName, false) {
  70. sysdb.NewTable(tableName)
  71. //Return true
  72. reply, _ := vm.ToValue(true)
  73. return reply
  74. }
  75. reply, _ := vm.ToValue(false)
  76. return reply
  77. })
  78. vm.Set("DBTableExists", func(call otto.FunctionCall) otto.Value {
  79. tableName, err := call.Argument(0).ToString()
  80. if err != nil {
  81. g.raiseError(err)
  82. reply, _ := vm.ToValue(false)
  83. return reply
  84. }
  85. //Create the table with given tableName
  86. if sysdb.TableExists(tableName) {
  87. return otto.TrueValue()
  88. }
  89. return otto.FalseValue()
  90. })
  91. //dropDBTable(tablename)
  92. vm.Set("dropDBTable", func(call otto.FunctionCall) otto.Value {
  93. tableName, err := call.Argument(0).ToString()
  94. if err != nil {
  95. g.raiseError(err)
  96. reply, _ := vm.ToValue(false)
  97. return reply
  98. }
  99. //Create the table with given tableName
  100. if g.filterDBTable(tableName, true) {
  101. sysdb.DropTable(tableName)
  102. reply, _ := vm.ToValue(true)
  103. return reply
  104. }
  105. //Return true
  106. reply, _ := vm.ToValue(false)
  107. return reply
  108. })
  109. //writeDBItem(tablename, key, value) => return true when suceed
  110. vm.Set("writeDBItem", func(call otto.FunctionCall) otto.Value {
  111. tableName, err := call.Argument(0).ToString()
  112. if err != nil {
  113. g.raiseError(err)
  114. reply, _ := vm.ToValue(false)
  115. return reply
  116. }
  117. //Check if the tablename is reserved
  118. if g.filterDBTable(tableName, true) {
  119. keyString, err := call.Argument(1).ToString()
  120. if err != nil {
  121. g.raiseError(err)
  122. reply, _ := vm.ToValue(false)
  123. return reply
  124. }
  125. valueString, err := call.Argument(2).ToString()
  126. if err != nil {
  127. g.raiseError(err)
  128. reply, _ := vm.ToValue(false)
  129. return reply
  130. }
  131. sysdb.Write(tableName, keyString, valueString)
  132. reply, _ := vm.ToValue(true)
  133. return reply
  134. }
  135. reply, _ := vm.ToValue(false)
  136. return reply
  137. })
  138. //readDBItem(tablename, key) => return value
  139. vm.Set("readDBItem", func(call otto.FunctionCall) otto.Value {
  140. tableName, _ := call.Argument(0).ToString()
  141. keyString, _ := call.Argument(1).ToString()
  142. returnValue := ""
  143. reply, _ := vm.ToValue(nil)
  144. if g.filterDBTable(tableName, true) {
  145. sysdb.Read(tableName, keyString, &returnValue)
  146. r, _ := vm.ToValue(returnValue)
  147. reply = r
  148. } else {
  149. reply = otto.FalseValue()
  150. }
  151. return reply
  152. })
  153. //listDBTable(tablename) => Return key values array
  154. vm.Set("listDBTable", func(call otto.FunctionCall) otto.Value {
  155. tableName, _ := call.Argument(0).ToString()
  156. returnValue := map[string]string{}
  157. reply, _ := vm.ToValue(nil)
  158. if g.filterDBTable(tableName, true) {
  159. entries, _ := sysdb.ListTable(tableName)
  160. for _, keypairs := range entries {
  161. //Decode the string
  162. result := ""
  163. json.Unmarshal(keypairs[1], &result)
  164. returnValue[string(keypairs[0])] = result
  165. }
  166. r, err := vm.ToValue(returnValue)
  167. if err != nil {
  168. return otto.NullValue()
  169. }
  170. return r
  171. } else {
  172. reply = otto.FalseValue()
  173. }
  174. return reply
  175. })
  176. //deleteDBItem(tablename, key) => Return true if success, false if failed
  177. vm.Set("deleteDBItem", func(call otto.FunctionCall) otto.Value {
  178. tableName, _ := call.Argument(0).ToString()
  179. keyString, _ := call.Argument(1).ToString()
  180. if g.filterDBTable(tableName, true) {
  181. err := sysdb.Delete(tableName, keyString)
  182. if err != nil {
  183. return otto.FalseValue()
  184. }
  185. } else {
  186. //Permission denied
  187. return otto.FalseValue()
  188. }
  189. return otto.TrueValue()
  190. })
  191. //Module registry
  192. vm.Set("registerModule", func(call otto.FunctionCall) otto.Value {
  193. jsonModuleConfig, err := call.Argument(0).ToString()
  194. if err != nil {
  195. g.raiseError(err)
  196. reply, _ := vm.ToValue(false)
  197. return reply
  198. }
  199. //Try to decode it to a module Info
  200. g.Option.ModuleRegisterParser(jsonModuleConfig)
  201. if err != nil {
  202. g.raiseError(err)
  203. reply, _ := vm.ToValue(false)
  204. return reply
  205. }
  206. return otto.Value{}
  207. })
  208. //Package Executation. Only usable when called to a given script File.
  209. if scriptFile != "" && scriptScope != "" {
  210. //Package request --> Install linux package if not exists
  211. vm.Set("requirepkg", func(call otto.FunctionCall) otto.Value {
  212. packageName, err := call.Argument(0).ToString()
  213. if err != nil {
  214. g.raiseError(err)
  215. return otto.FalseValue()
  216. }
  217. requireComply, err := call.Argument(1).ToBoolean()
  218. if err != nil {
  219. g.raiseError(err)
  220. return otto.FalseValue()
  221. }
  222. scriptRoot := getScriptRoot(scriptFile, scriptScope)
  223. //Check if this module already get registered.
  224. alreadyRegistered := false
  225. for _, pkgRequest := range g.AllowAccessPkgs[strings.ToLower(packageName)] {
  226. if pkgRequest.InitRoot == scriptRoot {
  227. alreadyRegistered = true
  228. break
  229. }
  230. }
  231. if !alreadyRegistered {
  232. //Register this packge to this script and allow the module to call this package
  233. g.AllowAccessPkgs[strings.ToLower(packageName)] = append(g.AllowAccessPkgs[strings.ToLower(packageName)], AgiPackage{
  234. InitRoot: scriptRoot,
  235. })
  236. }
  237. //Try to install the package via apt
  238. err = g.Option.PackageManager.InstallIfNotExists(packageName, requireComply)
  239. if err != nil {
  240. g.raiseError(err)
  241. return otto.FalseValue()
  242. }
  243. return otto.TrueValue()
  244. })
  245. //Exec required pkg with permission control
  246. vm.Set("execpkg", func(call otto.FunctionCall) otto.Value {
  247. //Check if the pkg is already registered
  248. scriptRoot := getScriptRoot(scriptFile, scriptScope)
  249. packageName, err := call.Argument(0).ToString()
  250. if err != nil {
  251. g.raiseError(err)
  252. return otto.FalseValue()
  253. }
  254. if val, ok := g.AllowAccessPkgs[packageName]; ok {
  255. //Package already registered by at least one module. Check if this script root registered
  256. thisModuleRegistered := false
  257. for _, registeredPkgInterface := range val {
  258. if registeredPkgInterface.InitRoot == scriptRoot {
  259. //This package registered this command. Allow access
  260. thisModuleRegistered = true
  261. }
  262. }
  263. if !thisModuleRegistered {
  264. g.raiseError(errors.New("Package request not registered: " + packageName))
  265. return otto.FalseValue()
  266. }
  267. } else {
  268. g.raiseError(errors.New("Package request not registered: " + packageName))
  269. return otto.FalseValue()
  270. }
  271. //Ok. Allow paramter to be loaded
  272. execParamters, _ := call.Argument(1).ToString()
  273. // Split input paramters into []string
  274. r := csv.NewReader(strings.NewReader(execParamters))
  275. r.Comma = ' ' // space
  276. fields, err := r.Read()
  277. if err != nil {
  278. g.raiseError(err)
  279. return otto.FalseValue()
  280. }
  281. //Run os.Exec on the given commands
  282. cmd := exec.Command(packageName, fields...)
  283. out, err := cmd.CombinedOutput()
  284. if err != nil {
  285. log.Println(string(out))
  286. g.raiseError(err)
  287. return otto.FalseValue()
  288. }
  289. reply, _ := vm.ToValue(string(out))
  290. return reply
  291. })
  292. //Include another js in runtime
  293. vm.Set("includes", func(call otto.FunctionCall) otto.Value {
  294. //Check if the pkg is already registered
  295. scriptName, err := call.Argument(0).ToString()
  296. if err != nil {
  297. g.raiseError(err)
  298. return otto.FalseValue()
  299. }
  300. //Check if it is calling itself
  301. if filepath.Base(scriptFile) == filepath.Base(scriptName) {
  302. g.raiseError(errors.New("*AGI* Self calling is not allowed"))
  303. return otto.FalseValue()
  304. }
  305. //Check if the script file exists
  306. targetScriptPath := filepath.ToSlash(filepath.Join(filepath.Dir(scriptFile), scriptName))
  307. if !fileExists(targetScriptPath) {
  308. g.raiseError(errors.New("*AGI* Target path not exists!"))
  309. return otto.FalseValue()
  310. }
  311. //Run the script
  312. scriptContent, _ := ioutil.ReadFile(targetScriptPath)
  313. _, err = vm.Run(string(scriptContent))
  314. if err != nil {
  315. //Script execution failed
  316. log.Println("Script Execution Failed: ", err.Error())
  317. g.raiseError(err)
  318. return otto.FalseValue()
  319. }
  320. return otto.TrueValue()
  321. })
  322. }
  323. //Delay, sleep given ms
  324. vm.Set("delay", func(call otto.FunctionCall) otto.Value {
  325. delayTime, err := call.Argument(0).ToInteger()
  326. if err != nil {
  327. g.raiseError(err)
  328. return otto.FalseValue()
  329. }
  330. time.Sleep(time.Duration(delayTime) * time.Millisecond)
  331. return otto.TrueValue()
  332. })
  333. }