Sign in to follow this  
Arkante

[Suggestion] CEF improvment

Recommended Posts

Hello,

I develop some apps for fun and i was developping something on your framework and i suffer from a lack of functionnalities. Not a big deal but, something can be improve here.
I explain myself. I develop something simple with Node.js + Angular 6, i try rage-angular module but not fine for me. The problem is when you open a CEF (browser) and this browser check for data.

Currently it's like this :

/************************/
/* Component on Angular */
/************************/

declare var mp: any;

.
.
.

export class CharacterSelectionComponent implements OnInit {

  charachers: Character[] = [];

  constructor(
    private formBuilder: FormBuilder
  ) {}

  ngOnInit() {
	this.buildForm();
	mp.trigger('getCharacters');
	/* No data initialize : charachers == [] :'( */
  }

}

/************************/
/* Client-Side Js       */
/************************/

var characterSelectionCEF; // This is the CEF loaded before i don't put all the code like in the component


mp.events.add('getCharacters', function() {
    let characters = JSON.stringify([{"firstname":"SomeOne","lastname":"Cool","birthdate":new Date("1992-02-12"),"birthcity":"Los Angeles","gender":"Man","origin":"American","familystatus":"Single"},{"firstname":"AnotherOne","lastname":"Bad","birthdate":new Date("1983-09-10"),"birthcity":"New-York","gender":"Man","origin":"American","familystatus":"Maried"}]);
  characterSelectionCEF.execute("window.CharacterService.sendCharacters("+characters+");");
});

// The data come after the ngOnInit sadly because one thing.
// mp.trigger don't return data
// If events can return data it will be awesome !

The idea is to implement for the ragemp events (so for mp.trigger) a return value.
What kind of value ? Well an Observable will be a great idea but, sadly we don't have this kind of object in standard Javascript, it's something coming from Angular. But we have Promise.

And now ladies and gentlemen :

/************************/
/* Component on Angular */
/************************/

declare var mp: any;

.
.
.

export class CharacterSelectionComponent implements OnInit {

  charachers: Character[] = [];

  constructor(
    private formBuilder: FormBuilder
  ) {}

  ngOnInit() {
	this.buildForm();
	mp.trigger('getCharacters').then((characters)=>{
      this.characters = characters;
    }), (reason) => {
		switch(reason.code){
			case 0:
				mp.trigger('closeCharacterSelection',reason);
					break;
			default:
				mp.trigger('closeCharacterSelection');
		}
    });
  }

}

/************************/
/* Client-Side Js       */
/************************/

var characterSelectionCEF; // This is the CEF loaded before i don't put all the code like in the component


mp.events.add('getCharacters', function() {
	return new Promise((resolve, reject) => {
		let characters = JSON.stringify([{"firstname":"SomeOne","lastname":"Cool","birthdate":new Date("1992-02-12"),"birthcity":"Los Angeles","gender":"Man","origin":"American","familystatus":"Single"},{"firstname":"AnotherOne","lastname":"Bad","birthdate":new Date("1983-09-10"),"birthcity":"New-York","gender":"Man","origin":"American","familystatus":"Maried"}]);
		if(characters != null){
			resolve(characters);
		}else{
			reject({error:true,code:0,error_message:"[ERROR]: Can't access to the data. Sorry."});
		}
    });
});

Maybe it's not possible in your code architecture. The problem i see it's the events handler. We need to kind of handler so to kind of function (mp.trigger + mp.triggerPromise) because sometime we don't need to have something in return.

For me, you will never do something about it because... slackness ahah. And i understand that. But, if you do something, that will be f*cking great.

Kiss.

PS: Maybe it's a little bit confusing, i write this really quickly. So if you have questions, ask ;)

 

Share this post


Link to post
Share on other sites

It's not us who decided it to make us but CEF which is completely asynchronous therefore mp.trigger return values is something impossible in CEF generally.

  • Like 1

Share this post


Link to post
Share on other sites

Hello,

So if i understand, so can't get the result of CEF because it's asynchronous right ? Well... i done it. Really quickly.
So maybe your architecture can't handle it but..yeah check this code we don't know maybe that can help you :
 

INSTALL :

 - Visual Studio 2017 :  Create a new project Window Forms Application in .NET Framework 4.5.2

- Right-click on your project and click on NuGet

- Search and install : CefSharp.WinForms

- Create a folder "resources" :  It's where you will have your index.html

- Create CefCustomAsyncObject.cs

[EDIT] - For the Serialization of JSON you need to do a little trick : Right click on project Add a References -> Assembly -> And check the System.Web.Extensions
 

index.html - RESOURCE

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>CharacterSelection</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
    </head>
    <body>
        <main>
            <h1>HELLO WORLD</h1>
            <section id="listCharacters">
          
            </section>
        </main>
        <script>
            (async function()
            {
                await CefSharp.BindObjectAsync("mpAsync");
        
                mpAsync.trigger('getCharacters').then(function (charactersData)
                {
                    let characters = JSON.parse(charactersData);
                    if (characters.length > 0) {
                        characters.forEach((character) => {
                            let chart = "<div><h2>" + character.Firstname + " " + character.Lastname +"</h2></div>";
                            $("section").append(chart); 
                        })
                    } else {
                        let modelNoCharacter = "<div><h2>Aucun</h2></div>";
                        $("section").append(modelNoCharacter); 
                    }
                });
            })();
        </script>
   </body>
