systemFunc.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. package agi
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "log"
  6. "os"
  7. "path/filepath"
  8. "time"
  9. "github.com/robertkrimen/otto"
  10. "imuslab.com/arozos/mod/agi/static"
  11. "imuslab.com/arozos/mod/utils"
  12. )
  13. // Inject aroz online custom functions into the virtual machine
  14. func (g *Gateway) injectStandardLibs(vm *otto.Otto, scriptFile string, scriptScope string) {
  15. //Define system core modules and definations
  16. sysdb := g.Option.UserHandler.GetDatabase()
  17. //Define VM global variables
  18. vm.Set("BUILD_VERSION", g.Option.BuildVersion)
  19. vm.Set("INTERNAL_VERSION", g.Option.InternalVersion)
  20. vm.Set("LOADED_MODULES", g.Option.LoadedModule)
  21. vm.Set("LOADED_STORAGES", g.Option.UserHandler.GetStoragePool())
  22. vm.Set("__FILE__", scriptFile)
  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 static.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. g.RaiseError(errors.New("requirepkg has been deprecated in agi v3.0"))
  228. return otto.FalseValue()
  229. /*
  230. packageName, err := call.Argument(0).ToString()
  231. if err != nil {
  232. g.RaiseError(err)
  233. return otto.FalseValue()
  234. }
  235. requireComply, err := call.Argument(1).ToBoolean()
  236. if err != nil {
  237. g.RaiseError(err)
  238. return otto.FalseValue()
  239. }
  240. scriptRoot := static.GetScriptRoot(scriptFile, scriptScope)
  241. //Check if this module already get registered.
  242. alreadyRegistered := false
  243. for _, pkgRequest := range g.AllowAccessPkgs[strings.ToLower(packageName)] {
  244. if pkgRequest.InitRoot == scriptRoot {
  245. alreadyRegistered = true
  246. break
  247. }
  248. }
  249. if !alreadyRegistered {
  250. //Register this packge to this script and allow the module to call this package
  251. g.AllowAccessPkgs[strings.ToLower(packageName)] = append(g.AllowAccessPkgs[strings.ToLower(packageName)], AgiPackage{
  252. InitRoot: scriptRoot,
  253. })
  254. }
  255. //Try to install the package via apt
  256. err = g.Option.PackageManager.InstallIfNotExists(packageName, requireComply)
  257. if err != nil {
  258. g.RaiseError(err)
  259. return otto.FalseValue()
  260. }
  261. return otto.TrueValue()
  262. */
  263. })
  264. //Exec required pkg with permission control
  265. vm.Set("execpkg", func(call otto.FunctionCall) otto.Value {
  266. g.RaiseError(errors.New("execpkg has been deprecated in agi v3.0"))
  267. return otto.FalseValue()
  268. /*
  269. //Check if the pkg is already registered
  270. scriptRoot := static.GetScriptRoot(scriptFile, scriptScope)
  271. packageName, err := call.Argument(0).ToString()
  272. if err != nil {
  273. g.RaiseError(err)
  274. return otto.FalseValue()
  275. }
  276. if val, ok := g.AllowAccessPkgs[packageName]; ok {
  277. //Package already registered by at least one module. Check if this script root registered
  278. thisModuleRegistered := false
  279. for _, registeredPkgInterface := range val {
  280. if registeredPkgInterface.InitRoot == scriptRoot {
  281. //This package registered this command. Allow access
  282. thisModuleRegistered = true
  283. }
  284. }
  285. if !thisModuleRegistered {
  286. g.RaiseError(errors.New("Package request not registered: " + packageName))
  287. return otto.FalseValue()
  288. }
  289. } else {
  290. g.RaiseError(errors.New("Package request not registered: " + packageName))
  291. return otto.FalseValue()
  292. }
  293. //Ok. Allow paramter to be loaded
  294. execParamters, _ := call.Argument(1).ToString()
  295. // Split input paramters into []string
  296. r := csv.NewReader(strings.NewReader(execParamters))
  297. r.Comma = ' ' // space
  298. fields, err := r.Read()
  299. if err != nil {
  300. g.RaiseError(err)
  301. return otto.FalseValue()
  302. }
  303. //Run os.Exec on the given commands
  304. cmd := exec.Command(packageName, fields...)
  305. out, err := cmd.CombinedOutput()
  306. if err != nil {
  307. log.Println(string(out))
  308. g.RaiseError(err)
  309. return otto.FalseValue()
  310. }
  311. reply, _ := vm.ToValue(string(out))
  312. return reply
  313. */
  314. })
  315. //Include another js in runtime
  316. vm.Set("includes", func(call otto.FunctionCall) otto.Value {
  317. //Check if the pkg is already registered
  318. scriptName, err := call.Argument(0).ToString()
  319. if err != nil {
  320. g.RaiseError(err)
  321. return otto.FalseValue()
  322. }
  323. //Check if it is calling itself
  324. if filepath.Base(scriptFile) == filepath.Base(scriptName) {
  325. g.RaiseError(errors.New("*AGI* Self calling is not allowed"))
  326. return otto.FalseValue()
  327. }
  328. //Check if the script file exists
  329. targetScriptPath := filepath.ToSlash(filepath.Join(filepath.Dir(scriptFile), scriptName))
  330. if !utils.FileExists(targetScriptPath) {
  331. g.RaiseError(errors.New("*AGI* Target path not exists!"))
  332. return otto.FalseValue()
  333. }
  334. //Run the script
  335. scriptContent, _ := os.ReadFile(targetScriptPath)
  336. _, err = vm.Run(string(scriptContent))
  337. if err != nil {
  338. //Script execution failed
  339. log.Println("Script Execution Failed: ", err.Error())
  340. g.RaiseError(err)
  341. return otto.FalseValue()
  342. }
  343. return otto.TrueValue()
  344. })
  345. }
  346. //Delay, sleep given ms
  347. vm.Set("delay", func(call otto.FunctionCall) otto.Value {
  348. delayTime, err := call.Argument(0).ToInteger()
  349. if err != nil {
  350. g.RaiseError(err)
  351. return otto.FalseValue()
  352. }
  353. time.Sleep(time.Duration(delayTime) * time.Millisecond)
  354. return otto.TrueValue()
  355. })
  356. //Exit
  357. vm.Set("exit", func(call otto.FunctionCall) otto.Value {
  358. vm.Interrupt <- func() {
  359. panic(errExitcall)
  360. }
  361. return otto.NullValue()
  362. })
  363. }