UNPKG

appsapp-cli

Version:

This command line program is the important counterpart of appsapp-module for connecting built-in or custom backend services.

332 lines (331 loc) 11.3 kB
"use strict"; /** * Copyright (c) 2017 by Michael Egli * * * * firebase database structure * * - user * --- {userid} * ----- storage * ------ {object} business objects * ------- {objectid} business object identifier / single record * --------- version (mixed, timestamp|uui|identifier) change it to fetch current content data from api * --------- data (mixed) * ---------- bind (mixed) json data of current version (is three way binding to client) * ---------- stable (mixed) json data of current version (is last version of fetched data) * --------- saved (mixed, timestamp|uui|identifier) change or set it to save current bind data back to api * ----- profile * ------ userid (integer) * ------ name (string) * ------ lastname (string) * ------ email (string) * ----- history (old and new values are stored here) * ----- notification (realtime notification to user) * */ Object.defineProperty(exports, "__esModule", { value: true }); const firebase = require("firebase-admin"); const angular2_uuid_1 = require("angular2-uuid"); const path = require("path"); const chalk = require("chalk"); const clear = require("clear"); const clui = require("clui"); const figlet = require("figlet"); process.argv.forEach((val, index) => { require('app-module-path').addPath(path.dirname(val) + path.sep + 'node_modules'); }); /** * constructor loader */ var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; class Connector { /** * * constructs the connector * * @return void * */ constructor() { this.watchers = []; this.isWatching = false; this.output = { clear: () => { clear(); }, log: (message) => { console.log(message); }, figlet: (message) => { console.log(chalk.default(figlet.textSync(message, { horizontalLayout: 'full' }))); }, spinner: (message, callback) => { var status = new clui.Spinner(message); status.start(); return callback(status); } }; } /** * * init app * * @param string databaseURL of firebase database endpoint * @param string serviceAccountKey file content as json * @return mixed * */ init(databaseURL, serviceAccountKey) { /** * initialize firebase admin */ firebase.initializeApp({ credential: firebase.credential.cert(serviceAccountKey), databaseURL: databaseURL }); this.db = firebase.database(); this.watchers = []; this.loadModels(); return this; } /** * load all models from config constructors */ loadModels() { var self = this; this.db.ref('_config').once('value', (snapshot) => { var config = snapshot.val(); if (!self.isWatching) { self.watch(); } /** * first eval */ Object.keys(config).forEach((model) => { if (config[model].constructor !== undefined) { try { eval(Buffer.from(config[model].constructor, 'base64').toString()); } catch (e) { // skip } } }); /** * second eval, must be done two times because of self-referencing injections */ Object.keys(config).forEach((model) => { if (config[model].constructor !== undefined) { try { eval(Buffer.from(config[model].constructor, 'base64').toString()); } catch (e) { console.log(e); } } }); }); this.db.ref('_config').on('child_changed', (snapshot) => { var config = snapshot.val(); if (config.constructor !== undefined) { try { eval(Buffer.from(config.constructor, 'base64').toString()); } catch (e) { // skip } try { eval(Buffer.from(config.constructor, 'base64').toString()); } catch (e) { // skip } } }); } /** * * push notification to user if he's online * * @param string userid * @param string title * @param integer time * @return void * */ message(userid, title, time) { var self = this; var u = new angular2_uuid_1.UUID(); this.db.ref('user/' + userid + '/notification/' + u).set(title); setTimeout(function () { self.db.ref('user/' + userid + '/notification/' + u).remove(); }, time ? time : 3000); } /** * * push error notification to user if he's online * * @param string userid * @param string title * @param integer time * @return void * */ error(userid, title, time) { var self = this; var u = new angular2_uuid_1.UUID(); this.db.ref('user/' + userid + '/error/' + u).set(title); setTimeout(function () { self.db.ref('user/' + userid + '/error/' + u).remove(); }, time ? time : 3000); } /** * * push warning notification to user if he's online * * @param string userid * @param string title * @param integer time * @return void * */ warning(userid, title, time) { var self = this; var u = new angular2_uuid_1.UUID(); this.db.ref('user/' + userid + '/warning/' + u).set(title); setTimeout(function () { self.db.ref('user/' + userid + '/warning/' + u).remove(); }, time ? time : 3000); } /** * * watch for firebase events * * @return void * */ watch() { /** * watch for events and connect signal slots */ var self = this; self.isWatching = true; this.db.ref("_queue").on("child_added", function (snapshot) { self.executeQueue(snapshot); }); } /** * * execute queue from snapshot data * @param snapshot * @return void * */ executeQueue(snapshot) { var self = this; var e = snapshot.val(); var eventId = snapshot.key; self.watchers.forEach(function (watcher) { if ((e.object === watcher.object || watcher.object === null) && (e.project === watcher.project || watcher.project === null) && ((e.action.data !== undefined && e.action.data.name === watcher.action) || watcher.action === null)) { if (e.object === undefined || e.action.state == 'done') { self.db.ref('_queue/' + eventId).remove(() => { // removed old queue entry }); } else { let model = new global[e.object], data = model.loadJson(e.snapshot); watcher.callback({ user: e.user, object: e.object, objectId: e.objectid, project: e.project, action: e.action, eventId: eventId, }, data, { 'resolve': function () { data.validate().then(() => { e.action.state = 'done'; if (data.hasChanges()) { self.db.ref('_queue/' + eventId).update({ action: e.action, targetData: data !== undefined ? data.convertListPropertiesFromArrayToObject().serialize(true, true) : null }); } else { self.db.ref('_queue/' + eventId).update({ action: e.action }); } }).catch((error) => { e.action.state = 'error'; self.db.ref('_queue/' + eventId).update({ action: e.action, targetMessage: 'Validation error' }); console.log(error); }); }, 'reject': function (error) { e.action.state = 'error'; self.db.ref('_queue/' + eventId).update({ action: e.action, targetData: null, targetMessage: error !== undefined ? error : null }); } }); } } }); } /** * watch events * @param object params * @param function callback function (data,deferred) */ on(params, callback) { this.watchers.push({ object: params.object !== undefined ? params.object : null, action: params.action !== undefined ? params.action : null, project: params.project !== undefined ? params.project : null, callback: callback }); return this; } } exports.Connector = Connector;