FYI the version with automatic secret per each JSONChannel instance is
there. You can provide a secret from GJS for a global channel or accept any
channel ... it's your call on security side, really.

Regards

On Wed, Nov 1, 2017 at 2:44 PM, Andrea Giammarchi <
andrea.giammar...@gmail.com> wrote:

> 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.giammar...@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.jan...@starleaf.com>
>> wrote:
>>
>>>
>>>
>>> On 1 November 2017 at 15:23, Andrea Giammarchi <
>>> andrea.giammar...@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.JavascriptResult
>>>> 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 JavaScriptCore.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/sa
>>> ifulbkhan/wkjscore-result
>>>
>>>   7 import * as WkJsCore from '../../gjs/WkJsCore'
>>> ...
>>>  85         let contentManager = this.webkit.get_user_content_manager();
>>>  86         if (!contentManager.register_scri
>>> pt_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 JavaScriptCore 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.giammar...@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.jan...@starleaf.com>
>>>>> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On 1 November 2017 at 11:55, Andrea Giammarchi <
>>>>>> andrea.giammar...@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 = JSON.parse(document.title.slic
>>>>>>> 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.jan...@starleaf.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On 1 November 2017 at 05:43, <philip.chime...@gmail.com> wrote:
>>>>>>>>
>>>>>>>>> On Thu, Oct 12, 2017 at 5:23 AM Andrea Giammarchi <
>>>>>>>>> andrea.giammar...@gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> FWIW I've used the location with a private channel as protocol to
>>>>>>>>>> intercept calls to/from the page and GJS.
>>>>>>>>>>
>>>>>>>>>> https://github.com/WebReflection/jsgtk-twitter/blob/master/a
>>>>>>>>>> pp#L162-L175
>>>>>>>>>>
>>>>>>>>>> The channel is a random string: https://github.com/Web
>>>>>>>>>> Reflection/jsgtk-twitter/blob/master/app#L59
>>>>>>>>>>
>>>>>>>>>> From the page, which is aware of the "secret" channel, I call GJS
>>>>>>>>>> actions via location.href = `secret1234:method(${encodeURI
>>>>>>>>>> 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/WebReflect
>>>>>>>>>> ion/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":
>>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.usercont
>>>>>>>>> entmanager#method-register_script_message_handler
>>>>>>>>>
>>>>>>>>> To send a message to the page, use the same thing that Andrea uses:
>>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.webview#
>>>>>>>>> method-run_javascript
>>>>>>>>>
>>>>>>>>> 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:
>>>>>>>>> http://devdocs.baznga.org/webkit240~4.0_api/webkit2.usercont
>>>>>>>>> entmanager#signal-script-message-received
>>>>>>>>>
>>>>>>>>>
>>>>>>>> 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 
>>>>>>>>> JavaScriptCore 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:
>>>>>>>>
>>>>>>>> https://github.com/saifulbkhan/wkjscore-result
>>>>>>>>
>>>>>>>> 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.patri...@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
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>
_______________________________________________
javascript-list mailing list
javascript-list@gnome.org
https://mail.gnome.org/mailman/listinfo/javascript-list

Reply via email to