systemFunc.go 11 KB

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