2020-06-17 12:40:23 +03:00
|
|
|
import * as Middleware from "~/common/middleware";
|
|
|
|
import * as Strings from "~/common/strings";
|
2020-06-17 21:05:13 +03:00
|
|
|
import * as Utilities from "~/node_common/utilities";
|
|
|
|
import * as Constants from "~/node_common/constants";
|
|
|
|
|
|
|
|
import { createPow, ffs } from "@textile/powergate-client";
|
|
|
|
const PowerGate = createPow({ host: Constants.POWERGATE_HOST });
|
2020-02-19 09:30:47 +03:00
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
import FS from "fs-extra";
|
2020-06-17 21:05:13 +03:00
|
|
|
import WebSocketServer from "ws";
|
2020-06-17 12:40:23 +03:00
|
|
|
import express from "express";
|
|
|
|
import formidable from "formidable";
|
|
|
|
import next from "next";
|
|
|
|
import bodyParser from "body-parser";
|
|
|
|
import compression from "compression";
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
// TODO(jim): Support multiple desktop applications.
|
2020-06-09 21:00:36 +03:00
|
|
|
let client = null;
|
2020-06-17 21:05:13 +03:00
|
|
|
let state = null;
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
const production = process.env.NODE_ENV === "production";
|
|
|
|
const port = process.env.PORT || 1337;
|
|
|
|
const wsPort = process.env.WS_PORT || 2448;
|
|
|
|
const app = next({ dev: !production, quiet: false });
|
|
|
|
const nextRequestHandler = app.getRequestHandler();
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
const setIntervalViewerUpdatesUnsafe = async () => {
|
2020-06-09 21:00:36 +03:00
|
|
|
if (client) {
|
|
|
|
try {
|
2020-06-17 21:05:13 +03:00
|
|
|
console.log("[ prototype ] polling: new viewer state.");
|
|
|
|
state = await Utilities.emitState({
|
|
|
|
state,
|
|
|
|
client,
|
|
|
|
PG: PowerGate,
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log("[ prototype ] polling: new library state.");
|
|
|
|
state = await Utilities.refreshLibrary({
|
|
|
|
state,
|
|
|
|
PG: PowerGate,
|
|
|
|
FFS: ffs,
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
console.log(e);
|
|
|
|
}
|
2020-06-17 12:40:23 +03:00
|
|
|
}
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
setTimeout(setIntervalViewerUpdatesUnsafe, Constants.POLLING_RATE);
|
2020-06-09 21:00:36 +03:00
|
|
|
};
|
|
|
|
|
2020-04-09 00:29:13 +03:00
|
|
|
app.prepare().then(async () => {
|
2020-06-17 21:05:13 +03:00
|
|
|
console.log("[ prototype ] initializing ");
|
|
|
|
|
|
|
|
state = {
|
|
|
|
production,
|
|
|
|
port,
|
|
|
|
wsPort,
|
|
|
|
token: null,
|
|
|
|
library: null,
|
|
|
|
status: null,
|
|
|
|
messageList: null,
|
|
|
|
peersList: null,
|
|
|
|
addrsList: null,
|
|
|
|
info: null,
|
|
|
|
};
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
if (!production) {
|
|
|
|
// TODO(jim): Remove later.
|
|
|
|
// We wipe all of the local data each time you run the application.
|
2020-06-22 09:22:22 +03:00
|
|
|
try {
|
|
|
|
await Utilities.resetFileSystem();
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
const updates = await Utilities.refresh({ PG: PowerGate });
|
|
|
|
state = await Utilities.updateStateData(state, updates);
|
|
|
|
console.log("[ prototype ] updated without token");
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
// NOTE(jim): This is a configuration folder with all of the client tokens.
|
|
|
|
if (!FS.existsSync(`./.data`)) {
|
|
|
|
FS.mkdirSync(`./.data`, { recursive: true });
|
|
|
|
}
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
// NOTE(jim): This will create a token for authentication with powergate.
|
|
|
|
if (!FS.existsSync("./.data/powergate-token")) {
|
|
|
|
const FFS = await PowerGate.ffs.create();
|
|
|
|
state.token = FFS.token ? FFS.token : null;
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
// NOTE(jim): Write a new token file.
|
|
|
|
if (state.token) {
|
|
|
|
FS.writeFileSync("./.data/powergate-token", state.token);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
state.token = FS.readFileSync("./.data/powergate-token", "utf8");
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
if (state.token) {
|
|
|
|
console.log("[ prototype ] powergate token:", state.token);
|
|
|
|
PowerGate.setToken(state.token);
|
|
|
|
}
|
2020-04-09 00:29:13 +03:00
|
|
|
|
2020-06-22 09:22:22 +03:00
|
|
|
const tokenUpdates = await Utilities.refreshWithToken({
|
|
|
|
PG: PowerGate,
|
|
|
|
});
|
|
|
|
state = await Utilities.updateStateData(state, tokenUpdates);
|
|
|
|
console.log("[ prototype ] updated with token");
|
|
|
|
|
|
|
|
// TODO(jim): Needs to support nested folders in the future.
|
|
|
|
if (!FS.existsSync("./.data/library.json")) {
|
|
|
|
const librarySchema = {
|
|
|
|
library: [
|
|
|
|
{
|
|
|
|
...Utilities.createFolder({ id: Constants.FILE_STORAGE_URL }),
|
|
|
|
file: "Files",
|
|
|
|
name: "Files",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
FS.writeFileSync("./.data/library.json", JSON.stringify(librarySchema));
|
|
|
|
state.library = librarySchema.library;
|
|
|
|
} else {
|
|
|
|
const parsedLibrary = FS.readFileSync("./.data/library.json", "utf8");
|
|
|
|
state.library = JSON.parse(parsedLibrary).library;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.log(
|
|
|
|
"[ prototype ] you can not run the filecoin client, only web views allowed."
|
|
|
|
);
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
2020-06-08 09:45:53 +03:00
|
|
|
}
|
|
|
|
|
2020-02-19 09:30:47 +03:00
|
|
|
const server = express();
|
2020-06-09 21:00:36 +03:00
|
|
|
const WSS = new WebSocketServer.Server({ port: wsPort });
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
WSS.on("connection", (s) => {
|
2020-06-09 21:00:36 +03:00
|
|
|
// TODO(jim): Suppport more than one client.
|
|
|
|
client = s;
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
s.on("close", function() {
|
|
|
|
s.send(JSON.stringify({ action: null, data: "closed" }));
|
2020-06-09 21:00:36 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
s.send(JSON.stringify({ action: null, data: "connected" }));
|
2020-06-09 21:00:36 +03:00
|
|
|
});
|
2020-02-19 09:30:47 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
if (production) {
|
2020-02-19 09:30:47 +03:00
|
|
|
server.use(compression());
|
|
|
|
}
|
|
|
|
|
|
|
|
server.use(Middleware.CORS);
|
2020-06-17 12:40:23 +03:00
|
|
|
server.use("/public", express.static("public"));
|
2020-02-19 09:30:47 +03:00
|
|
|
server.use(bodyParser.json());
|
|
|
|
server.use(
|
|
|
|
bodyParser.urlencoded({
|
|
|
|
extended: false,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/viewer", async (req, res) => {
|
2020-06-17 21:05:13 +03:00
|
|
|
let data = state;
|
|
|
|
|
|
|
|
if (!production) {
|
|
|
|
const updates = await Utilities.refresh({ PG: PowerGate });
|
|
|
|
const updatesWithToken = await Utilities.refreshWithToken({
|
|
|
|
PG: PowerGate,
|
|
|
|
});
|
|
|
|
data = await Utilities.updateStateData(data, {
|
|
|
|
...updates,
|
|
|
|
...updatesWithToken,
|
|
|
|
});
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
return res.status(200).send({ success: true, data });
|
2020-02-19 09:30:47 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/deals/storage", async (req, res) => {
|
2020-06-09 21:00:36 +03:00
|
|
|
if (Strings.isEmpty(req.body.src)) {
|
|
|
|
return res.status(500).send({ success: false });
|
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
const localPath = `.${req.body.src}`;
|
2020-06-09 21:00:36 +03:00
|
|
|
const buffer = FS.readFileSync(localPath);
|
|
|
|
const { cid } = await PowerGate.ffs.addToHot(buffer);
|
|
|
|
const { jobId } = await PowerGate.ffs.pushConfig(cid);
|
|
|
|
|
|
|
|
// TODO(jim): Refactor this so we repeat this less often.
|
|
|
|
let write = false;
|
2020-06-17 21:05:13 +03:00
|
|
|
for (let i = 0; i < state.library.length; i++) {
|
|
|
|
for (let j = 0; j < state.library[i].children.length; j++) {
|
|
|
|
if (localPath === state.library[i].children[j].id) {
|
|
|
|
state.library[i].children[j].job_id = jobId;
|
|
|
|
state.library[i].children[j].cid = cid;
|
|
|
|
state.library[i].children[j].storage_status = 1;
|
2020-06-09 21:00:36 +03:00
|
|
|
write = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (write) {
|
2020-06-17 21:05:13 +03:00
|
|
|
FS.writeFileSync(
|
|
|
|
"./.data/library.json",
|
|
|
|
JSON.stringify({ library: state.library })
|
|
|
|
);
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({ state, client, PG: PowerGate });
|
2020-06-09 21:00:36 +03:00
|
|
|
return res.status(200).send({ success: true, cid, jobId });
|
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/storage/:file", async (req, res) => {
|
2020-06-17 21:05:13 +03:00
|
|
|
const form = formidable({
|
|
|
|
multiples: true,
|
|
|
|
uploadDir: Constants.FILE_STORAGE_URL,
|
2020-06-08 09:45:53 +03:00
|
|
|
});
|
|
|
|
|
2020-06-09 21:00:36 +03:00
|
|
|
form.parse(req, async (error, fields, files) => {
|
|
|
|
if (error) {
|
|
|
|
return res.status(500).send({ error });
|
|
|
|
} else {
|
2020-06-17 21:05:13 +03:00
|
|
|
// TODO(jim): Need to support other file types.
|
2020-06-09 21:00:36 +03:00
|
|
|
if (!files.image) {
|
2020-06-17 12:40:23 +03:00
|
|
|
console.error("[ prototype ] File type unspported", files);
|
|
|
|
return res
|
|
|
|
.status(500)
|
|
|
|
.send({ error: "File type unsupported", files });
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
2020-06-08 09:45:53 +03:00
|
|
|
|
2020-06-09 21:00:36 +03:00
|
|
|
const newPath = form.uploadDir + req.params.file;
|
2020-06-17 12:40:23 +03:00
|
|
|
FS.rename(files.image.path, newPath, function(err) {});
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
const localFile = Utilities.createFile({
|
|
|
|
id: newPath,
|
|
|
|
data: files.image,
|
|
|
|
});
|
2020-06-08 09:45:53 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
// TODO(jim): Messy, refactor.
|
2020-06-09 21:00:36 +03:00
|
|
|
let pushed = false;
|
2020-06-17 21:05:13 +03:00
|
|
|
for (let i = 0; i < state.library.length; i++) {
|
2020-06-09 21:00:36 +03:00
|
|
|
if (!pushed) {
|
2020-06-17 21:05:13 +03:00
|
|
|
state.library[i].children.push(localFile);
|
2020-06-09 21:00:36 +03:00
|
|
|
pushed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pushed) {
|
2020-06-17 21:05:13 +03:00
|
|
|
FS.writeFileSync(
|
|
|
|
"./.data/library.json",
|
|
|
|
JSON.stringify({ library: state.library })
|
|
|
|
);
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({
|
|
|
|
state,
|
|
|
|
client,
|
|
|
|
PG: PowerGate,
|
|
|
|
});
|
|
|
|
|
2020-06-09 21:00:36 +03:00
|
|
|
return res.status(200).send({ success: true, file: localFile });
|
|
|
|
}
|
2020-06-08 09:45:53 +03:00
|
|
|
});
|
2020-06-09 21:00:36 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/upload/avatar", async (req, res) => {
|
2020-06-17 21:05:13 +03:00
|
|
|
const form = formidable({
|
|
|
|
multiples: true,
|
|
|
|
uploadDir: Constants.AVATAR_STORAGE_URL,
|
2020-06-08 09:45:53 +03:00
|
|
|
});
|
|
|
|
|
2020-06-09 21:00:36 +03:00
|
|
|
form.parse(req, async (error, fields, files) => {
|
2020-06-08 09:45:53 +03:00
|
|
|
if (error) {
|
|
|
|
return res.status(500).send({ error });
|
|
|
|
} else {
|
2020-06-17 12:40:23 +03:00
|
|
|
const newPath = form.uploadDir + "avatar.png";
|
|
|
|
FS.rename(files.image.path, newPath, function(err) {});
|
2020-06-08 09:45:53 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({
|
|
|
|
state,
|
|
|
|
client,
|
|
|
|
PG: PowerGate,
|
|
|
|
});
|
2020-06-08 09:45:53 +03:00
|
|
|
return res.status(200).send({ success: true });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/settings", async (req, res) => {
|
2020-06-08 09:45:53 +03:00
|
|
|
let data;
|
|
|
|
try {
|
2020-06-09 21:00:36 +03:00
|
|
|
data = await PowerGate.ffs.setDefaultConfig(req.body.config);
|
2020-06-08 09:45:53 +03:00
|
|
|
} catch (e) {
|
|
|
|
return res.status(500).send({ error: e.message });
|
|
|
|
}
|
2020-06-04 09:26:20 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({ state, client, PG: PowerGate });
|
2020-06-04 09:26:20 +03:00
|
|
|
return res.status(200).send({ success: true, data });
|
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/wallet/create", async (req, res) => {
|
2020-04-09 00:29:13 +03:00
|
|
|
let data;
|
|
|
|
try {
|
2020-06-17 12:40:23 +03:00
|
|
|
data = await PowerGate.ffs.newAddr(
|
|
|
|
req.body.name,
|
|
|
|
req.body.type,
|
|
|
|
req.body.makeDefault
|
|
|
|
);
|
2020-04-09 00:29:13 +03:00
|
|
|
} catch (e) {
|
|
|
|
return res.status(500).send({ error: e.message });
|
|
|
|
}
|
2020-02-19 09:30:47 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({ state, client, PG: PowerGate });
|
2020-04-09 00:29:13 +03:00
|
|
|
return res.status(200).send({ success: true, data });
|
2020-02-19 09:30:47 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.post("/_/wallet/send", async (req, res) => {
|
2020-04-09 00:29:13 +03:00
|
|
|
let data;
|
|
|
|
try {
|
2020-06-17 12:40:23 +03:00
|
|
|
data = await PowerGate.ffs.sendFil(
|
|
|
|
req.body.source,
|
|
|
|
req.body.target,
|
|
|
|
req.body.amount
|
|
|
|
);
|
2020-04-09 00:29:13 +03:00
|
|
|
} catch (e) {
|
|
|
|
return res.status(500).send({ error: e.message });
|
2020-02-19 09:30:47 +03:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
state = await Utilities.emitState({ state, client, PG: PowerGate });
|
2020-06-17 12:40:23 +03:00
|
|
|
return res
|
|
|
|
.status(200)
|
|
|
|
.send({ success: true, data: { ...data, ...req.body } });
|
2020-02-19 09:30:47 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.get("/", async (req, res) => {
|
2020-06-22 09:22:22 +03:00
|
|
|
if (production || !state.token) {
|
2020-06-17 21:05:13 +03:00
|
|
|
return res.redirect(Constants.GITHUB_URL);
|
2020-06-09 21:00:36 +03:00
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
return app.render(req, res, "/", {
|
|
|
|
production,
|
|
|
|
wsPort,
|
|
|
|
});
|
2020-02-19 09:30:47 +03:00
|
|
|
});
|
|
|
|
|
2020-06-17 12:40:23 +03:00
|
|
|
server.get("*", async (req, res) => {
|
2020-02-19 09:30:47 +03:00
|
|
|
return nextRequestHandler(req, res, req.url);
|
|
|
|
});
|
|
|
|
|
2020-06-09 21:00:36 +03:00
|
|
|
server.listen(port, async (err) => {
|
2020-02-19 09:30:47 +03:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
console.log(`[ prototype ] client: http://localhost:${port}`);
|
|
|
|
console.log(`[ prototype ] constants:`, Constants);
|
2020-06-09 21:00:36 +03:00
|
|
|
|
2020-06-17 21:05:13 +03:00
|
|
|
await setIntervalViewerUpdatesUnsafe();
|
2020-02-19 09:30:47 +03:00
|
|
|
});
|
|
|
|
});
|