Re: GJS WebKit2 Extension



OK, I've done some test and apparently `notify::title` is queue so even if you change title twice in a row in WebKit/JS land, GJS will receive all changes.

This made me able to create a simple JSONChannel class:
https://gist.github.com/WebReflection/7ab0addec037508cc8380a9c37d285f2

I have that class and the following code in a browser.js file

```js
const PageChannel = new JSONChannel('super-secret');
PageChannel
  .on('message', (err, data) => {
    if (err) console.error(err);
    else console.log(data);
  })
  .send('ping');
```

The index page is nothing more than just this:
```html
<!doctype html>
<script src="browser.js"></script>
```

The GJS part, simplified for demo purpose, is basically just this
```js
const secret = 'super-secret';
const re = new RegExp(`^${secret}:js=`);
webView.connect('notify::title', (self, params) => {
  if (re.test(self.title)) {
    const data = JSON.parse(self.title.slice(RegExp['$&'].length));
    print(data);
    self.run_javascript(
      `document.dispatchEvent(
        new CustomEvent(
          '${secret}:gjs',
          {detail: ${JSON.stringify('pong')}}
        )
      );`,
      null,
      (self, result, error) => {
        self.run_javascript_finish(result);
      }
    );
  }
});
```


You will see ping followed by pong in the console once you load that index.html

Please note that document.title changes could be intercepted via MutationObserver or DOMSubtreeModified on a document with a title element and/or hacking the title accessor itself or the document, meaning the "secret" is not really secret but it's a way to setup a unique channel.

