/**
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import("comet");
import("ejs");
import("etherpad.collab.ace.easysync2.{AttribPool,Changeset}");
import("etherpad.log");
import("etherpad.pad.activepads");
import("etherpad.pad.model");
import("etherpad.pad.padutils");
import("etherpad.pad.padevents");
import("etherpad.pro.pro_padmeta");
import("fastJSON");
import("fileutils.readFile");
import("jsutils.eachProperty");
import("etherpad.collab.server_utils.*");
import("etherpad.collab.collabroom_server");
jimport("java.util.concurrent.ConcurrentHashMap");
jimport("java.lang.System.out.println");
var PADVIEW_ROOMTYPE = 'padview';
var _serverDebug = println;//function(x) {};
// "view id" is either a padId or an ro.id
function _viewIdToRoom(padId) {
return "padview/"+padId;
}
function _roomToViewId(roomName) {
return roomName.substring(roomName.indexOf("/")+1);
}
function getRoomCallbacks(roomName, emptyCallbacks) {
var callbacks = emptyCallbacks;
var viewId = _roomToViewId(roomName);
callbacks.handleConnect = function(data) {
if (data.userInfo && data.userInfo.userId) {
return data.userInfo;
}
return null;
};
callbacks.clientReady =
function(newConnection, data) {
newConnection.data.lastRev = data.lastRev;
collabroom_server.updateRoomConnectionData(newConnection.connectionId,
newConnection.data);
};
return callbacks;
}
function updatePadClients(pad) {
var padId = pad.getId();
var roId = padIdToReadonly(padId);
function update(connection) {
updateClient(pad, connection.connectionId);
}
collabroom_server.getRoomConnections(_viewIdToRoom(padId)).forEach(update);
collabroom_server.getRoomConnections(_viewIdToRoom(roId)).forEach(update);
}
// Get arrays of text lines and attribute lines for a revision
// of a pad.
function _getPadLines(pad, revNum) {
var atext;
if (revNum >= 0) {
atext = pad.getInternalRevisionAText(revNum);
} else {
atext = Changeset.makeAText("\n");
}
var result = {};
result.textlines = Changeset.splitTextLines(atext.text);
result.alines = Changeset.splitAttributionLines(atext.attribs,
atext.text);
return result;
}
function updateClient(pad, connectionId) {
var conn = collabroom_server.getConnection(connectionId);
if (! conn) {
return;
}
var lastRev = conn.data.lastRev;
while (lastRev < pad.getHeadRevisionNumber()) {
var r = ++lastRev;
var author = pad.getRevisionAuthor(r);
var lines = _getPadLines(pad, r-1);
var wirePool = new AttribPool();
var forwards = pad.getRevisionChangeset(r);
var backwards = Changeset.inverse(forwards, lines.textlines,
lines.alines, pad.pool());
var forwards2 = Changeset.moveOpsToNewPool(forwards, pad.pool(),
wirePool);
var backwards2 = Changeset.moveOpsToNewPool(backwards, pad.pool(),
wirePool);
function revTime(r) {
var date = pad.getRevisionDate(r);
var s = Math.floor((+date)/1000);
//java.lang.System.out.println("time "+r+": "+s);
return s;
}
var msg = {type:"NEW_CHANGES", newRev:r,
changeset: forwards2,
changesetBack: backwards2,
apool: wirePool.toJsonable(),
author: author,
timeDelta: revTime(r) - revTime(r-1) };
collabroom_server.sendMessage(connectionId, msg);
}
conn.data.lastRev = pad.getHeadRevisionNumber();
collabroom_server.updateRoomConnectionData(connectionId, conn.data);
}
function sendMessageToPadConnections(pad, msg) {
var padId = pad.getId();
var roId = padIdToReadonly(padId);
function update(connection) {
collabroom_server.sendMessage(connection.connectionId, msg);
}
collabroom_server.getRoomConnections(_viewIdToRoom(padId)).forEach(update);
collabroom_server.getRoomConnections(_viewIdToRoom(roId)).forEach(update);
}
function updateUserInfo(pad, userInfo) {
var msg = { type:"NEW_AUTHORDATA",
author: userInfo.userId,
data: {} };
var hasData = false;
if ((typeof (userInfo.colorId)) == "number") {
msg.data.colorId = userInfo.colorId;
hasData = true;
}
if (userInfo.name) {
msg.data.name = userInfo.name;
hasData = true;
}
if (hasData) {
sendMessageToPadConnections(pad, msg);
}
}
function broadcastNewRevision(pad, revObj) {
var msg = { type:"NEW_SAVEDREV",
savedRev: revObj };
delete revObj.ip; // we try not to share info like IP addresses on slider
sendMessageToPadConnections(pad, msg);
}