Merge "veyron/services/wspr/wsprd: Added identity store for wspr."
diff --git a/examples/pipetobrowser/browser/actions/navigate-help.js b/examples/pipetobrowser/browser/actions/navigate-help.js
new file mode 100644
index 0000000..d2c0691
--- /dev/null
+++ b/examples/pipetobrowser/browser/actions/navigate-help.js
@@ -0,0 +1,43 @@
+/*
+ * Navigates to help page
+ * @fileoverview
+ */
+import { Logger } from 'libs/logs/logger'
+import { register, trigger } from 'libs/mvc/actions'
+
+import { state as publishState } from 'services/pipe-to-browser-server'
+
+import { page } from 'runtime/context'
+
+import { HelpView } from 'views/help/view'
+
+var log = new Logger('actions/navigate-help');
+const ACTION_NAME = 'help';
+
+/*
+ * Registers the action
+ */
+export function registerHelpAction() {
+ register(ACTION_NAME, actionHandler);
+}
+
+/*
+ * Triggers the action
+ */
+export function navigateHelp() {
+ return trigger(ACTION_NAME);
+}
+
+/*
+ * Handles the action.
+ *
+ * @private
+ */
+function actionHandler() {
+ log.debug('navigate help triggered');
+
+ // create a help view
+ var helpView = new HelpView(publishState);
+
+ page.setSubPageView('help', helpView);
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/index.html b/examples/pipetobrowser/browser/index.html
index e37405b..a73e258 100644
--- a/examples/pipetobrowser/browser/index.html
+++ b/examples/pipetobrowser/browser/index.html
@@ -21,6 +21,7 @@
<link rel="import" href="views/pipes/component.html"/>
<link rel="import" href="views/redirect-pipe-dialog/component.html"/>
<link rel="import" href="views/neighborhood/component.html"/>
+ <link rel="import" href="views/help/component.html"/>
<link rel="import" href="libs/ui-components/blackhole/component.html"/>
diff --git a/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.css b/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.css
index 2dc25c7..b7c7a91 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.css
@@ -15,8 +15,8 @@
position: absolute;
top: 50%;
left: 50%;
- margin-left: -9px;
- margin-top: -9px;
+ margin-left: -14px;
+ margin-top: -14px;
}
.attribution {
diff --git a/examples/pipetobrowser/browser/libs/ui-components/common/spinner.gif b/examples/pipetobrowser/browser/libs/ui-components/common/spinner.gif
index d03237b..ebb7cad 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/common/spinner.gif
+++ b/examples/pipetobrowser/browser/libs/ui-components/common/spinner.gif
Binary files differ
diff --git a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
index 67b1779..76d52a2 100644
--- a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
+++ b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
@@ -3,7 +3,7 @@
* Please note that Veyron writes logs to stderr stream, in *nix systems 2>&1
* can be used to redirect stderr to stdout which can be then piped to P2B.
* @tutorial myVeyronServerd -v=3 2>&1 | p2b google/p2b/[name]/vlog
- * @tutorial cat logfile.text | p2b google/p2b/[name]/vlog
+ * @tutorial cat logfile.txt | p2b google/p2b/[name]/vlog
* @fileoverview
*/
import { View } from 'view';
diff --git a/examples/pipetobrowser/browser/pipe-viewers/manager.js b/examples/pipetobrowser/browser/pipe-viewers/manager.js
index a97e96b..086dfc9 100644
--- a/examples/pipetobrowser/browser/pipe-viewers/manager.js
+++ b/examples/pipetobrowser/browser/pipe-viewers/manager.js
@@ -56,8 +56,9 @@
loadedPipeViewers[name] = pipeViewerClass;
return pipeViewerClass;
}).catch((e) => {
- log.debug('could not load viewer JavaScript module for:', name, e);
- return Promise.reject(e);
+ var errMessage = 'could not load viewer for: ' + name;
+ log.debug(errMessage, e);
+ return Promise.reject(new Error(errMessage));
})
}
diff --git a/examples/pipetobrowser/browser/runtime/app.js b/examples/pipetobrowser/browser/runtime/app.js
index d66ad2b..59e6b55 100644
--- a/examples/pipetobrowser/browser/runtime/app.js
+++ b/examples/pipetobrowser/browser/runtime/app.js
@@ -5,6 +5,7 @@
import { registerAddPipeViewerAction } from 'actions/add-pipe-viewer'
import { registerNavigatePipesPageAction, navigatePipesPage } from 'actions/navigate-pipes-page'
import { registerNavigateNeigbourhoodAction, navigateNeigbourhood } from 'actions/navigate-neighborhood'
+import { registerHelpAction, navigateHelp } from 'actions/navigate-help'
import { registerRedirectPipeAction } from 'actions/redirect-pipe'
import { SubPageItem } from 'views/page/view'
@@ -44,6 +45,7 @@
registerNavigatePipesPageAction();
registerNavigateNeigbourhoodAction();
registerRedirectPipeAction();
+ registerHelpAction();
}
/*
@@ -75,9 +77,8 @@
var helpSubPageItem = new SubPageItem('help');
helpSubPageItem.name = 'Help';
helpSubPageItem.icon = 'help';
- helpSubPageItem.onActivate = function() {
- alert('Not Implemented');
- };
+ helpSubPageItem.onActivate = navigateHelp;
+
page.subPages.push(helpSubPageItem);
document.body.appendChild(page.element);
diff --git a/examples/pipetobrowser/browser/services/pipe-to-browser-server.js b/examples/pipetobrowser/browser/services/pipe-to-browser-server.js
index 5f40da4..16cc738 100644
--- a/examples/pipetobrowser/browser/services/pipe-to-browser-server.js
+++ b/examples/pipetobrowser/browser/services/pipe-to-browser-server.js
@@ -32,12 +32,12 @@
/*
* Publishes the p2b service under google/p2b/{name}
- * e.g. If name is "JohnTablet", p2b service will be accessible under name:
- * 'google/p2b/JohnTablet'
+ * e.g. If name is "john-tablet", p2b service will be accessible under name:
+ * 'google/p2b/john-tablet'
*
* pipe() method can be invoked on any 'google/p2b/{name}/suffix' name where
* suffix identifies the viewer that can format and display the stream data
- * e.g. 'google/p2b/JohnTablet/DataTable'.pipe() will display the incoming
+ * e.g. 'google/p2b/john-tablet/console'.pipe() will display the incoming
* data in a data table. See /app/viewer/ for a list of available viewers.
* @param {string} name Name to publish the service under
* @param {function} pipeRequestHandler A function that will be called when
@@ -55,8 +55,6 @@
var p2b = {
pipe($suffix, $stream) {
return new Promise(function(resolve, reject) {
- //TODO(aghassemi) publish-issue remove /pipe from the suffix
- $suffix = $suffix.substr(5);
log.debug('received pipe request for:', $suffix);
var numBytesForThisCall = 0;
@@ -91,17 +89,15 @@
state.publishing = true;
- return server.register('pipe', p2b).then(() => { //TODO(aghassemi) publish-issue add pipe for now since we can't register under empty name
- return server.publish(config.publishNamePrefix + '/' + name).then((endpoint) => { //TODO(aghassemi) publish-issue
- log.debug('published with endpoint:', endpoint);
+ return server.serve(config.publishNamePrefix + '/' + name + '/pipe', p2b).then((endpoint) => { //TODO(aghassemi) publish-issue
+ log.debug('published with endpoint:', endpoint);
- state.published = true;
- state.publishing = false;
- state.fullServiceName = config.publishNamePrefix + '/' + name + '/pipe'; //TODO(aghassemi) publish-issue
- state.date = new Date();
+ state.published = true;
+ state.publishing = false;
+ state.fullServiceName = config.publishNamePrefix + '/' + name + '/pipe'; //TODO(aghassemi) publish-issue
+ state.date = new Date();
- return endpoint;
- });
+ return endpoint;
}).catch((err) => { state.reset(); throw err; });
}
diff --git a/examples/pipetobrowser/browser/views/error/broken_robot.png b/examples/pipetobrowser/browser/views/error/broken_robot.png
new file mode 100644
index 0000000..dc0b7f1
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/error/broken_robot.png
Binary files differ
diff --git a/examples/pipetobrowser/browser/views/error/component.css b/examples/pipetobrowser/browser/views/error/component.css
new file mode 100644
index 0000000..94237b0
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/error/component.css
@@ -0,0 +1,19 @@
+:host {
+ background-image: url('broken_robot.png');
+ background-repeat: no-repeat;
+ background-position: right 50%;
+ min-height: 300px;
+ width: 100%;
+ max-width: 600px;
+ display: block;
+}
+
+h2 {
+ font-size: 1.1em;
+}
+
+h3 {
+ font-size: 0.9em;
+ color: rgba(0,0,0,0.54);
+ margin-right: 100px;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/views/error/component.html b/examples/pipetobrowser/browser/views/error/component.html
index 3df3570..d746a14 100644
--- a/examples/pipetobrowser/browser/views/error/component.html
+++ b/examples/pipetobrowser/browser/views/error/component.html
@@ -2,7 +2,10 @@
<polymer-element name="p2b-error">
<template>
- <h1>error: {{errorMessage}}</h1>
+ <link rel="stylesheet" href="component.css">
+ <h2 page-title>Error</h2>
+ <h3>Sorry, some of the 1s and 0s got mixed.</h3>
+ <h3>{{errorMessage}}</h3>
</template>
<script>
Polymer('p2b-error', {
diff --git a/examples/pipetobrowser/browser/views/error/view.js b/examples/pipetobrowser/browser/views/error/view.js
index 3b9024f..c99c1d2 100644
--- a/examples/pipetobrowser/browser/views/error/view.js
+++ b/examples/pipetobrowser/browser/views/error/view.js
@@ -1,5 +1,8 @@
import { exists } from 'libs/utils/exists'
import { View } from 'libs/mvc/view'
+import { Logger } from 'libs/logs/logger'
+
+var log = new Logger('views/error');
/*
* View representing application error.
@@ -21,8 +24,9 @@
}
var errorMessage = err.toString();
+ log.debug(errorMessage);
if(exists(err.stack)) {
- errorMessage += err.stack;
+ log.debug(err.stack);
}
this.element.errorMessage = errorMessage;
diff --git a/examples/pipetobrowser/browser/views/help/component.css b/examples/pipetobrowser/browser/views/help/component.css
new file mode 100644
index 0000000..faf1990
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/help/component.css
@@ -0,0 +1,32 @@
+.name {
+ font-weight: bold;
+ color: rgba(0, 0, 0, 0.8);
+}
+
+.mono, .code {
+ font-size: 1.1em;
+ font-family: monospace;
+}
+
+.code {
+ background-color: #222;
+ color: #fafafa;
+ padding: 1em;
+ white-space: normal;
+ word-break: break-all;
+}
+
+h3 {
+ font-size: 1.3em;
+}
+
+h4 {
+ font-size: 1.2em;
+ color: rgb(51, 103, 214);
+ margin-bottom: 0.5em;
+}
+
+a {
+ color: #5677fc;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/views/help/component.html b/examples/pipetobrowser/browser/views/help/component.html
new file mode 100644
index 0000000..46e1d2c
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/help/component.html
@@ -0,0 +1,64 @@
+<link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
+
+<polymer-element name="p2b-help">
+<template>
+ <link rel="stylesheet" href="component.css">
+ <link rel="stylesheet" href="../common/common.css">
+ <h2 page-title>Help</h2>
+ <p>Pipe To Browser allows you to pipe anything from shell console to the browser. Piped data is then displayed in a graphical and formatted way by a viewer you can specify.</p>
+ <h3>Getting Started</h3>
+ <template if="{{serviceState.published}}">
+ <p>Looks like you have already started the service under <span class="name">{{publishedName}}</span>, great!</p>
+ </template>
+ <template if="{{!serviceState.published}}">
+ <p>Before we start, you need to start the service under a name. Go to Home and publish this instance of P2B under a name like <span class="name">john-tablet</span> or <span class="name">jane-desktop</span>
+ </p>
+ </template>
+ <p>Now let's use the <span class="name">console</span> viewer. It can pretty much display anything, so it's a good one to start with</p>
+ <p>In your Linux or Mac console run:</p>
+ <pre class="code">echo "Hello World" | p2b {{publishedName}}/console</pre>
+ <p>P2B follows a basic <span class="mono">cmd | p2b google/p2b/[name]/[viewer]</span> pattern. Where <span class="mono">[name]</span> is what you publish the service under and <span class="mono">[viewer]</span> can be the name of a built-in viewer like <span class="mono">image</span> or <span class="mono">console</span> or a Url to a remote viewer that is a P2B plug-in.</p>
+ <h3>Built-in Viewers</h3>
+ <p>In addition to the basic <span class="name">console</span> viewer, P2B is preloaded with the following viewers</p>
+
+ <h4>Image</h4>
+ <p><span class="name">image</span> can display most types of images.</p>
+ <pre class="code">cat grumpy-cat.jpg | p2b {{publishedName}}/image</pre>
+
+ <h4>Git Status</h4>
+ <p>Ever wanted to sort, search and filter result of <span class="mono">git status</span> to make sense of it all? <span class="name">git/status</span> can do that. You need to use <span class="mono">git status --short</span> though, so we can parse it.</p>
+ <pre class="code">git status --short | p2b {{publishedName}}/git/status</pre>
+
+ <h4>Veyron Log Viewer</h4>
+ <span class="name">vlog</span> displays Veyron logs in a DataGrid and supports sorting, searching, paging, pausing and filtering based on time and log level. DataGrid is responsive and may hide columns on smaller screens but you can always see all the fields by using the more info icon.</p>
+ <pre class="code">cat vlogfile.txt | p2b {{publishedName}}/vlog</pre>
+ <p>If you want to pipe logs from a Veyron service directly, you need to pipe stderr or strout first using <span class="mono">2>&1</span></p>
+ <pre class="code">myVeyronServerd -v=3 2>&1 | p2b {{publishedName}}/vlog</pre>
+
+ <h4>dev/null</h4>
+ <p>No system is complete without a <span class="name">dev/null</span>. Similar to *nix <span class="mono">dev/null</span>, anything piped to it will be discarded without mercy.</p>
+ <pre class="code">cat /dev/urandom | p2b {{publishedName}}/dev/null</pre>
+
+ <h3>Remote Viewers</h3>
+ <p>In addition to built-in viewers, ad-hoc remote viewers can be hosted anywhere and used with P2B. Remote viewers are referenced by their Url without the .js extension at the end og the plug-in JavaScript file</p>
+ <pre class="code">echo "Hello World" | p2b {{publishedName}}/http://googledrive.com/host/0BzmT5cnKdCAKa3hzNEVCU2tnd3c/helloworld</pre>
+ <p>Writing remote viewers is not different than writing built-in ones and basic plug-ins are pretty straight forward to write.</p>
+ <p>At high level, plug-ins are expected to implement a <span class="mono">PipeViewer</span> interface which has a <span class="mono">play(stream)</span> method. A <span class="mono">view</span> (which is a wrapper for a DOM element) is expected to be returned from <span class="mono">play(stream)</span>. You can look at the hello world remote plug-in <a href="http://googledrive.com/host/0BzmT5cnKdCAKa3hzNEVCU2tnd3c/helloworld.js" target="_blank">code on Google drive</a> to get started on writing new remote plug-ins</p>
+</template>
+<script>
+ Polymer('p2b-help', {
+ /*
+ * Dynamic binding for the state of publishing p2b service.
+ */
+ serviceState: null,
+ get publishedName() {
+ if( this.serviceState && this.serviceState.published ) {
+ return this.serviceState.fullServiceName
+ } else {
+ return 'google/p2b/[name]';
+ }
+ },
+
+ });
+ </script>
+</polymer-element>
diff --git a/examples/pipetobrowser/browser/views/help/view.js b/examples/pipetobrowser/browser/views/help/view.js
new file mode 100644
index 0000000..3ca0592
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/help/view.js
@@ -0,0 +1,15 @@
+import { exists } from 'libs/utils/exists'
+import { View } from 'libs/mvc/view'
+
+/*
+ * View representing the help page
+ * @class
+ * @extends {View}
+ */
+export class HelpView extends View {
+ constructor(serviceState) {
+ var el = document.createElement('p2b-help');
+ el.serviceState = serviceState;
+ super(el);
+ }
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/views/loading/component.css b/examples/pipetobrowser/browser/views/loading/component.css
new file mode 100644
index 0000000..4411080
--- /dev/null
+++ b/examples/pipetobrowser/browser/views/loading/component.css
@@ -0,0 +1,3 @@
+.spinner {
+ margin: 1em;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/views/loading/component.html b/examples/pipetobrowser/browser/views/loading/component.html
index 2017642..0483301 100644
--- a/examples/pipetobrowser/browser/views/loading/component.html
+++ b/examples/pipetobrowser/browser/views/loading/component.html
@@ -2,7 +2,8 @@
<polymer-element name="p2b-loading">
<template>
- <div>Loading...</div>
+ <link rel="stylesheet" href="component.css">
+ <img class="spinner" src="/libs/ui-components/common/spinner.gif" alt="Loading"/>
</template>
<script>
Polymer('p2b-loading', {
diff --git a/examples/pipetobrowser/browser/views/publish/component.html b/examples/pipetobrowser/browser/views/publish/component.html
index e32d8dd..d17b40a 100644
--- a/examples/pipetobrowser/browser/views/publish/component.html
+++ b/examples/pipetobrowser/browser/views/publish/component.html
@@ -7,7 +7,7 @@
<template id="template">
<link rel="stylesheet" href="../common/common.css">
<link rel="stylesheet" href="component.css">
- <paper-input id="publishNameInput" label="Name to publish under (e.g. JohnTablet)" error="You must pick a name!" floatinglabel/></paper-input>
+ <paper-input id="publishNameInput" label="Name to publish under (e.g. john-tablet)" error="You must pick a name!" floatinglabel/></paper-input>
<paper-button class="paper colored" inkColor="#3367d6" on-click="{{ publishAction }}">Publish</paper-button>
</template>
<script>
@@ -19,7 +19,7 @@
* @event
*/
publishAction: function() {
- var name = this.$.publishNameInput.value;
+ var name = this.$.publishNameInput.value.trim();
if(name === "") {
this.$.publishNameInput.invalid = true;
this.$.publishNameInput.classList.toggle('invalid', true);
diff --git a/lib/bluetooth/bluetooth_linux.go b/lib/bluetooth/bluetooth_linux.go
index 10c4346..ed7e378 100644
--- a/lib/bluetooth/bluetooth_linux.go
+++ b/lib/bluetooth/bluetooth_linux.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,!android
package bluetooth
diff --git a/lib/bluetooth/bluetooth_other.go b/lib/bluetooth/bluetooth_other.go
index fa75d80..abe0f7a 100644
--- a/lib/bluetooth/bluetooth_other.go
+++ b/lib/bluetooth/bluetooth_other.go
@@ -1,4 +1,4 @@
-// +build !linux
+// +build !linux android
package bluetooth
diff --git a/lib/bluetooth/bt.c b/lib/bluetooth/bt.c
index 1dde981..4744f43 100644
--- a/lib/bluetooth/bt.c
+++ b/lib/bluetooth/bt.c
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,!android
#include "bt.h"
diff --git a/lib/bluetooth/bt.h b/lib/bluetooth/bt.h
index 2a72c97..cc36b31 100644
--- a/lib/bluetooth/bt.h
+++ b/lib/bluetooth/bt.h
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,!android
#include <stdlib.h>
diff --git a/lib/bluetooth/listener.go b/lib/bluetooth/listener.go
index 5d53386..da383ad 100644
--- a/lib/bluetooth/listener.go
+++ b/lib/bluetooth/listener.go
@@ -1,4 +1,4 @@
-// +build linux
+// +build linux,!android
package bluetooth
diff --git a/runtimes/google/ipc/jni/arg_getter.go b/runtimes/google/ipc/jni/arg_getter.go
index 7540bd3..fc6bf3b 100644
--- a/runtimes/google/ipc/jni/arg_getter.go
+++ b/runtimes/google/ipc/jni/arg_getter.go
@@ -24,8 +24,8 @@
registerInterface((*proximity.ProximityAnnouncerService)(nil))
}
-// A list of all registered argGetter-s.
-var register map[string]*argGetter = make(map[string]*argGetter)
+// A list of all registered serviceArgGetter-s.
+var register map[string]*serviceArgGetter = make(map[string]*serviceArgGetter)
// registerInterface registers the provided VDL client or server interface
// so that its methods' arguments can be created on-the-fly.
@@ -81,7 +81,7 @@
methods[m.Name] = append(methods[m.Name], &mArgs)
}
path := path.Join(t.PkgPath(), t.Name())
- register[path] = &argGetter{
+ register[path] = &serviceArgGetter{
methods: methods,
vdlPath: path,
}
@@ -115,19 +115,47 @@
return nil
}
-// newArgGetter returns the argument getter for the provided VDL interface.
-func newArgGetter(vdlIfacePath string) *argGetter {
- return register[vdlIfacePath]
-}
-
-// argGetter serves method arguments for a specific interface.
-type argGetter struct {
+// serviceArgGetter serves method arguments for a specific service.
+type serviceArgGetter struct {
methods map[string][]*methodArgs
vdlPath string
}
+func (sag *serviceArgGetter) String() (ret string) {
+ ret = "VDLPath: " + sag.vdlPath
+ for k, v := range sag.methods {
+ for _, m := range v {
+ ret += "; "
+ ret += fmt.Sprintf("Method: %s, Args: %v", k, m)
+ }
+ }
+ return
+}
+
+// argGetter serves method arguments for a service object.
+// (which may implement multiple services)
+type argGetter struct {
+ methods map[string][]*methodArgs
+}
+
+// newArgGetter returns the argument getter for the provided service object.
+func newArgGetter(paths []string) (*argGetter, error) {
+ ag := &argGetter{
+ methods: make(map[string][]*methodArgs),
+ }
+ for _, path := range paths {
+ sag := register[path]
+ if sag == nil {
+ return nil, fmt.Errorf("unknown service %s", path)
+ }
+ for method, args := range sag.methods {
+ ag.methods[method] = args
+ }
+ }
+ return ag, nil
+}
+
func (ag *argGetter) String() (ret string) {
- ret = "VDLPath: " + ag.vdlPath
for k, v := range ag.methods {
for _, m := range v {
ret += "; "
@@ -154,9 +182,6 @@
return m
}
-// argGetters is a cache of created argument getters, keyed by VDL interface path.
-var argGetters map[string]*argGetter = make(map[string]*argGetter)
-
// method contains argument type information for a method belonging to an interface.
type methodArgs struct {
inTypes []reflect.Type
diff --git a/runtimes/google/ipc/jni/client.go b/runtimes/google/ipc/jni/client.go
index 58b446c..c55adff 100644
--- a/runtimes/google/ipc/jni/client.go
+++ b/runtimes/google/ipc/jni/client.go
@@ -38,13 +38,13 @@
}
// Get argument instances that correspond to the provided method.
vdlPackagePath := strings.Join(strings.Split(goString(env, jPath), ".")[1:], "/")
- getter := newArgGetter(vdlPackagePath)
- if getter == nil {
- return nil, fmt.Errorf("couldn't find VDL interface corresponding to path %q", vdlPackagePath)
+ getter, err := newArgGetter([]string{vdlPackagePath})
+ if err != nil {
+ return nil, err
}
mArgs := getter.FindMethod(method, len(argStrs))
if mArgs == nil {
- return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q, getter: %v", method, len(argStrs), goString(env, jPath), getter)
+ return nil, fmt.Errorf("couldn't find method %s with %d args in VDL interface at path %q", method, len(argStrs), goString(env, jPath))
}
argptrs := mArgs.InPtrs()
if len(argptrs) != len(argStrs) {
diff --git a/runtimes/google/ipc/jni/invoker.go b/runtimes/google/ipc/jni/invoker.go
index 12d8c57..5835d86 100644
--- a/runtimes/google/ipc/jni/invoker.go
+++ b/runtimes/google/ipc/jni/invoker.go
@@ -6,7 +6,6 @@
"encoding/json"
"fmt"
"runtime"
- "strings"
"veyron2/ipc"
"veyron2/security"
@@ -42,12 +41,12 @@
return nil, fmt.Errorf("error creating Java VDLInvoker object: %v", err)
}
// Fetch the argGetter for the object.
- pid := jMethodID(env, jVDLInvokerClass, "getInterfacePath", fmt.Sprintf("()%s", stringSign))
- jPath := C.jstring(C.CallGetInterfacePath(env, jInvoker, pid))
- vdlPackagePath := strings.Join(strings.Split(goString(env, jPath), ".")[1:], "/")
- getter := newArgGetter(vdlPackagePath)
- if getter == nil {
- return nil, fmt.Errorf("couldn't find VDL interface corresponding to path %q", vdlPackagePath)
+ pid := jMethodID(env, jVDLInvokerClass, "getImplementedServices", fmt.Sprintf("()%s", arraySign(stringSign)))
+ jPathArray := C.jobjectArray(C.CallGetInterfacePath(env, jInvoker, pid))
+ paths := goStringArray(env, jPathArray)
+ getter, err := newArgGetter(paths)
+ if err != nil {
+ return nil, err
}
// Reference Java invoker; it will be de-referenced when the go invoker
// created below is garbage-collected (through the finalizer callback we
diff --git a/runtimes/google/ipc/jni/util.go b/runtimes/google/ipc/jni/util.go
index b122926..d87f3bd 100644
--- a/runtimes/google/ipc/jni/util.go
+++ b/runtimes/google/ipc/jni/util.go
@@ -35,6 +35,10 @@
objectSign = "Ljava/lang/Object;"
)
+func arraySign(sign string) string {
+ return "[" + sign
+}
+
// refs stores references to instances of various Go types, namely instances
// that are referenced only by the Java code. The only purpose of this store
// is to prevent Go runtime from garbage collecting those instances.
@@ -96,6 +100,19 @@
return C.NewStringUTF(env, cString)
}
+// goStringArray converts a Java string array to a go string array.
+func goStringArray(env *C.JNIEnv, jStrArray C.jobjectArray) []string {
+ if jStrArray == nil {
+ return nil
+ }
+ length := C.GetArrayLength(env, C.jarray(jStrArray))
+ ret := make([]string, int(length))
+ for i := 0; i < int(length); i++ {
+ ret[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jStrArray, C.jsize(i))))
+ }
+ return ret
+}
+
// jThrow throws a new Java exception of the provided type with the given message.
func jThrow(env *C.JNIEnv, class C.jclass, msg string) {
s := C.CString(msg)
@@ -165,15 +182,7 @@
defer C.free(unsafe.Pointer(cSig))
fid := C.GetFieldID(env, C.GetObjectClass(env, obj), cField, cSig)
jStrArray := C.jobjectArray(C.GetObjectField(env, obj, fid))
- if jStrArray == nil {
- return nil
- }
- length := C.GetArrayLength(env, C.jarray(jStrArray))
- ret := make([]string, int(length))
- for i := 0; i < int(length); i++ {
- ret[i] = goString(env, C.jstring(C.GetObjectArrayElement(env, jStrArray, C.jsize(i))))
- }
- return ret
+ return goStringArray(env, jStrArray)
}
// jMethodID returns the Java method ID for the given method.
diff --git a/services/mgmt/node/impl/invoker.go b/services/mgmt/node/impl/invoker.go
index c6ca55d..6cbc12a 100644
--- a/services/mgmt/node/impl/invoker.go
+++ b/services/mgmt/node/impl/invoker.go
@@ -386,7 +386,8 @@
output := "#!/bin/bash\n"
output += PreviousEnv + "=" + filepath.Dir(path) + " "
output += strings.Join(envelope.Env, " ") + " "
- output += os.Args[0] + " " + strings.Join(envelope.Args, " ")
+ output += filepath.Join(workspace, "noded") + " "
+ output += strings.Join(envelope.Args, " ")
path = filepath.Join(workspace, "noded.sh")
if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
vlog.Errorf("WriteFile(%v) failed: %v", path, err)
diff --git a/services/wspr/wsprd/lib/server.go b/services/wspr/wsprd/lib/server.go
index 901287e..8b95ea2 100644
--- a/services/wspr/wsprd/lib/server.go
+++ b/services/wspr/wsprd/lib/server.go
@@ -6,7 +6,6 @@
"bytes"
"encoding/json"
"fmt"
- "strings"
"sync"
"veyron2"
@@ -22,6 +21,20 @@
writer clientWriter
}
+// A request from the proxy to javascript to handle an RPC
+type serverRPCRequest struct {
+ ServerId uint64
+ Method string
+ Args []interface{}
+ Context serverRPCRequestContext
+}
+
+// call context for a serverRPCRequest
+type serverRPCRequestContext struct {
+ Suffix string
+ Name string
+}
+
type serverHelper interface {
createNewFlow(server *server, sender sender) *flow
@@ -37,8 +50,10 @@
// The server that handles the ipc layer. Listen on this server is
// lazily started.
- server ipc.Server
- dispatcher exactMatchDispatcher
+ server ipc.Server
+
+ // The saved dispatcher to reuse when serve is called multiple times.
+ dispatcher ipc.Dispatcher
// The endpoint of the server. This is empty until the server has been
// started and listen has been called on it.
@@ -61,7 +76,6 @@
helper: helper,
veyronProxy: veyronProxy,
outstandingServerRequests: make(map[int64]chan *serverRPCReply),
- dispatcher: exactMatchDispatcher{dispatchers: make(map[string]ipc.Dispatcher)},
}
var err error
if server.server, err = helper.rt().NewServer(); err != nil {
@@ -74,7 +88,7 @@
// communicate the result back via a channel to the caller
type remoteInvokeFunc func(methodName string, args []interface{}, call ipc.ServerCall) <-chan *serverRPCReply
-func (s *server) createRemoteInvokerFunc(serviceName string) remoteInvokeFunc {
+func (s *server) createRemoteInvokerFunc() remoteInvokeFunc {
return func(methodName string, args []interface{}, call ipc.ServerCall) <-chan *serverRPCReply {
flow := s.helper.createNewFlow(s, senderWrapper{stream: call})
replyChan := make(chan *serverRPCReply, 1)
@@ -87,11 +101,10 @@
}
// Send a invocation request to JavaScript
message := serverRPCRequest{
- ServerId: s.id,
- ServiceName: serviceName,
- Method: lowercaseFirstCharacter(methodName),
- Args: args,
- Context: context,
+ ServerId: s.id,
+ Method: lowercaseFirstCharacter(methodName),
+ Args: args,
+ Context: context,
}
data := response{Type: responseServerRequest, Message: message}
@@ -114,8 +127,8 @@
}
s.helper.getLogger().VI(3).Infof("request received to call method %q on "+
- "JavaScript server %q with args %v, MessageId %d was assigned.",
- methodName, serviceName, args, flow.id)
+ "JavaScript server with args %v, MessageId %d was assigned.",
+ methodName, args, flow.id)
go proxyStream(call, flow.writer, s.helper.getLogger())
return replyChan
@@ -146,62 +159,28 @@
}
}
-type exactMatchDispatcher struct {
- sync.Mutex
- dispatchers map[string]ipc.Dispatcher
-}
+func (s *server) serve(name string, sig JSONServiceSignature) (string, error) {
+ s.Lock()
+ defer s.Unlock()
-func (em *exactMatchDispatcher) Lookup(suffix string) (ipc.Invoker, security.Authorizer, error) {
- parts := strings.Split(suffix, "/")
- if len(parts) == 0 || len(parts[0]) == 0 {
- return nil, nil, fmt.Errorf("can't extract first path component from %q", suffix)
- }
- name := parts[0]
- em.Lock()
- defer em.Unlock()
- if disp := em.dispatchers[name]; disp == nil {
- return nil, nil, fmt.Errorf("no dispatcher registered for %q, from %q", name, suffix)
- } else {
- suffix = strings.TrimLeft(suffix, "/")
- suffix = strings.TrimPrefix(suffix, name)
- suffix = strings.TrimLeft(suffix, "/")
- return disp.Lookup(suffix)
- }
-}
-
-// register associates a dispatcher with name, where name cannot contain
-// any /s. Incoming invocations of the form <name>/... will be passed
-// on to the dispatcher with <name>/... as the parameter to its lookup
-// method.
-func (s *server) register(name string, sig JSONServiceSignature) error {
serviceSig, err := sig.ServiceSignature()
if err != nil {
- return err
+ return "", err
}
- if strings.Contains(name, "/") {
- return fmt.Errorf("%q must not contain /", name)
- }
-
- remoteInvokeFunc := s.createRemoteInvokerFunc(name)
+ remoteInvokeFunc := s.createRemoteInvokerFunc()
invoker, err := newInvoker(serviceSig, remoteInvokeFunc)
if err != nil {
- return err
+ return "", err
}
- dispatcher := newDispatcher(invoker, security.NewACLAuthorizer(
- security.ACL{security.AllPrincipals: security.AllLabels},
- ))
- s.dispatcher.Lock()
- s.dispatcher.dispatchers[name] = dispatcher
- s.dispatcher.Unlock()
- return nil
-}
+ if s.dispatcher == nil {
+ s.dispatcher = newDispatcher(invoker, security.NewACLAuthorizer(
+ security.ACL{security.AllPrincipals: security.AllLabels},
+ ))
+ }
-func (s *server) publish(name string) (string, error) {
- s.Lock()
- defer s.Unlock()
if s.endpoint == "" {
endpoint, err := s.server.Listen("veyron", s.veyronProxy)
@@ -210,7 +189,7 @@
}
s.endpoint = endpoint.String()
}
- if err := s.server.Serve(name, &s.dispatcher); err != nil {
+ if err := s.server.Serve(name, s.dispatcher); err != nil {
return "", err
}
s.helper.getLogger().VI(1).Infof("endpoint is %s", s.endpoint)
diff --git a/services/wspr/wsprd/lib/wspr.go b/services/wspr/wsprd/lib/wspr.go
index 0147432..b48a310 100644
--- a/services/wspr/wsprd/lib/wspr.go
+++ b/services/wspr/wsprd/lib/wspr.go
@@ -87,8 +87,8 @@
// Making a veyron client request, streaming or otherwise
websocketVeyronRequest websocketMessageType = 0
- // Publishing this websocket under an object name
- websocketPublishServer = 1
+ // Serving this websocket under an object name
+ websocketServe = 1
// A response from a service in javascript to a request
// from the proxy.
@@ -112,7 +112,7 @@
// This contains the json encoded payload.
Data string
- // Whether it is an rpc request or a publish request.
+ // Whether it is an rpc request or a serve request.
Type websocketMessageType
}
@@ -135,32 +135,11 @@
IsStreaming bool
}
-// A request javascript to publish on a particular name
-type publishRequest struct {
+// A request javascript to serve undern a particular name
+type serveRequest struct {
Name string
ServerId uint64
- Services map[string]JSONServiceSignature
-}
-
-// A request from javascript to register a particular prefix
-type registerRequest struct {
- Prefix string
- // TODO(bjornick): Do we care about the methods?
-}
-
-// A request from the proxy to javascript to handle an RPC
-type serverRPCRequest struct {
- ServerId uint64
- ServiceName string
- Method string
- Args []interface{}
- Context serverRPCRequestContext
-}
-
-// call context for a serverRPCRequest
-type serverRPCRequestContext struct {
- Suffix string
- Name string
+ Service JSONServiceSignature
}
// The response from the javascript server to the proxy.
@@ -355,7 +334,7 @@
// A manager that handles fetching and caching signature of remote services
signatureManager *signatureManager
- // We maintain multiple Veyron server per websocket pipe for publishing JavaScript
+ // We maintain multiple Veyron server per websocket pipe for serving JavaScript
// services.
servers map[uint64]*server
@@ -613,8 +592,8 @@
wsp.sendOnStream(msg.Id, msg.Data, ww)
case websocketStreamClose:
wsp.closeStream(msg.Id)
- case websocketPublishServer:
- go wsp.handlePublishRequest(msg.Data, ww)
+ case websocketServe:
+ go wsp.handleServeRequest(msg.Data, ww)
case websocketStopServer:
go wsp.handleStopRequest(msg.Data, ww)
case websocketServerResponse:
@@ -655,25 +634,18 @@
server.Stop()
}
-func (wsp *websocketPipe) publish(publishRequest publishRequest, w clientWriter) {
+func (wsp *websocketPipe) serve(serveRequest serveRequest, w clientWriter) {
// Create a server for the websocket pipe, if it does not exist already
- server, err := wsp.maybeCreateServer(publishRequest.ServerId)
+ server, err := wsp.maybeCreateServer(serveRequest.ServerId)
if err != nil {
w.sendError(verror.Internalf("error creating server: %v", err))
}
- wsp.ctx.logger.VI(2).Infof("publishing under name: %q", publishRequest.Name)
+ wsp.ctx.logger.VI(2).Infof("serving under name: %q", serveRequest.Name)
- // Register each service under the server
- for serviceName, jsonIDLSig := range publishRequest.Services {
- if err := server.register(serviceName, jsonIDLSig); err != nil {
- w.sendError(verror.Internalf("error registering service: %v", err))
- }
- }
-
- endpoint, err := server.publish(publishRequest.Name)
+ endpoint, err := server.serve(serveRequest.Name, serveRequest.Service)
if err != nil {
- w.sendError(verror.Internalf("error publishing service: %v", err))
+ w.sendError(verror.Internalf("error serving service: %v", err))
return
}
// Send the endpoint back
@@ -689,17 +661,17 @@
}
}
-// handlePublishRequest takes a request to publish a server, creates
+// handleServeRequest takes a request to serve a server, creates
// a server, registers the provided services and sends the endpoint back.
-func (wsp *websocketPipe) handlePublishRequest(data string, w *websocketWriter) {
- // Decode the publish request which includes IDL, registered services and name
- var publishRequest publishRequest
+func (wsp *websocketPipe) handleServeRequest(data string, w *websocketWriter) {
+ // Decode the serve request which includes IDL, registered services and name
+ var serveRequest serveRequest
decoder := json.NewDecoder(bytes.NewBufferString(data))
- if err := decoder.Decode(&publishRequest); err != nil {
+ if err := decoder.Decode(&serveRequest); err != nil {
w.sendError(verror.Internalf("can't unmarshal JSONMessage: %v", err))
return
}
- wsp.publish(publishRequest, w)
+ wsp.serve(serveRequest, w)
}
// handleStopRequest takes a request to stop a server.
diff --git a/services/wspr/wsprd/lib/wspr_test.go b/services/wspr/wsprd/lib/wspr_test.go
index 15d4ac3..f8d6b9f 100644
--- a/services/wspr/wsprd/lib/wspr_test.go
+++ b/services/wspr/wsprd/lib/wspr_test.go
@@ -364,7 +364,7 @@
proxyServer *proxy.Proxy
}
-func publishServer() (*runningTest, error) {
+func serveServer() (*runningTest, error) {
mounttableServer, endpoint, err := startMountTableServer()
if err != nil {
@@ -389,11 +389,9 @@
return &writer
}
wsp.setup()
- wsp.publish(publishRequest{
- Name: "adder",
- Services: map[string]JSONServiceSignature{
- "adder": adderServiceSignature,
- },
+ wsp.serve(serveRequest{
+ Name: "adder",
+ Service: adderServiceSignature,
}, &writer)
return &runningTest{
@@ -401,14 +399,14 @@
}, nil
}
-func TestJavascriptPublishServer(t *testing.T) {
- rt, err := publishServer()
+func TestJavascriptServeServer(t *testing.T) {
+ rt, err := serveServer()
defer rt.mounttableServer.Stop()
defer rt.proxyServer.Shutdown()
defer rt.wsp.cleanup()
if err != nil {
- t.Errorf("could not publish server %v", err)
+ t.Errorf("could not serve server %v", err)
}
if len(rt.writer.stream) != 1 {
@@ -419,7 +417,7 @@
resp := rt.writer.stream[0]
if resp.Type != responseFinal {
- t.Errorf("unknown stream message Got: %v, expected: publish response", resp)
+ t.Errorf("unknown stream message Got: %v, expected: serve response", resp)
return
}
@@ -428,17 +426,17 @@
return
}
}
- t.Errorf("invalid endpdoint returned from publish: %v", resp.Message)
+ t.Errorf("invalid endpdoint returned from serve: %v", resp.Message)
}
func TestJavascriptStopServer(t *testing.T) {
- rt, err := publishServer()
+ rt, err := serveServer()
defer rt.mounttableServer.Stop()
defer rt.proxyServer.Shutdown()
defer rt.wsp.cleanup()
if err != nil {
- t.Errorf("could not publish server %v", err)
+ t.Errorf("could not serve server %v", err)
return
}
@@ -489,13 +487,13 @@
}
func runJsServerTestCase(t *testing.T, test jsServerTestCase) {
- rt, err := publishServer()
+ rt, err := serveServer()
defer rt.mounttableServer.Stop()
defer rt.proxyServer.Shutdown()
defer rt.wsp.cleanup()
if err != nil {
- t.Errorf("could not publish server %v", err)
+ t.Errorf("could not serve server %v", err)
}
if len(rt.writer.stream) != 1 {
@@ -506,17 +504,17 @@
resp := rt.writer.stream[0]
if resp.Type != responseFinal {
- t.Errorf("unknown stream message Got: %v, expected: publish response", resp)
+ t.Errorf("unknown stream message Got: %v, expected: serve response", resp)
return
}
msg, ok := resp.Message.(string)
if !ok {
- t.Errorf("invalid endpdoint returned from publish: %v", resp.Message)
+ t.Errorf("invalid endpdoint returned from serve: %v", resp.Message)
}
if _, err := r.NewEndpoint(msg); err != nil {
- t.Errorf("invalid endpdoint returned from publish: %v", resp.Message)
+ t.Errorf("invalid endpdoint returned from serve: %v", resp.Message)
}
rt.writer.stream = nil
@@ -528,7 +526,7 @@
t.Errorf("unable to create client: %v", err)
}
- call, err := client.StartCall(rt.wspr.rt.NewContext(), "/"+msg+"//adder", test.method, test.inArgs)
+ call, err := client.StartCall(rt.wspr.rt.NewContext(), "/"+msg+"/adder", test.method, test.inArgs)
if err != nil {
t.Errorf("failed to start call: %v", err)
}
@@ -537,10 +535,9 @@
response{
Type: responseServerRequest,
Message: map[string]interface{}{
- "serverId": 0.0,
- "serviceName": "adder",
- "method": lowercaseFirstCharacter(test.method),
- "args": test.inArgs,
+ "serverId": 0.0,
+ "method": lowercaseFirstCharacter(test.method),
+ "args": test.inArgs,
"context": map[string]interface{}{
"name": "adder",
"suffix": "adder",