systemFunc.go 11 KB

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