There could be a convention to setup a channel automatically adding some extra logic on both sides (and I'll giv it a try in few minutes) but I hope you got the proof of concept and it works for your needs.

It's simpler to implement than my hack on location and it works better/faster.

Regards






On Wed, Nov 1, 2017 at 1:17 PM, Andrea Giammarchi <andrea giammarchi gmail com> wrote:
I'd be OK if WebKitGTK could at least accept strings and pass them along ... wkjscore-result should be part of the core, IMO.



On Wed, Nov 1, 2017 at 12:28 PM, Sam Jansen <sam jansen starleaf com> wrote:


On 1 November 2017 at 15:23, Andrea Giammarchi <andrea giammarchi gmail com> wrote:
so ... it looks really like the exposed API is completely useless as it is

```js
webkit.messageHandlers.gjs.postMessage('hello');
```

Returns a

[boxed instance proxy GIName:WebKit2._javascript_Result jsobj@0x7fa08c2e4160 native@0x7fa052081d80]


and if you try to get its value it goes bananas with a message like:

Gjs-WARNING **: JS ERROR: Error: Unable to find module implementing foreign type _javascript_Core.Value


What's the purpose of register_script_message_handler at all? What am I missing?


Andrea, this is the problem Philip raised earlier and I replied to. I use this library to solve the problem: https://github.com/saifulbkhan/wkjscore-result

  7 import * as WkJsCore from '../../gjs/WkJsCore'
...
 85         let contentManager = this.webkit.get_user_content_manager();
 86         if (!contentManager.register_script_message_handler('slinternal')) {
 87             throw "register_script_message_handler() failed";
 88         }
 89         contentManager.connect("script-message-received::foobar", (obj, jsResult) => {
 90             let wkResult = WkJsCore.Result.new(jsResult);
 91             let str = wkResult.process_result_as_string();

 
Unfortunately _javascript_Core doesn't provide it's own GIR API to access the JS data :(




On Wed, Nov 1, 2017 at 11:02 AM, Andrea Giammarchi <andrea giammarchi gmail com> wrote:
I've quickly provided a proof of concept but you could have a JSONChannel class singleton on the client side that queue each info and wait for the GJS side to receive one before sending another.

I might try a real implementation though and see how it works.

however, this is just a work around for the fact you can send messages without any content (... and I wonder how that can be useful in any way ...)

Regards

On Wed, Nov 1, 2017 at 10:50 AM, Sam Jansen <sam jansen starleaf com> wrote:


On 1 November 2017 at 11:55, Andrea Giammarchi <andrea giammarchi gmail com> wrote:
Actually the `notify::title` with a prefixed "secret-channel" and serialized JSON looks like the best of them all, for the time being, as it makes it straight forward for both client and server to communicate.

```js
// listen to each response
new MutationObserver(m => {
  if (/^secret:response=/.test(document.title)) {
    const data = "">e(RegExp['$&'].length));
    document.title = '';
    console.log(data);
  }
}).observe(
  document.querySelector('title'),
  {childList: true}
);

// send info using client or simulate server sending in responses
document.title = 'secret:response=' + JSON.stringify({some: 'value'});
```

with a proper class/wrap to handle events and send data transparently it might be a great way to exchange info


I've just come to the opposite conclusion, though I don't disagree as such...

My concern is that setting document.title, and having notify::title called is asynchronous (I believe). So in your JS, if one had:

```
document.title = '1'
document.title = '2'
```

Then by the time notify::title is called, and you inspect your "webkit.title" property, I'd expect you'd only see the '2' value, and (likely) not the '1'.

It's possible to solve this by ensuring the GJS side has picked up a message, and e.g. reset the title, I suppose. This feels like an awkward solution to me though.
 


On Wed, Nov 1, 2017 at 5:53 AM, Sam Jansen <sam jansen starleaf com> wrote:


On 1 November 2017 at 05:43, <philip chimento gmail com> wrote:
On Thu, Oct 12, 2017 at 5:23 AM Andrea Giammarchi <andrea giammarchi gmail com> wrote:
FWIW I've used the location with a private channel as protocol to intercept calls to/from the page and GJS.



From the page, which is aware of the "secret" channel, I call GJS actions via location.href = "">Component(JSON.stringify(value))})`;

The protocol secret1234 is intercepted and the `controller.method(JSON.parse(decodeURIComponent(restOfURI)))` invoked.

To signal the page everything is fine I use this.webView.runJavaScript https://github.com/WebReflection/jsgtk-twitter/blob/master/app#L377

The page has a listener for the `secret1234` event on the main window, and such listener is instrumented to react accordingly with the CustomEvent .detail payload/info.

This might look a bit convoluted, and it has JSON serialization as limitation for the kind of data you want to pass (i.e. I use base64 encoded images as source from remotely fetched files enabling somehow CORS for whatever I want) but it worked well, circumventing the missing communication channel available in Qt.

Maybe today there are better ways for doing a similar thing and if that's the case, please share.

Here is another, fairly new, way to do it. Start out by registering a "script message handler":

To send a message to the page, use the same thing that Andrea uses:

To send a message from the page to the GJS program, use the postMessage() method mentioned in the documentation, and connect to this signal in your GJS program to receive the message:


Excellent - I had not noticed this. My first attempt at communicating between WebKit2 and GJS was via setting "document.title" and having GJS connect to the "notify::title" signal! Not a great approach, this looks much better.
 
Although I just realized that unfortunately the values won't be able to be marshalled into GJS since you need to use the _javascript_Core API to get at them. This is a really nice method in C, but in JS you can only use it to send a message without any content. That is annoying. I should probably open up an issue about this.


I just hit upon this problem myself. In researching it, I found it is solved (at least well enough for my use-case) with this open source library:


It's awkward having another dependency for me, especially one that isn't in a normal Ubuntu/Fedora/etc. package, but otherwise this approach worked fine for me.
 
On Wed, Oct 11, 2017 at 12:57 PM, Adriano Patrizio <adriano patrizio hotmail com> wrote:
Thank you for response, this is my problem: have necessity to implement methods into my web application webkit2 based and comunicate with GJS script (example: filesystem functions to read and write files or window managment).

Regards,
Philip C 

_______________________________________________
_javascript_-list mailing list
_javascript_-list gnome org
https://mail.gnome.org/mailman/listinfo/_javascript_-list











[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]