systemFunc.go 9.4 KB

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