diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 73383be..2885243 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,4 +1,5 @@ -using System.Net; +using System.Linq; +using System.Net; using Example.Backend; using mROA.Abstract; using mROA.Cbor; @@ -23,19 +24,20 @@ class Program builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor))); builder.UseBasicExecution(); - + builder.Modules.Add(new CreativeRepresentationModuleProducer( + new IInjectableModule[] { builder.GetModule()! }, + typeof(RepresentationModule))); builder.Modules.Add(new RemoteContextRepository()); // builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly); builder.Modules.Add(new MultiClientContextRepository(i => { var repo = new ContextRepository(); repo.FillSingletons(typeof(PrinterFactory).Assembly); + repo.Inject(builder.Modules.OfType().First()); return repo; })); builder.SetupMethodsRepository(new CoCodegenMethodRepository()); - builder.Modules.Add(new CreativeRepresentationModuleProducer( - new IInjectableModule[] { builder.GetModule()! }, - typeof(RepresentationModule))); + builder.Modules.Add(new CancellationRepository()); builder.Build(); diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 8db3063..cc8d06b 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -67,6 +67,7 @@ namespace mROA.Codegen // var reader = new StreamReader(test); // var allText = reader.ReadToEnd(); var frontendContextRepo = new List(); + var eventBinders = new List(); List totalMethods = new List(); @@ -145,7 +146,7 @@ namespace mROA.Codegen } } - GenerateEventImplementation(classSymbol, invokers, declaredMethods, context); + GenerateEventImplementation(classSymbol, invokers, declaredMethods, context, eventBinders); var code = $@"// @@ -222,11 +223,12 @@ namespace mROA.Codegen if (frontendContextRepo.Count != 0) { var fronendRepoCode = @$"// -using mROA.Implementation; -using mROA.Abstract; using System.Collections.Generic; -using System; using System.Reflection; +using System; +using mROA.Abstract; +using mROA.Implementation.Backend; +using mROA.Implementation; namespace mROA.Codegen {{ @@ -235,6 +237,8 @@ namespace mROA.Codegen static RemoteTypeBinder(){{ RemoteContextRepository.RemoteTypes = new Dictionary {{ {string.Join(", \r\n\t\t\t", frontendContextRepo)}}}; + ContextRepository.EventBinders = new object[] {{ + {string.Join(",\r\n\t\t\t", eventBinders)}}}; }} }} }} @@ -246,7 +250,7 @@ namespace mROA.Codegen } private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List invokers, - List declaredMethods, GeneratorExecutionContext context) + List declaredMethods, GeneratorExecutionContext context, List binders) { var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) .OfType().ToList(); @@ -254,8 +258,7 @@ namespace mROA.Codegen return; var additionalSignatures = new List(events.Count); - var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); - + var singleEventBinder = new List(events.Count); for (int i = 0; i < events.Count; i++) { var currentEvent = events[i]; @@ -264,6 +267,7 @@ namespace mROA.Codegen declaredMethods.Add(additionalMethod); additionalSignatures.Add(signature); GenerateEventCode(currentEvent, invokers, classSymbol); + GenerateBinderCode(currentEvent, invokers, classSymbol, singleEventBinder); } var partialInterface = $@" @@ -275,6 +279,16 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} }} }} "; + var binder = $@"new EventBinder<{classSymbol.ToDisplayString()}> + {{ + BindAction = (instance, context, representationProducer, index) => + {{ + var module = representationProducer.Produce(context.OwnerId); + +{string.Join("\r\n", singleEventBinder)} + }} +}}"; + binders.Add(binder); #if !DONT_ADD context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8)); #endif @@ -439,6 +453,41 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} invokers.Add(backend); } + private void GenerateBinderCode(IEventSymbol eventSymbol, List invokers, INamedTypeSymbol baseType, + List binders) + { + var index = invokers.Count - 1; + var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments.ToList(); + int parameterIndex = 0; + var parametersDeclaration = string.Join(", ", + JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i++))); + + var transferParameters = + JoinWithComa(parameters.Where(i => ParameterFilterForType(i)).Select(i => "p" + parameters.IndexOf(i))); + + var callFilter = ""; + + var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); + if (requestIndex != -1) + { + callFilter = $"\n\r\t\t\tif(context.OwnerId == p{requestIndex}.OwnerId) return;"; + } + + var eventBinderCode = + $@" (instance as {baseType.ToDisplayString()}).{eventSymbol.Name} += ({parametersDeclaration}) => + {{ {callFilter} + var request = new DefaultCallRequest + {{ + CommandId = {index}, ObjectId = index, Parameters = new object[] {{ {transferParameters} }} + }}; + module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); + }}; +"; + binders.Add(eventBinderCode); + } + + public static string JoinWithComa(IEnumerable parts) => string.Join(", ", parts); + private void GenerateEventCode(IEventSymbol eventSymbol, List invokers, ITypeSymbol baseInterface) { var level = "\t\t\t"; diff --git a/mROA/Abstract/IEventBinder.cs b/mROA/Abstract/IEventBinder.cs index 3527128..737bfd2 100644 --- a/mROA/Abstract/IEventBinder.cs +++ b/mROA/Abstract/IEventBinder.cs @@ -2,6 +2,7 @@ { public interface IEventBinder { - public void BindEvents(T source, IEndPointContext context); + public void BindEvents(T source, IEndPointContext context, + IRepresentationModuleProducer representationModuleProducer, int index); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 89bacf5..d97bdc2 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -10,38 +10,27 @@ namespace mROA.Implementation.Backend { public class ContextRepository : IContextRepository { - public static object[] EventBinders = new object[]{}; - private int _debugId = -1; + private const int StartupSize = 1024; + private const int GrowSize = 128; + public static object[] EventBinders = new object[] { }; private static int LastDebugId = -1; + private int _debugId = -1; + + private Task _lastIndexFinder = Task.FromResult(0); + + private IRepresentationModuleProducer? _representationModuleProducer; // [CanBeNull] private Dictionary _singletons; private object?[] _storage; - private Task _lastIndexFinder = Task.FromResult(0); - - private const int StartupSize = 1024; - private const int GrowSize = 128; - public ContextRepository() { _storage = new object[StartupSize]; } - public void FillSingletons(params Assembly[] assembly) - { - var types = assembly.SelectMany(x => x.GetTypes()).Where(type => - type is { IsClass: true, IsAbstract: false, IsGenericType: false } && - type.GetCustomAttributes(typeof(SharedObjectSingletonAttribute), true).Length > 0); - _singletons = - types.ToDictionary( - t => t.GetInterfaces().FirstOrDefault(i => - i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(), - Activator.CreateInstance); - } - public int ResisterObject(object o, IEndPointContext context) { if (!_lastIndexFinder.IsCompleted) @@ -49,10 +38,11 @@ namespace mROA.Implementation.Backend _storage[_lastIndexFinder.Result] = o; - EventBinders.OfType>().FirstOrDefault()?.BindEvents((T)o, context); var last = _lastIndexFinder.Result; _lastIndexFinder = Task.Run(FindLastIndex); + EventBinders.OfType>().FirstOrDefault() + ?.BindEvents((T)o, context, _representationModuleProducer!, last); return last; } @@ -68,12 +58,6 @@ namespace mROA.Implementation.Backend return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); } - public object GetObject(int id) - { - // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); - return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); - } - public T GetObject(int id) { return id == -1 || _storage.Length <= id @@ -93,6 +77,32 @@ namespace mROA.Implementation.Backend return index == -1 ? ResisterObject(o, context) : index; } + public void Inject(T dependency) + { + if (dependency is IRepresentationModuleProducer moduleProducer) + { + _representationModuleProducer = moduleProducer; + } + } + + public void FillSingletons(params Assembly[] assembly) + { + var types = assembly.SelectMany(x => x.GetTypes()).Where(type => + type is { IsClass: true, IsAbstract: false, IsGenericType: false } && + type.GetCustomAttributes(typeof(SharedObjectSingletonAttribute), true).Length > 0); + _singletons = + types.ToDictionary( + t => t.GetInterfaces().FirstOrDefault(i => + i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(), + Activator.CreateInstance); + } + + public object GetObject(int id) + { + // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); + return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); + } + private int FindLastIndex() { for (var i = 0; i < _storage.Length; i++) @@ -106,9 +116,5 @@ namespace mROA.Implementation.Backend _storage = nextStorage; return _storage.Length; } - - public void Inject(T dependency) - { - } } } \ No newline at end of file diff --git a/mROA/Implementation/EventBinder.cs b/mROA/Implementation/EventBinder.cs new file mode 100644 index 0000000..8354c4f --- /dev/null +++ b/mROA/Implementation/EventBinder.cs @@ -0,0 +1,15 @@ +using System; + +namespace mROA.Abstract +{ + public class EventBinder : IEventBinder + { + public Action BindAction { get; set; } + + public void BindEvents(T source, IEndPointContext context, + IRepresentationModuleProducer representationModuleProducer, int index) + { + BindAction(source, context, representationModuleProducer, index); + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index ecda96d..b13a5d1 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -75,8 +75,10 @@ namespace mROA.Implementation.Frontend var cancelRequest = _representationModule!.GetMessageAsync( messageType: MessageType.CancelRequest, token: token); - - Task.WaitAny(defaultRequest, cancelRequest); + var eventRequest = + _representationModule!.GetMessageAsync( + messageType: MessageType.EventRequest, token: token); + Task.WaitAny(defaultRequest, cancelRequest, eventRequest); #if TRACE Console.WriteLine("Request received"); #endif @@ -89,7 +91,7 @@ namespace mROA.Implementation.Frontend tokenSource.Cancel(); _executeModule.Execute(req, _contextRepository, _representationModule); } - else + else if (defaultRequest.IsCompleted) { tokenSource.Cancel(); var request = defaultRequest.Result; @@ -97,7 +99,7 @@ namespace mROA.Implementation.Frontend var result = _executeModule.Execute(request, _contextRepository, _representationModule); var resultType = MessageType.Unknown; - + switch (result) { case FinalCommandExecution: @@ -113,6 +115,12 @@ namespace mROA.Implementation.Frontend _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); } + else + { + tokenSource.Cancel(); + var request = defaultRequest.Result; + _executeModule.Execute(request, _contextRepository, _representationModule); + } } } catch