# имя: 'Reflex Center' # описание: подсистема реакций и сценариев # тип триггера: 'EgsScenario' # создан: 2019.11.27 14:22:07, Сельченков Н.Ю. # изменен: '2019.12.27 12.40.32', Сельченков Н.Ю. # подробности: https://redmine.integra-s.com:11000/projects/eilyacuario/wiki/Reflex_Center use System.Random use System.Activator use System.Linq.Expressions.Expression use acuario2.dynamic.DynamicExpression use acuario2.dynamic.ParseException use acuario2.utils.ReflectionExtension use acuario2.utils.TextExtension use System.Collections.Generic.List(Object) as ObjectList use System.Collections.Generic.List(Type) as TypeList use System.Collections.Generic.List(string) as StringList use System.Collections.Generic.List(string[]) as StringArrayList use System.Collections.Generic.Dictionary(string, object) as GenericDictionary use json_schema ` { "type": "object", "properties": {}, "additionalProperties": { "type": "object", "properties": { "enabled": { "type": "boolean" }, "source": { "type": "array", "items": { "type": "string" } }, "target": { "type": "array", "items": { "type": "string" } }, "condition": { "type": "string", "format": "EGS" }, "action": { "type": "string", "format": "EGS" }, "params": { "type": "object", "additionalProperties": { "type": "string" } }, "tree": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": { "type": "string" } } } }, "operation": { "type": "array", "items": { "type": "string", "format": "Protocol+Operation" } }, "schedule": { "type": "array", "items": { "type": "string" } }, "comment": { "type": "string" } } } } ` as SETTINGS const false_condition(source as Object, changes as string[]) = false const Condition = typeof(false_condition) const false_action(target as Object, source as Object) = false const Action = typeof(false_action) #################################################################### let settings = SETTINGS(trigger.settings) from settings where Value.enabled do let scope = Key.Replace(' ', '_') this.Scope = scope with Value do let externals = GenericDictionary() let myprint(line as int, msg as string) = print(msg) externals["print"] = myprint let source_params = StringList() let source_objs = ObjectList() let source_types = TypeList() this.Scope = scope.."/source" from source do try let obj = graph[Guid(it)] as Object source_types.Add(obj.GetType()) source_objs.Add(obj) else source_types.Add(Type(it)) now let source_type = from ReflectionExtension.GetCommonBaseInterfaces(source_types) single let allowed_source_type(type as Type) = from source_types any it.IsAssignableFrom(type) let allowed_source_obj(obj as Object) = (source_objs is empty) or (obj in source_objs) let allowed_source(obj as Object) = (obj isnt null) and (obj.GetType() is allowed_source_type) and (obj is allowed_source_obj) let target_type_name = from target try last let target_type = Type(target_type_name) let allowed_target_type(type as Type) = target_type.IsAssignableFrom(type) let allowed_target(obj as Object) = (obj isnt null) and (obj.GetType() is allowed_target_type) let process_targets(source as Object, action as Action) = from graph.Find(source, target) of type Object where it is allowed_target all action(it, source) end let target_is_event = Type(Event).IsAssignableFrom(target_type) if target_is_event then target_type = Type.GetType("acuario2.client."..target_type_name..",acuario2.types", true) let proc(source as Object, action as Action) = let event = Activator.CreateInstance(target_type) as Object let continue = action(event, source) let server = params["server"] let server = Guid(if '-' in server then server else event[server]?.Text) let request = event.ExportCreate(server) let channel = this.Module.GetWampChannel(server) Protocol.Put(channel.RealmProxy.RpcCatalog, request) continue end process_targets = proc end print scope.." source: "..source_type print scope.." target: "..target_type let compile_condition(code as string) = let args = new [ Expression.Parameter(source_type), Expression.Parameter(string[] as Type, "changes") ] let lambda = DynamicExpression.TryParseLambda(args, bool, code, externals, source_params) let delegate = lambda.Compile() let proc(source as Object, changes as string[]) = delegate.DynamicInvoke(new [source, changes]) as bool end let compile_action(code as string) = let args = new [ Expression.Parameter(target_type), Expression.Parameter(source_type, "source") ] let lambda = DynamicExpression.TryParseLambda(args, null, code, externals, null) let delegate = lambda.Compile() let proc(target as Object, source as Object) = let continue = delegate.DynamicInvoke(new [target, source]) (continue isnt bool) or (continue as bool) end let replace(text as string, key as string, value as string) = text.Replace("{" ..key.."}", value) .Replace("{↑"..key.."}", TextExtension.UppercaseFirst(value)) .Replace("{↓"..key.."}", TextExtension.LowercaseFirst(value)) end let replace_params(text as string) = from params do text = replace(text, Key, Value) now text end let condition = replace_params(it.condition) let action = replace_params(it.action) print scope.." condition: "..condition print scope.." action: "..action let replace_flow(text as string, flow as string[]) = from 0 to flow.Length - 1 do text = replace(text, string(it), flow[it]) now text end let compile_flow(flow as string[]) = this.Scope = scope.."/tree/"..string.Join("/", flow) let scope = this.Scope let condition = compile_condition(replace_params(replace_flow(condition, flow))) let action = compile_action (replace_params(replace_flow(action, flow))) let proc(source as Object, changes as string[]) = this.Scope = scope condition(source, changes) and process_targets(source, action) end let flows = StringArrayList() from tree do let keys = new [ Key ] if Value is empty then flows.Add(keys) else from Value do let keys = from keys concat new [ Key ] to array if Value is empty then flows.Add(keys) else from Value do let keys = from keys concat new [ Key, Value ] to array flows.Add(keys) now now now let flows = from flows select compile_flow(it) to list if flows is empty then flows.Add(compile_flow(string[](0))) this.Scope = scope let expected(changes) = from source_params any it in changes print scope.." source params used: "..string.Join(", ", source_params) let execute(source as Object, changes as string[]) = if source is allowed_source then from flows where Invoke(source, changes) try first this.Scope = scope void() end let no_changes = string[](0) let on_update(source as AbstractObject, changes as string[]) = if changes is expected then execute(source as Object, changes) let on_delete(source as AbstractObject) = execute(source as Object, no_changes) let on_schedule() = from graph.Values of type Object do execute(it, no_changes) now from operation do print scope.." runs on "..it switch it when "create" then this.RunOnCreated(on_update) when "update" then this.RunOnUpdated(on_update) when "delete" then this.RunOnDeleted(on_delete) now from schedule do print scope.." runs on "..it this.RunOnSchedule(it, on_schedule) now now