|
|
@@ -2,16 +2,24 @@
|
|
|
using Expressive;
|
|
|
using InABox.Core;
|
|
|
using InABox.Database;
|
|
|
+using Org.BouncyCastle.Asn1.X509.Qualified;
|
|
|
using System;
|
|
|
using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Diagnostics.CodeAnalysis;
|
|
|
using System.Linq;
|
|
|
+using System.Reflection;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
namespace PRS.Shared.Events;
|
|
|
|
|
|
-public class EventData<T, TDataModel>
|
|
|
+public interface IEventData : ISerializeBinary
|
|
|
+{
|
|
|
+ IEvent Event { get; }
|
|
|
+}
|
|
|
+
|
|
|
+public class EventData<T, TDataModel> : IEventData
|
|
|
where T : IEvent<TDataModel>
|
|
|
where TDataModel : IEventDataModel
|
|
|
{
|
|
|
@@ -24,6 +32,8 @@ public class EventData<T, TDataModel>
|
|
|
|
|
|
public List<IEventAction<T>> Actions { get; set; }
|
|
|
|
|
|
+ IEvent IEventData.Event => Event;
|
|
|
+
|
|
|
public EventData(T eventData)
|
|
|
{
|
|
|
Event = eventData;
|
|
|
@@ -32,10 +42,183 @@ public class EventData<T, TDataModel>
|
|
|
}
|
|
|
|
|
|
public Notification GenerateNotification(TDataModel model) => Event.GenerateNotification(model);
|
|
|
+
|
|
|
+ public void SerializeBinary(CoreBinaryWriter writer)
|
|
|
+ {
|
|
|
+ Event.SerializeBinary(writer);
|
|
|
+ writer.Write(Triggers.Count);
|
|
|
+ foreach(var trigger in Triggers)
|
|
|
+ {
|
|
|
+ EventUtils.SerializeObject(trigger, writer);
|
|
|
+ }
|
|
|
+ writer.Write(Actions.Count);
|
|
|
+ foreach(var action in Actions)
|
|
|
+ {
|
|
|
+ EventUtils.SerializeObject(action, writer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void DeserializeBinary(CoreBinaryReader reader)
|
|
|
+ {
|
|
|
+ Event.DeserializeBinary(reader);
|
|
|
+ var nTriggers = reader.ReadInt32();
|
|
|
+ for(int i = 0; i < nTriggers; ++i)
|
|
|
+ {
|
|
|
+ var trigger = EventUtils.DeserializeObject<ITrigger<T, TDataModel>>(EventUtils.GetTriggerType, reader);
|
|
|
+ Triggers.Add(trigger);
|
|
|
+ }
|
|
|
+ var nActions = reader.ReadInt32();
|
|
|
+ for(int i = 0; i < nActions; ++i)
|
|
|
+ {
|
|
|
+ var action = EventUtils.DeserializeObject<IEventAction<T>>(EventUtils.GetTriggerType, reader);
|
|
|
+ Actions.Add(action);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
public static class EventUtils
|
|
|
{
|
|
|
+ #region Serialisation
|
|
|
+
|
|
|
+ public static void SerializeObject(ISerializeBinary obj, CoreBinaryWriter writer)
|
|
|
+ {
|
|
|
+ writer.Write(obj.GetType().Name);
|
|
|
+ foreach(var arg in obj.GetType().GenericTypeArguments)
|
|
|
+ {
|
|
|
+ writer.Write(CoreUtils.EntityName(arg));
|
|
|
+ }
|
|
|
+ obj.SerializeBinary(writer);
|
|
|
+ }
|
|
|
+ public static T DeserializeObject<T>(Func<string, Type> typeSource, CoreBinaryReader reader)
|
|
|
+ where T : class, ISerializeBinary
|
|
|
+ {
|
|
|
+ var eventTypeName = reader.ReadString();
|
|
|
+ var objType = typeSource(eventTypeName);
|
|
|
+
|
|
|
+ var typeParams = objType.GetTypeInfo().GenericTypeParameters;
|
|
|
+ var typeArgs = new Type[typeParams.Length];
|
|
|
+ for(int i = 0; i < typeParams.Length; ++i)
|
|
|
+ {
|
|
|
+ var entityType = CoreUtils.GetEntity(reader.ReadString());
|
|
|
+ typeArgs[i] = entityType;
|
|
|
+ }
|
|
|
+ if(typeArgs.Length > 0)
|
|
|
+ {
|
|
|
+ objType = objType.MakeGenericType(typeArgs);
|
|
|
+ }
|
|
|
+ var obj = (Activator.CreateInstance(objType) as T)!;
|
|
|
+ obj.DeserializeBinary(reader);
|
|
|
+
|
|
|
+ return obj;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void Serialize(IEventData data, CoreBinaryWriter writer)
|
|
|
+ {
|
|
|
+ writer.Write(data.Event.GetType().Name);
|
|
|
+ foreach(var arg in data.Event.GetType().GenericTypeArguments)
|
|
|
+ {
|
|
|
+ writer.Write(CoreUtils.EntityName(arg));
|
|
|
+ }
|
|
|
+ data.SerializeBinary(writer);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static IEventData Deserialize(CoreBinaryReader reader)
|
|
|
+ {
|
|
|
+ var eventTypeName = reader.ReadString();
|
|
|
+ var eventType = EventUtils.GetEventType(eventTypeName);
|
|
|
+
|
|
|
+ var typeParams = eventType.GetTypeInfo().GenericTypeParameters;
|
|
|
+ var typeArgs = new Type[typeParams.Length];
|
|
|
+ for(int i = 0; i < typeParams.Length; ++i)
|
|
|
+ {
|
|
|
+ var entityType = CoreUtils.GetEntity(reader.ReadString());
|
|
|
+ typeArgs[i] = entityType;
|
|
|
+ }
|
|
|
+ if(typeArgs.Length > 0)
|
|
|
+ {
|
|
|
+ eventType = eventType.MakeGenericType(typeArgs);
|
|
|
+ }
|
|
|
+ var ev = (Activator.CreateInstance(eventType) as IEvent)!;
|
|
|
+
|
|
|
+ var dataModelType = ev.GetType().GetInterfaceDefinition(typeof(IEvent<>))!.GenericTypeArguments[0];
|
|
|
+
|
|
|
+ var eventDataType = typeof(EventData<,>).MakeGenericType(ev.GetType(), dataModelType);
|
|
|
+
|
|
|
+ var eventData = (Activator.CreateInstance(eventDataType, ev) as IEventData)!;
|
|
|
+
|
|
|
+ eventData.DeserializeBinary(reader);
|
|
|
+
|
|
|
+ return eventData;
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Event Types
|
|
|
+
|
|
|
+ private static Dictionary<string, Type>? _eventTypes;
|
|
|
+ private static Dictionary<string, Type>? _triggerTypes;
|
|
|
+ private static Dictionary<string, Type>? _actionTypes;
|
|
|
+
|
|
|
+ [MemberNotNullWhen(true, nameof(_eventTypes), nameof(_triggerTypes), nameof(_actionTypes))]
|
|
|
+ private static bool _loadedTypes { get; set; }
|
|
|
+
|
|
|
+ [MemberNotNull(nameof(_eventTypes), nameof(_triggerTypes), nameof(_actionTypes))]
|
|
|
+ private static void LoadTypes()
|
|
|
+ {
|
|
|
+ if (_loadedTypes) return;
|
|
|
+
|
|
|
+ _loadedTypes = true;
|
|
|
+ _eventTypes = new();
|
|
|
+ _triggerTypes = new();
|
|
|
+ _actionTypes = new();
|
|
|
+ foreach(var type in CoreUtils.TypeList(x => true))
|
|
|
+ {
|
|
|
+ if (type.HasInterface(typeof(IEvent<>)))
|
|
|
+ {
|
|
|
+ if (type.GetConstructor([]) is not null)
|
|
|
+ {
|
|
|
+ _eventTypes[type.Name] = type;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (type.HasInterface(typeof(ITrigger<,>)))
|
|
|
+ {
|
|
|
+ if (type.GetConstructor([]) is not null)
|
|
|
+ {
|
|
|
+ _triggerTypes[type.Name] = type;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (type.HasInterface(typeof(IEventAction<>)))
|
|
|
+ {
|
|
|
+ if (type.GetConstructor([]) is not null)
|
|
|
+ {
|
|
|
+ _triggerTypes[type.Name] = type;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Type GetEventType(string type)
|
|
|
+ {
|
|
|
+ LoadTypes();
|
|
|
+ return _eventTypes[type]; // Force exception if not a valid type name.
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Type GetTriggerType(string type)
|
|
|
+ {
|
|
|
+ LoadTypes();
|
|
|
+ return _triggerTypes[type]; // Force exception if not a valid type name.
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Type GetActionType(string type)
|
|
|
+ {
|
|
|
+ LoadTypes();
|
|
|
+ return _actionTypes[type]; // Force exception if not a valid type name.
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Execution
|
|
|
+
|
|
|
private static bool Check<T, TDataModel>(EventData<T, TDataModel> ev, TDataModel dataModel)
|
|
|
where T : IEvent<TDataModel>
|
|
|
where TDataModel : IEventDataModel
|
|
|
@@ -94,6 +277,8 @@ public static class EventUtils
|
|
|
}
|
|
|
store.Provider.Save(notifications);
|
|
|
}
|
|
|
+
|
|
|
+ #endregion
|
|
|
}
|
|
|
|
|
|
#region DataModel Definition
|
|
|
@@ -199,7 +384,7 @@ public class ChildEventDataModel : IChildEventDataModel
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
-public interface IEvent
|
|
|
+public interface IEvent : ISerializeBinary
|
|
|
{
|
|
|
IEventDataModelDefinition DataModelDefinition();
|
|
|
|
|
|
@@ -263,14 +448,14 @@ public interface IEvent<TDataModel> : IEvent
|
|
|
Notification GenerateNotification(TDataModel model);
|
|
|
}
|
|
|
|
|
|
-public interface ITrigger<TEvent, TDataModel>
|
|
|
+public interface ITrigger<TEvent, TDataModel> : ISerializeBinary
|
|
|
where TEvent : IEvent<TDataModel>
|
|
|
where TDataModel : IEventDataModel
|
|
|
{
|
|
|
bool Check(TDataModel dataModel);
|
|
|
}
|
|
|
|
|
|
-public interface IEventAction
|
|
|
+public interface IEventAction : ISerializeBinary
|
|
|
{
|
|
|
IEnumerable<string> ReferencedVariables();
|
|
|
|