c9-core/plugins/c9.vfs.standalone/standalone.js

392 wiersze
12 KiB
JavaScript

"use strict";
plugin.consumes = [
"connect.static",
"connect",
"preview.handler",
"connect.render",
"connect.render.ejs"
];
plugin.provides = ["api", "passport"];
module.exports = plugin;
var fs = require("fs");
var assert = require("assert");
var async = require("async");
var join = require("path").join;
var extend = require("util")._extend;
var resolve = require("path").resolve;
var basename = require("path").basename;
var frontdoor = require("frontdoor");
function plugin(options, imports, register) {
var previewHandler = imports["preview.handler"];
var statics = imports["connect.static"];
assert(options.workspaceDir, "Option 'workspaceDir' is required");
assert(options.options, "Option 'options' is required");
// serve index.html
statics.addStatics([{
path: __dirname + "/www",
mount: "/"
}]);
statics.addStatics([{
path: __dirname + "/../../configs",
mount: "/configs"
}]);
statics.addStatics([{
path: __dirname + "/../../test/resources",
mount: "/test"
}]);
var api = frontdoor();
imports.connect.use(api);
api.get("/", function(req, res, next) {
res.writeHead(302, { "Location": options.sdk ? "/ide.html" : "/static/places.html" });
res.end();
});
api.get("/ide.html", {
params: {
workspacetype: {
source: "query",
optional: true
},
devel: {
source: "query",
optional: true
},
collab: {
type: "number",
optional: true,
source: "query"
},
nocollab: {
type: "number",
optional: true,
source: "query"
},
debug: {
optional: true,
source: "query"
},
packed: {
source: "query",
type: "number",
optional: true
},
token: {
source: "query",
optional: true
},
w: {
source: "query",
optional: true
},
}
}, function(req, res, next) {
var configName = getConfigName(req.params, options);
var collab = options.collab && req.params.collab !== 0 && req.params.nocollab != 1;
var opts = extend({}, options);
opts.options.collab = collab;
if (req.params.packed == 1)
opts.packed = opts.options.packed = true;
var cdn = options.options.cdn;
options.options.themePrefix = "/static/" + cdn.version + "/skin/" + configName;
options.options.workerPrefix = "/static/" + cdn.version + "/worker";
options.options.CORSWorkerPrefix = opts.packed ? "/static/" + cdn.version + "/worker" : "";
api.updatConfig(opts.options, {
w: req.params.w,
token: req.params.token
});
opts.options.debug = req.params.debug !== undefined;
res.setHeader("Cache-Control", "no-cache, no-store");
res.render(__dirname + "/views/standalone.html.ejs", {
architectConfig: getConfig(configName, opts),
configName: configName,
packed: opts.packed,
version: opts.version
}, next);
});
api.get("/_ping", function(params, callback) {
return callback(null, {"ping": "pong"});
});
api.get("/preview/:path*", [
function(req, res, next) {
req.projectSession = {
pid: 1
};
req.session = {};
api.authenticate()(req, res, next);
},
previewHandler.getProxyUrl(function() {
return {
url: "http://localhost:" + options.options.port + "/vfs"
};
}),
previewHandler.proxyCall()
]);
api.get("/preview", function(req, res, next) {
res.redirect(req.url + "/");
});
api.get("/vfs-root", function(req, res, next) {
if (!options.options.testing)
return next();
res.writeHead(200, {"Content-Type": "application/javascript"});
res.end("define(function(require, exports, module) { return '"
+ options.workspaceDir + "'; });");
});
api.get("/vfs-home", function(req, res, next) {
if (!options.options.testing)
return next();
res.writeHead(200, {"Content-Type": "application/javascript"});
res.end("define(function(require, exports, module) { return '"
+ process.env.HOME + "'; });");
});
api.get("/update", function(req, res, next) {
res.writeHead(200, {
"Content-Type": "application/javascript",
"Access-Control-Allow-Origin": "*"
});
var path = resolve(__dirname + "/../../build/output/latest.tar.gz");
fs.readlink(path, function(err, target) {
if (err) return next(err);
res.end((target || "").split(".")[0]);
});
});
api.get("/update/:path*", function(req, res, next) {
var filename = req.params.path;
var path = resolve(__dirname + "/../../build/output/" + filename);
var stream = fs.createReadStream(path);
stream.on("error", function(err) {
next(err);
});
stream.on("data", function(data) {
if (!res.headersSent)
res.writeHead(200, {"Content-Type": "application/octet-stream"});
res.write(data);
});
stream.on("end", function(data) {
res.end();
});
});
api.get("/configs/require_config.js", function(req, res, next) {
var config = res.getOptions().requirejsConfig || {};
res.writeHead(200, {"Content-Type": "application/javascript"});
res.end("requirejs.config(" + JSON.stringify(config) + ");");
});
api.get("/test/all.json", function(req, res, next) {
var base = __dirname + "/../../";
var blacklistfile = base + "/test/blacklist.txt";
var filefinder = require(base + "/test/lib/filefinder.js");
filefinder.find(base, "plugins", ".*_test.js", blacklistfile, function(err, result) {
result.all = result.list.concat(result.blacklist);
async.filterSeries(result.list, function(file, next) {
fs.readFile(file, "utf8", function(err, file) {
if (err) return next(false);
if (file.match(/^"use server"/m) && !file.match(/^"use client"/m))
return next(false);
next(file.match(/^define\(|^require\(\[/m));
});
}, function(files) {
result.list = files;
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify(result, null, 2));
});
});
});
api.get("/api.json", {name: "api"}, frontdoor.middleware.describeApi(api));
api.get("/api/project/:pid/persistent/:apikey", {
params: {
pid: { type: "number" },
apikey: { type: "string" }
}
}, persistentDataApiMock);
api.put("/api/project/:pid/persistent/:apikey", {
params: {
data: { type: "string", source: "body" },
pid: { type: "number" },
apikey: { type: "string" },
}
}, persistentDataApiMock);
api.get("/api/user/persistent/:apikey", {
params: {
apikey: { type: "string" }
}
}, persistentDataApiMock);
api.put("/api/user/persistent/:apikey", {
params: {
data: { type: "string", source: "body" },
apikey: { type: "string" },
}
}, persistentDataApiMock);
function persistentDataApiMock(req, res, next) {
var name = (req.params.pid || 0) + "-" + req.params.apikey;
var data = req.params.data;
console.log(name, data)
if (/[^\w+=\-]/.test(name))
return next(new Error("Invalid apikey"));
var path = join(options.installPath, ".c9", "persistent");
var method = req.method.toLowerCase()
if (method == "get") {
res.writeHead(200, {"Content-Type": "application/octet-stream"});
var stream = fs.createReadStream(path + "/" + name);
stream.pipe(res);
} else if (method == "put") {
require("mkdirp")(path, function(e) {
fs.writeFile(path + "/" + name, data, "", function(err) {
if (err) return next(err);
res.writeHead(200, {"Content-Type": "application/octet-stream"});
res.end("");
});
});
}
}
// fake authentication
api.authenticate = api.authenticate || function() {
return function(req, res, next) {
req.user = extend({}, options.options.extendOptions.user);
next();
};
};
api.ensureAdmin = api.ensureAdmin || function() {
return function(req, res, next) {
next();
};
};
api.getVfsOptions = api.getVfsOptions || function(user, pid) {
if (!options._projects) {
options._projects = [options.workspaceDir];
}
var wd = options._projects[pid] || options._projects[0];
return {
workspaceDir: wd,
extendOptions: {
user: user,
project: {
id: pid,
name: pid + "-" + options._projects[pid]
},
readonly: user.id > 100
}
};
};
api.updatConfig = api.updatConfig || function(opts, params) {
var id = params.token;
opts.accessToken = opts.extendToken = id || "token";
var user = opts.extendOptions.user;
user.id = id || -1;
user.name = id ? "user" + id : "johndoe";
user.email = id ? "user" + id + "@c9.io" : "johndoe@example.org";
user.fullname = id ? "User " + id : "John Doe";
opts.workspaceDir = params.w ? params.w : options.workspaceDir;
opts.projectName = basename(opts.workspaceDir);
if (!options._projects) {
options._projects = [options.workspaceDir];
}
var project = opts.extendOptions.project;
var pid = options._projects.indexOf(opts.workspaceDir);
if (pid == -1)
pid = options._projects.push(opts.workspaceDir) - 1;
project.id = pid;
};
imports.connect.setGlobalOption("apiBaseUrl", "");
register(null, {
"api": api,
"passport": {
authenticate: function() {
return function(req, res, next) {
req.user = extend({}, options.options.extendOptions.user);
next();
};
}
}
});
}
function getConfigName(requested, options) {
var name;
if (requested && requested.workspacetype) {
name = requested.workspacetype;
if (name == "readonly" || name == "ro")
name = "default-ro";
else
name = "workspace-" + name;
}
else if (options.workspaceType) {
name = "workspace-" + options.workspaceType;
}
else if (options.options.client_config) {
// pick up client config from settings, if present
name = options.options.client_config;
}
else if (options.readonly) {
name = "default-ro";
}
else {
name = "default";
}
if (options.local)
name += "-local";
return name;
}
function getConfig(configName, options) {
var filename = __dirname + "/../../configs/client-" + configName + ".js";
var installPath = options.settingDir || options.installPath || "";
var workspaceDir = options.options.workspaceDir;
var settings = {
"user": join(installPath, "user.settings"),
"project": join(options.local ? installPath : join(workspaceDir, ".c9"), "project.settings"),
"state": join(options.local ? installPath : join(workspaceDir, ".c9"), "state.settings")
};
var fs = require("fs");
for (var type in settings) {
var data = "";
try {
data = fs.readFileSync(settings[type], "utf8");
} catch (e) {
}
settings[type] = data;
}
options.options.settings = settings;
return require(filename)(options.options);
}