</html>

 

 

C# Side for client CEF handler :

I use Application Windows Forms for this project.

Form1.cs - It's a default file created when you create the project. Modify it like below.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;

namespace CefTest
{
    public partial class Form1 : Form
    {
        public ChromiumWebBrowser chromeBrowser;

        public Form1()
        {
            InitializeComponent();
            InitializeChromium();

            CefSharpSettings.LegacyJavascriptBindingEnabled = true;

            chromeBrowser.RegisterJsObject("mp", new CefCustomObject(chromeBrowser,this));
            chromeBrowser.RegisterAsyncJsObject("mpAsync", new CefCustomAsyncObject(chromeBrowser, this));
        }

        private void InitializeChromium()
        {
            CefSettings settings = new CefSettings();
            

            String page = string.Format(@"{0}\resources\test\index.html",Application.StartupPath);

            if (!File.Exists(page))
            {
                MessageBox.Show("Error, the HTML file doesn't exist : "+ page);
            }
            Cef.Initialize(settings);
            chromeBrowser = new ChromiumWebBrowser(page);

            this.Controls.Add(chromeBrowser);

            chromeBrowser.Dock = DockStyle.Fill;

            BrowserSettings browserSettings = new BrowserSettings();
            browserSettings.FileAccessFromFileUrls = CefState.Enabled;
            browserSettings.UniversalAccessFromFileUrls = CefState.Enabled;
            
            chromeBrowser.BrowserSettings = browserSettings;

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Cef.Shutdown();
        }
    }
}

Asynchrone "mp" so become "mpAsync" 😛 .

CefCustomAsyncObject.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Windows.Forms;

using CefSharp;
using CefSharp.WinForms;

using System.Web.Script.Serialization;

namespace CefTest
{

    class Character
    {
        private string _firstname, _lastname, _birthcity, _gender, _origin, _familystatus;
        private DateTime _birthdate;

        public string Firstname { get => _firstname; set => _firstname = value; }
        public string Lastname { get => _lastname; set => _lastname = value; }
        public string Birthcity { get => _birthcity; set => _birthcity = value; }
        public string Gender { get => _gender; set => _gender = value; }
        public string Origin { get => _origin; set => _origin = value; }
        public string Familystatus { get => _familystatus; set => _familystatus = value; }
        public DateTime Birthdate { get => _birthdate; set => _birthdate = value; }

        public Character(string firstname, string lastname, DateTime birthdate, string birthcity, string gender, string origin, string familystatus)
        {
            _firstname = firstname;
            _lastname = lastname;
            _birthcity = birthcity;
            _gender = gender;
            _origin = origin;
            _familystatus = familystatus;
            _birthdate = birthdate;
        }

        public override string ToString()
        {
            return "Character : " + _firstname + " " + _lastname + " birth the " + _birthdate.ToString() + " in " + _birthcity + " is a " + _gender + " and is " + _origin + ", is family status is " + _familystatus + ".";
        }

    }

    class CefCustomAsyncObject
    {
        private static ChromiumWebBrowser _instanceBrowser = null;

        private static Form1 _instanceMainForm = null;

        private static JavaScriptSerializer _serializer = new JavaScriptSerializer();

        public CefCustomAsyncObject(ChromiumWebBrowser originalBrowser, Form1 mainForm)
        {
            _instanceBrowser = originalBrowser;
            _instanceMainForm = mainForm;
        }

        public void showDevTools()
        {
            _instanceBrowser.ShowDevTools();
        }

        public void opencmd()
        {
            ProcessStartInfo start = new ProcessStartInfo("cmd.exe", "/c pause");
            Process.Start(start);
        }

        public string trigger(string funcName, params object[] args)
        {
            List<Character> characters = new List<Character>
            {
                new Character("Paul", "Brondo", new DateTime(1998,6,2), "London", "Man", "British", "Single"),
                new Character("Jordan", "Cooper", new DateTime(1983, 4, 5), "New-York", "Man", "American", "Divorced")
            };

            string data = _serializer.Serialize(characters);

            return data;
        }
    }
}

So yeah it's pretty simple and it's not represent your work but i think we got something interresting here. The trigger function need to be modify and we can pass into it a callback parameter.

If you need more details look the doc :
https://github.com/cefsharp/CefSharp/wiki/General-Usage#3-how-do-you-expose-a-net-class-to-javascript

or

https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md

 

Maybe that don't help, but i do what i can to help you.

Edited by Arkante

Share this post


Link to post
Share on other sites
On 11/15/2018 at 8:17 PM, Arkante said:

 

So if i understand, so can't get the result of CEF because it's asynchronous right ? Well... i done it. Really quickly.
So maybe your architecture can't handle it but..yeah check this code we don't know maybe that can help you :
 

Why didn't you make it *really quickly* before posting the thread then? Though you gotta read more about "Promises" in JavaScript before posting anything like that. Your code doesn't make it synchronous but only wraps asynchronous stuff. What you did could be easily and *really quickly* made by scripters like you as we provide all the required API so it's not related to RAGE MP. Here's an example btw:

 

As for the real synchronous calls, I'd suggest you read more about CEF's multi-process architecture which makes it just impossible.

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.