UNPKG

@blockv/sdk

Version:

Allows web apps to display and interact with vatoms.

197 lines (162 loc) 6.79 kB
/* gloabl Events */ import BLOCKvRegion from './BLOCKvRegion' import DataObject from '../DataObject' import Events from '../EventEmitter' /** * This region plugin provides access to a collection of vatoms that has been dropped within the specified region on the map. * * To get an instance, call `DataPool.region('geopos', { top_right: { lat: ..., lon: ... }, bottom_left: { lat: ..., lon: ... } })` */ export default class GeoPosRegion extends BLOCKvRegion { /** Plugin ID */ static get id () { return 'geopos' } /** Constructor */ constructor (dataPool, coordinates) { super(dataPool) // Don't cache this content this.noCache = true // Fail if coordinates are invalid if (!coordinates || !coordinates.top_right || !coordinates.top_right.lat || !coordinates.top_right.lon || !coordinates.bottom_left || !coordinates.bottom_left.lat || !coordinates.bottom_left.lon) { throw new Error('Please specify the top_right and bottom_left coordinates in the region descriptor.') } // Store coordinates this.coordinates = coordinates // Send region command to the WebSocket this.sendRegionCommand() // Listen for events this.onWebSocketOpen = this.onWebSocketOpen.bind(this) this.socket.addEventListener('connected', this.onWebSocketOpen) } /** Called when this region is going to be shut down */ close () { super.close() // Remove listeners this.socket.removeEventListener('connected', this.onWebSocketOpen) } /** Called when the WebSocket connection re-opens */ onWebSocketOpen () { this.sendRegionCommand() } /** Sends the region command up the websocket to enable region monitoring */ sendRegionCommand () { // Convert our coordinates into the ones needed by the command let topLeft = { lat: Math.max(this.coordinates.top_right.lat, this.coordinates.bottom_left.lat), lon: Math.min(this.coordinates.top_right.lon, this.coordinates.bottom_left.lon) } let bottomRight = { lat: Math.min(this.coordinates.top_right.lat, this.coordinates.bottom_left.lat), lon: Math.max(this.coordinates.top_right.lon, this.coordinates.bottom_left.lon) } // Create command payload let cmd = { id: '1', version: '1', type: 'command', cmd: 'monitor', payload: { top_left: topLeft, bottom_right: bottomRight } } // Send it up console.log('Sending WS command: ' + JSON.stringify(cmd)) // this.dataPool.Blockv.WebSockets.sendMessage(cmd) } /** Our state key is the region */ get stateKey () { return 'geopos:' + this.coordinates.top_right.lat + ',' + this.coordinates.top_right.lon + ' ' + this.coordinates.bottom_left.lat + ',' + this.coordinates.bottom_left.lon } /** Check if a region request matches our region */ matches (id, descriptor) { // Check all filters match if (id !== 'geopos') return false if (!descriptor || !descriptor.top_right || !descriptor.bottom_left) return false if (descriptor.top_right.lat !== this.coordinates.top_right.lat) return false if (descriptor.top_right.lon !== this.coordinates.top_right.lon) return false if (descriptor.bottom_left.lat !== this.coordinates.bottom_left.lat) return false if (descriptor.bottom_left.lon !== this.coordinates.bottom_left.lon) return false // Yes they do return true } /** Load current state from the server */ async load () { // Pause websocket events this.pauseMessages() // Fetch data let response = await this.dataPool.Blockv.client.request('POST', '/v1/vatom/geodiscover', { top_right: this.coordinates.top_right, bottom_left: this.coordinates.bottom_left, filter: 'all', limit: 10000 }, true) // Add vatom to new objects list let objects = [] response.vatoms.map(v => new DataObject('vatom', v.id, v)).forEach(f => objects.push(f)) // Add faces to new objects list response.faces.map(f => new DataObject('face', f.id, f)).forEach(f => objects.push(f)) // Add actions to new objects list response.actions.map(a => new DataObject('action', a.name, a)).forEach(a => objects.push(a)) // Add new objects this.addObjects(objects) // Resume websocket messages this.resumeMessages() // Return array of IDs return objects.map(o => o.id) } /** This region type should not be cached */ save () {} /** Don't return vatoms which are not dropped */ map (object) { // Check if dropped if (object.data && object.data['vAtom::vAtomType'] && object.data['vAtom::vAtomType'].dropped) { return super.map(object) } // Vatom is not dropped! return null } /** * Processes a WebSocket message. * * @private Called by BVWebSocketRegion. * @abstract Subclasses can override to process other WebSocket messages. Always call super.processMessage(msg) though. * @param {Object} msg The raw JSON from the websocket event message */ processMessage (msg) { super.processMessage(msg) // Get vatom ID let vatomID = msg.payload && msg.payload.id if (!vatomID) { return console.warn(`[DataPool > BVWebSocketRegion] Got websocket message with no vatom ID in it: `, msg) } // Check if this is a newly dropped vatom let dropped = msg.payload.new_object && msg.payload.new_object['vAtom::vAtomType'] && msg.payload.new_object['vAtom::vAtomType'].dropped if (msg.msg_type !== 'state_update' || !dropped) { return } // Check if we already have this vatom if (this.objects.get(vatomID)) { return } // A new vatom was dropped! Pause WebSocket message processing this.pauseMessages() // Fetch vatom payload this.dataPool.Blockv.client.request('POST', '/v1/user/vatom/get', { ids: [vatomID] }).then(response => { // Add vatom to new objects list let objects = [] objects.push(new DataObject('vatom', response.vatoms[0].id, response.vatoms[0])) // Add faces to new objects list response.faces.map(f => new DataObject('face', f.id, f)).forEach(f => objects.push(f)) // Add actions to new objects list response.actions.map(a => new DataObject('action', a.name, a)).forEach(a => objects.push(a)) // Add new objects this.addObjects(objects) }).catch(err => { // Log it console.warn(`[DataPool > GeoPosRegion] A vatom was dropped, bbut we could not fetch it's payload! ` + err.message) }).then(e => { // Resume message processing this.resumeMessages() }) } }