interpreter.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package ecal
  11. import (
  12. "fmt"
  13. "io/ioutil"
  14. "path/filepath"
  15. "strings"
  16. "devt.de/krotik/common/fileutil"
  17. "devt.de/krotik/ecal/cli/tool"
  18. "devt.de/krotik/ecal/stdlib"
  19. "devt.de/krotik/ecal/util"
  20. "devt.de/krotik/eliasdb/config"
  21. "devt.de/krotik/eliasdb/ecal/dbfunc"
  22. "devt.de/krotik/eliasdb/graph"
  23. )
  24. /*
  25. ScriptingInterpreter models a ECAL script interpreter instance.
  26. */
  27. type ScriptingInterpreter struct {
  28. GM *graph.Manager // GraphManager for the interpreter
  29. Interpreter *tool.CLIInterpreter // ECAL Interpreter object
  30. Dir string // Root dir for interpreter
  31. EntryFile string // Entry file for the program
  32. LogLevel string // Log level string (Debug, Info, Error)
  33. LogFile string // Logfile (blank for stdout)
  34. RunDebugServer bool // Run a debug server
  35. DebugServerHost string // Debug server host
  36. DebugServerPort string // Debug server port
  37. }
  38. /*
  39. NewScriptingInterpreter returns a new ECAL scripting interpreter.
  40. */
  41. func NewScriptingInterpreter(scriptFolder string, gm *graph.Manager) *ScriptingInterpreter {
  42. return &ScriptingInterpreter{
  43. GM: gm,
  44. Dir: scriptFolder,
  45. EntryFile: filepath.Join(scriptFolder, config.Str(config.ECALEntryScript)),
  46. LogLevel: config.Str(config.ECALLogLevel),
  47. LogFile: config.Str(config.ECALLogFile),
  48. RunDebugServer: config.Bool(config.EnableECALDebugServer),
  49. DebugServerHost: config.Str(config.ECALDebugServerHost),
  50. DebugServerPort: config.Str(config.ECALDebugServerPort),
  51. }
  52. }
  53. /*
  54. dummyEntryFile is a small valid ECAL which does not do anything. It is used
  55. as the default entry file if no entry file exists.
  56. */
  57. const dummyEntryFile = `0 # Write your ECAL code here
  58. `
  59. /*
  60. Run runs the ECAL scripting interpreter.
  61. After this function completes:
  62. - EntryScript in config and all related scripts in the interpreter root dir have been executed
  63. - ECAL Interpreter object is fully initialized
  64. - A debug server might be running which can reload the entry script
  65. - ECAL's event processor has been started
  66. - GraphManager events are being forwarded to ECAL
  67. */
  68. func (si *ScriptingInterpreter) Run() error {
  69. var err error
  70. // Ensure we have a dummy entry point
  71. if ok, _ := fileutil.PathExists(si.EntryFile); !ok {
  72. err = ioutil.WriteFile(si.EntryFile, []byte(dummyEntryFile), 0600)
  73. }
  74. if err == nil {
  75. i := tool.NewCLIInterpreter()
  76. si.Interpreter = i
  77. i.Dir = &si.Dir
  78. i.LogFile = &si.LogFile
  79. i.LogLevel = &si.LogLevel
  80. i.EntryFile = si.EntryFile
  81. i.LoadPlugins = true
  82. i.CreateRuntimeProvider("eliasdb-runtime")
  83. // Adding functions
  84. AddEliasDBStdlibFunctions(si.GM)
  85. if err == nil {
  86. if si.RunDebugServer {
  87. di := tool.NewCLIDebugInterpreter(i)
  88. addr := fmt.Sprintf("%v:%v", si.DebugServerHost, si.DebugServerPort)
  89. di.DebugServerAddr = &addr
  90. di.RunDebugServer = &si.RunDebugServer
  91. falseFlag := false
  92. di.EchoDebugServer = &falseFlag
  93. di.Interactive = &falseFlag
  94. di.BreakOnStart = &falseFlag
  95. di.BreakOnError = &falseFlag
  96. err = di.Interpret()
  97. } else {
  98. err = i.Interpret(false)
  99. }
  100. // EliasDB graph events are now forwarded to ECAL via the eventbridge.
  101. si.GM.SetGraphRule(&EventBridge{
  102. Processor: i.RuntimeProvider.Processor,
  103. Logger: i.RuntimeProvider.Logger,
  104. })
  105. }
  106. }
  107. // Include a traceback if possible
  108. if ss, ok := err.(util.TraceableRuntimeError); ok {
  109. err = fmt.Errorf("%v\n %v", err.Error(), strings.Join(ss.GetTraceString(), "\n "))
  110. }
  111. return err
  112. }
  113. func AddEliasDBStdlibFunctions(gm *graph.Manager) {
  114. stdlib.AddStdlibPkg("db", "EliasDB related functions")
  115. stdlib.AddStdlibFunc("db", "storeNode", &dbfunc.StoreNodeFunc{GM: gm})
  116. stdlib.AddStdlibFunc("db", "updateNode", &dbfunc.UpdateNodeFunc{GM: gm})
  117. stdlib.AddStdlibFunc("db", "removeNode", &dbfunc.RemoveNodeFunc{GM: gm})
  118. stdlib.AddStdlibFunc("db", "fetchNode", &dbfunc.FetchNodeFunc{GM: gm})
  119. stdlib.AddStdlibFunc("db", "storeEdge", &dbfunc.StoreEdgeFunc{GM: gm})
  120. stdlib.AddStdlibFunc("db", "removeEdge", &dbfunc.RemoveEdgeFunc{GM: gm})
  121. stdlib.AddStdlibFunc("db", "fetchEdge", &dbfunc.FetchEdgeFunc{GM: gm})
  122. stdlib.AddStdlibFunc("db", "traverse", &dbfunc.TraverseFunc{GM: gm})
  123. stdlib.AddStdlibFunc("db", "newTrans", &dbfunc.NewTransFunc{GM: gm})
  124. stdlib.AddStdlibFunc("db", "newRollingTrans", &dbfunc.NewRollingTransFunc{GM: gm})
  125. stdlib.AddStdlibFunc("db", "commit", &dbfunc.CommitTransFunc{GM: gm})
  126. stdlib.AddStdlibFunc("db", "query", &dbfunc.QueryFunc{GM: gm})
  127. stdlib.AddStdlibFunc("db", "graphQL", &dbfunc.GraphQLFunc{GM: gm})
  128. stdlib.AddStdlibFunc("db", "raiseGraphEventHandled", &dbfunc.RaiseGraphEventHandledFunc{})
  129. stdlib.AddStdlibFunc("db", "raiseWebEventHandled", &dbfunc.RaiseWebEventHandledFunc{})
  130. }