systemFunc.go 9.3 KB

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