123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- package ecal
- import (
- "fmt"
- "io/ioutil"
- "path/filepath"
- "strings"
- "devt.de/krotik/common/datautil"
- "devt.de/krotik/common/fileutil"
- "devt.de/krotik/common/stringutil"
- "devt.de/krotik/ecal/cli/tool"
- ecalconfig "devt.de/krotik/ecal/config"
- "devt.de/krotik/ecal/engine"
- "devt.de/krotik/ecal/scope"
- "devt.de/krotik/ecal/stdlib"
- "devt.de/krotik/ecal/util"
- "devt.de/krotik/eliasdb/config"
- "devt.de/krotik/eliasdb/ecal/dbfunc"
- "devt.de/krotik/eliasdb/graph"
- )
- type ScriptingInterpreter struct {
- GM *graph.Manager
- Interpreter *tool.CLIInterpreter
- Dir string
- EntryFile string
- LogLevel string
- LogFile string
- RunDebugServer bool
- DebugServerHost string
- DebugServerPort string
- WebsocketConnections *datautil.MapCache
- }
- func NewScriptingInterpreter(scriptFolder string, gm *graph.Manager) *ScriptingInterpreter {
- return &ScriptingInterpreter{
- GM: gm,
- Dir: scriptFolder,
- EntryFile: filepath.Join(scriptFolder, config.Str(config.ECALEntryScript)),
- LogLevel: config.Str(config.ECALLogLevel),
- LogFile: config.Str(config.ECALLogFile),
- RunDebugServer: config.Bool(config.EnableECALDebugServer),
- DebugServerHost: config.Str(config.ECALDebugServerHost),
- DebugServerPort: config.Str(config.ECALDebugServerPort),
- WebsocketConnections: datautil.NewMapCache(5000, 0),
- }
- }
- const dummyEntryFile = `0 # Write your ECAL code here
- `
- func (si *ScriptingInterpreter) Run() error {
- var err error
-
- if ok, _ := fileutil.PathExists(si.EntryFile); !ok {
- err = ioutil.WriteFile(si.EntryFile, []byte(dummyEntryFile), 0600)
- }
- if err == nil {
- i := tool.NewCLIInterpreter()
- si.Interpreter = i
-
- ecalconfig.Config[ecalconfig.WorkerCount] = config.Config[config.ECALWorkerCount]
- i.Dir = &si.Dir
- i.LogFile = &si.LogFile
- i.LogLevel = &si.LogLevel
- i.EntryFile = si.EntryFile
- i.LoadPlugins = true
- i.CreateRuntimeProvider("eliasdb-runtime")
-
- AddEliasDBStdlibFunctions(si.GM)
-
- sockRule := &engine.Rule{
- Name: "EliasDB-websocket-communication-rule",
- Desc: "Handles a websocket communication",
- KindMatch: []string{"db.web.sock.msg"},
- ScopeMatch: []string{},
- StateMatch: nil,
- Priority: 0,
- SuppressionList: nil,
- Action: si.HandleECALSockEvent,
- }
- si.Interpreter.CustomRules = append(si.Interpreter.CustomRules, sockRule)
- if err == nil {
- if si.RunDebugServer {
- di := tool.NewCLIDebugInterpreter(i)
- addr := fmt.Sprintf("%v:%v", si.DebugServerHost, si.DebugServerPort)
- di.DebugServerAddr = &addr
- di.RunDebugServer = &si.RunDebugServer
- falseFlag := false
- di.EchoDebugServer = &falseFlag
- di.Interactive = &falseFlag
- di.BreakOnStart = &falseFlag
- di.BreakOnError = &falseFlag
- err = di.Interpret()
- } else {
- err = i.Interpret(false)
- }
-
- si.GM.SetGraphRule(&EventBridge{
- Processor: i.RuntimeProvider.Processor,
- Logger: i.RuntimeProvider.Logger,
- })
- }
- }
-
- if ss, ok := err.(util.TraceableRuntimeError); ok {
- err = fmt.Errorf("%v\n %v", err.Error(), strings.Join(ss.GetTraceString(), "\n "))
- }
- return err
- }
- func (si *ScriptingInterpreter) RegisterECALSock(conn *WebsocketConnection) {
- si.WebsocketConnections.Put(conn.CommID, conn)
- }
- func (si *ScriptingInterpreter) DeregisterECALSock(conn *WebsocketConnection) {
- si.WebsocketConnections.Remove(conn.CommID)
- }
- func (si *ScriptingInterpreter) HandleECALSockEvent(p engine.Processor, m engine.Monitor, e *engine.Event, tid uint64) error {
- state := e.State()
- payload := scope.ConvertECALToJSONObject(state["payload"])
- shouldClose := stringutil.IsTrueValue(fmt.Sprint(state["close"]))
- id := "null"
- if commID, ok := state["commID"]; ok {
- id = fmt.Sprint(commID)
- }
- err := fmt.Errorf("Could not send data to unknown websocket - commID: %v", id)
- if conn, ok := si.WebsocketConnections.Get(id); ok {
- err = nil
- wconn := conn.(*WebsocketConnection)
- wconn.WriteData(map[string]interface{}{
- "commID": id,
- "payload": payload,
- "close": shouldClose,
- })
- if shouldClose {
- wconn.Close("")
- }
- }
- return err
- }
- func AddEliasDBStdlibFunctions(gm *graph.Manager) {
- stdlib.AddStdlibPkg("db", "EliasDB related functions")
- stdlib.AddStdlibFunc("db", "storeNode", &dbfunc.StoreNodeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "updateNode", &dbfunc.UpdateNodeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "removeNode", &dbfunc.RemoveNodeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "fetchNode", &dbfunc.FetchNodeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "storeEdge", &dbfunc.StoreEdgeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "removeEdge", &dbfunc.RemoveEdgeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "fetchEdge", &dbfunc.FetchEdgeFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "traverse", &dbfunc.TraverseFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "newTrans", &dbfunc.NewTransFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "newRollingTrans", &dbfunc.NewRollingTransFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "commit", &dbfunc.CommitTransFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "query", &dbfunc.QueryFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "graphQL", &dbfunc.GraphQLFunc{GM: gm})
- stdlib.AddStdlibFunc("db", "raiseGraphEventHandled", &dbfunc.RaiseGraphEventHandledFunc{})
- stdlib.AddStdlibFunc("db", "raiseWebEventHandled", &dbfunc.RaiseWebEventHandledFunc{})
- }
|