UNPKG

webcom-reach

Version:
200 lines (192 loc) 5.54 kB
import * as DataSync from './util/DataSync'; import cache from './util/cache'; import * as Log from './util/Log'; import Room from './Room'; import Device from './Device'; import {CONNECTED, NOT_CONNECTED} from './util/constants'; import Webcom from 'webcom/webcom'; let initializing = false; /** * User informations * @public */ export default class User { /** * Create a user * @param {Webcom/api.DataSnapshot|object} snapData The data snapshot * @access protected */ constructor(snapData) { const values = Object.assign({}, snapData.val()); /** * User's unique id * @type {string} */ this.uid = snapData.name(); /** * User's display name * @type {string} */ this.name = values.name; /** * User's status * @type {string} */ this.status = values.status; /** * User's last know connection ts * @type {number} */ this.lastSeen = values.lastSeen; /** * Indicates if the user is an anonymous user * @type {boolean} */ this.anonymous = /^anonymous/.test(values.provider); // TODO #Feat: Add 'extra' property for unrestricted additional information ? } /** * Invite a user directly. This will create a new Room, log you in it & invite the user. * @param {string} [message] a message to add to the invite * @return {Promise<{room: Room, invite: Invite}, Error>} */ invite(message) { if(!cache.user) { return Promise.reject(new Error('Only an authenticated user can invite another User.')); } return Room.create(`${cache.user.uid}-${this.uid}`) .then(room => { return room.invite([this], null, message); }) .then(data => { return {room: data.room, invite: data.invites[0]}; }) .catch(Log.r('User~invite')); } /** * List Users's devices. Only for current user. * @access protected * @return {Promise<Device[], Error>} */ devices() { return DataSync.list(`_/devices/${this.uid}`, Device); } /** * Init the current user * @access protected * @param {json} auth The user's identity (webcom JSON structure) * @param {string} [name] The user's display name * @returns {Promise<User, Error>} */ static init (auth, name) { const uid = auth.uid; if(!initializing) { initializing = true; const d = {status: CONNECTED, lastSeen: DataSync.ts(), provider: auth.provider}; if(name) { Object.assign(d, {name}); } let deviceId = Webcom.INTERNAL.PersistentStorage.get(uid); return DataSync.update(`users/${uid}`, d) // Register current device .then(() => { const deviceMetadata = { status: CONNECTED, sdk: { reach: SDK_VERSION, webcom: Webcom.SDK_VERSION }, userAgent: navigator.userAgent }; cache.userAgent = deviceMetadata.userAgent; if(deviceId) { return DataSync.update(`_/devices/${uid}/${deviceId}`, deviceMetadata); } return DataSync.push(`_/devices/${uid}`, deviceMetadata); }) // Save device .then(deviceRef => { if (!deviceId) { deviceId = deviceRef.name(); Webcom.INTERNAL.PersistentStorage.set(uid, deviceId); } cache.device = deviceId; }) // Add onDisconnect actions .then(() => { // Disconnect device DataSync.onDisconnect(`_/devices/${uid}/${deviceId}/status`).set(NOT_CONNECTED); // Update user status DataSync.onDisconnect(`users/${uid}`).update({ status: NOT_CONNECTED, lastSeen: DataSync.ts() }); }) // Get user .then(() => User.get(uid)) .then(user => { initializing = false; return user; }) .catch(e => { Log.e(e); initializing = false; return Promise.reject(e); }); } return User.get(uid); } /** * Disconnect the current user * @access protected * @param {User} user The current user * @returns {Promise} */ static disconnect(user) { // Cancel onDisconnect DataSync.onDisconnect(`_/devices/${user.uid}/${cache.device}/status`).cancel(); DataSync.onDisconnect(`users/${user.uid}`).cancel(); if(user.anonymous) { return DataSync.remove(`_/devices/${user.uid}`) .then(() => DataSync.get(`_/invites/${user.uid}`)) .then(invites => { const inviteIds = []; invites.forEach(invite => { inviteIds.push(invite.name()); }); return Promise.all(inviteIds.map(inviteId => DataSync.remove(`_/invites/${user.uid}/${inviteId}`))); }) // TODO refactor data model for invites so we can delete _/invites/${user.uid} // .then(() => DataSync.remove(`_/invites/${user.uid}`)) .then(() => DataSync.remove(`users/${user.uid}`)) .then(() => { Webcom.INTERNAL.PersistentStorage.remove(user.uid); }) .catch(Log.r('User#anonymous_disconnect')); } return DataSync.set(`_/devices/${user.uid}/${cache.device}/status`, NOT_CONNECTED) .then(() => DataSync.get(`_/devices/${user.uid}`)) .then(devices => { // Only change user's status if no other device connected const hasConnectedDevices = devices.forEach(device => { return (new RegExp(`^${CONNECTED}$`)).test(device.val().status); }); if(!hasConnectedDevices) { return DataSync.update(`users/${user.uid}`, {status: NOT_CONNECTED}); } return true; }) .catch(Log.r('User#disconnect')); } /** * Get a user by its uid * @access private * @param {string} uid The user's uid * @returns {Promise<User, Error>} */ static get(uid) { return DataSync.get(`users/${uid}`) .then(snapData => snapData ? new User(snapData) : null) .catch(Log.r('User#get')); } }