#!/usr/bin/env node // Concepto TI DSL LIVE /* - inicialmente asociado a ti.dsl (hacer agnostico despues) 1. saludar en consola (todo hacer config.json para considerar opciones o usar argumentos) 1.1 se debe ejecutar en la carpeta del proyecto donde estan los archivos 'live_*.json' :: OK! 2. se debe conectar (o intentar cada x segundos) a Concepto en modo Live (usando smart.js->bridge) :: OK! 3. se debe conectar (o intentar cada x segundos) a TiShadow socket (puerto 3000) (usando ts.js) 4. cuando el punto 4 y 5 esten ok: 4.1 debe leer archivo app/live_properties.json de proyecto actual y dejar en memoria. :: OK! 4.2 debe leer archivo app/live_styles.json de proyecto actual y dejar en memoria. 5. leer cada transaccion y llamar funcion procesarTransaccion(nodo) :: OK! 5.1 ver si nodeid existe como llave en live_properties de memoria (4.2). :: OK! 5.2 ve si atributo tiene match en registro identificado de live_properties del punto 5.1 :: OK! 5.3 reemplazar de contenidos texto 'nodeid' por valor de nuestro nodo (getSpy('nodeid').) y dejar string en temporal. :: OK! 5.3 si tiene llave 'before_set', asignar valor de atributo a var temp 'setvalue' y asignar a string a enviar. :: OK! 5.4 si tiene llave 'set' asignar contenido a string a enviar: ej: getSpy('nodeid').setTitle(setvalue).. :: OK! */ var bridge = require('./smart'); var tis = require('./ts.js'); var apple = require('./apple'); var notifier = require('node-notifier'); var watch = require('node-watch'); // watched file changes. var jsonfile = require('jsonfile') var fs = require('fs'); var path = require('path'); var cheerio = require('cheerio'); var _colors = require('colors'); var pkginfo = require('pkginfo')(module); var args = process.argv.slice(2), cwd = '', lprop = ''; var nodes = {}, nodes_meta = {}, last_cmd = ''; var $; // define here all files that must be read (key)->live_key.json var _live = { properties : {}, //style : {} }; var _config = { title: 'Concepto DSL Live Mode', dsl: 'ti.dsl', ti_connected: false, live_retry_delay: 2000 }; if (args.length>0) { // tiene un argumento (directorio del proyecto) cwd = args[0]; } else { // no tiene un argumento, intentamos usar directorio en donde estamos cwd = process.cwd(); } // SEND WELCOME MESSAGE consoleTitle('Concepto DSL Live Mode Bridge :: ver '+module.exports.version,'yellow','magenta'); // READ DSL AND JSON FILES loadLive(cwd, function(){ // read json files loadJSON(cwd); }); var _startAll = function() { if (last_cmd!='_startAll') { console.log('bridge:on'.underline.green); // if live on, execute update on json properties : 14-1-2016 PSB loadJSON(cwd); // TI SHADOW SOCKET tis.disconnect(); var socket = tis.connect( function(e) { //console.log("shadow:connected.\n".green); _config.ti_connected = true; // try to start Concepto Live Bridge bridge.init(function(){}); // }, function(msg) { console.log("shadow:message received:".green,msg); }, function() { // on error //console.log("shadow:disconnected.\n".red); _config.ti_connected = false; } ); last_cmd = '_startAll'; } }; var _stopAll = function() { if (last_cmd!='_stopAll') { console.log('bridge:off'.underline.red+'\n\n'); if (_config.ti_connected==true) { // desconectamos ti_shadow tis.disconnect(); //console.log("shadow:disconnected.\n\n".green); } last_cmd = '_stopAll'; } }; // MONITOR OPEN PORTS var portastic = require('portastic'); var monitor = new portastic.Monitor([3000,9000]); var _live_running = false, _ts_running = false; monitor.on('close', function(port) { // seems monitos close/open are inverted. if (port==9000) { _live_running = true; //console.log('concepto live seems running'); } else { // tishadow server is online _ts_running = true; //console.log('tishadow seems running'); } // only run if both ports are opened if (_live_running==true && _ts_running==true) { //console.log('both servers seems running: calling startAll'); _startAll(); } }); monitor.on('open', function(port) { if (port==9000) { // concepto mode live is deactivated _live_running = false; //console.log('concepto live seems stop'); } else { // tishadow server is offline _ts_running = false; //console.log('tishadow seems stop'); } // _stopAll(); }); // WATCH FILE CHANGES (ti.dsl and live_*.json) var files_to_watch = [path.join(cwd,'ti.dsl')]; for (var el in _live) { files_to_watch.push('live_'+el+'.json'); var ltmp = path.join(cwd, 'live_'+el+'.json'); } watch(files_to_watch, function(file) { // we should call LoadLive(cwd); console.log('watch:file:'.grey+file.yellow+', changed.'); if (file.indexOf('.json')!=-1) { loadJSON(cwd); console.log('watch:json reloaded'); } else { loadLive(cwd, function(){}, function(){}); console.log('watch:dsl reloaded'); } }); // CONCEPTO DSL LIVE MODE (bridge) events var slow_ping = 0; bridge.on({ '_error' : function(error) { // error connecting to concepto - bridge //console.log('live:error connecting:retrying in 3 seconds'.grey); /*setTimeout(function(){ bridge.destroy(); bridge.init(function(){}); }, 3000);*/ }, 'who_are_you' : function(data) { bridge.send.login('nexo'); console.log('live:login sent'.yellow); // Concepto DSL Bridge Ready apple.say('Laiv conectado.'); console.log('live:welcome'.green); notifier.notify({ 'title': _config.title, 'message': 'Bridge Activated', sound: false }); }, 'user_information' : function(data) { slow_ping++; if (slow_ping%5==0) { console.log('live:ping ..'.grey); } }, 'welcome' : function(data) { //console.log('live:welcome:'.green,data); }, 'goodbye' : function(data) { apple.say('laiv desconectado.'); console.log('live:goodbye'.yellow); }, 'transaction' : function(data) { if (bridge.getLastID()!=data['$'].id) { // solo ejecutamos transaccion si no fuimos nosotros mismos. bridge.parseXml(data['$'].do_action, function(tag, js) { var nodeid = ''; if ('$' in js && 'node' in js['$']) nodeid = js['$'].node; if (nodeid!='') { var accion = tag.split('_').join(' '); switch(tag) { case 'insert_attribute_elementary_action': case 'set_attribute_name_elementary_action': var _row = ('row' in js.$)? eval(js.$.row) : 0; //console.log('fila en donde quiero insertar atributo:'+_row); if (nodeid in nodes==false) nodes[nodeid] = []; if (!nodes[nodeid][_row]) nodes[nodeid][_row]={}; nodes[nodeid][_row].name = js.$.name; break; case 'edit_node_action': case 'set_attribute_value_elementary_action': if ('text' in js) { // se solicito modificar el nodo: text (usamos nodes_meta) if (nodeid in nodes_meta==false) nodes_meta[nodeid] = { _text:'', _color:'', _bgcolor:'', _icons:'' }; if (js.text[0].indexOf(' max_len) { max_len = message.split('\n')[lines].length; } } } else { // single line message max_len = message.length; to_show_open = Array(max_len+(left_right_margin*2)).join('*') + '\n'; to_show_open += left_right_chars + Array(left_right_space).join(' '); if (bordercolor) to_show_open = _colors[bordercolor](to_show_open); if (color) { to_show = _colors[color](message); } else { to_show = message; } to_show_close += Array(left_right_space).join(' ') + left_right_chars + '\n'; to_show_close += Array(max_len+(left_right_margin*2)).join('*') + '\n'; if (bordercolor) to_show_close = _colors[bordercolor](to_show_close); // glue message to_show = to_show_open + to_show + to_show_close; } console.log(to_show); } function fileExists(filePath) { try { return fs.statSync(filePath).isFile(); } catch (err) { return false; } } function getHash(str) { var hash = 5381, i = str.length while(i) hash = (hash * 33) ^ str.charCodeAt(--i) /* JavaScript does bitwise operations (like XOR, above) on 32-bit signed * integers. Since we want the results to be always positive, convert the * signed int to an unsigned by doing an unsigned bitshift. */ return hash >>> 0; }