Chrome Extension RPC Router

When developing chrome extension, communication between background script and content scripts is very typical use case. Chrome provides messaging APIs to achieve this goal. But this API has limitation that every message goes to the same listener.

Background script in Chrome extension usually works as a function hub for the whole extension, so background scripts usually required to process different types of messages. Then the limit of Chrome messaging API become an issue we need to face.

There are several approaches to resolve the limitation. Since API allow multiple listener, a simple and cheap solution is Responsibility Chain; adding listener for each message type, and checking message type at beginning of the listener.

Responsbility Chain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
if(message.type != 'reloadData')
return;
// reload data logic here
});
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
if(message.type != 'updateBrowerAction')
return;
// update browser action logic here
});

This approach works, but not that graceful. And there is potential performance issue when message types increases.

So I come up a new more graceful solution: RPC Message Router

RCPRouter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
extractResponseHandler = (args) ->
return undefined if args.length == 0
last = args.pop()
if typeof last == 'function'
return last
else
args.push last
return undefined
class @RPCRouter
constructor: ->
chrome.runtime.onMessage.addListener @handleMassage
handleMassage: (message, sender, sendResponse) =>
{method: methodName, args} = message
method = this[methodName]
unless method?
console.error "Unknown RPC method: %s", methodName
return
args.push sendResponse
console.log "RPC Call: %s, args: %o", methodName, args
method.apply(this, args)
callBackground: (method, args...) ->
responseHandler = extractResponseHandler(args)
console.log "RPC Call to Background: %s, args: %o", method, args
chrome.runtime.sendMessage {method, args}, responseHandler
callTab: (tabId, method, args...) ->
responseHandler = extractResponseHandler(args)
console.log "RPC Call to Tab \"%s\": %s, args: %o", tabId, method, args
chrome.tabs.sendMessage tabId, {method, args}, responseHandler

So this new RPCRouter wraps the chrome original messaging API and provides a more convenient way to invoke a remote method. To create a specific RPC Router for background page or content page is quite easy.

Responsbility Chain
1
2
3
4
5
6
7
8
9
10
11
12
class BackgroundRPCRouter extends RPCRouter
refreshData: (isForceUpdate, dataLoadedCallback) ->
# reload data logic here
dataLoadedCallback(data)
updateBrowerAction: (icon, hintText) ->
# update browser action logic here
return false # protection: avoid channel leak

HINT:
Using messaging API in chrome here should be careful. Coffee script will return the last executed statement result as function result, which could be potentially truthy, such as non-zero number, object. The truthy return value will make the channel become a async channel, which won’t be closed until the sendResponse callback is invoked. But just as the handler updateBrowserAction, the handler doesn’t need a sendResponse callback, the issue will keep the channel alive forever. So do add false or return false at the end of the method unless you can ensure the function will never yield truthy value in last statement.

Create shortcut for your project Mingle with Chrome OmniBox

Mingle is a common choice of story wall management system in ThoughtWorks internal projects.

Mingle uses rest style url to identify card or entities in the system, so the url contains the account id and project id in it.
Hosted Mingle is used in most project, to distinguish between accounts and projects, the url of the project mingle site is usually long, e.g., https://minglehosting.thoughtworks.com/telstra_de/projects/telstra_24x7_apps/. And other resources in the project, such as cards, whose url will be even longer.

When working in the team, open a specific card is a very common scenario, such as kicking off story, moving card, update story ACs, etc. To open a card, user usually need to open the project mingle home page, and use the search feature in the project. To open the home page, usually you need to save the url into your bookmark.

Today I found a better way to solve this issue, using the Chrome OmniBox! Chrome OmniBox is usually configured by Open Search Description. But it also allow user to manually add search engine configuration.

After the registration, we can use Mingle search direct from OmniBox, and we can open a specific card by typing “#card number”.

  1. Keyword Mingle in OmniBoxKeyword mingle in OmniBox
  2. Search in OmniBoxSearch in OmniBox
  3. Open the pageOpen the page

