forked from mozilla-b2g/gaia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bridge.js
274 lines (225 loc) · 7.65 KB
/
bridge.js
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
define(function(require, exports) {
'use strict';
var EventEmitter2 = require('ext/eventemitter2');
var co = require('ext/co');
var core = require('core');
var dayObserver = require('day_observer');
var nextTick = require('common/next_tick');
var object = require('common/object');
/**
* Fetch all the data needed to display the busytime information on the event
* views based on the busytimeId
*/
exports.fetchRecord = function(busytimeId) {
return co(function *() {
var record = yield dayObserver.findAssociated(busytimeId);
var eventStore = core.storeFactory.get('Event');
var owners = yield eventStore.ownersOf(record.event);
var provider = core.providerFactory.get(owners.account.providerType);
var capabilities = yield provider.eventCapabilities(record.event);
record.calendar = owners.calendar;
record.account = owners.account;
record.capabilities = capabilities;
return record;
});
};
/**
* Fetch all the calendars from database and emits a new event every time the
* values changes.
*
* @returns {ClientStream}
*/
exports.observeCalendars = function() {
// TODO: replace with real threads.client.stream when we get db into worker
var stream = new FakeClientStream();
var calendarStore = core.storeFactory.get('Calendar');
var getAllAndWrite = co.wrap(function *() {
// calendarStore.all() returns an object! we convert into an array since
// that is easier to render/manipulate
var calendars = yield calendarStore.all();
var data = yield object.map(calendars, co.wrap(function *(id, calendar) {
var provider = yield calendarStore.providerFor(calendar);
var caps = provider.calendarCapabilities(calendar);
return { calendar: calendar, capabilities: caps };
}));
stream.write(data);
});
calendarStore.on('add', getAllAndWrite);
calendarStore.on('remove', getAllAndWrite);
calendarStore.on('update', getAllAndWrite);
stream.cancel = function() {
calendarStore.off('add', getAllAndWrite);
calendarStore.off('remove', getAllAndWrite);
calendarStore.off('update', getAllAndWrite);
stream._cancel();
};
nextTick(getAllAndWrite);
return stream;
};
exports.updateCalendar = function(calendar) {
var calendarStore = core.storeFactory.get('Calendar');
return calendarStore.persist(calendar);
};
exports.createEvent = function(event) {
return persistEvent(event, 'create', 'canCreate');
};
exports.updateEvent = function(event) {
return persistEvent(event, 'update', 'canUpdate');
};
exports.deleteEvent = function(event) {
return persistEvent(event, 'delete', 'canDelete');
};
var persistEvent = co.wrap(function *(event, action, capability) {
event = event.data || event;
try {
var eventStore = core.storeFactory.get('Event');
var provider = yield eventStore.providerFor(event);
var caps = yield provider.eventCapabilities(event);
if (!caps[capability]) {
return Promise.reject(new Error(`Can't ${action} event`));
}
return provider[action + 'Event'](event);
} catch(err) {
console.error(
`${action} Error for event "${event._id}" ` +
`on calendar "${event.calendarId}"`
);
console.error(err);
return Promise.reject(err);
}
});
exports.getSetting = function(id) {
var settingStore = core.storeFactory.get('Setting');
return settingStore.getValue(id);
};
exports.setSetting = function(id, value) {
var settingStore = core.storeFactory.get('Setting');
return settingStore.set(id, value);
};
exports.observeSetting = function(id) {
var stream = new FakeClientStream();
var settingStore = core.storeFactory.get('Setting');
var writeOnChange = function(value) {
stream.write(value);
};
settingStore.on(`${id}Change`, writeOnChange);
stream.cancel = function() {
settingStore.off(`${id}Change`, writeOnChange);
stream._cancel();
};
exports.getSetting(id).then(writeOnChange);
return stream;
};
exports.getAccount = function(id) {
var accountStore = core.storeFactory.get('Account');
return accountStore.get(id);
};
exports.deleteAccount = function(id) {
var accountStore = core.storeFactory.get('Account');
return accountStore.remove(id);
};
/**
* Sends a request to create an account.
*
* @param {Calendar.Models.Account} model account details.
*/
exports.createAccount = co.wrap(function *(model) {
var storeFactory = core.storeFactory;
var accountStore = storeFactory.get('Account');
var calendarStore = storeFactory.get('Calendar');
// begin by persisting the account
var [, result] = yield accountStore.verifyAndPersist(model);
// finally sync the account so when
// we exit the request the user actually
// has some calendars. This should not take
// too long (compared to event sync).
yield accountStore.sync(result);
// begin sync of calendars
var calendars = yield calendarStore.remotesByAccount(result._id);
// note we don't wait for any of this to complete
// we just begin the sync and let the event handlers
// on the sync controller do the work.
for (var key in calendars) {
core.syncController.calendar(
result,
calendars[key]
);
}
return result;
});
exports.observeAccounts = function() {
var stream = new FakeClientStream();
var accountStore = core.storeFactory.get('Account');
var getAllAndWrite = co.wrap(function *() {
try {
var accounts = yield accountStore.all();
var data = object.map(accounts, (id, account) => {
return {
account: account,
provider: core.providerFactory.get(account.providerType)
};
});
stream.write(data);
} catch(err) {
console.error(`Error fetching accounts: ${err.message}`);
}
});
accountStore.on('add', getAllAndWrite);
accountStore.on('remove', getAllAndWrite);
accountStore.on('update', getAllAndWrite);
stream.cancel = function() {
accountStore.off('add', getAllAndWrite);
accountStore.off('remove', getAllAndWrite);
accountStore.off('update', getAllAndWrite);
stream._cancel();
};
nextTick(getAllAndWrite);
return stream;
};
exports.observeDay = function(date) {
var stream = new FakeClientStream();
var emit = stream.write.bind(stream);
stream.cancel = function() {
dayObserver.off(date, emit);
stream._cancel();
};
// FIXME: nextTick only really needed because dayObserver dispatches the
// first callback synchronously, easier to solve it here than to change
// dayObserver; we can remove this nextTick call after moving to threads.js
// (since it will always be async)
nextTick(() => dayObserver.on(date, emit));
return stream;
};
/**
* Returns a list of available presets filtered by
* the currently used presets in the database.
* (can't create multiple local calendars)
*/
exports.availablePresets = function(presetList) {
var accountStore = core.storeFactory.get('Account');
return accountStore.availablePresets(presetList);
};
/**
* FakeClientStream is used as a temporary solution while we move all the db
* calls into the worker. In the end all the methods inside this file will be
* transfered into the "backend/calendar_service.js" and we will simply call
* the `threads.client('calendar')` API
*/
function FakeClientStream() {
this._emitter = new EventEmitter2();
this._enabled = true;
}
FakeClientStream.prototype.write = function(data) {
this._enabled && this._emitter.emit('data', data);
};
FakeClientStream.prototype.listen = function(callback) {
this._enabled && this._emitter.on('data', callback);
};
FakeClientStream.prototype.unlisten = function(callback) {
this._enabled && this._emitter.off('data', callback);
};
FakeClientStream.prototype._cancel = function() {
this._emitter.removeAllListeners();
this._enabled = false;
};
});