Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

initial commit

  • Loading branch information...
commit dcd4fc102723b0812a66e88f6e430a4eea96b60b 0 parents
@juzna authored
22 README
@@ -0,0 +1,22 @@
+LiveConnect is set of tools, with which you can make live forms or tables easily.
+"Live" means that if someone changes the same entity, which you are just editing,
+you will see a notification. Or, when having a table displayed in your browser while
+someone else adds a new row into that table, you will get immediate response
+in updating that table. These are some examples, how LiveConnect can work.
+However, LiveConnect is a general tool for any features like this.
+
+LiveConnect is based on these libraries:
+ - Nette + Doctrine 2 ORM in PHP application
+ - Node.js as event subscriber and notifier
+ - jQuery + jQuery UI on client side
+ - Socket.IO for communication between client and server
+
+
+LiveConnect consists of these parts:
+ ....TODO: write more doc
+
+
+Dependancies:
+ - ActiveEntity from https://github.com/juzna/iManaJUZment/tree/56fc2e0542cee2fc81d28fe961de4fdfc5433d0a/app/classes/ActiveEntity
+
+
26 daemons/bootstrap.php
@@ -0,0 +1,26 @@
+<?php
+/**
+* Basic initializer for all daemons
+*/
+
+// absolute filesystem path to the application root
+define('APP_DIR', realpath(__DIR__ . '/../app/'));
+define('LIBS_DIR', realpath(APP_DIR . '/../libs/'));
+define('TMP_DIR', realpath(APP_DIR . '/../temp/'));
+define('LOG_DIR', realpath(APP_DIR . '/../log/'));
+
+require_once __DIR__ . '/common.php';
+
+// Flush automatically
+ob_implicit_flush(true);
+
+// Load Nette framweork
+require_once(LIBS_DIR . '/Nette/loader.php');
+
+use Nette\Environment;
+Nette\Debug::enable();
+Environment::loadConfig();
+
+// Load Doctrine as well
+if(isset($wantDoctrine) && $wantDoctrine) require_once APP_DIR . '/bootstrap-doctrine.php';
+
16 daemons/common.php
@@ -0,0 +1,16 @@
+<?php
+
+function runUnixSocketServer($name, $processor) {
+ // Create server on socket
+ $unixPath = TMP_DIR . '/sock/' . $name;
+ @unlink($unixPath);
+ if(!is_dir($socketDir = dirname($unixPath))) mkdir($socketDir, 0777);
+
+ $socket = new TServerSocket("unix://$unixPath", -1);
+ $socket->listen();
+ while(true) {
+ $socket->select($processor);
+ echo "."; flush();
+ }
+}
+
26 daemons/notify.php
@@ -0,0 +1,26 @@
+#!/usr/bin/php
+<?php
+/**
+* Send an event to LiveConnect server
+*/
+
+@list(, $userId, $table, $op) = $_SERVER['argv'];
+if(!isset($table)) die("Please pass arguments: user, table, operation!\n");
+
+require_once(__DIR__ . '/../bootstrap.php');
+$unixPath = TMP_DIR . '/sock/nagios-notify';
+
+$socket = new TSocket('localhost', 9090);
+//$transport = new TBufferedTransport($socket, 1024, 1024);
+$transport = new TFramedTransport($socket);
+$protocol = new TBinaryProtocol($transport, false, false);
+$client = new /*\Thrift\LiveConnect\*/LiveConnectClient($protocol);
+
+$oldData = array('name' => 'John');
+$newData = array('name' => 'Simon');
+
+$transport->open();
+$client->notify($userId, $table, $op, $oldData, $newData);
+$transport->close();
+
+echo "Message sent\n";
318 daemons/server.js
@@ -0,0 +1,318 @@
+/**
+ * LiveConnect server
+ *
+ * Will provide Thrift interface for communication with PHP
+ * and WebSockets (Socket.IO) interface for web clients
+ */
+
+var sys = require('sys'),
+ thrift = require('thrift'),
+ LiveConnectStub = require('../interface/gen-nodejs/LiveConnect.js'),
+ ttypes = require('../interface/gen-nodejs/liveconnect_types'),
+ http = require('http'),
+ io = require('socket.io'),
+ _;
+
+
+// Create thrift server
+var thriftServer = thrift.createServer(LiveConnectStub, {
+ notify: function(user, table, op, oldData, newData) {
+ console.log('Notify: ' + table);
+ ClientDB.onNotify.apply(null, arguments);
+ },
+
+ subscribe: function(clientKey, ev, timeout) {
+ // TODO: implement this method
+ },
+
+ unsubscribe: function(clientKey, ev) {
+ // TODO: implement this method
+ },
+
+ unsubscribeClient: function(clientKey) {
+ // TODO: implement this method
+ },
+
+ getSubscriptions: function() {
+ // TODO: implement this method
+ },
+
+ getClients: function() {
+ // TODO: implement this method
+ }
+});
+thriftServer.listen(9090);
+
+
+
+var ClientDB = {
+ // Counter of clients
+ counter: 0,
+
+ // Online counter
+ online: 0,
+
+ /**
+ * Storage for clients
+ * Each client has these properties:
+ * - sessionId - unique ID
+ * - registeredEvents: [ { table, operations[], columns[]?, conditions[{column, op, value}], expiry } ]
+ * - operations: either string 'all', or array with: add, edit, remove
+ *
+ */
+ storage: {},
+
+ /**
+ * Add new client and store it to storage
+ * @param Client Socket.IO client
+ */
+ add: function(client) {
+ // Increase counters
+ ClientDB.counter++;
+ ClientDB.online++;
+
+ // Store client
+ ClientDB.storage[client.sessionId] = client;
+
+ // Set-up basic properties
+ client.registeredEvents = [];
+ },
+
+ /**
+ * Dispatch incoming message
+ * @param client
+ * @param msg
+ */
+ onMessage: function(client, msg) {
+ var type = msg.messageType;
+ if(type in MessageHandlers) {
+ // Execute handler
+ var ret = MessageHandlers[type](client, msg);
+
+ // Send back response
+ if(typeof ret !== 'undefined') {
+ if(ret.__proto__ !== Object.prototype) ret = { data: ret }; // It's not plain object -> convert
+ ret.messageType = 'call-reply';
+ ret.sequenceId = msg.sequenceId;
+ if('memo' in msg) ret.memo = msg.memo;
+ client.send(ret);
+ }
+ }
+ },
+
+ onDisconnect: function(client) {
+ // Decrease counter
+ ClientDB.online--;
+
+ // Remove client from storage
+ delete ClientDB.storage[client.sessionId];
+ },
+
+ /**
+ * New notification received
+ */
+ onNotify: function(user, table, op, oldData, newData) {
+ // Prepare notification object to be sent to clients
+ var notification = {
+ user: user,
+ table: table,
+ operation: op,
+ oldData: oldData,
+ newData: newData
+ };
+
+ // Go thru all clients
+ for(var i in ClientDB.storage) {
+ var client = ClientDB.storage[i];
+
+ // Check their events
+ for(var j = 0; j < client.registeredEvents.length; j++) {
+ var ev = client.registeredEvents[j];
+
+ if(ClientDB.matchesEvent(ev, table, op, oldData, newData)) {
+ notification.id = ev.subscriptionId;
+ console.log('Sending notification to', client.sessionId, 'for subscription', ev.subscriptionId);
+ ClientDB.send(client, 'notify', notification);
+ }
+ }
+ }
+ },
+
+ /**
+ * Check if registered event (ev) matches the notification
+ * @param Object ev
+ * @param String table
+ * @param String op
+ * @param Object oldData
+ * @param Object newData
+ * @return bool
+ */
+ matchesEvent: function(ev, table, op, oldData, newData) {
+ // Is it our table?
+ if(typeof ev.table === 'string' && ev.table !== table) return false; // subscribed for string
+ if(ev.table instanceof Array && 'indexOf' in ev.table && ev.table.indexOf(table) == -1) return false; // subscribed for array
+
+ // Is it our operation?
+ if(ev.operations !== 'all' && ev.operations instanceof Array && ev.operations.indexOf(op) == -1) return false; // Not our op
+
+ // Try conditions
+ if(ev.conditions instanceof Array) {
+ for(var i = 0; i < ev.conditions.length; i++) {
+ if(!ClientDB.matchesCondition(ev.conditions[i], newData, oldData)) return false; // Doesn't match this cond
+ }
+ }
+
+ // Changes in columns we are interested in?
+ if(ev.columns && !ClientDB.columnsOfInterest(ev.columns, oldData, newData)) return false;
+
+ // All conditions passed
+ return true;
+ },
+
+ /**
+ * Test if notification matches to a condition
+ */
+ matchesCondition: function(cond, newData, oldData) {
+ return (newData || oldData) &&
+ (!newData || ClientDB._matchesCondition(cond, newData)) &&
+ (!oldData || ClientDB._matchesCondition(cond, oldData));
+ },
+
+ // Check if one condition matches
+ _matchesCondition: function(cond, object) {
+ var col = cond.column; // What column are we talking about?
+ var val = cond.value;
+
+ switch(cond.operation) {
+ case 'present':
+ case 1:
+ return (col in object) && (object[col] !== null);
+
+ case 'eq':
+ case 2:
+ return (col in object) && (object[col] == val);
+
+ // TODO: implement other operations
+ // lt = 3,
+ // lte = 4,
+ // gt = 5,
+ // gte = 6,
+
+ default:
+ return true;
+ }
+ },
+
+ // If change is in columns we care about
+ columnsOfInterest: function(cols, oldData, newData) {
+ if(!cols) return true;
+ for(var i = 0; i < cols.length; i++) {
+ var col = cols[i];
+ if((col in oldData) || (col in newData)) return true;
+ }
+
+ return false;
+ },
+
+ /**
+ * Send message to client
+ * @param client
+ * @param msgType
+ * @param msg
+ */
+ send: function(client, msgType, msg) {
+ msg.messageType = msgType;
+ client.send(msg);
+ }
+};
+
+var MessageHandlers = {
+ /**
+ * Get list of all available methods
+ */
+ availableMethods: function() {
+ return Object.keys(MessageHandlers);
+ },
+
+ /**
+ * Client wants to subscribe for a new event
+ * @param client
+ * @param msg: { event: { tbl, op, [ col ], [ cond ], timeout } }
+ */
+ subscribe: function(client, msg) {
+ var id = msg.id, eventRequests = msg.events, timeout = msg.timeout || 90;
+
+ for(var i = 0; i < eventRequests.length; i++) {
+ var ev = eventRequests[i];
+
+ // TODO: check if received valid event request
+
+ ev.subscriptionId = id;
+ ev.expire = (new Date).valueOf() + timeout * 1000; // Timeout in ms
+
+ // add to client
+ client.registeredEvents.push(ev);
+ }
+ },
+
+ extendSubscription: function(client, msg) {
+ // TODO:
+ },
+
+ unsubscribe: function(client, msg) {
+ // TODO:
+ },
+
+ /**
+ * Get client's ID
+ */
+ getId: function(client) {
+ return client.sessionId;
+ },
+
+ // Get number of online clients
+ getOnlineClientNum: function() {
+ return ClientDB.online;
+ },
+
+ // Get total number of clients ever connected
+ getTotalClientNum: function() {
+ return ClientDB.counter;
+ }
+
+};
+
+
+
+// Create HTTP server for Socket.IO
+server = http.createServer(function(req, res){
+ // your normal server code
+ res.writeHead(200, {'Content-Type': 'text/html'});
+ res.end('<h1>Hello world</h1>');
+});
+server.listen(9091);
+
+// socket.io, I choose you
+var socketIO = io.listen(server, {
+ transports: [ 'websocket' ]
+});
+socketIO.on('connection', function(client){
+ ClientDB.add(client);
+
+ // new client is here!
+ client.on('message', function(msg) {
+ try {
+ ClientDB.onMessage(client, msg);
+ }
+ catch(e) {
+ console.log('Exception on client', client.sessionId, ':', e);
+ client.send({ messageType: 'exception', error: e.toString() });
+ client.disconnect();
+ ClientDB.onDisconnect(client);
+ }
+ });
+
+ client.on('disconnect', function() {
+ ClientDB.onDisconnect(client);
+ })
+});
102 document_root/js/liveconnect-form.js
@@ -0,0 +1,102 @@
+/**
+ * This file is part of the "iManaJUZment" - complex system for internet service providers
+ *
+ * Copyright (c) 2005 - 2011 Jan Dolecek (http://juzna.cz)
+ *
+ * iManaJUZment is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with iManaJUZment. If not, see <http://www.gnu.org/licenses/gpl.txt>.
+ *
+ * @license http://www.gnu.org/licenses/gpl.txt
+ */
+
+// Add handlers
+/*jQuery(function($) {
+ // On new nodes inserted into DOM
+ $(document).bind('DOMNodeInserted', function(ev) {
+ console.log(ev, ev.target);
+ $('form.liveconnect', ev.target).frmLiveConnect();
+ })
+
+ // When nodes are removed from the DOM
+ .bind('DOMNodeRemoved', function(ev) {
+ console.log(ev, ev.target);
+ $('form.liveconnect', ev.target).frmLiveConnect('destroy');
+ });
+});
+*/
+
+(function($) {
+
+$.widget("ui.frmLiveConnect", {
+ options: {
+ operations: ['edit', 2]
+ },
+
+ _create: function() {
+ var dataset = this.element[0].dataset;
+ this.entityName = dataset.entityname;
+ this.entityId = dataset.entityid;
+
+ if(!this.entityName || !this.entityId) return;
+ // console.log('Creating liveconnect form', this.entityName, this.entityId);
+
+ this.sId = LiveConnect.connect()
+ .subscribe( {
+ table: this.entityName,
+ operations: this.options.operations,
+ conditions: 'ID=' + this.entityId
+ }, $.proxy(this._onMessage, this) );
+ },
+
+ // General callback
+ _onMessage: function(what, msg) {
+ switch(what) {
+ case 'timeout-soft':
+ case 'timeout':
+ console.log('Liveconnect form timeout, refreshing');
+ return true;
+
+ case 'notify':
+ this._onNofitication(msg);
+ break;
+
+ default:
+ console.log('Liveconnect unknown event:', what, msg);
+ }
+ },
+
+ // Notification received from server
+ _onNofitication: function(msg) {
+ var self = this, data = msg.newData, numChanged = 0;
+ $(this.element[0].elements).each(function() {
+ var name = this.name, el = $(this);
+ if(name && name in data && el.val() != data[name]) {
+ console.log('Change detected', name, el.val(), data[name]);
+ numChanged++;
+
+ if(!el.data('live-changed')) {
+ el.after('<span style="color: red;">(changed)</span>');
+ el.data('live-changed', true);
+ }
+ }
+ });
+ console.log('Changed', numChanged);
+ },
+
+ destroy: function() {
+ console.log('Destroying liveconnect form', this.element);
+
+ // Unsubscribe
+ if(this.sId) LiveConnect.unsubscribe(this.sId);
+
+ // Default destructor
+ $.Widget.prototype.destroy.apply(this, arguments);
+ }
+});
+
+})(jQuery);
458 document_root/js/liveconnect.js
@@ -0,0 +1,458 @@
+/**
+ * This file is part of the "iManaJUZment" - complex system for internet service providers
+ *
+ * Copyright (c) 2005 - 2011 Jan Dolecek (http://juzna.cz)
+ *
+ * iManaJUZment is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with iManaJUZment. If not, see <http://www.gnu.org/licenses/gpl.txt>.
+ *
+ * @license http://www.gnu.org/licenses/gpl.txt
+ */
+
+
+/**
+ * Example:
+ * LiveConnect.connect()
+ * .subscribe('APIP')
+ * .subscribe('AP')
+ * .on('test', function(msg) {
+ * console.log('Got test event', msg);
+ * })
+ * .call('getId', {}, function(msg) {
+ * console.log('Got ID:', msg);
+ * });
+ */
+
+var LiveConnect = (function($) {
+ var socketIOAdded = false;
+ var reconnectTimeout = 300; // In ms
+ var reconnectCounter = 0;
+ var socket;
+ var handlers = {}; // Map: msgType -> [ cb ]
+ var connected = false;
+ var state = 'initial';
+ var messageBuffer = [];
+ var sequenceId = 0; // For calls
+ var callbacks = {}; // For calls
+ var subscriptions = {}; // Map: id -> { [eventRequests], cb, timeout }
+ var subscriptionCounter = 0;
+
+
+ /****** Connection *******/
+
+
+ // Add socket IO library
+ function addSocketIO() {
+ if(socketIOAdded) return; // It's already there
+
+ $('script:first').after($('<script src="http://' + window.location.host + ':9091/socket.io/socket.io.js" />'))
+ socketIOAdded = true;
+ }
+
+ // Try to connect
+ function connectionAttempt() {
+ addSocketIO();
+ var no = reconnectCounter++; // Number of this attempt
+
+ if(!connect()) {
+ state = 'failed';
+ console.log('Connect unsuccessfull, will retry in ', reconnectTimeout / 1000, 'seconds');
+ setTimeout(connectionAttempt, reconnectTimeout);
+ reconnectTimeout *= 2;
+ }
+ }
+
+ // Do the connection
+ function connect() {
+ console.log('Trying to connect');
+ if(!window.io || !window.io.Socket) return false;
+
+ socket = new io.Socket(undefined, {
+ port: 9091,
+ transports: [ 'websocket' ]
+ })
+ .connect()
+ .on('connect', onConnect)
+ .on('message', onMessage)
+ .on('disconnect', onDisconnect);
+
+ state = 'connecting';
+ return true;
+ }
+
+ // Connection is estabilished
+ function onConnect() {
+ connected = true;
+ state = 'connected';
+
+ if(messageBuffer.length) sendMessagesFromBuffer();
+ }
+
+ // Send all messages from buffer
+ function sendMessagesFromBuffer() {
+ var msg;
+ console.log('Sending', messageBuffer.length, 'messages from buffer');
+ while(msg = messageBuffer.shift()) socket.send(msg);
+ }
+
+ // Server has been disconnected
+ function onDisconnect() {
+ console.log('Disconnected');
+ socket = null;
+ connected = false;
+ state = 'disconnected';
+ }
+
+
+
+
+
+ /******* Common messaging ***********/
+
+ // New message received
+ function onMessage(msg) {
+ var type = msg.messageType, seqId = msg.sequenceId;
+
+ // Just log it for now
+ console.log('Received message', type, msg);
+
+ // Unknown type
+ if(!type) {
+ console.log('Unknown message', msg);
+ return;
+ }
+
+ // Call-reply
+ else if(type === 'call-reply') {
+ if(callbacks[seqId]) {
+ clearTimeout(callbacks[seqId].timeout); // Remove timeout
+
+ try {
+ (callbacks[seqId].success || function() {})(msg, callbacks[seqId]);
+ } catch(e) {
+ console.log('Error in LiveConnect callback', e);
+ }
+
+ // Remove from memory
+ delete callbacks[seqId];
+ }
+ else {
+ console.log('LiveConnect callback response, but no call with that - probably expired');
+ }
+ }
+
+ // Exception
+ else if(type === 'exception') {
+ // Execute error callback
+ if(callbacks[seqId]) {
+ try {
+ (callbacks[seqId].error || function() {})(msg, callbacks[seqId]);
+ } catch(e) {
+ console.log('Error in LiveConnect exception callback', e);
+ }
+ }
+
+ console.log('Received exception', msg);
+ }
+
+ // LiveConnect change notification
+ else if(type == 'notify') onNotification(msg);
+
+ // Misc message -> fire event
+ else fireEvent(type, msg);
+ }
+
+ // Fire event
+ function fireEvent(name, msg) {
+ if(!(name in handlers)) return;
+ if(!handlers[name].length) return;
+
+ // Execute all callbacks
+ handlers[name].each(function(cb) {
+ cb(msg);
+ })
+ }
+
+
+
+
+
+
+ /****** Method calls *******/
+
+ // Call has expired
+ function callExpiry(seqId) {
+ var call = callbacks[seqId];
+ if(call && call.error) call.error('timeout');
+
+ delete callbacks[seqId];
+ }
+
+
+
+
+ /******* Subscription *******/
+
+ /**
+ * Notification received
+ * @package subscription
+ * @param Object msg Notification details, contains:
+ * - id - subscription ID
+ * - user
+ * - table
+ * - operation
+ * - rowIndex
+ * - oldData
+ * - newData
+ */
+ function onNotification(msg) {
+ var sId = msg.id;
+ if(subscriptions[sId]) subscriptions[sId].cb('notify', msg);
+ }
+
+ // Prepare message for subscription to an event
+ function sanitizeEventRequest(ev) {
+ var x;
+
+ // Check table
+ if(typeof ev.table !== 'string') throw new Error('Table is expected to be a string');
+
+
+ // Check operations
+ if(!ev.operations) ev.operations = 'all';
+ if(typeof ev.operations === 'string' && ev.operations !== 'all') ev.operations = ev.operations.split(',');
+
+ // Check conditions
+ var conds = ev.conditions;
+ if(typeof conds === 'string') conds = conds.split(',');
+ if(conds instanceof Array) conds = conds.map(function(item) {
+ if($.isPlainObject(item)) return item;
+ else if(item instanceof Array) return { column: item[0], operation: item[1], value: item[2] };
+ else if(typeof item === 'string') {
+ if(item.match(/^[a-z0-9]+$/i)) return { column: item, operation: 'present' };
+ else if(x = item.match(/^([a-z0-9]+)=(.+)$/i)) return { column: x[1], operation: 'eq', value: x[2] };
+ }
+ });
+ else conds = null;
+ ev.conditions = conds;
+
+
+ // Check columns
+ if(typeof ev.columns === 'string') ev.columns = ev.columns.split(',');
+
+ return ev;
+ }
+
+ /**
+ * Soft timeout of a subscription
+ * @package subscription
+ * @param sId Subscription ID
+ */
+ function subscriptionTimeout(sId) {
+ var sub;
+ if(!(sub = subscriptions[sId])) return; // Subscription not found
+
+ // Fire soft timeout callback
+ var ret = sub.cb('timeout-soft', sId);
+ if(ret === true) { // Extend this subscription
+ // Send subscription request
+ Lib.sendMessage('extendSubscription', {
+ id: sId,
+ events: sub.eventRequests,
+ timeout: sub.hardTimeout
+ });
+
+ // Renew timeout
+ sub.resTimeout = setTimeout(subscriptionTimeout, sub.softTimeout * 1000, sId);
+ }
+
+ // Should I do something when timeouted, or just wait for the server to drop?
+
+ }
+
+
+
+
+ // Exported methods
+ var Lib;
+ return Lib = {
+
+
+ /******* State methods *******/
+ isConnected: function() {
+ return connected;
+ },
+
+ getState: function() {
+ return state;
+ },
+
+
+
+
+
+ /******* Connection *******/
+
+ // Try to connect
+ connect: function() {
+ if(!socket) connectionAttempt();
+ return Lib; // provides fluent interface
+ },
+
+ // Disconnect
+ disconnect: function() {
+ // Do it
+ if(socket) {
+ socket.disconnect();
+ connected = false;
+ state = 'disconnected';
+ socket = null;
+ }
+
+ return Lib; // provides fluent interface
+ },
+
+
+
+
+ /******* Misc messages *******/
+
+ // Send a message
+ sendMessage: function(type, msg) {
+ msg.messageType = type;
+
+ if(connected) socket.send(msg);
+ else messageBuffer.push(msg);
+
+ return Lib; // provides fluent interface
+ },
+
+ on: function(eventName, cb) {
+ if(!handlers[eventName]) handlers[eventName] = [];
+ handlers[eventName].push(cb);
+
+ return Lib; // Provides fluent interface
+ },
+
+
+
+
+ /******* Subscription *******/
+
+ // Subscribe for events
+ subscribe: function(id, eventRequests, cb, timeout, hardTimeout) {
+ // Process smart arguments
+ if($.isPlainObject(id) || id instanceof Array) {
+ hardTimeout = timeout;
+ timeout = cb;
+ cb = eventRequests;
+ eventRequests = id;
+ id = '__' + ++subscriptionCounter;
+ }
+ if(!timeout) timeout = 90;
+ if(!hardTimeout || hardTimeout < timeout) hardTimeout = Math.ceil(timeout * 1.2);
+
+ // Sanitize event requests
+ eventRequests = ( $.isPlainObject(eventRequests) ? [ eventRequests ] : eventRequests ).map(sanitizeEventRequest);
+
+ // Send subscription request
+ Lib.sendMessage('subscribe', {
+ id: id,
+ events: eventRequests,
+ timeout: hardTimeout
+ });
+
+ // Store this request details
+ subscriptions[id] = {
+ eventRequests: eventRequests,
+ cb: cb || $.noop,
+ softTimeout: timeout,
+ hardTimeout: hardTimeout,
+ resTimeout: setTimeout(subscriptionTimeout, timeout * 1000, id)
+ };
+
+ return id;
+ },
+
+ /**
+ * Drop existing subscription
+ */
+ unsubscribe: function(sId) {
+ // Send unsubscribe to the server
+ Lib.sendMessage('unsubscribe', { id: sId } );
+
+ // Clean stored subscription
+ if(subscriptions[sId]) {
+ var sub = subscriptions[sId];
+
+ // Clear timeout
+ if(sub.resTimeout) clearTimeout(sub.resTimeout);
+ sub.resTimeout = null;
+
+ // Callback
+ sub.cb('unsubscribe-user');
+
+ delete subscriptions[sId];
+ }
+
+ return Lib; // Provides fluent interface
+ },
+
+
+
+
+
+ /******* Method calls *******/
+
+ /**
+ *
+ * @param method
+ * @param msg
+ * @param cb
+ * @param errCb
+ */
+ call: function(method, msg, cb, errCb, timeout) {
+ var seqId = ++sequenceId;
+
+ // Store callbacks
+ callbacks[seqId] = {
+ method: method,
+ success: cb,
+ error: errCb,
+ added: (new Date).valueOf()
+ }
+
+ // Add expiry callback
+ callbacks[seqId].timeout = setTimeout(callExpiry, (timeout || 10) * 1000, seqId);
+
+ // Send it
+ msg.sequenceId = seqId;
+ Lib.sendMessage(method, msg);
+
+ return Lib; // Provides fluent interface
+ },
+
+
+
+
+
+ /********* Debug ********/
+
+ getInternals: function() {
+ return ({
+ handlers: handlers,
+ state: state,
+ messageBuffer: messageBuffer,
+ sequenceId: sequenceId,
+ callbacks: callbacks,
+ subscriptions: subscriptions,
+ subscriptionCounter: subscriptionCounter
+ });
+ }
+ }
+})(jQuery);
1,022 interface/gen-nodejs/LiveConnect.js
@@ -0,0 +1,1022 @@
+//
+// Autogenerated by Thrift
+//
+// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+//
+var Thrift = require('thrift').Thrift;
+
+var ttypes = require('./liveconnect_types');
+//HELPER FUNCTIONS AND STRUCTURES
+
+var LiveConnect_notify_args = function(args){
+ this.user = null
+ this.table = null
+ this.op = null
+ this.oldData = null
+ this.nwData = null
+if( args != null ){ if (null != args.user)
+ this.user = args.user
+ if (null != args.table)
+ this.table = args.table
+ if (null != args.op)
+ this.op = args.op
+ if (null != args.oldData)
+ this.oldData = args.oldData
+ if (null != args.nwData)
+ this.nwData = args.nwData
+}}
+LiveConnect_notify_args.prototype = {}
+LiveConnect_notify_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.I32) {
+ this.user = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.STRING) {
+ this.table = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.I32) {
+ this.op = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 4: if (ftype == Thrift.Type.MAP) {
+ {
+ var _size21 = 0
+ var rtmp3
+ this.oldData = {}
+ var _ktype22 = 0
+ var _vtype23 = 0
+ rtmp3 = input.readMapBegin()
+ _ktype22= rtmp3.ktype
+ _vtype23= rtmp3.vtype
+ _size21= rtmp3.size
+ for (var _i25 = 0; _i25 < _size21; ++_i25)
+ {
+ key26 = null
+ val27 = null
+ key26 = input.readString()
+ val27 = input.readString()
+ this.oldData[key26] = val27
+ }
+ input.readMapEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 5: if (ftype == Thrift.Type.MAP) {
+ {
+ var _size28 = 0
+ var rtmp3
+ this.nwData = {}
+ var _ktype29 = 0
+ var _vtype30 = 0
+ rtmp3 = input.readMapBegin()
+ _ktype29= rtmp3.ktype
+ _vtype30= rtmp3.vtype
+ _size28= rtmp3.size
+ for (var _i32 = 0; _i32 < _size28; ++_i32)
+ {
+ key33 = null
+ val34 = null
+ key33 = input.readString()
+ val34 = input.readString()
+ this.nwData[key33] = val34
+ }
+ input.readMapEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_notify_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_notify_args')
+ if (null != this.user) {
+ output.writeFieldBegin('user', Thrift.Type.I32, 1)
+ output.writeI32(this.user)
+ output.writeFieldEnd()
+ }
+ if (null != this.table) {
+ output.writeFieldBegin('table', Thrift.Type.STRING, 2)
+ output.writeString(this.table)
+ output.writeFieldEnd()
+ }
+ if (null != this.op) {
+ output.writeFieldBegin('op', Thrift.Type.I32, 3)
+ output.writeI32(this.op)
+ output.writeFieldEnd()
+ }
+ if (null != this.oldData) {
+ output.writeFieldBegin('oldData', Thrift.Type.MAP, 4)
+ {
+ output.writeMapBegin(Thrift.Type.STRING, Thrift.Type.STRING, Thrift.objectLength(this.oldData))
+ {
+ for(var kiter35 in this.oldData) {
+ if (this.oldData.hasOwnProperty(kiter35))
+ {
+ var viter36 = this.oldData[kiter35]
+ output.writeString(kiter35)
+ output.writeString(viter36)
+ }
+ }
+ }
+ output.writeMapEnd()
+ }
+ output.writeFieldEnd()
+ }
+ if (null != this.nwData) {
+ output.writeFieldBegin('nwData', Thrift.Type.MAP, 5)
+ {
+ output.writeMapBegin(Thrift.Type.STRING, Thrift.Type.STRING, Thrift.objectLength(this.nwData))
+ {
+ for(var kiter37 in this.nwData) {
+ if (this.nwData.hasOwnProperty(kiter37))
+ {
+ var viter38 = this.nwData[kiter37]
+ output.writeString(kiter37)
+ output.writeString(viter38)
+ }
+ }
+ }
+ output.writeMapEnd()
+ }
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_notify_result = function(args){
+}
+LiveConnect_notify_result.prototype = {}
+LiveConnect_notify_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_notify_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_notify_result')
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_subscribe_args = function(args){
+ this.clientKey = null
+ this.ev = null
+ this.timeout = null
+if( args != null ){ if (null != args.clientKey)
+ this.clientKey = args.clientKey
+ if (null != args.ev)
+ this.ev = args.ev
+ if (null != args.timeout)
+ this.timeout = args.timeout
+}}
+LiveConnect_subscribe_args.prototype = {}
+LiveConnect_subscribe_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.clientKey = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.STRUCT) {
+ this.ev = new ttypes.EventDefinition()
+ this.ev.read(input)
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.I32) {
+ this.timeout = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_subscribe_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_subscribe_args')
+ if (null != this.clientKey) {
+ output.writeFieldBegin('clientKey', Thrift.Type.STRING, 1)
+ output.writeString(this.clientKey)
+ output.writeFieldEnd()
+ }
+ if (null != this.ev) {
+ output.writeFieldBegin('ev', Thrift.Type.STRUCT, 2)
+ this.ev.write(output)
+ output.writeFieldEnd()
+ }
+ if (null != this.timeout) {
+ output.writeFieldBegin('timeout', Thrift.Type.I32, 3)
+ output.writeI32(this.timeout)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_subscribe_result = function(args){
+ this.success = null
+if( args != null ){ if (null != args.success)
+ this.success = args.success
+}}
+LiveConnect_subscribe_result.prototype = {}
+LiveConnect_subscribe_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 0: if (ftype == Thrift.Type.BOOL) {
+ this.success = input.readBool()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_subscribe_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_subscribe_result')
+ if (null != this.success) {
+ output.writeFieldBegin('success', Thrift.Type.BOOL, 0)
+ output.writeBool(this.success)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_unsubscribe_args = function(args){
+ this.clientKey = null
+ this.ev = null
+if( args != null ){ if (null != args.clientKey)
+ this.clientKey = args.clientKey
+ if (null != args.ev)
+ this.ev = args.ev
+}}
+LiveConnect_unsubscribe_args.prototype = {}
+LiveConnect_unsubscribe_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.clientKey = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.STRUCT) {
+ this.ev = new ttypes.EventDefinition()
+ this.ev.read(input)
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_unsubscribe_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_unsubscribe_args')
+ if (null != this.clientKey) {
+ output.writeFieldBegin('clientKey', Thrift.Type.STRING, 1)
+ output.writeString(this.clientKey)
+ output.writeFieldEnd()
+ }
+ if (null != this.ev) {
+ output.writeFieldBegin('ev', Thrift.Type.STRUCT, 2)
+ this.ev.write(output)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_unsubscribe_result = function(args){
+ this.success = null
+if( args != null ){ if (null != args.success)
+ this.success = args.success
+}}
+LiveConnect_unsubscribe_result.prototype = {}
+LiveConnect_unsubscribe_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 0: if (ftype == Thrift.Type.BOOL) {
+ this.success = input.readBool()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_unsubscribe_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_unsubscribe_result')
+ if (null != this.success) {
+ output.writeFieldBegin('success', Thrift.Type.BOOL, 0)
+ output.writeBool(this.success)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_unsubscribeClient_args = function(args){
+ this.clientKey = null
+if( args != null ){ if (null != args.clientKey)
+ this.clientKey = args.clientKey
+}}
+LiveConnect_unsubscribeClient_args.prototype = {}
+LiveConnect_unsubscribeClient_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.clientKey = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_unsubscribeClient_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_unsubscribeClient_args')
+ if (null != this.clientKey) {
+ output.writeFieldBegin('clientKey', Thrift.Type.STRING, 1)
+ output.writeString(this.clientKey)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_unsubscribeClient_result = function(args){
+ this.success = null
+if( args != null ){ if (null != args.success)
+ this.success = args.success
+}}
+LiveConnect_unsubscribeClient_result.prototype = {}
+LiveConnect_unsubscribeClient_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 0: if (ftype == Thrift.Type.BOOL) {
+ this.success = input.readBool()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_unsubscribeClient_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_unsubscribeClient_result')
+ if (null != this.success) {
+ output.writeFieldBegin('success', Thrift.Type.BOOL, 0)
+ output.writeBool(this.success)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_getSubscriptions_args = function(args){
+}
+LiveConnect_getSubscriptions_args.prototype = {}
+LiveConnect_getSubscriptions_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_getSubscriptions_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_getSubscriptions_args')
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_getSubscriptions_result = function(args){
+ this.success = null
+if( args != null ){ if (null != args.success)
+ this.success = args.success
+}}
+LiveConnect_getSubscriptions_result.prototype = {}
+LiveConnect_getSubscriptions_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 0: if (ftype == Thrift.Type.LIST) {
+ {
+ var _size39 = 0
+ var rtmp3
+ this.success = []
+ var _etype42 = 0
+ rtmp3 = input.readListBegin()
+ _etype42 = rtmp3.etype
+ _size39 = rtmp3.size
+ for (var _i43 = 0; _i43 < _size39; ++_i43)
+ {
+ var elem44 = null
+ elem44 = new ttypes.Subscription()
+ elem44.read(input)
+ this.success.push(elem44)
+ }
+ input.readListEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_getSubscriptions_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_getSubscriptions_result')
+ if (null != this.success) {
+ output.writeFieldBegin('success', Thrift.Type.LIST, 0)
+ {
+ output.writeListBegin(Thrift.Type.STRUCT, this.success.length)
+ {
+ for(var iter45 in this.success)
+ {
+ if (this.success.hasOwnProperty(iter45))
+ {
+ iter45=this.success[iter45]
+ iter45.write(output)
+ }
+ }
+ }
+ output.writeListEnd()
+ }
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_getClients_args = function(args){
+}
+LiveConnect_getClients_args.prototype = {}
+LiveConnect_getClients_args.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_getClients_args.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_getClients_args')
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnect_getClients_result = function(args){
+ this.success = null
+if( args != null ){ if (null != args.success)
+ this.success = args.success
+}}
+LiveConnect_getClients_result.prototype = {}
+LiveConnect_getClients_result.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 0: if (ftype == Thrift.Type.LIST) {
+ {
+ var _size46 = 0
+ var rtmp3
+ this.success = []
+ var _etype49 = 0
+ rtmp3 = input.readListBegin()
+ _etype49 = rtmp3.etype
+ _size46 = rtmp3.size
+ for (var _i50 = 0; _i50 < _size46; ++_i50)
+ {
+ var elem51 = null
+ elem51 = new ttypes.ClientInfo()
+ elem51.read(input)
+ this.success.push(elem51)
+ }
+ input.readListEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+LiveConnect_getClients_result.prototype.write = function(output){
+ output.writeStructBegin('LiveConnect_getClients_result')
+ if (null != this.success) {
+ output.writeFieldBegin('success', Thrift.Type.LIST, 0)
+ {
+ output.writeListBegin(Thrift.Type.STRUCT, this.success.length)
+ {
+ for(var iter52 in this.success)
+ {
+ if (this.success.hasOwnProperty(iter52))
+ {
+ iter52=this.success[iter52]
+ iter52.write(output)
+ }
+ }
+ }
+ output.writeListEnd()
+ }
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var LiveConnectClient = exports.Client = function(output, pClass) {
+ this.output = output;
+ this.pClass = pClass;
+ this.seqid = 0;
+ this._reqs = {}
+}
+LiveConnectClient.prototype = {}
+LiveConnectClient.prototype.notify = function(user,table,op,oldData,nwData,callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_notify(user, table, op, oldData, nwData)
+}
+
+LiveConnectClient.prototype.send_notify = function(user,table,op,oldData,nwData){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('notify', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_notify_args()
+ args.user = user
+ args.table = table
+ args.op = op
+ args.oldData = oldData
+ args.nwData = nwData
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+LiveConnectClient.prototype.subscribe = function(clientKey,ev,timeout,callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_subscribe(clientKey, ev, timeout)
+}
+
+LiveConnectClient.prototype.send_subscribe = function(clientKey,ev,timeout){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('subscribe', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_subscribe_args()
+ args.clientKey = clientKey
+ args.ev = ev
+ args.timeout = timeout
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+
+LiveConnectClient.prototype.recv_subscribe = function(input,mtype,rseqid){
+ var callback = this._reqs[rseqid] || function() {};
+ delete this._reqs[rseqid];
+ if (mtype == Thrift.MessageType.EXCEPTION) {
+ var x = new Thrift.TApplicationException()
+ x.read(input)
+ input.readMessageEnd()
+ return callback(x);
+ }
+ var result = new LiveConnect_subscribe_result()
+ result.read(input)
+ input.readMessageEnd()
+
+ if (null != result.success ) {
+ return callback(null, result.success);
+ }
+ return callback("subscribe failed: unknown result");
+}
+LiveConnectClient.prototype.unsubscribe = function(clientKey,ev,callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_unsubscribe(clientKey, ev)
+}
+
+LiveConnectClient.prototype.send_unsubscribe = function(clientKey,ev){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('unsubscribe', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_unsubscribe_args()
+ args.clientKey = clientKey
+ args.ev = ev
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+
+LiveConnectClient.prototype.recv_unsubscribe = function(input,mtype,rseqid){
+ var callback = this._reqs[rseqid] || function() {};
+ delete this._reqs[rseqid];
+ if (mtype == Thrift.MessageType.EXCEPTION) {
+ var x = new Thrift.TApplicationException()
+ x.read(input)
+ input.readMessageEnd()
+ return callback(x);
+ }
+ var result = new LiveConnect_unsubscribe_result()
+ result.read(input)
+ input.readMessageEnd()
+
+ if (null != result.success ) {
+ return callback(null, result.success);
+ }
+ return callback("unsubscribe failed: unknown result");
+}
+LiveConnectClient.prototype.unsubscribeClient = function(clientKey,callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_unsubscribeClient(clientKey)
+}
+
+LiveConnectClient.prototype.send_unsubscribeClient = function(clientKey){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('unsubscribeClient', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_unsubscribeClient_args()
+ args.clientKey = clientKey
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+
+LiveConnectClient.prototype.recv_unsubscribeClient = function(input,mtype,rseqid){
+ var callback = this._reqs[rseqid] || function() {};
+ delete this._reqs[rseqid];
+ if (mtype == Thrift.MessageType.EXCEPTION) {
+ var x = new Thrift.TApplicationException()
+ x.read(input)
+ input.readMessageEnd()
+ return callback(x);
+ }
+ var result = new LiveConnect_unsubscribeClient_result()
+ result.read(input)
+ input.readMessageEnd()
+
+ if (null != result.success ) {
+ return callback(null, result.success);
+ }
+ return callback("unsubscribeClient failed: unknown result");
+}
+LiveConnectClient.prototype.getSubscriptions = function(callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_getSubscriptions()
+}
+
+LiveConnectClient.prototype.send_getSubscriptions = function(){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('getSubscriptions', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_getSubscriptions_args()
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+
+LiveConnectClient.prototype.recv_getSubscriptions = function(input,mtype,rseqid){
+ var callback = this._reqs[rseqid] || function() {};
+ delete this._reqs[rseqid];
+ if (mtype == Thrift.MessageType.EXCEPTION) {
+ var x = new Thrift.TApplicationException()
+ x.read(input)
+ input.readMessageEnd()
+ return callback(x);
+ }
+ var result = new LiveConnect_getSubscriptions_result()
+ result.read(input)
+ input.readMessageEnd()
+
+ if (null != result.success ) {
+ return callback(null, result.success);
+ }
+ return callback("getSubscriptions failed: unknown result");
+}
+LiveConnectClient.prototype.getClients = function(callback){
+ this.seqid += 1;
+ this._reqs[this.seqid] = callback;
+ this.send_getClients()
+}
+
+LiveConnectClient.prototype.send_getClients = function(){
+ var output = new this.pClass(this.output);
+ output.writeMessageBegin('getClients', Thrift.MessageType.CALL, this.seqid)
+ var args = new LiveConnect_getClients_args()
+ args.write(output)
+ output.writeMessageEnd()
+ return this.output.flush()
+}
+
+LiveConnectClient.prototype.recv_getClients = function(input,mtype,rseqid){
+ var callback = this._reqs[rseqid] || function() {};
+ delete this._reqs[rseqid];
+ if (mtype == Thrift.MessageType.EXCEPTION) {
+ var x = new Thrift.TApplicationException()
+ x.read(input)
+ input.readMessageEnd()
+ return callback(x);
+ }
+ var result = new LiveConnect_getClients_result()
+ result.read(input)
+ input.readMessageEnd()
+
+ if (null != result.success ) {
+ return callback(null, result.success);
+ }
+ return callback("getClients failed: unknown result");
+}
+var LiveConnectProcessor = exports.Processor = function(handler) {
+ this._handler = handler
+}
+LiveConnectProcessor.prototype.process = function(input, output) {
+ var r = input.readMessageBegin()
+ if (this['process_' + r.fname]) {
+ return this['process_' + r.fname].call(this, r.rseqid, input, output)
+ } else {
+ input.skip(Thrift.Type.STRUCT)
+ input.readMessageEnd()
+ var x = new Thrift.TApplicationException(Thrift.TApplicationExceptionType.UNKNOWN_METHOD, 'Unknown function ' + r.fname)
+ output.writeMessageBegin(r.fname, Thrift.MessageType.Exception, r.rseqid)
+ x.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ }
+}
+
+LiveConnectProcessor.prototype.process_notify = function(seqid, input, output) {
+ var args = new LiveConnect_notify_args()
+ args.read(input)
+ input.readMessageEnd()
+ this._handler.notify(args.user, args.table, args.op, args.oldData, args.nwData)
+}
+
+LiveConnectProcessor.prototype.process_subscribe = function(seqid, input, output) {
+ var args = new LiveConnect_subscribe_args()
+ args.read(input)
+ input.readMessageEnd()
+ var result = new LiveConnect_subscribe_result()
+ this._handler.subscribe(args.clientKey, args.ev, args.timeout, function(success) {
+ result.success = success
+ output.writeMessageBegin("subscribe", Thrift.MessageType.REPLY, seqid)
+ result.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ })
+}
+
+LiveConnectProcessor.prototype.process_unsubscribe = function(seqid, input, output) {
+ var args = new LiveConnect_unsubscribe_args()
+ args.read(input)
+ input.readMessageEnd()
+ var result = new LiveConnect_unsubscribe_result()
+ this._handler.unsubscribe(args.clientKey, args.ev, function(success) {
+ result.success = success
+ output.writeMessageBegin("unsubscribe", Thrift.MessageType.REPLY, seqid)
+ result.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ })
+}
+
+LiveConnectProcessor.prototype.process_unsubscribeClient = function(seqid, input, output) {
+ var args = new LiveConnect_unsubscribeClient_args()
+ args.read(input)
+ input.readMessageEnd()
+ var result = new LiveConnect_unsubscribeClient_result()
+ this._handler.unsubscribeClient(args.clientKey, function(success) {
+ result.success = success
+ output.writeMessageBegin("unsubscribeClient", Thrift.MessageType.REPLY, seqid)
+ result.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ })
+}
+
+LiveConnectProcessor.prototype.process_getSubscriptions = function(seqid, input, output) {
+ var args = new LiveConnect_getSubscriptions_args()
+ args.read(input)
+ input.readMessageEnd()
+ var result = new LiveConnect_getSubscriptions_result()
+ this._handler.getSubscriptions(function(success) {
+ result.success = success
+ output.writeMessageBegin("getSubscriptions", Thrift.MessageType.REPLY, seqid)
+ result.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ })
+}
+
+LiveConnectProcessor.prototype.process_getClients = function(seqid, input, output) {
+ var args = new LiveConnect_getClients_args()
+ args.read(input)
+ input.readMessageEnd()
+ var result = new LiveConnect_getClients_result()
+ this._handler.getClients(function(success) {
+ result.success = success
+ output.writeMessageBegin("getClients", Thrift.MessageType.REPLY, seqid)
+ result.write(output)
+ output.writeMessageEnd()
+ output.flush()
+ })
+}
+
456 interface/gen-nodejs/liveconnect_types.js
@@ -0,0 +1,456 @@
+//
+// Autogenerated by Thrift
+//
+// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+//
+var Thrift = require('thrift').Thrift;
+var ttypes = module.exports = {};
+ttypes.LiveConnectOp = {
+'opAdd' : 1
+,'opEdit' : 2
+,'opRemove' : 3
+,'opClone' : 4
+,'all' : 255
+}
+ttypes.LiveConnectConditionOp = {
+'present' : 1
+,'eq' : 2
+,'lt' : 3
+,'lte' : 4
+,'gt' : 5
+,'gte' : 6
+}
+var Condition = module.exports.Condition = function(args){
+ this.column = null
+ this.operation = null
+ this.value = null
+if( args != null ){ if (null != args.column)
+ this.column = args.column
+ if (null != args.operation)
+ this.operation = args.operation
+ if (null != args.value)
+ this.value = args.value
+}}
+Condition.prototype = {}
+Condition.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.column = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.I32) {
+ this.operation = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.STRING) {
+ this.value = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+Condition.prototype.write = function(output){
+ output.writeStructBegin('Condition')
+ if (null != this.column) {
+ output.writeFieldBegin('column', Thrift.Type.STRING, 1)
+ output.writeString(this.column)
+ output.writeFieldEnd()
+ }
+ if (null != this.operation) {
+ output.writeFieldBegin('operation', Thrift.Type.I32, 2)
+ output.writeI32(this.operation)
+ output.writeFieldEnd()
+ }
+ if (null != this.value) {
+ output.writeFieldBegin('value', Thrift.Type.STRING, 3)
+ output.writeString(this.value)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var EventDefinition = module.exports.EventDefinition = function(args){
+ this.table = null
+ this.operations = null
+ this.columns = null
+ this.conditions = null
+if( args != null ){ if (null != args.table)
+ this.table = args.table
+ if (null != args.operations)
+ this.operations = args.operations
+ if (null != args.columns)
+ this.columns = args.columns
+ if (null != args.conditions)
+ this.conditions = args.conditions
+}}
+EventDefinition.prototype = {}
+EventDefinition.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.table = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.SET) {
+ {
+ var _size0 = 0
+ var rtmp3
+ this.operations = []
+ var _etype3 = 0
+ rtmp3 = input.readSetBegin()
+ _etype3= rtmp3.etype
+ _size0 = rtmp3.size
+ for (var _i4 = 0; _i4 < _size0; ++_i4)
+ {
+ var elem5 = null
+ elem5 = input.readI32()
+ this.operations.push(elem5)
+ }
+ input.readSetEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.SET) {
+ {
+ var _size6 = 0
+ var rtmp3
+ this.columns = []
+ var _etype9 = 0
+ rtmp3 = input.readSetBegin()
+ _etype9= rtmp3.etype
+ _size6 = rtmp3.size
+ for (var _i10 = 0; _i10 < _size6; ++_i10)
+ {
+ var elem11 = null
+ elem11 = input.readString()
+ this.columns.push(elem11)
+ }
+ input.readSetEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 4: if (ftype == Thrift.Type.SET) {
+ {
+ var _size12 = 0
+ var rtmp3
+ this.conditions = []
+ var _etype15 = 0
+ rtmp3 = input.readSetBegin()
+ _etype15= rtmp3.etype
+ _size12 = rtmp3.size
+ for (var _i16 = 0; _i16 < _size12; ++_i16)
+ {
+ var elem17 = null
+ elem17 = new ttypes.Condition()
+ elem17.read(input)
+ this.conditions.push(elem17)
+ }
+ input.readSetEnd()
+ }
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+EventDefinition.prototype.write = function(output){
+ output.writeStructBegin('EventDefinition')
+ if (null != this.table) {
+ output.writeFieldBegin('table', Thrift.Type.STRING, 1)
+ output.writeString(this.table)
+ output.writeFieldEnd()
+ }
+ if (null != this.operations) {
+ output.writeFieldBegin('operations', Thrift.Type.SET, 2)
+ {
+ output.writeSetBegin(Thrift.Type.I32, this.operations.length)
+ {
+ for(var iter18 in this.operations)
+ {
+ if (this.operations.hasOwnProperty(iter18))
+ {
+ iter18=this.operations[iter18]
+ output.writeI32(iter18)
+ }
+ }
+ }
+ output.writeSetEnd()
+ }
+ output.writeFieldEnd()
+ }
+ if (null != this.columns) {
+ output.writeFieldBegin('columns', Thrift.Type.SET, 3)
+ {
+ output.writeSetBegin(Thrift.Type.STRING, this.columns.length)
+ {
+ for(var iter19 in this.columns)
+ {
+ if (this.columns.hasOwnProperty(iter19))
+ {
+ iter19=this.columns[iter19]
+ output.writeString(iter19)
+ }
+ }
+ }
+ output.writeSetEnd()
+ }
+ output.writeFieldEnd()
+ }
+ if (null != this.conditions) {
+ output.writeFieldBegin('conditions', Thrift.Type.SET, 4)
+ {
+ output.writeSetBegin(Thrift.Type.STRUCT, this.conditions.length)
+ {
+ for(var iter20 in this.conditions)
+ {
+ if (this.conditions.hasOwnProperty(iter20))
+ {
+ iter20=this.conditions[iter20]
+ iter20.write(output)
+ }
+ }
+ }
+ output.writeSetEnd()
+ }
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var Subscription = module.exports.Subscription = function(args){
+ this.clientKey = null
+ this.ev = null
+ this.expiry = null
+ this.renewals = null
+ this.eventReceived = null
+if( args != null ){ if (null != args.clientKey)
+ this.clientKey = args.clientKey
+ if (null != args.ev)
+ this.ev = args.ev
+ if (null != args.expiry)
+ this.expiry = args.expiry
+ if (null != args.renewals)
+ this.renewals = args.renewals
+ if (null != args.eventReceived)
+ this.eventReceived = args.eventReceived
+}}
+Subscription.prototype = {}
+Subscription.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.clientKey = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.STRUCT) {
+ this.ev = new ttypes.EventDefinition()
+ this.ev.read(input)
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.I32) {
+ this.expiry = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 4: if (ftype == Thrift.Type.I32) {
+ this.renewals = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 5: if (ftype == Thrift.Type.I32) {
+ this.eventReceived = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+Subscription.prototype.write = function(output){
+ output.writeStructBegin('Subscription')
+ if (null != this.clientKey) {
+ output.writeFieldBegin('clientKey', Thrift.Type.STRING, 1)
+ output.writeString(this.clientKey)
+ output.writeFieldEnd()
+ }
+ if (null != this.ev) {
+ output.writeFieldBegin('ev', Thrift.Type.STRUCT, 2)
+ this.ev.write(output)
+ output.writeFieldEnd()
+ }
+ if (null != this.expiry) {
+ output.writeFieldBegin('expiry', Thrift.Type.I32, 3)
+ output.writeI32(this.expiry)
+ output.writeFieldEnd()
+ }
+ if (null != this.renewals) {
+ output.writeFieldBegin('renewals', Thrift.Type.I32, 4)
+ output.writeI32(this.renewals)
+ output.writeFieldEnd()
+ }
+ if (null != this.eventReceived) {
+ output.writeFieldBegin('eventReceived', Thrift.Type.I32, 5)
+ output.writeI32(this.eventReceived)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
+var ClientInfo = module.exports.ClientInfo = function(args){
+ this.clientKey = null
+ this.numEventsRegistered = null
+ this.numEventsTotal = null
+ this.uptime = null
+if( args != null ){ if (null != args.clientKey)
+ this.clientKey = args.clientKey
+ if (null != args.numEventsRegistered)
+ this.numEventsRegistered = args.numEventsRegistered
+ if (null != args.numEventsTotal)
+ this.numEventsTotal = args.numEventsTotal
+ if (null != args.uptime)
+ this.uptime = args.uptime
+}}
+ClientInfo.prototype = {}
+ClientInfo.prototype.read = function(input){
+ var ret = input.readStructBegin()
+ while (1)
+ {
+ var ret = input.readFieldBegin()
+ var fname = ret.fname
+ var ftype = ret.ftype
+ var fid = ret.fid
+ if (ftype == Thrift.Type.STOP)
+ break
+ switch(fid)
+ {
+ case 1: if (ftype == Thrift.Type.STRING) {
+ this.clientKey = input.readString()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 2: if (ftype == Thrift.Type.I32) {
+ this.numEventsRegistered = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 3: if (ftype == Thrift.Type.I32) {
+ this.numEventsTotal = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ case 4: if (ftype == Thrift.Type.I32) {
+ this.uptime = input.readI32()
+ } else {
+ input.skip(ftype)
+ }
+ break
+ default:
+ input.skip(ftype)
+ }
+ input.readFieldEnd()
+ }
+ input.readStructEnd()
+ return
+}
+
+ClientInfo.prototype.write = function(output){
+ output.writeStructBegin('ClientInfo')
+ if (null != this.clientKey) {
+ output.writeFieldBegin('clientKey', Thrift.Type.STRING, 1)
+ output.writeString(this.clientKey)
+ output.writeFieldEnd()
+ }
+ if (null != this.numEventsRegistered) {
+ output.writeFieldBegin('numEventsRegistered', Thrift.Type.I32, 2)
+ output.writeI32(this.numEventsRegistered)
+ output.writeFieldEnd()
+ }
+ if (null != this.numEventsTotal) {
+ output.writeFieldBegin('numEventsTotal', Thrift.Type.I32, 3)
+ output.writeI32(this.numEventsTotal)
+ output.writeFieldEnd()
+ }
+ if (null != this.uptime) {
+ output.writeFieldBegin('uptime', Thrift.Type.I32, 4)
+ output.writeI32(this.uptime)
+ output.writeFieldEnd()
+ }
+ output.writeFieldStop()
+ output.writeStructEnd()
+ return
+}
+
841 interface/gen-php/liveconnect/LiveConnect.php
@@ -0,0 +1,841 @@
+<?php
+/**
+ * Autogenerated by Thrift
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ */
+//include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
+
+//include_once $GLOBALS['THRIFT_ROOT'].'/packages/liveconnect/liveconnect_types.php';
+
+interface LiveConnectIf {
+ public function notify($user, $table, $op, $oldData, $nwData);
+ public function subscribe($clientKey, $ev, $timeout);
+ public function unsubscribe($clientKey, $ev);
+ public function unsubscribeClient($clientKey);
+ public function getSubscriptions();
+ public function getClients();
+}
+
+class LiveConnectClient implements LiveConnectIf {
+ protected $input_ = null;
+ protected $output_ = null;
+
+ protected $seqid_ = 0;
+
+ public function __construct($input, $output=null) {
+ $this->input_ = $input;
+ $this->output_ = $output ? $output : $input;
+ }
+
+ public function notify($user, $table, $op, $oldData, $nwData)
+ {
+ $this->send_notify($user, $table, $op, $oldData, $nwData);
+ }
+
+ public function send_notify($user, $table, $op, $oldData, $nwData)
+ {
+ $args = new LiveConnect_LiveConnect_notify_args();
+ $args->user = $user;
+ $args->table = $table;
+ $args->op = $op;
+ $args->oldData = $oldData;
+ $args->nwData = $nwData;
+ $bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');
+ if ($bin_accel)
+ {
+ thrift_protocol_write_binary($this->output_, 'notify', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());
+ }
+ else
+ {
+ $this->output_->writeMessageBegin('notify', TMessageType::CALL, $this->seqid_);
+ $args->write($this->output_);
+ $this->output_->writeMessageEnd();
+ $this->output_->getTransport()->flush();
+ }
+ }
+ public function subscribe($clientKey, $ev, $timeout)
+ {
+ $this->send_subscribe($clientKey, $ev, $timeout);
+ return $this->recv_subscribe();
+ }
+
+ public function send_subscribe($clientKey, $ev, $timeout)
+ {
+ $args = new LiveConnect_LiveConnect_subscribe_args();
+ $args->clientKey = $clientKey;
+ $args->ev = $ev;
+ $args->timeout = $timeout;
+ $bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');
+ if ($bin_accel)
+ {
+ thrift_protocol_write_binary($this->output_, 'subscribe', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());
+ }
+ else
+ {
+ $this->output_->writeMessageBegin('subscribe', TMessageType::CALL, $this->seqid_);
+ $args->write($this->output_);
+ $this->output_->writeMessageEnd();
+ $this->output_->getTransport()->flush();
+ }
+ }
+
+ public function recv_subscribe()
+ {
+ $bin_accel = ($this->input_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_read_binary');
+ if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, 'LiveConnect_LiveConnect_subscribe_result', $this->input_->isStrictRead());
+ else
+ {
+ $rseqid = 0;
+ $fname = null;
+ $mtype = 0;
+
+ $this->input_->readMessageBegin($fname, $mtype, $rseqid);
+ if ($mtype == TMessageType::EXCEPTION) {
+ $x = new TApplicationException();
+ $x->read($this->input_);
+ $this->input_->readMessageEnd();
+ throw $x;
+ }
+ $result = new LiveConnect_LiveConnect_subscribe_result();
+ $result->read($this->input_);
+ $this->input_->readMessageEnd();
+ }
+ if ($result->success !== null) {
+ return $result->success;
+ }
+ throw new Exception("subscribe failed: unknown result");
+ }
+
+ public function unsubscribe($clientKey, $ev)
+ {
+ $this->send_unsubscribe($clientKey, $ev);
+ return $this->recv_unsubscribe();
+ }
+
+ public function send_unsubscribe($clientKey, $ev)
+ {
+ $args = new LiveConnect_LiveConnect_unsubscribe_args();
+ $args->clientKey = $clientKey;
+ $args->ev = $ev;
+ $bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');
+ if ($bin_accel)
+ {
+ thrift_protocol_write_binary($this->output_, 'unsubscribe', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());
+ }
+ else
+ {
+ $this->output_->writeMessageBegin('unsubscribe', TMessageType::CALL, $this->seqid_);
+ $args->write($this->output_);
+ $this->output_->writeMessageEnd();
+ $this->output_->getTransport()->flush();
+ }
+ }
+
+ public function recv_unsubscribe()
+ {
+ $bin_accel = ($this->input_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_read_binary');
+ if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, 'LiveConnect_LiveConnect_unsubscribe_result', $this->input_->isStrictRead());
+ else
+ {
+ $rseqid = 0;
+ $fname = null;
+ $mtype = 0;
+
+ $this->input_->readMessageBegin($fname, $mtype, $rseqid);
+ if ($mtype == TMessageType::EXCEPTION) {
+ $x = new TApplicationException();
+ $x->read($this->input_);
+ $this->input_->readMessageEnd();
+ throw $x;
+ }
+ $result = new LiveConnect_LiveConnect_unsubscribe_result();
+ $result->read($this->input_);
+ $this->input_->readMessageEnd();
+ }
+ if ($result->success !== null) {
+ return $result->success;
+ }
+ throw new Exception("unsubscribe failed: unknown result");
+ }
+
+ public function unsubscribeClient($clientKey)
+ {
+ $this->send_unsubscribeClient($clientKey);
+ return $this->recv_unsubscribeClient();
+ }
+
+ public function send_unsubscribeClient($clientKey)
+ {
+ $args = new LiveConnect_LiveConnect_unsubscribeClient_args();
+ $args->clientKey = $clientKey;
+ $bin_accel = ($this->output_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_write_binary');
+ if ($bin_accel)
+ {
+ thrift_protocol_write_binary($this->output_, 'unsubscribeClient', TMessageType::CALL, $args, $this->seqid_, $this->output_->isStrictWrite());
+ }
+ else
+ {
+ $this->output_->writeMessageBegin('unsubscribeClient', TMessageType::CALL, $this->seqid_);
+ $args->write($this->output_);
+ $this->output_->writeMessageEnd();
+ $this->output_->getTransport()->flush();
+ }
+ }
+
+ public function recv_unsubscribeClient()
+ {
+ $bin_accel = ($this->input_ instanceof TProtocol::$TBINARYPROTOCOLACCELERATED) && function_exists('thrift_protocol_read_binary');
+ if ($bin_accel) $result = thrift_protocol_read_binary($this->input_, 'LiveConnect_LiveConnect_unsubscribeClient_result', $this->input_->isStrictRead());
+ else
+ {
+ $rseqid = 0;
+ $fname = null;
+ $mtype = 0;
+
+ $this->input_->readMessageBegin($fname, $mtype, $rseqid);
+ if ($mtype == TMessageType::EXCEPTION) {
+ $x = new TApplicationException();
+ $x->read($this->input_);
+ $this->input_->readMessageEnd();
+ throw $x;
+ }
+ $result = new LiveConnect_LiveConnect_unsubscribeClient_result();
+ $result->read($this->input_);
+ $this->input_->readMessageEnd();
+ }
+ if ($result->success !== null) {
+ return $result->success;
+ }
+ throw new Exception("unsubscribeClient failed: unknown result&q