/// <summary> /// Registers the given bound service into this service manager /// </summary> /// <param name="service">The bound service to register</param> /// <returns>The boundID of this service</returns> public int BoundService(BoundService service) { lock (this.mBoundServices) { int boundID = this.mNextBoundID++; // add the service to the bound services map this.mBoundServices[boundID] = service; return boundID; } }
/// <summary> /// Binds a new object of this type with the given objectData to provide a stateful /// interface to itself /// /// WARNING: Some MachoBindObject calls also include a call to a method inside the new stateful /// service, this also handles that behaviour /// </summary> /// <param name="objectData">The information of the object to be stateful about</param> /// <param name="callInfo">The information on the call</param> /// <param name="call">The call object with extra information</param> /// <returns></returns> protected PyDataType MachoBindObject(PyDataType objectData, PyDataType callInfo, CallInformation call) { // create the bound instance and register it in the bound services BoundService instance = this.CreateBoundInstance(objectData, call); // bind the service int boundID = this.BoundServiceManager.BoundService(instance); // build the bound service string string boundServiceStr = this.BoundServiceManager.BuildBoundServiceString(boundID); // TODO: the expiration time is 1 day, might be better to properly support this? // TODO: investigate these a bit more closely in the future // TODO: i'm not so sure about the expiration time PyTuple boundServiceInformation = new PyTuple(new PyDataType[] { boundServiceStr, DateTime.UtcNow.Add(TimeSpan.FromDays(1)).ToFileTime() }); // after the service is bound the call can be run (if required) PyTuple result = new PyTuple(2); result[0] = new PySubStruct(new PySubStream(boundServiceInformation)); if (callInfo is PyNone) { result[1] = null; } else { PyTuple data = callInfo as PyTuple; string func = data[0] as PyString; PyTuple arguments = data[1] as PyTuple; PyDictionary namedArguments = data[2] as PyDictionary; CallInformation callInformation = new CallInformation { Client = call.Client, NamedPayload = namedArguments, CallID = call.CallID, From = call.From, PacketType = call.PacketType, Service = null, To = call.To }; result[1] = this.BoundServiceManager.ServiceCall(boundID, func, arguments, callInformation); } return(result); }
/// <summary> /// Takes the given payload and searches in this service manager for the best service match to call the given method /// if possible /// </summary> /// <param name="boundID">The boundID to call at</param> /// <param name="call">The method to call</param> /// <param name="payload">Parameters for the method</param> /// <param name="callInformation">Any extra information for the method call</param> /// <returns>The result of the call</returns> /// <exception cref="ServiceDoesNotExistsException">If the boundID doesn't match any registered bound service</exception> /// <exception cref="ServiceDoesNotContainCallException">If the service was found but no matching call was found</exception> public PyDataType ServiceCall(int boundID, string call, PyTuple payload, CallInformation callInformation) { // relay the exception throw by the call try { BoundService serviceInstance = this.mBoundServices[boundID]; Log.Trace($"Calling {serviceInstance.GetType().Name}::{call} on bound service {boundID}"); if(serviceInstance is null) throw new ServiceDoesNotExistsException($"Bound Service {boundID}"); List<MethodInfo> methods = this.FindMethods(serviceInstance, $"(boundID {boundID}) {serviceInstance.GetType().Name}", call); if (FindSuitableMethod(methods, payload, callInformation, out object[] invokeParameters, out MethodInfo method) == false)