diff --git a/README.md b/README.md index 18c145ef4..3d5ff1466 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ documented codebase makes it easier for developers to improve the code. Etherpad to be easy embeddable. Look at our [FAQ Page](https://github.com/Pita/etherpad-lite/wiki/FAQ) **Online demo**
-Visit to test it live. You can find the same instance behind a nginx, with ssl and in a subpath here -> [https://pad.pitapoison.de/pad/](https://pad.pitapoison.de/pad/) +Visit to test it live.
You can find the same instance behind a nginx, with ssl and in a subpath here -> [https://pad.pitapoison.de/pad/](https://pad.pitapoison.de/pad/) # Etherpad vs Etherpad Lite @@ -31,26 +31,36 @@ Visit to test it live. You can find the same instanc # Installation **As root:** -1. Download the latest **0.4.x** node.js release from , extract it and build it with `./configure && make && make install`.
-The Node.js version of your Linux repository might be too old/new. Please compile from the source to get sure you have the correct version. -2. Install npm `curl http://npmjs.org/install.sh | sh` -3. Ensure you have installed the sqlite develob libraries, gzip and git `apt-get install libsqlite3-dev gzip git-core` +
    +
  1. Install all dependencies. We need the sqlite develob libraries, gzip, git, curl, libssl develop libraries and python
    apt-get install libsqlite3-dev gzip git-core curl python libssl-dev

  2. +
  3. Install node.js +
      +
    1. Download the latest 0.4.x node.js release from http://nodejs.org/#download
    2. +
    3. Extract it with tar xf node-v0.4*
    4. +
    5. move into the node folder cd node-v0.4* and build node with ./configure && make && make install
    6. +
    +
  4. +
  5. Install npm curl http://npmjs.org/install.sh | sh
  6. +
**As any user (we recommend creating a seperate user called etherpad-lite):** -4. Clone the git repository `git clone 'git://github.com/Pita/etherpad-lite.git'` -5. Start it with `bin/run.sh` (the first run will install all dependencies) -6. Open your web browser and visit +
    +
  1. Clone the git repository git clone 'git://github.com/Pita/etherpad-lite.git'
     
  2. +
  3. Install the dependencies with bin/installDeps.sh (if you have problems at this step, look at the section Troubleshooting below)
     
  4. +
  5. Start it with bin/run.sh
     
  6. +
  7. Open your web browser and visit http://localhost:9001. You like it? Look at the 'Next Steps' section below
  8. +
## Troubleshooting ### It fails while installing the sqlite dependency -The sqlite package of some linux versions (including debian lenny) is too old. You have to use a PPA or debian backports +The sqlite package of some linux versions (including debian lenny) is too old. We need sqlite >=3.6. You have to use a PPA or debian backports. You find sqlite packages for Ubuntu Hardy [here](https://launchpad.net/~mirabilos/+archive/ppa/+sourcepub/1304941/+listing-archive-extra), Debian Backports can be found [here](http://backports-master.debian.org/Instructions/#index1h2) ### It fails while installing the express dependency, it says my node version is wrong You might have installed node.js version 0.5. You can check that with `node --version`. Please reinstall node 0.4.x -### I stopped the installing process, now it doesn't work anymore, what can I do? +### My installation process stopped, now it doesn't work anymore, what can I do? Remove the node_modules folder. This forces run.sh to reinstall all dependencies ## Next Steps @@ -59,6 +69,7 @@ You can modify the settings in the file settings.json You can update to the latest version with `git pull origin`. The next start with bin/run.sh will update the dependencies Look at this wiki pages: + * [How to deploy Etherpad Lite as a service](https://github.com/Pita/etherpad-lite/wiki/How-to-deploy-Etherpad-Lite-as-a-service) * [How to put Etherpad Lite behind a reverse Proxy](https://github.com/Pita/etherpad-lite/wiki/How-to-put-Etherpad-Lite-behind-a-reverse-Proxy) * [How to customize your Etherpad Lite installation](https://github.com/Pita/etherpad-lite/wiki/How-to-customize-your-Etherpad-Lite-installation) diff --git a/bin/debugRun.sh b/bin/debugRun.sh index fede0b50b..01197a6b8 100755 --- a/bin/debugRun.sh +++ b/bin/debugRun.sh @@ -1,8 +1,7 @@ #!/bin/sh #Move to the folder where ep-lite is installed -FOLDER=$(dirname $(readlink -f $0)) -cd $FOLDER +cd `dirname $0` #Was this script started in the bin folder? if yes move out if [ -d "../bin" ]; then @@ -21,7 +20,7 @@ hash node-inspector > /dev/null 2>&1 || { node-inspector & -echo "If you new to node-inspector, take a look at this video: http://youtu.be/AOnK3NVnxL8" +echo "If you are new to node-inspector, take a look at this video: http://youtu.be/AOnK3NVnxL8" cd "node" node --debug server.js diff --git a/bin/generateJsDoc.sh b/bin/generateJsDoc.sh index 1667c1ccc..8704d5ad0 100755 --- a/bin/generateJsDoc.sh +++ b/bin/generateJsDoc.sh @@ -1,8 +1,7 @@ #!/bin/sh #Move to the folder where ep-lite is installed -FOLDER=$(dirname $(readlink -f $0)) -cd $FOLDER +cd `dirname $0` #Was this script started in the bin folder? if yes move out if [ -d "../bin" ]; then diff --git a/bin/installDeps.sh b/bin/installDeps.sh index 2c880896c..db46dbfab 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -1,8 +1,7 @@ #!/bin/sh #Move to the folder where ep-lite is installed -FOLDER=$(dirname $(readlink -f $0)) -cd $FOLDER +cd `dirname $0` #Was this script started in the bin folder? if yes move out if [ -d "../bin" ]; then @@ -10,8 +9,8 @@ if [ -d "../bin" ]; then fi #Is wget installed? -hash wget > /dev/null 2>&1 || { - echo "Please install wget" >&2 +hash curl > /dev/null 2>&1 || { + echo "Please install curl" >&2 exit 1 } @@ -34,7 +33,7 @@ if [ ! -f "settings.json" ]; then fi echo "Ensure that all dependencies are up to date..." -npm install || exit 1 +npm install || rm -rf node_modules; exit 1 echo "Ensure jQuery is downloaded and up to date..." DOWNLOAD_JQUERY="true" @@ -48,7 +47,7 @@ if [ -f "static/js/jquery.min.js" ]; then fi if [ $DOWNLOAD_JQUERY = "true" ]; then - wget -O static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1 + curl -lo static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1 fi #Remove all minified data to force node creating it new diff --git a/bin/run.sh b/bin/run.sh index b5f851610..a5245ff77 100755 --- a/bin/run.sh +++ b/bin/run.sh @@ -1,8 +1,7 @@ #!/bin/sh #Move to the folder where ep-lite is installed -FOLDER=$(dirname $(readlink -f $0)) -cd $FOLDER +cd `dirname $0` #Was this script started in the bin folder? if yes move out if [ -d "../bin" ]; then @@ -16,7 +15,7 @@ if [ "$(id -u)" -eq 0 ]; then read rocks if [ ! $rocks = "Etherpad Lite rocks my socks" ] then - echo "You're input was wrong" + echo "Your input was incorrect" exit 1 fi fi diff --git a/bin/safeRun.sh b/bin/safeRun.sh index d7d2b99cc..b060f5d19 100755 --- a/bin/safeRun.sh +++ b/bin/safeRun.sh @@ -18,8 +18,7 @@ TIME_BETWEEN_EMAILS=600 # 10 minutes LAST_EMAIL_SEND=0 #Move to the folder where ep-lite is installed -FOLDER=$(dirname $(readlink -f $0)) -cd $FOLDER +cd `dirname $0` #Was this script started in the bin folder? if yes move out if [ -d "../bin" ]; then diff --git a/node/handler/ExportHandler.js b/node/handler/ExportHandler.js index e128fd7b7..674950f40 100644 --- a/node/handler/ExportHandler.js +++ b/node/handler/ExportHandler.js @@ -23,11 +23,20 @@ var padManager = require("../db/PadManager"); var async = require("async"); var fs = require("fs"); var settings = require('../utils/Settings'); +var os = require('os'); //load abiword only if its enabled if(settings.abiword != null) var abiword = require("../utils/Abiword"); +var tempDirectory = "/tmp"; + +//tempDirectory changes if the operating system is windows +if(os.type().indexOf("Windows") > -1) +{ + tempDirectory = "c:\\Temp"; +} + /** * do a requested export */ @@ -52,7 +61,7 @@ exports.doExport = function(req, res, padId, type) var html; var randNum; var srcFile, destFile; - + async.series([ //render the html document function(callback) @@ -76,7 +85,7 @@ exports.doExport = function(req, res, padId, type) else { randNum = Math.floor(Math.random()*new Date().getTime()); - srcFile = "/tmp/eplite_export_" + randNum + ".html"; + srcFile = tempDirectory + "/eplite_export_" + randNum + ".html"; fs.writeFile(srcFile, html, callback); } }, @@ -86,7 +95,7 @@ exports.doExport = function(req, res, padId, type) //ensure html can be collected by the garbage collector html = null; - destFile = "/tmp/eplite_export_" + randNum + "." + type; + destFile = tempDirectory + "/eplite_export_" + randNum + "." + type; abiword.convertFile(srcFile, destFile, type, callback); }, //send the file @@ -104,7 +113,11 @@ exports.doExport = function(req, res, padId, type) }, function(callback) { - fs.unlink(destFile, callback); + //100ms delay to accomidate for slow windows fs + setTimeout(function() + { + fs.unlink(destFile, callback); + }, 100); } ], callback); } diff --git a/node/handler/ImportHandler.js b/node/handler/ImportHandler.js index 489ee1b09..c02c9f508 100644 --- a/node/handler/ImportHandler.js +++ b/node/handler/ImportHandler.js @@ -24,10 +24,19 @@ var async = require("async"); var fs = require("fs"); var settings = require('../utils/Settings'); var formidable = require('formidable'); +var os = require("os"); //load abiword only if its enabled if(settings.abiword != null) var abiword = require("../utils/Abiword"); + +var tempDirectory = "/tmp/"; + +//tempDirectory changes if the operating system is windows +if(os.type().indexOf("Windows") > -1) +{ + tempDirectory = "c:\\Temp\\"; +} /** * do a requested import @@ -48,6 +57,7 @@ exports.doImport = function(req, res, padId) { var form = new formidable.IncomingForm(); form.keepExtensions = true; + form.uploadDir = tempDirectory; form.parse(req, function(err, fields, files) { @@ -94,7 +104,7 @@ exports.doImport = function(req, res, padId) function(callback) { var randNum = Math.floor(Math.random()*new Date().getTime()); - destFile = "/tmp/eplite_import_" + randNum + ".txt"; + destFile = tempDirectory + "eplite_import_" + randNum + ".txt"; abiword.convertFile(srcFile, destFile, "txt", callback); }, @@ -114,7 +124,13 @@ exports.doImport = function(req, res, padId) fs.readFile(destFile, "utf8", function(err, _text) { text = _text; - callback(err); + + //node on windows has a delay on releasing of the file lock. + //We add a 100ms delay to work around this + setTimeout(function() + { + callback(err); + }, 100); }); }, diff --git a/node/utils/Abiword.js b/node/utils/Abiword.js index edac46486..3a99f56be 100644 --- a/node/utils/Abiword.js +++ b/node/utils/Abiword.js @@ -22,71 +22,121 @@ var util = require('util'); var spawn = require('child_process').spawn; var async = require("async"); var settings = require("./Settings"); +var os = require('os'); -//Queue with the converts we have to do -var queue = async.queue(doConvertTask, 1); - -//spawn the abiword process -var abiword = spawn(settings.abiword, ["--plugin", "AbiCommand"]); - -//append error messages to the buffer -abiword.stderr.on('data', function (data) +//on windows we have to spawn a process for each convertion, cause the plugin abicommand doesn't exist on this platform +if(os.type().indexOf("Windows") > -1) { - stdoutBuffer += data.toString(); -}); + var stdoutBuffer = ""; -//throw exceptions if abiword is dieing -abiword.on('exit', function (code) -{ - throw "Abiword died with exit code " + code; -}); - -//delegate the processing of stdout to a other function -abiword.stdout.on('data',onAbiwordStdout); - -var stdoutCallback = null; -var stdoutBuffer = ""; -var firstPrompt = true; - -function onAbiwordStdout(data) -{ - //add data to buffer - stdoutBuffer+=data.toString(); - - //we're searching for the prompt, cause this means everything we need is in the buffer - if(stdoutBuffer.search("AbiWord:>") != -1) + function doConvertTask(task, callback) { - //filter the feedback message - var err = stdoutBuffer.search("OK") != -1 ? null : stdoutBuffer; + //span an abiword process to perform the conversion + var abiword = spawn(settings.abiword, ["--to=" + task.destFile, task.srcFile]); - //reset the buffer - stdoutBuffer = ""; - - //call the callback with the error message - //skip the first prompt - if(stdoutCallback != null && !firstPrompt) + //delegate the processing of stdout to another function + abiword.stdout.on('data', function (data) { - stdoutCallback(err); - stdoutCallback = null; - } - - firstPrompt = false; - } -} + //add data to buffer + stdoutBuffer+=data.toString(); + }); -function doConvertTask(task, callback) -{ - abiword.stdin.write("convert " + task.srcFile + " " + task.destFile + " " + task.type + "\n"); + //append error messages to the buffer + abiword.stderr.on('data', function (data) + { + stdoutBuffer += data.toString(); + }); + + //throw exceptions if abiword is dieing + abiword.on('exit', function (code) + { + if(code != 0) { + throw "Abiword died with exit code " + code; + } + + if(stdoutBuffer != "") + { + console.log(stdoutBuffer); + } + + callback(); + }); + } - //create a callback that calls the task callback and the caller callback - stdoutCallback = function (err) + exports.convertFile = function(srcFile, destFile, type, callback) { - callback(); - task.callback(err); + doConvertTask({"srcFile": srcFile, "destFile": destFile, "type": type}, callback); }; } - -exports.convertFile = function(srcFile, destFile, type, callback) +//on unix operating systems, we can start abiword with abicommand and communicate with it via stdin/stdout +//thats much faster, about factor 10 +else { - queue.push({"srcFile": srcFile, "destFile": destFile, "type": type, "callback": callback}); -}; + //Queue with the converts we have to do + var queue = async.queue(doConvertTask, 1); + + //spawn the abiword process + var abiword = spawn(settings.abiword, ["--plugin", "AbiCommand"]); + + //append error messages to the buffer + abiword.stderr.on('data', function (data) + { + stdoutBuffer += data.toString(); + }); + + //throw exceptions if abiword is dieing + abiword.on('exit', function (code) + { + throw "Abiword died with exit code " + code; + }); + + //delegate the processing of stdout to a other function + abiword.stdout.on('data',onAbiwordStdout); + + var stdoutCallback = null; + var stdoutBuffer = ""; + var firstPrompt = true; + + function onAbiwordStdout(data) + { + //add data to buffer + stdoutBuffer+=data.toString(); + + //we're searching for the prompt, cause this means everything we need is in the buffer + if(stdoutBuffer.search("AbiWord:>") != -1) + { + //filter the feedback message + var err = stdoutBuffer.search("OK") != -1 ? null : stdoutBuffer; + + //reset the buffer + stdoutBuffer = ""; + + //call the callback with the error message + //skip the first prompt + if(stdoutCallback != null && !firstPrompt) + { + stdoutCallback(err); + stdoutCallback = null; + } + + firstPrompt = false; + } + } + + function doConvertTask(task, callback) + { + abiword.stdin.write("convert " + task.srcFile + " " + task.destFile + " " + task.type + "\n"); + + //create a callback that calls the task callback and the caller callback + stdoutCallback = function (err) + { + callback(); + task.callback(err); + }; + } + + exports.convertFile = function(srcFile, destFile, type, callback) + { + queue.push({"srcFile": srcFile, "destFile": destFile, "type": type, "callback": callback}); + }; +} diff --git a/node/utils/Minify.js b/node/utils/Minify.js index 4f7170f93..a8146addd 100644 --- a/node/utils/Minify.js +++ b/node/utils/Minify.js @@ -29,6 +29,7 @@ var path = require('path'); var Buffer = require('buffer').Buffer; var gzip = require('gzip'); var server = require('../server'); +var os = require('os'); var padJS = ["jquery.min.js", "pad_utils.js", "plugins.js", "undo-xpopup.js", "json2.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js", "jquery-ui.js", "chat.js"]; @@ -222,11 +223,20 @@ exports.minifyJS = function(req, res, jsFilename) //write the results compressed in a file function(callback) { - gzip(result, 9, function(err, compressedResult){ - if(err) {callback(err); return} - - fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback); - }); + //spawn a gzip process if we're on a unix system + if(os.type().indexOf("Windows") == -1) + { + gzip(result, 9, function(err, compressedResult){ + if(err) {callback(err); return} + + fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback); + }); + } + //skip this step on windows + else + { + callback(); + } } ],callback); } @@ -238,7 +248,7 @@ exports.minifyJS = function(req, res, jsFilename) var gzipSupport = req.header('Accept-Encoding', '').indexOf('gzip') != -1; var pathStr; - if(gzipSupport) + if(gzipSupport && os.type().indexOf("Windows") == -1) { pathStr = path.normalize(__dirname + "/../../var/minified_" + jsFilename + ".gz"); res.header('Content-Encoding', 'gzip'); diff --git a/package.json b/package.json index 59e214f8a..4ae1a0877 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,11 @@ "name": "Robin Buse"} ], "dependencies" : { - "socket.io" : "0.7.7", - "ueberDB" : "0.0.13", + "socket.io" : "0.7.8", + "ueberDB" : "0.0.14", "async" : "0.1.9", "joose" : "3.18.0", - "express" : "2.4.3", + "express" : "2.4.4", "clean-css" : "0.2.4", "uglify-js" : "1.0.6", "gzip" : "0.1.0", diff --git a/static/index.html b/static/index.html index 1cc71bd9b..c4f2e4e92 100644 --- a/static/index.html +++ b/static/index.html @@ -57,14 +57,8 @@ #button:active { box-shadow: inset 0 1px 12px rgba(0, 0, 0, 0.9); background: #444; - /* - background: -webkit-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D); - background: -moz-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D); - background: -ms-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D); - background: -o-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D); - */ } - .label { + #label { text-align: left; margin: 0 auto; width: 300px; @@ -86,13 +80,13 @@
New Pad

-
or create/open a Pad with the name
+
or create/open a Pad with the name
-
-