public async Task <T> GenerateProxy <T>( IHardwareRepresentation hardwareRepresentation, T hardwareObject, IProxyGenerationConfiguration configuration) where T : class { if (!hardwareRepresentation.SoftAssemblyPaths.Contains(hardwareObject.GetType().Assembly.Location)) { throw new InvalidOperationException( "The supplied type is not part of any assembly that this hardware representation was generated from."); } try { return(await _host .RunGet(scope => Task.Run(() => scope.Resolve <IProxyGenerator>().CreateCommunicationProxy(hardwareRepresentation, hardwareObject, configuration)))); } catch (Exception ex) when(!ex.IsFatal()) { var message = "An error happened during generating the Hastlayer proxy for an object of the following type: " + hardwareObject.GetType().FullName; await _host.Run <ILoggerService>(logger => Task.Run(() => logger.Error(ex, message))); throw new HastlayerException(message, ex); } }
public T CreateCommunicationProxy <T>(IHardwareRepresentation hardwareRepresentation, T target, IProxyGenerationConfiguration configuration) where T : class { var memberInvocationHandler = _memberInvocationHandlerFactory.CreateMemberInvocationHandler(hardwareRepresentation, target, configuration); if (typeof(T).IsInterface) { return(_proxyGenerator.CreateInterfaceProxyWithTarget(target, new MemberInvocationInterceptor(memberInvocationHandler))); } return(_proxyGenerator.CreateClassProxyWithTarget(target, new MemberInvocationInterceptor(memberInvocationHandler))); }
/// <summary> /// Gets the custom configuration if it exists or creates and adds it if it doesn't. /// </summary> /// <typeparam name="T">Type of the configuration object.</typeparam> /// <param name="key">Key where the custom configuration object is stored in the /// <see cref="IProxyGenerationConfiguration"/> instance.</param> /// <returns>The existing or newly created configuration object.</returns> public static T GetOrAddCustomConfiguration <T>(this IProxyGenerationConfiguration proxyGenerationConfiguration, string key) where T : new() => proxyGenerationConfiguration.CustomConfiguration.GetOrAddCustomConfiguration <T>(key);
public MemberInvocationHandler CreateMemberInvocationHandler( IHardwareRepresentation hardwareRepresentation, object target, IProxyGenerationConfiguration configuration) { return(invocation => { var methodAsynchronicity = GetMethodAsynchronicity(invocation); if (methodAsynchronicity == MethodAsynchronicity.AsyncFunction) { throw new NotSupportedException("Only async methods that return a Task, not Task<T>, are supported."); } async Task invocationHandler() { using (var workContext = _wca.CreateWorkContextScope()) { // Although it says Method it can also be a property. var memberFullName = invocation.Method.GetFullName(); var invocationContext = new MemberInvocationContext { Invocation = invocation, MemberFullName = memberFullName, HardwareRepresentation = hardwareRepresentation }; var eventHandler = workContext.Resolve <IMemberInvocationEventHandler>(); eventHandler.MemberInvoking(invocationContext); workContext.Resolve <IEnumerable <IMemberInvocationPipelineStep> >().InvokePipelineSteps(step => { invocationContext.HardwareExecutionIsCancelled = step.CanContinueHardwareExecution(invocationContext); }); if (!invocationContext.HardwareExecutionIsCancelled) { var hardwareMembers = hardwareRepresentation.HardwareDescription.HardwareEntryPointNamesToMemberIdMappings; var memberNameAlternates = new HashSet <string>(hardwareMembers.Keys.SelectMany(member => member.GetMemberNameAlternates())); if (!hardwareMembers.ContainsKey(memberFullName) && !memberNameAlternates.Contains(memberFullName)) { invocationContext.HardwareExecutionIsCancelled = true; } } if (invocationContext.HardwareExecutionIsCancelled) { invocation.Proceed(); if (methodAsynchronicity == MethodAsynchronicity.AsyncAction) { await(Task) invocation.ReturnValue; } return; } var communicationChannelName = configuration.CommunicationChannelName; var deviceManifest = hardwareRepresentation.DeviceManifest; if (string.IsNullOrEmpty(communicationChannelName)) { communicationChannelName = deviceManifest.DefaultCommunicationChannelName; } if (!deviceManifest.SupportedCommunicationChannelNames.Contains(communicationChannelName)) { throw new NotSupportedException( "The configured communication channel \"" + communicationChannelName + "\" is not supported by the current device."); } var memory = (SimpleMemory)invocation.Arguments.SingleOrDefault(argument => argument is SimpleMemory); if (memory != null) { var memoryByteCount = (ulong)memory.CellCount * SimpleMemory.MemoryCellSizeBytes; if (memoryByteCount > deviceManifest.AvailableMemoryBytes) { throw new InvalidOperationException( "The input is too large to fit into the device's memory: the input is " + memoryByteCount + " bytes, the available memory is " + deviceManifest.AvailableMemoryBytes + " bytes."); } SimpleMemory softMemory = null; if (configuration.VerifyHardwareResults) { softMemory = new SimpleMemory(memory.CellCount); var memoryBytes = new SimpleMemoryAccessor(memory).Get(); memoryBytes.CopyTo(new SimpleMemoryAccessor(softMemory).Get()); var memoryArgumentIndex = invocation.Arguments .Select((argument, index) => new { Argument = argument, Index = index }) .Single(argument => argument.Argument is SimpleMemory) .Index; invocation.SetArgumentValue(memoryArgumentIndex, softMemory); // This needs to happen before the awaited Execute() call below, otherwise the Task // in ReturnValue wouldn't be the original one any more. invocation.Proceed(); if (methodAsynchronicity == MethodAsynchronicity.AsyncAction) { await(Task) invocation.ReturnValue; } } // At this point we checked that the hardware entry point does have a mapping. var memberId = hardwareRepresentation .HardwareDescription .HardwareEntryPointNamesToMemberIdMappings[memberFullName]; invocationContext.ExecutionInformation = await workContext .Resolve <ICommunicationServiceSelector>() .GetCommunicationService(communicationChannelName) .Execute( memory, memberId, new HardwareExecutionContext { ProxyGenerationConfiguration = configuration, HardwareRepresentation = hardwareRepresentation }); if (configuration.VerifyHardwareResults) { var mismatches = new List <HardwareExecutionResultMismatchException.Mismatch>(); if (memory.CellCount != softMemory.CellCount) { int overflowIndex = Math.Min(memory.CellCount, softMemory.CellCount); mismatches.Add(new HardwareExecutionResultMismatchException.LengthMismatch( memory.CellCount, softMemory.CellCount, overflowIndex, memory.CellCount > softMemory.CellCount ? memory.Read4Bytes(overflowIndex) : new byte[0], softMemory.CellCount > memory.CellCount ? softMemory.Read4Bytes(overflowIndex) : new byte[0])); } else { for (int i = 0; i < memory.CellCount; i++) { if (!memory.Read4Bytes(i).SequenceEqual(softMemory.Read4Bytes(i))) { mismatches.Add(new HardwareExecutionResultMismatchException.Mismatch( i, memory.Read4Bytes(i), softMemory.Read4Bytes(i))); } } } if (mismatches.Any()) { throw new HardwareExecutionResultMismatchException(mismatches); } } } else { throw new NotSupportedException( "Only SimpleMemory-using implementations are supported for hardware execution. The invocation didn't include a SimpleMemory argument."); } eventHandler.MemberExecutedOnHardware(invocationContext); } } if (methodAsynchronicity == MethodAsynchronicity.AsyncAction) { invocation.ReturnValue = invocationHandler(); } else { invocationHandler().Wait(); } }); }