/// <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);
            }
        }
Esempio n. 2
0
        public void Execute(CallbackExecution <CefValue> execution)
        {
            CefV8Exception exception = null;

            using (new ContextHelper(context))
            {
                var cefV8Values = execution.Parameters.Select(s => (CefV8Value)v8Serializer.Deserialize(s, typeof(CefV8Value))).ToArray();
                var result      = function.ExecuteFunction(null, cefV8Values);


                var browser = context.GetBrowser();

                if (result == null && function.HasException)
                {
                    exception = function.GetException();
                    function.ClearException();
                }

                if (promiseService.IsPromise(result, context))
                {
                    promiseService.Then(result, context, a => CallbackDone(a, browser, execution.ExecutionId));
                }
                else
                {
                    CallbackDone(new PromiseResult
                    {
                        Success = result != null,
                        Result  = result,
                        Error   = exception?.Message
                    }, browser, execution.ExecutionId);
                }
            }
        }
 public static int GetBrowserId(this CefV8Context context)
 {
     if (context == null)
     {
         throw new ArgumentNullException("context");
     }
     using (var browser = context.GetBrowser())
     {
         return(browser.Identifier);
     }
 }
        /// <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);
            }
        }
Esempio n. 5
0
            protected override void DoAsyncWork(CefV8Context ctx, PromiseTask promiseTask)
            {
                int promiseId = pendingPromises.AddPromise(promiseTask);

                var browser = ctx.GetBrowser();
                var frame   = browser.GetMainFrame();
                var msg     = CefProcessMessage.Create("openFileRequest");

                msg.Arguments.SetInt(0, (int)promiseId);

                // This kicks off the RFC chain.
                frame.SendProcessMessage(CefProcessId.Browser, msg);
            }
        /// <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);
            }
        }
Esempio n. 7
0
            protected override bool Execute(string name, CefV8Value obj, CefV8Value[] arguments, out CefV8Value returnValue, out string exception)
            {
                if (name == _config.JSQueryFunction)
                {
                    if (arguments.Length != 1 || !arguments[0].IsObject)
                    {
                        returnValue = null;
                        exception   = "Invalid arguments; expecting a single object";
                        return(true);
                    }

                    var arg = arguments[0];

                    var requestVal = arg.GetValue(CefMessageRouter.MemberRequest);
                    if (requestVal == null || !requestVal.IsString)
                    {
                        returnValue = null;
                        exception   = "Invalid arguments; object member '" +
                                      CefMessageRouter.MemberRequest + "' is required and must " +
                                      "have type string";
                        return(true);
                    }

                    CefV8Value successVal = null;
                    if (arg.HasValue(CefMessageRouter.MemberOnSuccess))
                    {
                        successVal = arg.GetValue(CefMessageRouter.MemberOnSuccess);
                        if (!successVal.IsFunction)
                        {
                            returnValue = null;
                            exception   = "Invalid arguments; object member '" +
                                          CefMessageRouter.MemberOnSuccess + "' must have type " +
                                          "function";
                            return(true);
                        }
                    }

                    CefV8Value failureVal = null;
                    if (arg.HasValue(CefMessageRouter.MemberOnFailure))
                    {
                        failureVal = arg.GetValue(CefMessageRouter.MemberOnFailure);
                        if (!failureVal.IsFunction)
                        {
                            returnValue = null;
                            exception   = "Invalid arguments; object member '" +
                                          CefMessageRouter.MemberOnFailure + "' must have type " +
                                          "function";
                            return(true);
                        }
                    }

                    CefV8Value persistentVal = null;
                    if (arg.HasValue(CefMessageRouter.MemberPersistent))
                    {
                        persistentVal = arg.GetValue(CefMessageRouter.MemberPersistent);
                        if (!persistentVal.IsBool)
                        {
                            returnValue = null;
                            exception   = "Invalid arguments; object member '" +
                                          CefMessageRouter.MemberPersistent + "' must have type " +
                                          "boolean";
                            return(true);
                        }
                    }

                    var context    = CefV8Context.GetCurrentContext();
                    var contextId  = GetIDForContext(context);
                    var frameId    = context.GetFrame().Identifier;
                    var persistent = (persistentVal != null && persistentVal.GetBoolValue());

                    var requestId = _router.SendQuery(context.GetBrowser(), frameId, contextId,
                                                      requestVal.GetStringValue(), persistent, successVal, failureVal);
                    returnValue = CefV8Value.CreateInt(requestId);
                    exception   = null;
                    return(true);
                }
                else if (name == _config.JSCancelFunction)
                {
                    if (arguments.Length != 1 || !arguments[0].IsInt)
                    {
                        returnValue = null;
                        exception   = "Invalid arguments; expecting a single integer";
                        return(true);
                    }

                    var result    = false;
                    var requestId = arguments[0].GetIntValue();
                    if (requestId != CefMessageRouter.ReservedId)
                    {
                        CefV8Context context   = CefV8Context.GetCurrentContext();
                        var          contextId = GetIDForContext(context);
                        var          frameId   = context.GetFrame().Identifier;

                        result = _router.SendCancel(context.GetBrowser(), frameId, contextId, requestId);
                    }
                    returnValue = CefV8Value.CreateBool(result);
                    exception   = null;
                    return(true);
                }

                returnValue = null;
                exception   = null;
                return(false);
            }
        protected override bool Execute(string name, CefV8Value obj, CefV8Value[] arguments, out CefV8Value returnValue, out string exception)
        {
            if (name == _name)
            {
                var bid = _context.GetBrowser()?.Identifier ?? 0;
                var fid = _context.GetFrame()?.Identifier ?? 0;

                var request = MessageBridgeRequest.Create(JavaScriptCommunicationBridge.EXECUTE_JAVASCRIPT_FUNCTION, bid, fid, _context.GetHashCode());

                request.Arguments.Add(MessageValue.CreateString(_parentKey));
                request.Arguments.Add(MessageValue.CreateString(_name));

                var args = JavaScriptValue.CreateArray();

                var index = 0;

                foreach (var arg in arguments)
                {
                    var value = arg.ToJSValue();

                    if (value != null)
                    {
                        args.SetValue(index++, value);
                    }
                }

                request.Arguments.Add(MessageValue.CreateString(args.ToDefinition()));

                var guid = Guid.NewGuid();

                request.Arguments.Add(MessageValue.CreateString($"{guid}"));

                var response = _bridge.SendExecutionRequest(request);

                if (response.IsSuccess)
                {
                    if (_functionInfo.IsAsync)
                    {
                        var callback = CefV8Value.CreateObject();

                        var successFunc = CefV8Value.CreateFunction("success", new JavaScriptBridgeFunctionCallbackHandler(/*_parentKey, _name,*/ guid, _context));

                        var errorFunc = CefV8Value.CreateFunction("error", new JavaScriptBridgeFunctionCallbackHandler(/*_parentKey, _name,*/ guid, _context));

                        callback.SetValue("success", successFunc);
                        callback.SetValue("error", errorFunc);

                        returnValue = callback;
                        exception   = null;
                    }
                    else
                    {
                        var retval = JavaScriptValue.FromJson(response.Arguments[0].GetString())?.ToCefV8Value();

                        exception = null;

                        if (retval != null)
                        {
                            returnValue = retval;
                        }
                        else
                        {
                            returnValue = CefV8Value.CreateUndefined();
                        }
                    }
                }
                else
                {
                    exception   = response.ExceptionMessage;
                    returnValue = null;
                }

                return(true);
            }

            returnValue = null;
            exception   = $"{name} is not defined.";

            return(true);
        }