You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
richdocuments/js/3rdparty/webodf/editor/server/pullbox/Server.js

285 lines
10 KiB
JavaScript

/**
* @license
* Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
*
* @licstart
* This file is part of WebODF.
*
* WebODF is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License (GNU AGPL)
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* WebODF is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
* @licend
*
* @source: http://www.webodf.org/
* @source: https://github.com/kogmbh/WebODF/
*/
/*global XMLHttpRequest, runtime, core, ops*/
define("webodf/editor/server/pullbox/Server", [], function () {
"use strict";
runtime.loadClass("core.Base64");
runtime.loadClass("core.ByteArrayWriter");
/**
* @constructor
* @implements ops.Server
* @param {{url:string}} args
*/
return function PullBoxServer(args) {
var self = this,
token,
/**@const*/serverCallTimeout = 10000,
base64 = new core.Base64();
args = args || {};
args.url = args.url || "/WSER";
args.sessionStateToFileUrl = args.sessionStateToFileUrl || "/SS2F"
this.getGenesisUrl = function (sessionId) {
return "/session/" + sessionId + "/genesis";
};
/**
* @param {!Object} message
* @param {!function(!string)} cb
* @param {!function(!number,!string)} cbError passes the status number
* and the statustext, or -1 if there was an exception on sending
* @return {undefined}
*/
function call(message, cb, cbError) {
var xhr = new XMLHttpRequest(),
messageString = JSON.stringify(message);
function handleResult() {
if (xhr.readyState === 4) {
if (xhr.status < 200 || xhr.status >= 300) {
// report error
runtime.log("Status " + String(xhr.status) + ": " +
xhr.responseText || xhr.statusText);
cbError(xhr.status, xhr.statusText);
} else {
runtime.log("Status " + String(xhr.status) + ": " +
xhr.responseText || xhr.statusText);
cb(xhr.responseText);
}
}
}
function handleTimeout() {
runtime.log("Timeout on call to server.");
cbError(0, xhr.statusText);
}
runtime.log("Sending message to server: "+messageString);
// create body data for request from metadata and payload
// do the request
xhr.open('POST', args.url, true);
xhr.setRequestHeader("Content-type","application/json");
if (token) {
xhr.setRequestHeader("requesttoken", token);
}
xhr.onreadystatechange = handleResult;
xhr.timeout = serverCallTimeout;
// TODO: seems handleResult is called on timeout as well, with xhr.status === 0
// xhr.ontimeout = handleTimeout;
try {
xhr.send(messageString);
} catch (e) {
runtime.log("Problem with calling server: " + e + " " + data);
cbError(-1, e.message);
}
}
this.call = call;
this.getToken = function () {
return token;
};
/**
* for pre-authenticated use
*/
this.setToken = function (a_token) {
token = a_token;
};
/*jslint unparam: true*/
/**
* @param {!number} timeout in milliseconds
* @param {!function(!string)} callback
* @return {undefined}
*/
this.connect = function (timeout, callback) {
/*
var accumulatedWaitingTime = 0;
// already tried connecting?
if (self.networkStatus() === "ready") {
return;
}
*/
callback("ready");
};
/*jslint unparam: false*/
/**
* @return {!string}
*/
this.networkStatus = function () {
return "ready";
};
/**
* @param {!string} login
* @param {!string} password
* @param {function(!Object)} successCb
* @param {function(!string)} failCb
* @return {undefined}
*/
this.login = function (login, password, successCb, failCb) {
call({
command: "login",
args: {
login: base64.toBase64(login),
password: base64.toBase64(password)
}
}, function(responseData) {
var response = /**@type {{token:string}}*/(runtime.fromJson(responseData));
runtime.log("Login reply: " + responseData);
if (response.hasOwnProperty("token")) {
token = response.token;
runtime.log("Caching token: " + self.getToken());
successCb(response);
} else {
failCb(responseData);
}
}, failCb);
};
/**
* @param {!string} userId
* @param {!string} sessionId
* @param {!function(!string)} successCb
* @param {!function()} failCb
* @return {undefined}
*/
this.joinSession = function (userId, sessionId, successCb, failCb) {
call({
command: "join_session",
args: {
user_id: userId,
es_id: sessionId
}
}, function(responseData) {
var response = /**@type {{success:string, member_id:string}}*/(runtime.fromJson(responseData));
runtime.log("join_session reply: " + responseData);
if (response.hasOwnProperty("success") && response.success) {
successCb(response.member_id);
} else {
failCb();
}
}, failCb);
};
/**
* @param {!string} sessionId
* @param {!string} memberId
* @param {!function()} successCb
* @param {!function()} failCb
* @return {undefined}
*/
this.leaveSession = function (sessionId, memberId, successCb, failCb) {
call({
command: "leave_session",
args: {
es_id: sessionId,
member_id: memberId
}
}, function(responseData) {
var response = /**@type {{success:string, member_id:string}}*/(runtime.fromJson(responseData));
runtime.log("leave_session reply: " + responseData);
if (response.hasOwnProperty("success") && response.success) {
successCb();
} else {
failCb();
}
}, failCb);
};
/**
* @param {!string} sessionId
* @param {!string} memberId
* @param {!string} seqHead
* @param {!function(!Object=)} callback
* @return {undefined}
*/
this.writeSessionStateToFile = function(sessionId, memberId, seqHead, fileData, callback) {
// code copied from BrowserRuntime.writeFile and adapted
var xhr = new XMLHttpRequest();
function handleResult() {
if (xhr.readyState === 4) {
if (xhr.status === 0 && !xhr.responseText) {// TODO: check makes sense here as well?
// for local files there is no difference between missing
// and empty files, so empty files are considered as errors
runtime.log("File " + args.sessionStateToFileUrl + " is empty.");
} else if ((xhr.status >= 200 && xhr.status < 300) ||
xhr.status === 0) {
// report success
runtime.log(null);
} else {
// report error
runtime.log("Status " + String(xhr.status) + ": " +
xhr.responseText || xhr.statusText);
}
callback();
}
}
// do the request
xhr.open('POST', args.sessionStateToFileUrl, true);
if (token) {
xhr.setRequestHeader("requesttoken", token);
}
xhr.setRequestHeader("webodf-session-id", sessionId);
xhr.setRequestHeader("webodf-member-id", memberId);
xhr.setRequestHeader("webodf-session-revision", seqHead);
xhr.onreadystatechange = handleResult;
// ArrayBufferView will have an ArrayBuffer property, in WebKit, XHR can send()
// an ArrayBuffer, In Firefox, one must use sendAsBinary with a string
if (fileData.buffer && !xhr.sendAsBinary) {
fileData = fileData.buffer; // webkit supports sending an ArrayBuffer
} else {
// encode into a string, this works in FireFox >= 3
fileData = runtime.byteArrayToString(fileData, "binary");
}
try {
if (xhr.sendAsBinary) {
xhr.sendAsBinary(fileData);
} else {
xhr.send(fileData);
}
} catch (e) {
runtime.log("Problem with calling \"writeSessionStateToFile\" on server");
callback(e.message);
}
};
};
});