systemFunc.go 11 KB

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