To register Mingle to Chrome OmniBox, you can use following approach:

Find out the Mingle search page url first:

  1. Open Mingle project home page, type test in the Search Box. Press enter, copy the url, and replace word test with %s. That’s the search url.Find Search Url
  2. Open url chrome://settings, find Manage search engines.Find Manage search engines
  3. Register new search engine.
    The first box is the display name of item, Mingle, project_name Mingle is recommended The second box is the keyword triggers the search, mingle is recommended. In most cases, you will work with only 1 mingle instance, so it will not cause confusion. But if it does, add more specific keyword to it.
    ** The third box is the url search url, paste the url you just foundRegister mingle

JSONView Chrome Extension Dark Theme

JSONView is a very popular JSON formatter for Chrome, which automatically prettifies the JSON content.

JSONView provide a very sweety feature that allow user to customize the css used to format the JSON. And I love dark theme and the Consolas font so much, so I customized my dark own dark theme for JSONView.

Here is my theme css, and you can copy it to your JSONView theme editor to apply.
Also you can find code on gist: https://gist.github.com/timnew/5167241

Theme Preview
Dark Theme for JSONView
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
body {
white-space: pre;
font-family: consolas;
color: white;
background: black;
}
.property {
color: orange;
font-weight: bold;
}
.type-null {
color: gray;
}
.type-boolean {
color: orangered;
}
.type-number {
color: lightblue;
}
.type-string {
color: lightgreen;
}
a {
color: dodgerBlue;
}
.callback-function {
color: gray;
}
.collapser:after {
content: "-";
}
.collapsed > .collapser:after {
content: "+";
}
.ellipsis:after {
content: "...";
}
.collapsible {
margin-left: 2em;
}
.hoverable {
padding: 1px 2px 1px 2px;
border-radius: 3px;
}
.hovered {
background-color: rgba(255, 255, 255, .3);
}
.collapser {
padding-right: 6px;
padding-left: 6px;
}

Remote Desktop from Win to Mac via Chrome Remote Desktop

Google Chrome Remote Desktop Extension is really amazing!!!!!
I try to install the extension on both Chrome on my iMac and the one on my laptop with Win 7.
Then I try to connect the iMac from Win 7 via Chrome Remote Desktop!
The performance is really amazing!!!! It is less well than Windows RDP but much better than the famous but sucks VNC!!!!!
I totally have no idea how Google implemented this! But it do works super well in my environment!

Chrome Remote Desktop to Mac

You know, before Chrome Remote Desktop, there is only one real cross platform remote desktop solution: VNC, and the performance of which is unacceptable poor, and we have to install a lot of ugly software to make it happen.
But now, we can achieve it by simply install chrome and the chrome extension….
It is amazing!

I found the desktop fade in animation works smoothly via remote desktop! And I can even play movie from Mac!!!!!

Play Movie on Mac via Chrome Remote Desktop

While playing video, the peak of the network traffic might be reach 800kBps to 1MBps… but normally it should be 300 kBps…..

But since it is only the beta version, so there are some limitations in Chrome Remote Desktop:

  1. The Hotkey doesn’t work well, which means you cannot Press Cmd+Space to pop up quick-silver or spot-light…
  2. Mouse Wheel doesn’t work well, which means you cannot scroll the page with your mouse wheel, or magic mouse.
  3. Sound doesn’t bring to remote side, if you wanna play movie with Chrome Remote Desktop, then you might be have to read the subtitle rather than hear the speech.
  4. CPU consuming is high, I guess Chrome Remote Desktop spend a lot of CPU power on compressing the data to be transferred, so the CPU consuming is higher than other Remote Desktop solution……

And special Precondition required for Chinese Netizens:
If you are try to use Chrome Remote Desktop in China, this miracle land, you might need some other special technology tool to help you get rid of the famous GFW. To my experience, sometimes Remote Desktop OAuth might be blocked by GFW.