Compare commits
14 Commits
greenkeepe
...
docker
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
820203625c | ||
|
|
03059b67f1 | ||
|
|
1426bc9c24 | ||
|
|
bd0471dad6 | ||
|
|
bbdcb2b2fe | ||
|
|
af5335025f | ||
|
|
f9cf8ba7e8 | ||
|
|
9877977750 | ||
|
|
bda60bf877 | ||
|
|
7605b8f373 | ||
|
|
dfcfd7f0b8 | ||
|
|
a3e2129b79 | ||
|
|
2e34b317a4 | ||
|
|
d887d56dd3 |
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@@ -0,0 +1,14 @@
|
||||
.DS_Store
|
||||
.git
|
||||
logs
|
||||
*.log
|
||||
scripts
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
lib-cov
|
||||
coverage
|
||||
.grunt
|
||||
.lock-wscript
|
||||
build/Release
|
||||
node_modules
|
||||
19
Dockerfile
Normal file
19
Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM spacedeck/docker-baseimage:latest
|
||||
ENV NODE_ENV production
|
||||
|
||||
RUN mkdir -p /usr/src/app
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package.json /usr/src/app/
|
||||
RUN npm install
|
||||
RUN npm install gulp-rev-replace gulp-clean gulp-fingerprint gulp-rev gulp-rev-all gulp-rev-replace
|
||||
RUN npm install -g --save-dev gulp
|
||||
|
||||
COPY . /usr/src/app
|
||||
RUN gulp styles
|
||||
RUN npm cache clean
|
||||
|
||||
CMD [ "npm", "start" ]
|
||||
|
||||
EXPOSE 9666
|
||||
|
||||
@@ -12,10 +12,9 @@ var uglify = require('gulp-uglify');
|
||||
var fingerprint = require('gulp-fingerprint');
|
||||
var rev = require('gulp-rev');
|
||||
|
||||
var RevAll = require('gulp-rev-all');
|
||||
var revAll = require('gulp-rev-all');
|
||||
|
||||
gulp.task('rev', () => {
|
||||
var revAll = new RevAll();
|
||||
return gulp.src(['public/**'])
|
||||
.pipe(gulp.dest('build/assets'))
|
||||
.pipe(revAll.revision())
|
||||
|
||||
22
README.md
22
README.md
@@ -1,7 +1,5 @@
|
||||
# Spacedeck Open
|
||||
|
||||
[](https://greenkeeper.io/)
|
||||
|
||||
This is the free and open source version of Spacedeck, a web based, real time, collaborative whiteboard application with rich media support. Spacedeck was developed in 6 major releases during Autumn 2011 until the end of 2016 and was originally a commercial SaaS. The developers were Lukas F. Hartmann (mntmn) and Martin GĂĽther (magegu). All icons and large parts of the CSS were designed by Thomas Helbig (dergraph).
|
||||
|
||||
As we plan to retire the subscription based service at spacedeck.com in late 2017, we decided to open-source Spacedeck to allow educational and other organizations who currently rely on Spacedeck to migrate to a self-hosted version.
|
||||
@@ -25,16 +23,16 @@ We appreciate filed issues, pull requests and general discussion.
|
||||
|
||||
Spacedeck uses the following major building blocks:
|
||||
|
||||
- Node.js 4.x (Backend / API)
|
||||
- Vue.js (Frontend)
|
||||
- Node.js 7.x (Backend / API)
|
||||
- MongoDB 3.x (Datastore)
|
||||
- Redis 3.x (Datastore for realtime channels)
|
||||
- Vue.js (Frontend)
|
||||
|
||||
It also has some binary dependencies for media conversion and PDF export:
|
||||
|
||||
- imagemagick
|
||||
- imagemagick, graphicsmagick, libav(+codecs, ffmpeg replacement), audiowaveform (https://github.com/bbcrd/audiowaveform), phantomjs (http://phantomjs.org/)
|
||||
|
||||
Currently, media files are stored in Amazon S3, so you need an Amazon AWS account and have the ```AWS_ACCESS_KEY_ID``` and ```AWS_SECRET_ACCESS_KEY``` environment variables defined. For sending emails, Amazon SES is required.
|
||||
Currently, media files are stored in Amazon S3, so you need an Amazon AWS account and have the ```AWS_ACCESS_KEY_ID``` and ```AWS_SECRET_ACCESS_KEY``` environment variables defined. For sending emails in production, Amazon SES is required.
|
||||
|
||||
To install Spacedeck, you need node.js 4.x and a running MongoDB instance. Then, to install all node dependencies, run
|
||||
|
||||
@@ -44,10 +42,22 @@ To rebuild the frontend CSS styles (you need to do this at least once):
|
||||
|
||||
gulp styles
|
||||
|
||||
# Configuration
|
||||
|
||||
see: config/config.json
|
||||
|
||||
# Run
|
||||
|
||||
export NODE_ENV=development
|
||||
npm start
|
||||
open http://localhost:9666
|
||||
|
||||
# experimental docker(compose) support
|
||||
|
||||
We have a docker base image at https://github.com/spacedeck/docker-baseimage that includes all required binaries. Based on this image we can use Docker-Compose to bootstrap a Spacedeck including data storages.
|
||||
|
||||
docker-compose build
|
||||
docker-compose run -e ENV=development -p 9666:9666 -e NODE_ENV=development spacedeck-open
|
||||
|
||||
# License
|
||||
|
||||
|
||||
6
app.js
6
app.js
@@ -47,7 +47,7 @@ swig.setFilter('cdn', function(input, idx) {
|
||||
app.engine('html', swig.renderFile);
|
||||
app.set('view engine', 'html');
|
||||
|
||||
if (app.get('env') != 'development') {
|
||||
if (isProduction) {
|
||||
app.set('views', path.join(__dirname, 'build', 'views'));
|
||||
app.use(favicon(path.join(__dirname, 'build', 'assets', 'images', 'favicon.png')));
|
||||
app.use(express.static(path.join(__dirname, 'build', 'assets')));
|
||||
@@ -121,11 +121,11 @@ if (app.get('env') == 'development') {
|
||||
module.exports = app;
|
||||
|
||||
// CONNECT TO DATABASE
|
||||
const mongoHost = process.env.MONGO_PORT_27017_TCP_ADDR || 'localhost';
|
||||
const mongoHost = process.env.MONGO_PORT_27017_TCP_ADDR || 'db';
|
||||
mongoose.connect('mongodb://' + mongoHost + '/spacedeck');
|
||||
|
||||
// START WEBSERVER
|
||||
const port = 9000;
|
||||
const port = 9666;
|
||||
|
||||
const server = http.Server(app).listen(port, () => {
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"endpoint": "http://localhost:9000",
|
||||
"storage_bucket": "my_spacedeck_s3_bucket",
|
||||
"storage_cdn": "xyz.cloudfront.net",
|
||||
"endpoint": "http://localhost:9666",
|
||||
"storage_bucket": "sdeck-development",
|
||||
"storage_cdn": "http://localhost:9123/sdeck-development",
|
||||
"storage_endpoint": "http://storage:9000",
|
||||
"google_access" : "",
|
||||
"google_secret" : "",
|
||||
"admin_pass": "very_secret_admin_password",
|
||||
|
||||
34
docker-compose.yml
Normal file
34
docker-compose.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
version: '2'
|
||||
services:
|
||||
sync:
|
||||
image: redis
|
||||
storage:
|
||||
image: minio/minio
|
||||
environment:
|
||||
- MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
|
||||
- MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
ports:
|
||||
- 9123:9000
|
||||
command: server /export
|
||||
db:
|
||||
image: mongo
|
||||
spacedeck-open:
|
||||
environment:
|
||||
- env=development
|
||||
- MINIO_ACCESS_KEY=AKIAIOSFODNN7EXAMPLE
|
||||
- MINIO_SECRET_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
build: .
|
||||
volumes:
|
||||
# - ./:/usr/src/app
|
||||
- /usr/src/app/node_modules
|
||||
command: npm start
|
||||
ports:
|
||||
- 9666:9666
|
||||
depends_on:
|
||||
- db
|
||||
- sync
|
||||
- storage
|
||||
links:
|
||||
- storage
|
||||
- db
|
||||
- sync
|
||||
@@ -32,31 +32,36 @@ module.exports = {
|
||||
};
|
||||
|
||||
phantom.create({ path: require('phantomjs-prebuilt').path }, function (err, browser) {
|
||||
return browser.createPage(function (err, page) {
|
||||
console.log("page created, opening ",space_url);
|
||||
if(err){
|
||||
console.log(err);
|
||||
}else{
|
||||
return browser.createPage(function (err, page) {
|
||||
console.log("page created, opening ",space_url);
|
||||
|
||||
if (type=="pdf") {
|
||||
var psz = {
|
||||
width: space.advanced.width+"px",
|
||||
height: space.advanced.height+"px"
|
||||
};
|
||||
page.set('paperSize', psz);
|
||||
}
|
||||
if (type=="pdf") {
|
||||
var psz = {
|
||||
width: space.advanced.width+"px",
|
||||
height: space.advanced.height+"px"
|
||||
};
|
||||
page.set('paperSize', psz);
|
||||
}
|
||||
|
||||
page.set('settings.resourceTimeout',timeout);
|
||||
page.set('settings.javascriptEnabled',false);
|
||||
page.set('settings.resourceTimeout',timeout);
|
||||
page.set('settings.javascriptEnabled',false);
|
||||
|
||||
return page.open(space_url, function (err,status) {
|
||||
page.render(export_path, function() {
|
||||
on_success_called = true;
|
||||
if (on_success) {
|
||||
on_success(export_path);
|
||||
}
|
||||
page.close();
|
||||
browser.exit();
|
||||
return page.open(space_url, function (err,status) {
|
||||
page.render(export_path, function() {
|
||||
on_success_called = true;
|
||||
if (on_success) {
|
||||
on_success(export_path);
|
||||
}
|
||||
page.close();
|
||||
browser.exit();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}, {
|
||||
onExit: on_exit
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@ const websockets = require('./websockets');
|
||||
|
||||
module.exports = {
|
||||
connectRedis(){
|
||||
const redisHost = process.env.REDIS_PORT_6379_TCP_ADDR || 'localhost';
|
||||
const redisHost = process.env.REDIS_PORT_6379_TCP_ADDR || 'sync';
|
||||
this.connection = new RedisConnection(6379, redisHost);
|
||||
},
|
||||
sendMessage(action, model, attributes, channelId) {
|
||||
|
||||
@@ -6,11 +6,34 @@ AWS.config.region = 'eu-central-1';
|
||||
var fs = require('fs');
|
||||
var config = require('config');
|
||||
|
||||
var cdn = config.get("storage_cdn");
|
||||
var storage_endpoint = config.get("storage_endpoint");
|
||||
|
||||
const bucketName = "sdeck-fresh-development";
|
||||
const ep = new AWS.Endpoint(storage_endpoint);
|
||||
|
||||
AWS.config.update(new AWS.Config({
|
||||
accessKeyId: process.env.MINIO_ACCESS_KEY,
|
||||
secretAccessKey: process.env.MINIO_SECRET_KEY,
|
||||
region: 'us-east-1',
|
||||
s3ForcePathStyle: true,
|
||||
signatureVersion: 'v4'
|
||||
}));
|
||||
|
||||
const s3 = new AWS.S3({
|
||||
endpoint: ep
|
||||
});
|
||||
|
||||
s3.createBucket({
|
||||
Bucket: config.get("storage_bucket"),
|
||||
ACL: "public-read",
|
||||
GrantRead: "*"
|
||||
}, (err,res) => {
|
||||
console.log("createBucket",err,res);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
removeFile: (path, callback) => {
|
||||
const s3 = new AWS.S3({
|
||||
region: 'eu-central-1'
|
||||
});
|
||||
const bucket = config.get("storage_bucket");
|
||||
s3.deleteObject({
|
||||
Bucket: bucket, Key: path
|
||||
@@ -28,7 +51,7 @@ module.exports = {
|
||||
callback({error:"missing path"}, null);
|
||||
return;
|
||||
}
|
||||
console.log("[s3] uploading", localFilePath, " to ", fileName);
|
||||
console.log("[storage] uploading", localFilePath, " to ", fileName);
|
||||
|
||||
const bucket = config.get("storage_bucket");
|
||||
const fileStream = fs.createReadStream(localFilePath);
|
||||
@@ -39,11 +62,6 @@ module.exports = {
|
||||
}
|
||||
});
|
||||
fileStream.on('open', function () {
|
||||
// FIXME
|
||||
var s3 = new AWS.S3({
|
||||
region: 'eu-central-1'
|
||||
});
|
||||
|
||||
s3.putObject({
|
||||
Bucket: bucket,
|
||||
Key: fileName,
|
||||
@@ -54,7 +72,7 @@ module.exports = {
|
||||
console.error(err);
|
||||
callback(err);
|
||||
}else {
|
||||
const url = "https://"+ config.get("storage_cdn") + "/" + fileName;
|
||||
const url = cdn + "/" + fileName;
|
||||
console.log("[s3]" + localFilePath + " to " + url);
|
||||
callback(null, url);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ require('../models/schema');
|
||||
|
||||
const WebSocketServer = require('ws').Server;
|
||||
|
||||
const Redis = require('ioredis');
|
||||
const RedisConnection = require('ioredis');
|
||||
const async = require('async');
|
||||
const _ = require("underscore");
|
||||
const mongoose = require("mongoose");
|
||||
@@ -12,7 +12,7 @@ const crypto = require('crypto');
|
||||
module.exports = {
|
||||
startWebsockets: function(server){
|
||||
this.setupSubscription();
|
||||
this.state = new Redis(6379, process.env.REDIS_PORT_6379_TCP_ADDR || 'localhost');
|
||||
this.state = new RedisConnection(6379, process.env.REDIS_PORT_6379_TCP_ADDR || 'sync');
|
||||
|
||||
if(!this.current_websockets){
|
||||
this.current_websockets = [];
|
||||
@@ -117,7 +117,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
setupSubscription: function() {
|
||||
this.cursorSubscriber = new Redis(6379, process.env.REDIS_PORT_6379_TCP_ADDR || 'localhost');
|
||||
this.cursorSubscriber = new RedisConnection(6379, process.env.REDIS_PORT_6379_TCP_ADDR || 'sync');
|
||||
this.cursorSubscriber.subscribe(['cursors', 'users', 'updates'], function (err, count) {
|
||||
console.log("[redis] websockets to " + count + " topics." );
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var mongoose = require('mongoose');
|
||||
var Schema = mongoose.Schema;
|
||||
|
||||
module.exports.artifactSchema = mongoose.model('Artifact', {
|
||||
module.exports.artifactSchema = Schema({
|
||||
mime: String,
|
||||
thumbnail_uri: String,
|
||||
space_id: Schema.Types.ObjectId,
|
||||
|
||||
@@ -45,7 +45,7 @@ module.exports.teamSchema.index({
|
||||
|
||||
module.exports.teamSchema.statics.getTeamForHost = (host, cb) => {
|
||||
|
||||
if (host != "127.0.0.1:9000") { //phantomjs check
|
||||
if (host != "127.0.0.1:9666") { //phantomjs check
|
||||
let subDomainParts = host.split('.');
|
||||
|
||||
if (subDomainParts.length > 2) {
|
||||
|
||||
22
package.json
22
package.json
@@ -6,12 +6,15 @@
|
||||
"start": "nodemon -e .js,.html bin/www",
|
||||
"test": "mocha"
|
||||
},
|
||||
"engines" : {
|
||||
"node" : ">=7.8.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"archiver": "1.3.0",
|
||||
"async": "2.3.0",
|
||||
"aws-sdk": "2.39.0",
|
||||
"basic-auth": "1.1.0",
|
||||
"bcrypt": "*",
|
||||
"bcryptjs": "2.4.3",
|
||||
"body-parser": "~1.17.1",
|
||||
"cheerio": "0.22.0",
|
||||
"config": "1.25.1",
|
||||
@@ -19,17 +22,17 @@
|
||||
"csurf": "1.9.0",
|
||||
"debug": "~2.6.3",
|
||||
"execSync": "latest",
|
||||
"express": "~4.15.2",
|
||||
"express": "~4.13.0",
|
||||
"glob": "7.1.1",
|
||||
"gm": "1.23.0",
|
||||
"googleapis": "18.0.0",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "2.6.0",
|
||||
"gulp-eslint": "*",
|
||||
"gulp-express": "0.3.5",
|
||||
"gulp-express": "0.3.0",
|
||||
"gulp-nodemon": "*",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"gulp-sass": "^2.0.3",
|
||||
"gulp-uglify": "^1.5.1",
|
||||
"gulp-util": "^3.0.6",
|
||||
"helmet": "^3.5.0",
|
||||
"i18n-2": "0.6.3",
|
||||
@@ -59,7 +62,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"express": "^4.13.3",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-clean": "^0.3.2",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-eslint": "^3.0.1",
|
||||
@@ -71,8 +74,7 @@
|
||||
"gulp-rev-replace": "^0.4.3",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-uglify": "^2.1.2",
|
||||
"mocha": "*",
|
||||
"nodemon": "*",
|
||||
"nodemon": "1.11.0",
|
||||
"should": "^11.2.1",
|
||||
"supertest": "^3.0.0",
|
||||
"winston": "^2.3.1"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
var config = require('config');
|
||||
require('../../models/schema');
|
||||
|
||||
var bcrypt = require('bcrypt');
|
||||
var bcrypt = require('bcryptjs');
|
||||
var crypo = require('crypto');
|
||||
|
||||
var express = require('express');
|
||||
|
||||
@@ -9,7 +9,7 @@ var mailer = require('../../helpers/mailer');
|
||||
var fs = require('fs');
|
||||
var _ = require('underscore');
|
||||
var crypto = require('crypto');
|
||||
var bcrypt = require('bcrypt');
|
||||
var bcrypt = require('bcryptjs');
|
||||
|
||||
var express = require('express');
|
||||
var router = express.Router();
|
||||
|
||||
@@ -6,7 +6,7 @@ require('../../models/schema');
|
||||
var mailer = require('../../helpers/mailer');
|
||||
var uploader = require('../../helpers/uploader');
|
||||
|
||||
var bcrypt = require('bcrypt');
|
||||
var bcrypt = require('bcryptjs');
|
||||
var crypo = require('crypto');
|
||||
var swig = require('swig');
|
||||
var async = require('async');
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
{% if process.env.NODE_ENV != "production" %}
|
||||
var ENV = {
|
||||
name: 'development',
|
||||
webHost: "localhost:9000",
|
||||
webEndpoint:"http://localhost:9000",
|
||||
apiEndpoint: "http://localhost:9000",
|
||||
websocketsEndpoint: "ws://localhost:9000"
|
||||
webHost: "localhost:9666",
|
||||
webEndpoint:"http://localhost:9666",
|
||||
apiEndpoint: "http://localhost:9666",
|
||||
websocketsEndpoint: "ws://localhost:9666"
|
||||
};
|
||||
{% endif %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user