├── app ├── package.json └── valence.js ├── LICENSE ├── logo.svg └── README.md /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "valence", 3 | "version" : "0.1.0", 4 | "main" : "valence.js" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016, Doug Hoyte 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /app/valence.js: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2015-2016 Doug Hoyte 3 | // 4 | // This project is licensed under the 2-clause BSD license. 5 | // 6 | 7 | "use strict"; 8 | 9 | var readline = require('readline'); 10 | 11 | 12 | var object_map = {}; 13 | 14 | 15 | var rl = readline.createInterface({ 16 | input: process.stdin, 17 | output: process.stdout, 18 | terminal: false 19 | }); 20 | 21 | rl.on('line', function(line) { 22 | var msg = JSON.parse(line); 23 | 24 | if (msg['cmd'] === 'call') { 25 | // Acquire object 26 | 27 | var obj; 28 | 29 | if (msg['obj'] === undefined) { 30 | obj = module; 31 | } else { 32 | obj = object_map[msg['obj']]; 33 | } 34 | 35 | // Manipulate arguments 36 | 37 | if (msg['args_cb']) { 38 | msg['args_cb'].map(function(spec) { 39 | var cb_id = spec[1]; 40 | 41 | msg['args'][spec[0]] = (function() { 42 | var args_array = []; 43 | 44 | for (var i=0; i 0) { 137 | var thisPos = stack.indexOf(this) 138 | ~thisPos ? stack.splice(thisPos + 1) : stack.push(this) 139 | ~thisPos ? keys.splice(thisPos, Infinity, key) : keys.push(key) 140 | if (~stack.indexOf(value)) value = cycleReplacer.call(this, key, value) 141 | } 142 | else stack.push(value) 143 | 144 | return replacer == null ? value : replacer.call(this, key, value) 145 | } 146 | } 147 | 148 | /* 149 | end of json-stringify-safe code 150 | */ 151 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 69 | 79 | 89 | 99 | VALENCE 110 | 120 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Valence Logo](https://hoytech.github.io/valence/logo.svg)](https://github.com/hoytech/valence) 2 | 3 | ## Description 4 | 5 | `valence.js` is an interface for controlling github's [electron](https://github.com/atom/electron) GUI toolkit from another process. It is inspired by the [Thrust](https://github.com/breach/thrust) project. 6 | 7 | Essentially, electron is a node.js process connected to a chromium process. The idea is that you write node.js javascript code to control a chromium process in order to build applications that look and feel like native applications. 8 | 9 | Valence is a protocol for communicating between this node.js process and another controller process, and `valence.js` is the node.js component of the implementation. `valence.js` runs in the electron main process as depicted in this diagram: 10 | 11 | |------------| stdio |--------------| IPC |----------------| 12 | | Your app |--------->| electron |---->| electron | 13 | | |<---------| main process |<----| render process | 14 | |------------| |--------------| |----------------| 15 | perl/whatever valence.js chromium 16 | 17 | `valence.js` is compatible with electron versions 0.25.1 through 1.4.1 (and probably later). 18 | 19 | 20 | ## Rationale 21 | 22 | Why have a separate controller process at all? Why not just write the controller logic in javascript and run it in the electron main process? 23 | 24 | First of all, the obvious reason is that not everybody wants to write substantial controller logic in javascript. Different languages have different strengths and libraries that may not be available in javascript/node.js. For example, when communicating with SQL databases it's hard to beat perl's [DBI](https://metacpan.org/pod/DBI) module (see [AnyEvent::DBI](https://metacpan.org/pod/AnyEvent::DBI) or [AnyEvent::Task](https://metacpan.org/pod/AnyEvent::Task) for how to use DBI in an async program). 25 | 26 | Secondly, sometimes we already have significant existing programs written in another language that we would like to add a GUI front-end to. Rather than re-write such apps in javascript, `valence.js` provides a "glue" option for other environments to use electron. 27 | 28 | Finally, even if your app is written in javascript, in order to use electron directly, your app needs to support the exact version of `node` that electron is currently compiled with. This can especially be an issue with native modules that depend on older `node` APIs. With `valence.js` you can use any `node` environment that is applicable to your application -- well, once we have a javascript driver that is :). 29 | 30 | 31 | ## Drivers 32 | 33 | ### Perl 34 | 35 | The reference implementation of the app-side of the valence protocol is written in perl 5. 36 | 37 | It can be installed with the following cpan minus command (use `--sudo` if you with to install it for all users on your machine): 38 | 39 | $ cpanm Valence --sudo 40 | 41 | After it is installed, see the [Valence](https://metacpan.org/pod/Valence) documentation for how to use it. To work on the code itself, please fork it on [github](https://github.com/hoytech/Valence-p5). 42 | 43 | 44 | 45 | ## Protocol 46 | 47 | `valence.js` is an electron app and you can run it as you would any other: 48 | 49 | /path/to/electron /path/to/valence/app/ 50 | 51 | After this, the app will wait until it receives messages on standard input, and will subsequently emit messages over its standard output. All of your app's communication with `valence.js` is done over electron's stdio pipes. 52 | 53 | All messages (both input and output) are minified JSON, followed by a new-line. This means there is exactly one message per line. 54 | 55 | Every method has a `cmd` parameter which indicates the "command" to be invoked by the message. The other parameters depend on which command was sent. 56 | 57 | ### Commands 58 | 59 | #### call 60 | 61 | APP -> VALENCE 62 | 63 | Indicates that valence should call a method on a particular object. 64 | 65 | Parameters: 66 | 67 | - `obj`: The object id (see `save` below) corresponding to the object that the method should be called on. Optional. If omitted, assumed to be `node.js`'s `module` object. 68 | 69 | - `method`: The name of the method to be invoked. Required. 70 | 71 | - `save`: The object id to assign to whatever is returned from the method call. Typically this is a counter that is maintained by the app which is incremented for every method call. Optional. If omitted, the return result is discarded. 72 | 73 | - `args`: An array of arguments that should be passed to the method. Required (but can be empty). 74 | 75 | - `args_cb`: An array of arrays. Each array represents a callback insertion that should be applied to `args` above. The first element in each sub-array is the offset in args where a callback should be inserted, and the second element is the callback id (see the `cb` command). Optional. 76 | 77 | #### destroy 78 | 79 | APP -> VALENCE 80 | 81 | Indicates that the app is finished with an object and valence can discard its reference to it. 82 | 83 | Parameters: 84 | 85 | - `obj`: The object id of the object to be destroyed. This should have been passed in via a previous `save` parameter. Required. 86 | 87 | #### attr 88 | 89 | APP -> VALENCE 90 | 91 | Used to lookup an attribute from an object and save it in a new object. 92 | 93 | Parameters: 94 | 95 | - `obj`: The object id of which to lookup an attribute from. Required. 96 | 97 | - `attr`: The name of the attribute. Required. 98 | 99 | - `save`: The object id to assign to the result. Optional (but pointless without). 100 | 101 | #### get 102 | 103 | APP -> VALENCE 104 | 105 | Retrieves a value stored in an object id by having it passed to a callback. 106 | 107 | Parameters: 108 | 109 | - `obj`: The object id of the object to retrieve. Required. 110 | 111 | - `cb`: The callback id (see the `cb` command) to invoke with the result. Required. 112 | 113 | #### cb 114 | 115 | VALENCE -> APP 116 | 117 | Sent by `valence.js` when it wishes to invoke a callback in your application. 118 | 119 | Parameters: 120 | 121 | - `cb`: The callback id to be invoked. This was passed in from a `call` or `get` command. Required. 122 | 123 | - `args`: An array of arguments to be passed to the callback. Required (but may be empty). 124 | 125 | 126 | ### Examples 127 | 128 | Here is the detailed description of a few selected messages. 129 | 130 | Note that the JSON in these examples has been "prettified" and in the actual valence protocol they **must** be minified and one-per-line. 131 | 132 | When experimenting, if you are using the perl module you can set the `VALENCE_DEBUG` environment variable to sniff the traffic between a perl app and `valence.js` (see the [Valence](https://metacpan.org/pod/Valence) docs). 133 | 134 | #### Example 1 135 | 136 | This example is of an app calling a method which contains a callback. It is roughly equivalent to executing this code: 137 | 138 | get_object(3).on('closed', function() { 139 | notify_callback(4); 140 | }); 141 | 142 | Here is what the message might look like: 143 | 144 | { 145 | "args" : [ 146 | "closed", 147 | null 148 | ], 149 | "args_cb" : [ 150 | [ 151 | 1, 152 | 4 153 | ] 154 | ], 155 | "cmd" : "call", 156 | "method" : "on", 157 | "obj" : "3" 158 | } 159 | 160 | The `obj` above is `3` which presumably was the object resulting from the creation of a [BrowserWindow](https://github.com/atom/electron/blob/master/docs/api/browser-window.md) object. We are attaching a callback to listen for `closed` events. The callback id is `4`, and its location in the args array is `1`. Note that the callback has been stubbed out with a `null` value and will be replaced by an actual javascript function by `valence.js`, and how there is no `save` parameter because we aren't interested in the returned result of the `on` method. 161 | 162 | #### Example 2 163 | 164 | This is what `valence.js` might send when the `closed` event was triggered: 165 | 166 | { 167 | "args" : [ 168 | {} 169 | ], 170 | "cb" : 4, 171 | "cmd" : "cb" 172 | } 173 | 174 | The callback id is `4` (see the previous example). There is an empty hash in the `args` list. This corresponds to the javascript event, but has been converted into an empty hash because the `node.js` `JSON.stringify()` method could not serialize this value. 175 | 176 | 177 | ## TODO 178 | 179 | - Currently the `args_cb` values can only reference the first level of the arguments and cannot replace a callback inside a nested structure like an object or array. Eventually the protocol should support location specifiers such as `[1][3]['field']` 180 | 181 | - It needs to spec out behaviour for what happens when exceptions are thrown. 182 | 183 | - The protocol should expose a way to eval raw javascript in the main process (you can already do it in the render process with `WebContents.executeJavaScript()`). 184 | 185 | - The special `new` method can currently only support 1 parameter because of a limitation in javascript. 186 | 187 | - `valence.js` currently doesn't know when a callback it has installed has been garbage collected. If it did then it could send a "callback destroy" command to the app. This may be possible with the npm [weak](https://www.npmjs.com/package/weak) module. 188 | 189 | 190 | ## See Also 191 | 192 | The [Valence perl module](https://metacpan.org/pod/Valence) 193 | 194 | Some examples that use Valence: [DB-Browser](https://github.com/hoytech/db-browser), [HackRF-RCCar](https://github.com/hoytech/Radio-HackRF-RCCar) 195 | 196 | [Presentation for Perl Mongers](https://www.youtube.com/watch?v=u3S2vhN0S1M&t=2m23s) 197 | 198 | 199 | 200 | ## Author 201 | 202 | Doug Hoyte, doug@hcsw.org 203 | 204 | ## COPYRIGHT & LICENSE 205 | 206 | Copyright 2015-2016 Doug Hoyte. 207 | 208 | This project is licensed under the 2-clause BSD license. 209 | 210 | Electron itself is Copyright (c) 2014-2016 GitHub Inc. and is licensed under the MIT license. 211 | --------------------------------------------------------------------------------