private LocalRenderCallInfo AddLocalCallback(PluginMessage pluginMessage, IV8Callback callback, IJavaScriptParameterCallback parameterCallback)
        {
            var info = new LocalRenderCallInfo(this, pluginMessage, callback, parameterCallback);

            _pendingCallbacks.Add(info);
            return(info);
        }
        public void RemoveEventListener(JavaScriptPlugin targetPlugin, string eventName,
                                        IV8Callback callback)
        {
            Logger.Info("RemoveEventListener Local Plugin {0} Event {1}", targetPlugin.Descriptor.PluginId, eventName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            try
            {
                var info = (LocalRenderCallInfo)_pendingCallbacks.Remove(callback.Identifier);
                info.Dispose();

                targetPlugin.RemoveEventListener(eventName, info);
            }
            catch (Exception exception)
            {
                Logger.Error("RemoveEventListener Failed Local Plugin {0} Event {1}: {2}",
                             targetPlugin.Descriptor.PluginId,
                             eventName,
                             exception);
            }
        }
        private RenderCallInfo AddRemoteCallback(PluginMessage pluginMessage, IV8Callback callback)
        {
            var info = new RenderCallInfo(pluginMessage, callback);

            _pendingCallbacks.Add(info);
            return(info);
        }
        /// <summary>
        /// Invoke a local function.
        /// </summary>
        /// <param name="context">
        /// The current V8 context that is making the function call.
        /// </param>
        /// <param name="targetPlugin">
        /// The local plugin that owns the target method.
        /// </param>
        /// <param name="methodDescriptor">
        /// The method to invoke.
        /// </param>
        /// <param name="parameters">
        /// An interface for the local plugin to obtain the parameters from before invoking the function.
        /// </param>
        /// <param name="callback">
        /// Optional callback into V8.
        /// </param>
        public void InvokeFunction(
            CefV8Context context,
            JavaScriptPlugin targetPlugin,
            MethodDescriptor methodDescriptor,
            IJavaScriptParameters parameters,
            IV8Callback callback)
        {
            Logger.Info("InvokeFunction Local Plugin {0} Method {1}", targetPlugin.Descriptor.PluginId, methodDescriptor.MethodName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            if (!targetPlugin.IsValid)
            {
                Logger.Warn("InvokeFunction Local Plugin {0} is invalid", targetPlugin.Descriptor.PluginId);
                if (callback != null)
                {
                    callback.Invoke(this, context, null, CallInfo.ErrorCodeCallCanceled, CallInfo.ErrorCallCanceled);
                }
                return;
            }

            var parameterCallbackInfo = GetOrCreateParameterCallback(context, methodDescriptor, callback);

            var functionInvokeMessage = CreateMessage(context, targetPlugin.Descriptor, methodDescriptor.MethodName, callback);

            functionInvokeMessage.MessageId   = Guid.NewGuid();
            functionInvokeMessage.MessageType = PluginMessageType.FunctionInvoke;

            // Add the call info into the pending calls for the browser
            var info = methodDescriptor.HasCallbackParameter
                ? AddLocalCallback(functionInvokeMessage, null, parameterCallbackInfo)
                : AddLocalCallback(functionInvokeMessage, callback, null);

            try
            {
                targetPlugin.InvokeFunctionDirect(
                    null,
                    functionInvokeMessage.BrowserId,
                    functionInvokeMessage.FrameId,
                    functionInvokeMessage.ContextId,
                    methodDescriptor.MethodName,
                    parameters,
                    info);
            }
            catch (Exception ex)
            {
                LocalCallbackInvoked(info, null, -1, ex.Message);
                Logger.Error("InvokeFunction Failed Local Plugin {0} Method {1}: {2}",
                             targetPlugin.Descriptor.PluginId,
                             methodDescriptor.MethodName,
                             ex);
            }
        }
        /// <summary>
        /// Invoke a remote function.
        /// </summary>
        /// <param name="context">
        /// The current V8 context that is making the function call.
        /// </param>
        /// <param name="targetPlugin">
        /// The remote plugin that owns the target method.
        /// </param>
        /// <param name="methodDescriptor">
        /// The method to invoke.
        /// </param>
        /// <param name="parameters">
        /// The parameters to pass to the remote function.
        /// </param>
        /// <param name="callback">
        /// Optional callback into V8.
        /// </param>
        public void InvokeFunction(
            CefV8Context context,
            PluginDescriptor targetPlugin,
            MethodDescriptor methodDescriptor,
            JArray parameters,
            IV8Callback callback)
        {
            Logger.Debug("InvokeFunction Remote Plugin {0} Method {1}", targetPlugin.PluginId, methodDescriptor.MethodName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            GetOrCreateParameterCallback(context, methodDescriptor, callback);

            var functionInvokeMessage = CreateMessage(context, targetPlugin, methodDescriptor.MethodName, callback);

            functionInvokeMessage.MessageId   = Guid.NewGuid();
            functionInvokeMessage.MessageType = PluginMessageType.FunctionInvoke;
            functionInvokeMessage.Data        = parameters != null?parameters.ToString() : string.Empty;

            // Add the call info into the pending calls for the browser if the return type
            // is not void or the method has a callback arg.
            // TODO: We should verify that the signature of the JavaScript call matches the plugin method and throw an exception for invalid invocations.
            if (!methodDescriptor.IsVoid ||
                methodDescriptor.HasCallbackParameter ||
                callback != null)
            {
                AddRemoteCallback(functionInvokeMessage, methodDescriptor.HasCallbackParameter ? null : callback);
            }

            try
            {
                using (var browser = context.GetBrowser())
                {
                    // Send the request message to the browser
                    SendMessage(browser, functionInvokeMessage);
                }
            }
            catch (Exception ex)
            {
                // If the request could not be sent, remove the call from the list
                var error = new ResultData {
                    ErrorCode = -1, Error = ex.Message
                };
                OnBrowserCallbackInvokeReceived(functionInvokeMessage, error);
                Logger.Error("InvokeFunction Failed Remote Plugin {0} Method {1}: {2}",
                             targetPlugin.PluginId,
                             methodDescriptor.MethodName,
                             ex);
            }
        }
        private PluginMessage CreateMessage(
            CefV8Context context,
            PluginDescriptor targetPlugin,
            string memberName,
            IV8Callback callback)
        {
            var message = new PluginMessage
            {
                PluginId     = targetPlugin.PluginId,
                MemberName   = memberName,
                BrowserId    = context.GetBrowserId(),
                ContextId    = GetIdForContext(context, false),
                FrameId      = context.GetFrame().Identifier,
                V8CallbackId = callback != null ? callback.Identifier : Guid.Empty
            };

            return(message);
        }
        private LocalRenderCallInfo GetOrCreateParameterCallback(CefV8Context context, MethodDescriptor methodDescriptor, IV8Callback callback)
        {
            LocalRenderCallInfo parameterCallbackInfo = null;

            if (methodDescriptor.HasCallbackParameter && callback != null)
            {
                // Create a second stored callback info which represents the V8 callback function itself
                // rather than the method that is being invoked now. This allows the callback function
                // to be passed to and invoked by multiple native methods that accept a callback parameter.
                parameterCallbackInfo = (LocalRenderCallInfo)_pendingCallbacks.Get(callback.Identifier);
                if (parameterCallbackInfo == null)
                {
                    var parameterCallbackMessage = new PluginMessage
                    {
                        MessageId    = callback.Identifier,
                        MessageType  = PluginMessageType.ParameterCallback,
                        PluginId     = string.Empty,
                        MemberName   = string.Empty,
                        BrowserId    = context.GetBrowserId(),
                        ContextId    = GetIdForContext(context, false),
                        FrameId      = context.GetFrame().Identifier,
                        V8CallbackId = Guid.Empty
                    };

                    parameterCallbackInfo = AddLocalCallback(parameterCallbackMessage, callback, null);
                }
            }
            return(parameterCallbackInfo);
        }
        /// <summary>
        /// Add a local V8 callback to a local event as a listener.
        /// </summary>
        /// <param name="context">
        /// The current V8 context that is adding the listener.
        /// </param>
        /// <param name="targetPlugin">
        /// The local plugin that owns the event.
        /// </param>
        /// <param name="eventName">
        /// The name of the event to attach to.
        /// </param>
        /// <param name="callback">
        /// The callback to V8 to invoke when the event is raised.
        /// </param>
        public void AddEventListener(CefV8Context context, JavaScriptPlugin targetPlugin, string eventName, IV8Callback callback)
        {
            Logger.Info("AddEventListener Local Plugin {0} Event {1}", targetPlugin.Descriptor.PluginId, eventName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            if (!targetPlugin.IsValid)
            {
                Logger.Warn("AddEventListener Local Plugin {0} is invalid", targetPlugin.Descriptor.PluginId);
                if (callback != null)
                {
                    callback.Invoke(this, context, null, CallInfo.ErrorCodeCallCanceled, CallInfo.ErrorCallCanceled);
                }
                return;
            }

            var addListenerMessage = CreateMessage(context, targetPlugin.Descriptor, eventName, callback);

            addListenerMessage.MessageId   = callback.Identifier;
            addListenerMessage.MessageType = PluginMessageType.AddListener;

            // Add the call info into the pending calls for the browser
            var info = AddLocalCallback(addListenerMessage, callback, null);

            try
            {
                targetPlugin.AddEventListener(eventName, info);
            }
            catch (Exception ex)
            {
                // Remove listener from calls cache
                _pendingCallbacks.Remove(info);
                info.Dispose();
                Logger.Error("AddEventListener Failed Local Plugin {0} Event {1}: {2}", targetPlugin.Descriptor.PluginId, eventName, ex);
            }
        }
        /// <summary>
        /// Remove a local V8 callback from a remote event.
        /// </summary>
        /// <param name="context">
        /// The current V8 context that is removing the listener.
        /// </param>
        /// <param name="targetPlugin">
        /// The remote plugin that owns the event.
        /// </param>
        /// <param name="eventName">
        /// The name of the event to detach from.
        /// </param>
        /// <param name="callback">
        /// The callback to remove.</param>
        public void RemoveEventListener(CefV8Context context, PluginDescriptor targetPlugin, string eventName, IV8Callback callback)
        {
            Logger.Info("RemoveEventListener Remote Plugin {0} Event {1}", targetPlugin.PluginId, eventName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            var callId = callback.Identifier;
            var info   = _pendingCallbacks.Remove(callId);

            info.Dispose();

            var removeListenerMessage = CreateMessage(context, targetPlugin, eventName, callback);

            // Use identifier from callback as ID for listener message.
            // Remote process will find and remove listener based on the MessageId.
            removeListenerMessage.MessageId   = callId;
            removeListenerMessage.MessageType = PluginMessageType.RemoveRetained;
            removeListenerMessage.Data        = string.Empty;

            // Send the request message to the browser
            try
            {
                using (var browser = context.GetBrowser())
                {
                    SendMessage(browser, removeListenerMessage);
                }
            }
            catch (Exception ex)
            {
                Logger.Error("RemoveEventListener Failed Remote Plugin {0} Event {1}: {2}", targetPlugin.PluginId, eventName, ex);
            }
        }
        /// <summary>
        /// Add a local V8 callback to a remote event as a listener.
        /// </summary>
        /// <param name="context">
        /// The current V8 context that is adding the listener.
        /// </param>
        /// <param name="targetPlugin">
        /// The remote plugin that owns the event.
        /// </param>
        /// <param name="eventName">
        /// The name of the event to attach to.
        /// </param>
        /// <param name="callback">
        /// The callback to V8 to invoke when the remote event is raised.
        /// </param>
        public void AddEventListener(CefV8Context context, PluginDescriptor targetPlugin, string eventName, IV8Callback callback)
        {
            Logger.Info("AddEventListener Remote Plugin {0} Event {1}", targetPlugin.PluginId, eventName);

            if (!EnsureOnRendererThread())
            {
                return;
            }

            var addListenerMessage = CreateMessage(context, targetPlugin, eventName, callback);

            // Use identifier from callback as ID for listener message.
            // When remote event fired, renderer will receive an EventFired message with this same ID as its MessageId.
            addListenerMessage.MessageId   = callback.Identifier;
            addListenerMessage.MessageType = PluginMessageType.AddListener;
            addListenerMessage.Data        = string.Empty;

            // Add the call info into the pending calls for the browser
            var info = AddRemoteCallback(addListenerMessage, callback);

            // Send the request message to the browser
            try
            {
                using (var browser = context.GetBrowser())
                {
                    SendMessage(browser, addListenerMessage);
                }
            }
            catch (Exception ex)
            {
                // If the request could not be sent, remove the call from the list
                _pendingCallbacks.Remove(info);
                info.Dispose();
                Logger.Error("AddEventListener Failed Remote Plugin {0} Event {1}: {2}", targetPlugin.PluginId, eventName, ex);
            }
        }
 public LocalRenderCallInfo(IRenderSideMessageRouter router, PluginMessage requestMesage, IV8Callback callback, IJavaScriptParameterCallback parameterCallback)
     : base(requestMesage, callback)
 {
     _router            = router;
     _parameterCallback = parameterCallback;
 }
Пример #12
0
 public RenderCallInfo(PluginMessage requestMessage, IV8Callback callback)
     : base(requestMessage)
 {
     Callback = callback;
 }