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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/*******************************************************************************
µBlock - a Chromium browser extension to block requests.
Copyright (C) 2014 Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
// This is the reference client-side implementation of µBlock's messaging
// infrastructure. The "server"-side implementation is in messaging.js.
// The client-side implementation creates a port in order to connect to
// µBlock's background page. With this port we can "ask", "tell" or "announce":
//
// "ask": send a request and expect an answer using a callback.
// "tell": send a request with no expectation of an answer.
// "announce": send a request to be relayed to all connections -- no answer
// expected.
//
// The tricky part in this implementation is to ensure all the requests are
// uniquely identified, so that the background-page can keep track of these
// until it is ready to send back an answer, which will be tagged with the
// same id. The uniqueness must be true for all ports which connect to the
// background page at any given time.
//
// Currently using Math.random() to generate this id... I don't know about the
// implementation of Math.random(), but as long as I have a good expectation
// of uniqueness, it's ok, we are not dealing with critical stuff here.
var messaging = (function(name){
var port = null;
var dangling = false;
var requestId = 1;
var requestIdToCallbackMap = {};
var listenCallback = null;
var onPortMessage = function(details) {
if ( typeof details.id !== 'number' ) {
return;
}
// Announcement?
if ( details.id < 0 ) {
if ( listenCallback ) {
listenCallback(details.msg);
}
return;
}
var callback = requestIdToCallbackMap[details.id];
if ( !callback ) {
return;
}
callback(details.msg);
delete requestIdToCallbackMap[details.id];
checkDisconnect();
};
var start = function(name) {
port = chrome.runtime.connect({
name: name +
'/' +
String.fromCharCode(
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0,
Math.random() * 0x7FFF | 0
)
});
port.onMessage.addListener(onPortMessage);
};
if ( typeof name === 'string' && name.length > 0 ) {
start(name);
}
var stop = function() {
listenCallback = null;
dangling = true;
checkDisconnect();
};
var ask = function(msg, callback) {
if ( !callback ) {
tell(msg);
return;
}
var id = requestId++;
port.postMessage({ id: id, msg: msg });
requestIdToCallbackMap[id] = callback;
};
var tell = function(msg) {
port.postMessage({ id: 0, msg: msg });
};
var listen = function(callback) {
listenCallback = callback;
};
var checkDisconnect = function() {
if ( !dangling ) {
return;
}
if ( Object.keys(requestIdToCallbackMap).length ) {
return;
}
port.disconnect();
port = null;
};
return {
start: start,
stop: stop,
ask: ask,
tell: tell,
listen: listen
};
})();
|