hotplate.hotEvents.onCollect( 'stores', 'hotCoreStoreLogger', hotplate.cacheable( function( done ){ hotCoreStore.get( function( err, s ){ if( err ) return done( err ); var BasicDbStore = s.BasicDbStore; var BasicSchema = s.BasicSchema; var Log = declare( [ BasicDbStore ], { schema: new BasicSchema({ logLevel : { type: 'number', required: true, default: 1 }, error : { type: 'serialize', required: false }, errorName : { type: 'string', required: false }, errorMessage: { type: 'string', required: false }, errorStack : { type: 'string', required: false }, errors : { type: 'serialize', required: false }, message : { type: 'string', required: false }, data : { type: 'serialize', required: false }, loggedOn : { type: 'date', required: true, default: function(){ return new Date() } }, workspaceId: { type: 'id' }, userId : { type: 'id', required: false }, system : { type: 'boolean', required: true, defaule: false }, }), storeName: 'log', paramIds: [ 'id' ], }); stores.log = new Log(); done( null, stores ); }); }));
hotplate.hotEvents.onCollect('stores', 'hotCoreComet', hotplate.cacheable(function (done) { // This module only uses JsonRestStores as a way to access the DB and expose methods, // it doesn't mixin with hotJsonRestStores (which would do Comet event emission etc.) hotCoreStore.get(function (err, s) { if (err) return done(err) var BasicDbStore = s.BasicDbStore var BasicSchema = s.BasicSchema var HotStore = s.HotStore var HotSchema = s.HotSchema // *********************************** // *** OPEN TABS ******************* // *********************************** var Tabs = declare(HotStore, { schema: new BasicSchema({ id: { type: 'string', searchable: true, unique: true }, lastSync: { type: 'date', searchable: true, default: function () { return new Date() } } }), handlePost: true, handleDelete: true, storeName: 'tabs', paramIds: [ 'id' ] /* nested: [ { type: 'multiple', store: 'tabMessages', join: { tabId: 'tabId'}, }, ] */ }) stores.tabs = new Tabs() // Internal store, only used via API var TabMessages = declare(BasicDbStore, { schema: new BasicSchema({ message: { type: 'serialize', required: true }, added: { type: 'date', searchable: true, protected: true, default: function () { return new Date() } }, tabId: { type: 'string', searchable: true, required: true } }), paramIds: [ 'id' ], storeName: 'tabMessages', autoLookup: { tabId: 'tabs' }, sortableFields: [ 'added' ], defaultSort: { added: 1 } }) stores.tabMessages = new TabMessages() // Internal store, only used via API var TabSubscriptions = declare(BasicDbStore, { schema: new BasicSchema({ added: { type: 'date', protected: true, searchable: true, default: function () { return new Date() } }, tabId: { type: 'string', searchable: true, required: true }, handle: { type: 'string', searchable: true, required: true, trim: 255 }, p1: { type: 'string', searchable: true, required: false, trim: 1024 }, p2: { type: 'string', searchable: true, required: false, trim: 1024 }, p3: { type: 'string', searchable: true, required: false, trim: 1024 }, p4: { type: 'string', searchable: true, required: false, trim: 1024 }, hash: { type: 'string', searchable: true, required: false, trim: 1024 } }), paramIds: [ 'id' ], storeName: 'tabSubscriptions' }) stores.tabSubscriptions = new TabSubscriptions() // FINISHED var UserOnline = declare([JsonRestStores, JsonRestStores.HTTPMixin], { schema: new HotSchema({ userId: { type: 'id' } }), handleGet: true, storeName: 'userOnline', publicURL: '/userOnline/:userId', hotExpose: true, implementFetchOne: function (request, cb) { consolelog('*************************Checking online status of:', request.params.userId) consolelog('Connections:', connections) for (var k in connections) { var $c = connections[ k ] consolelog('CHECKING: ', request.params.userId, $c.userId, $c.loggedIn, $c.ws && $c.ws.readyState) if ($c && $c.userId && $c.loggedIn && request.params.userId.toString() === $c.userId.toString() && $c.ws && $c.ws.readyState === 1) { consolelog('Returning YES!') return cb(null, { online: true }) } } consolelog('Returning NO!') return cb(null, { online: false }) } }) stores.userOnline = new UserOnline() done(null, stores) }) }))
hotplate.hotEvents.onCollect('setRoutes', 'hotCoreComet', function (app, done) { hotCoreStore.get(function (err, s) { if (err) return done(err) Object.keys(s.HotStore.registry).forEach((k) => { var store = s.HotStore.registry[ k ] if ((store.emitCometDbEvents) && store.dbLayer) { [ 'simpledblayer-update-one', 'simpledblayer-delete-one', 'simpledblayer-insert' ].forEach((op) => { consolelog('Adding listener for', store.storeName, 'for op:', op) store.dbLayer.onCollect(op, function (info, cb) { var k consolelog('SPROUT: DB OP ', op, 'WILL GENERATE A COMET EVENT. INFO:', require('util').inspect(info, { dpeth: 1 })) // WAIT. If the query was initiated within JsonRestStores, and the store is also store-aware, // will stop here since stores with both emitCometStoreEvents and emitCometDbEvents will // generate TWO events per REST call if (info.options.fromJsonRestStores && store.emitCometStoreEvents) { consolelog('Quitting, since this DB query came from JsonRestStores, and this store ALREADY has emitCometStoreEvents on') return cb(null) } // Suppress comet messages if (info.options.noComet) { consolelog('Quitting, since noComet is on') return cb(null) } // TEMPORARY // if( ! info.options.request ){ // console.log("WARNING: REQUEST NOT PASSED IN OPTION", info ); // } // console.log("OPTION REQUEST:", info.options.request ); var request = info.options.request || {} var sessionData = request.session || {} // Make a new request object that is a mere approximation of a "real" // JsonRestStores request object, borrowing as much as possible from // the "original" one. var newRequest = {} for (k in request) { newRequest[ k ] = request[ k ] } newRequest.body = info.record newRequest.params = [] newRequest.data = [] for (k in request.data) { newRequest.data[ k ] = request.data } newRequest.data.doc = info.recordBefore newRequest.data.fullDoc = info.recordBefore newRequest.data.docAfter = info.record newRequest.data.fullDocAfter = info.record newRequest.fromDbComet = true var method = { 'simpledblayer-update-one': 'put', 'simpledblayer-delete-one': 'delete', 'simpledblayer-insert': 'post' }[op] store.prepareBeforeSendProxy(newRequest, method, info.record, function (err, preparedDoc) { if (err) { logger.log({ error: err, system: true, logLevel: 3, message: 'Error preparing doc using prepareBeforeSendProxy' }) cb(null) } consolelog("Session data from db's 'request' option:", sessionData) /* stores.tabs.dbLayer.select( { }, function( err, tabs ){ if( err ){ logger.log( { error: err, system: true, logLevel: 3, message: "Error selecting tabs from db" } ); cb( null ); } */ var message = { type: 'store-change', op: method, record: info.record, storeName: store.storeName, fromDb: true } if (op === 'simpledblayer-update-one') message.existing = true if (op === 'simpledblayer-insert') message.new = true // This will only work if the store was enriched with the // Comet mixin _and_ the client sent the tabId if (request.data && request.data.fromTabId) { var fromTabId = request.data.fromTabId consolelog('Store is comet-emabled, it will also have a fromTabId:', fromTabId) } var cometEvent = { message: message, sessionData: sessionData, fromClient: false, fromTabId: fromTabId, store: store } var ce = cometEvent consolelog('Comet event: ', { message: ce.message, sessionData: ce.sessionData, connections: ce.connections, tabs: ce.tabs }) // The message doesn't have tabId, since... it can't. emitAndSendMessages(cometEvent, function (err) { if (err) consolelog('Error runnign emitAndSendMessages:', err) cb(null) }) // }); }) }) }) } }) // All listeners are set! done(null) }) })