1 | import angular from './angularCompatibility.js';
|
2 | import Vue from 'vue';
|
3 | import Reference from './Reference.js';
|
4 |
|
5 |
|
6 | export default class MetaTree {
|
7 | constructor(rootUrl, tree, bridge, dispatcher) {
|
8 | this._rootUrl = rootUrl;
|
9 | this._tree = tree;
|
10 | this._dispatcher = dispatcher;
|
11 | this._bridge = bridge;
|
12 | this._vue = new Vue({data: {$root: {
|
13 | connected: undefined, timeOffset: 0, user: undefined, userid: undefined,
|
14 | nowAtInterval(intervalMillis) {
|
15 | const key = 'now' + intervalMillis;
|
16 | if (!this.hasOwnProperty(key)) {
|
17 | const update = () => {
|
18 | Vue.set(this, key, Date.now() + this.timeOffset);
|
19 | angular.digest();
|
20 | };
|
21 | update();
|
22 | setInterval(update, intervalMillis);
|
23 | }
|
24 | return this[key];
|
25 | }
|
26 | }}});
|
27 |
|
28 | this._auth = {serial: 0, initialAuthChangeReceived: false};
|
29 |
|
30 | bridge.onAuth(rootUrl, this._handleAuthChange, this);
|
31 |
|
32 | this._connectInfoProperty('serverTimeOffset', 'timeOffset');
|
33 | this._connectInfoProperty('connected', 'connected');
|
34 | Object.freeze(this);
|
35 | }
|
36 |
|
37 | get root() {
|
38 | return this._vue.$data.$root;
|
39 | }
|
40 |
|
41 | destroy() {
|
42 | this._bridge.offAuth(this._rootUrl, this._handleAuthChange, this);
|
43 | this._vue.$destroy();
|
44 | }
|
45 |
|
46 | authenticate(token) {
|
47 | this._auth.serial++;
|
48 | return this._dispatcher.execute(
|
49 | 'auth', 'authenticate', new Reference(this._tree, '/'), token, () => {
|
50 | return this._bridge.authWithCustomToken(this._rootUrl, token);
|
51 | }
|
52 | );
|
53 | }
|
54 |
|
55 | unauthenticate() {
|
56 |
|
57 |
|
58 |
|
59 | this._auth.serial++;
|
60 | return this._handleAuthChange(null).then(approved => {
|
61 |
|
62 |
|
63 | if (!approved) return;
|
64 | return this._dispatcher.execute(
|
65 | 'auth', 'unauthenticate', new Reference(this._tree, '/'), undefined, () => {
|
66 | return this._bridge.unauth(this._rootUrl);
|
67 | }
|
68 | );
|
69 | });
|
70 | }
|
71 |
|
72 | _handleAuthChange(user) {
|
73 | const supersededChange = !this._auth.initialAuthChangeReceived && this._auth.serial;
|
74 | if (user !== undefined) this._auth.initialAuthChangeReceived = true;
|
75 | if (supersededChange) return;
|
76 | const authSerial = this._auth.serial;
|
77 | if (this.root.user === user) return Promise.resolve(false);
|
78 | return this._dispatcher.execute('auth', 'certify', new Reference(this._tree, '/'), user, () => {
|
79 | if (this.root.user === user || authSerial !== this._auth.serial) return false;
|
80 | if (user) Object.freeze(user);
|
81 | this.root.user = user;
|
82 | this.root.userid = user && user.uid;
|
83 | angular.digest();
|
84 | return true;
|
85 | });
|
86 | }
|
87 |
|
88 | _isAuthChangeStale(user) {
|
89 | return this.root.user === user;
|
90 | }
|
91 |
|
92 | _connectInfoProperty(property, attribute) {
|
93 | const propertyUrl = `${this._rootUrl}/.info/${property}`;
|
94 | this._bridge.on(propertyUrl, propertyUrl, null, 'value', snap => {
|
95 | this.root[attribute] = snap.value;
|
96 | angular.digest();
|
97 | });
|
98 | }
|
99 | }
|