diff options
Diffstat (limited to 'trunk/etherpad/src/etherpad/importexport/importexport.js')
-rw-r--r-- | trunk/etherpad/src/etherpad/importexport/importexport.js | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/trunk/etherpad/src/etherpad/importexport/importexport.js b/trunk/etherpad/src/etherpad/importexport/importexport.js new file mode 100644 index 0000000..304a1f4 --- /dev/null +++ b/trunk/etherpad/src/etherpad/importexport/importexport.js @@ -0,0 +1,241 @@ +/** + * 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. + */ + +jimport("java.io.File"); +jimport("java.io.FileOutputStream"); +jimport("java.lang.System.out.println"); +jimport("java.io.ByteArrayInputStream"); +jimport("java.io.ByteArrayOutputStream"); +jimport("java.io.DataInputStream"); +jimport("java.io.DataOutputStream"); +jimport("net.appjet.common.sars.SarsClient"); +jimport("com.etherpad.openofficeservice.OpenOfficeService"); +jimport("com.etherpad.openofficeservice.UnsupportedFormatException"); +jimport("com.etherpad.openofficeservice.TemporaryFailure"); + +import("etherpad.log"); +import("etherpad.utils"); +import("sync"); +import("execution"); +import("varz"); +import("exceptionutils"); + +function _log(obj) { + log.custom("import-export", obj); +} + +function onStartup() { + execution.initTaskThreadPool("importexport", 1); +} + +var formats = { + pdf: 'application/pdf', + doc: 'application/msword', + html: 'text/html; charset=utf-8', + odt: 'application/vnd.oasis.opendocument.text', + txt: 'text/plain; charset=utf-8' +} + +function _createTempFile(bytes, type) { + var f = File.createTempFile("ooconvert-", (type === null ? null : (type == "" ? "" : "."+type))); + if (bytes) { + var fos = new FileOutputStream(f); + fos.write(bytes); + } + return f; +} + +function _initConverterClient(convertServer) { + if (convertServer) { + var convertHost = convertServer.split(":")[0]; + var convertPort = Number(convertServer.split(":")[1]); + if (! appjet.scopeCache.converter) { + var converter = new SarsClient("ooffice-password", convertHost, convertPort); + appjet.scopeCache.converter = converter; + converter.setConnectTimeout(5000); + converter.setReadTimeout(40000); + appjet.scopeCache.converter.connect(); + } + return appjet.scopeCache.converter; + } else { + return null; + } +} + +function _conversionSarsFailure() { + delete appjet.scopeCache.converter; +} + +function errorUnsupported(from) { + return "Unsupported file type"+(from ? ": <strong>"+from+"</strong>." : ".")+" Etherpad can only import <strong>txt</strong>, <strong>html</strong>, <strong>rtf</strong>, <strong>doc</strong>, and <strong>docx</strong> files."; +} +var errorTemporary = "A temporary failure occurred; please try again later."; + +function doSlowFileConversion(from, to, bytes, continuation) { + var bytes = convertFileSlowly(from, to, bytes); + continuation.resume(); + return bytes; +} + +function _convertOverNetwork(convertServer, from, to, bytes) { + var c = _initConverterClient(convertServer); + var reqBytes = new ByteArrayOutputStream(); + var req = new DataOutputStream(reqBytes); + req.writeUTF(from); + req.writeUTF(to); + req.writeInt(bytes.length); + req.write(bytes, 0, bytes.length); + + var retBtyes; + try { + retBytes = c.message(reqBytes.toByteArray()); + } catch (e) { + if (e.javaException) { + net.appjet.oui.exceptionlog.apply(e.javaException) + } + _conversionSarsFailure(); + return "A communications failure occurred; please try again later."; + } + + if (retBytes.length == 0) { + return "An unknown failure occurred; please try again later. (#5)"; + } + var res = new DataInputStream(new ByteArrayInputStream(retBytes)); + var status = res.readInt(); + if (status == 0) { // success + var len = res.readInt(); + var resBytes = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, len); + res.readFully(resBytes); + return resBytes; + } else if (status == 1) { + return errorTemporary; + } else if (status == 2) { + var permFailureCode = res.readInt(); + if (permFailureCode == 0) { + return "An unknown failure occurred. (#1)"; + } else if (permFailureCode == 1) { + return errorUnsupported(from); + } + } else { + return "An unknown failure occurred. (#2)"; + } +} + +function convertFileSlowly(from, to, bytes) { + var convertServer = appjet.config["etherpad.sofficeConversionServer"]; + if (convertServer) { + return _convertOverNetwork(convertServer, from, to, bytes); + } + + if (! utils.hasOffice()) { + return "EtherPad is not configured to import or export formats other than <strong>txt</strong> and <strong>html</strong>. Please contact your system administrator for details."; + } + OpenOfficeService.setExecutable(appjet.config["etherpad.soffice"]); + try { + return OpenOfficeService.convertFile(from, to, bytes); + } catch (e) { + if (e.javaException instanceof TemporaryFailure) { + return errorTemporary; + } else if (e.javaException instanceof UnsupportedFormatException) { + return errorUnsupported(from); + } else { + return "An unknown failure occurred. (#3)"; + } + } +} + +function _noteConversionAttempt() { + varz.incrementInt("importexport-conversions-attempted"); +} + +function _noteConversionSuccess() { + varz.incrementInt("importexport-conversions-successful"); +} + +function _noteConversionFailure() { + varz.incrementInt("importexport-conversions-failed"); +} + +function _noteConversionTimeout() { + varz.incrementInt("importexport-conversions-timeout"); +} + +function _noteConversionImpossible() { + varz.incrementInt("importexport-conversions-impossible"); +} + +function precomputedConversionResult(from, to, bytes) { + try { + var retBytes = request.cache.conversionCallable.get(500, java.util.concurrent.TimeUnit.MILLISECONDS); + var delay = Date.now() - request.cache.startTime; + _log({type: "conversion-latency", from: from, to: to, + numBytes: request.cache.conversionByteLength, + delay: delay}); + varz.addToInt("importexport-total-conversion-millis", delay); + if (typeof(retBytes) == 'string') { + _log({type: "error", error: "conversion-failed", from: from, to: to, + numBytes: request.cache.conversionByteLength, + delay: delay}); + _noteConversionFailure(); + } else { + _noteConversionSuccess(); + } + return retBytes; + } catch (e) { + if (e.javaException instanceof java.util.concurrent.TimeoutException) { + _noteConversionTimeout(); + request.cache.conversionCallable.cancel(false); + _log({type: "error", error: "conversion-failed", from: from, to: to, + numBytes: request.cache.conversionByteLength, + delay: -1}); + return "Conversion timed out. Please try again later."; + } + _log({type: "error", error: "conversion-failed", from: from, to: to, + numBytes: request.cache.conversionByteLength, + trace: exceptionutils.getStackTracePlain(e)}); + _noteConversionFailure(); + return "An unknown failure occurred. (#4)"; + } +} + +function convertFile(from, to, bytes) { + if (request.cache.conversionCallable) { + return precomputedConversionResult(from, to, bytes); + } + + _noteConversionAttempt(); + if (from == to) { + _noteConversionSuccess(); + return bytes; + } + if (from == "txt" && to == "html") { + _noteConversionSuccess(); + return (new java.lang.String(utils.renderTemplateAsString('pad/exporthtml.ejs', { + content: String(new java.lang.String(bytes, "UTF-8")).replace(/&/g, "&").replace(/</g, "<"), + pre: true + }))).getBytes("UTF-8"); + } + + request.cache.conversionByteLength = bytes.length; + request.cache.conversionCallable = + execution.scheduleTask("importexport", "doSlowFileConversion", 0, [ + from, to, bytes, request.continuation + ]); + request.cache.startTime = Date.now(); + request.continuation.suspend(45000); + _noteConversionImpossible(); + return "An unexpected error occurred."; // Shouldn't ever get here. +}
\ No newline at end of file |