basic startup-resolve
This commit is contained in:
commit
3d103b9462
9 changed files with 2451 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
node_modules
|
||||||
|
static/daemon
|
||||||
|
dist
|
||||||
|
build/daemon.ver
|
105
build/download-daemon.js
Normal file
105
build/download-daemon.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/* eslint-disable no-console,import/no-extraneous-dependencies,import/no-commonjs */
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const packageJSON = require("../package.json");
|
||||||
|
const axios = require("axios");
|
||||||
|
const decompress = require("decompress");
|
||||||
|
const os = require("os");
|
||||||
|
const del = require("del");
|
||||||
|
|
||||||
|
const downloadDaemon = targetPlatform =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const daemonURLTemplate = packageJSON.lbrySettings.lbrynetDaemonUrlTemplate;
|
||||||
|
const daemonVersion = packageJSON.lbrySettings.lbrynetDaemonVersion;
|
||||||
|
const daemonDir = path.join(
|
||||||
|
__dirname,
|
||||||
|
"..",
|
||||||
|
packageJSON.lbrySettings.lbrynetDaemonDir
|
||||||
|
);
|
||||||
|
let daemonFileName = packageJSON.lbrySettings.lbrynetDaemonFileName;
|
||||||
|
|
||||||
|
let currentPlatform = os.platform();
|
||||||
|
|
||||||
|
var daemonPlatform =
|
||||||
|
process.env.TARGET || targetPlatform || currentPlatform;
|
||||||
|
if (daemonPlatform === "mac" || daemonPlatform === "darwin")
|
||||||
|
daemonPlatform = "mac";
|
||||||
|
if (daemonPlatform === "win32" || daemonPlatform === "windows") {
|
||||||
|
daemonPlatform = "windows";
|
||||||
|
daemonFileName = daemonFileName + ".exe";
|
||||||
|
}
|
||||||
|
const daemonFilePath = path.join(daemonDir, daemonFileName);
|
||||||
|
const daemonVersionPath = path.join(__dirname, "daemon.ver");
|
||||||
|
const tmpZipPath = path.join(__dirname, "..", "dist", "daemon.zip");
|
||||||
|
const daemonURL = daemonURLTemplate
|
||||||
|
.replace(/DAEMONVER/g, daemonVersion)
|
||||||
|
.replace(/OSNAME/g, daemonPlatform);
|
||||||
|
|
||||||
|
// If a daemon and daemon.ver exists, check to see if it matches the current daemon version
|
||||||
|
const hasDaemonDownloaded = fs.existsSync(daemonFilePath);
|
||||||
|
const hasDaemonVersion = fs.existsSync(daemonVersionPath);
|
||||||
|
let downloadedDaemonVersion;
|
||||||
|
if (hasDaemonVersion) {
|
||||||
|
downloadedDaemonVersion = fs.readFileSync(daemonVersionPath, "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
hasDaemonDownloaded &&
|
||||||
|
hasDaemonVersion &&
|
||||||
|
downloadedDaemonVersion === daemonVersion
|
||||||
|
) {
|
||||||
|
console.log("\x1b[34minfo\x1b[0m Daemon already downloaded");
|
||||||
|
resolve("Done");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log("\x1b[34minfo\x1b[0m Downloading daemon...");
|
||||||
|
axios
|
||||||
|
.request({
|
||||||
|
responseType: "arraybuffer",
|
||||||
|
url: daemonURL,
|
||||||
|
method: "get",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/zip"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(
|
||||||
|
result =>
|
||||||
|
new Promise((newResolve, newReject) => {
|
||||||
|
const distPath = path.join(__dirname, "..", "dist");
|
||||||
|
const hasDistFolder = fs.existsSync(distPath);
|
||||||
|
|
||||||
|
if (!hasDistFolder) {
|
||||||
|
fs.mkdirSync(distPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(tmpZipPath, result.data, error => {
|
||||||
|
if (error) return newReject(error);
|
||||||
|
return newResolve();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => del(`${daemonFilePath}*`))
|
||||||
|
.then(() =>
|
||||||
|
decompress(tmpZipPath, daemonDir, {
|
||||||
|
filter: file => path.basename(file.path) === daemonFileName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
console.log("\x1b[32msuccess\x1b[0m Daemon downloaded!");
|
||||||
|
if (hasDaemonVersion) {
|
||||||
|
del(daemonVersionPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(daemonVersionPath, daemonVersion, "utf8");
|
||||||
|
resolve("Done");
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(
|
||||||
|
`\x1b[31merror\x1b[0m Daemon download failed due to: \x1b[35m${error}\x1b[0m`
|
||||||
|
);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadDaemon();
|
39
package.json
Normal file
39
package.json
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
"name": "lbry-electron-starter",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "A simple starter application that bundles the lbry sdk",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "electron ./src/main",
|
||||||
|
"dev": "NODE_ENV=development electron ./src/main/index.js",
|
||||||
|
"postinstall": "node build/download-daemon.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/lbry-developers/lbry-electron-starter.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/lbry-developers/lbry-electron-starter/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/lbry-developers/lbry-electron-starter#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"electron": "^3.0.8",
|
||||||
|
"find-process": "^1.2.0",
|
||||||
|
"lbry-redux": "lbryio/lbry-redux",
|
||||||
|
"url": "^0.11.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"axios": "^0.18.0",
|
||||||
|
"decompress": "^4.2.0",
|
||||||
|
"del": "^3.0.0",
|
||||||
|
"electron-reload": "^1.2.5"
|
||||||
|
},
|
||||||
|
"lbrySettings": {
|
||||||
|
"lbrynetDaemonVersion": "0.30.0",
|
||||||
|
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-OSNAME.zip",
|
||||||
|
"lbrynetDaemonDir": "static/daemon",
|
||||||
|
"lbrynetDaemonFileName": "lbrynet"
|
||||||
|
}
|
||||||
|
}
|
37
src/main/create-window.js
Normal file
37
src/main/create-window.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const { BrowserWindow } = require("electron");
|
||||||
|
const url = require("url");
|
||||||
|
const path = require("path");
|
||||||
|
const IS_DEV = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
|
// Keep a global reference of the window object, if you don't, the window will
|
||||||
|
// be closed automatically when the JavaScript object is garbage collected.
|
||||||
|
let mainWindow;
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
// Create the browser window.
|
||||||
|
mainWindow = new BrowserWindow({ width: 800, height: 600 });
|
||||||
|
|
||||||
|
// and load the index.html of the app.
|
||||||
|
mainWindow.loadURL(
|
||||||
|
url.format({
|
||||||
|
pathname: path.join(__dirname, "index.html"),
|
||||||
|
protocol: "file:",
|
||||||
|
slashes: true
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Open the DevTools.
|
||||||
|
if (IS_DEV) {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emitted when the window is closed.
|
||||||
|
mainWindow.on("closed", function() {
|
||||||
|
// Dereference the window object, usually you would store windows
|
||||||
|
// in an array if your app supports multi windows, this is the time
|
||||||
|
// when you should delete the corresponding element.
|
||||||
|
mainWindow = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = createWindow;
|
50
src/main/daemon.js
Normal file
50
src/main/daemon.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
const path = require("path");
|
||||||
|
const { spawn, execSync } = require("child_process");
|
||||||
|
|
||||||
|
class Daemon {
|
||||||
|
constructor() {
|
||||||
|
this.path =
|
||||||
|
process.env.LBRY_DAEMON ||
|
||||||
|
path.join(__dirname, "../../static/daemon/lbrynet");
|
||||||
|
this.handlers = [];
|
||||||
|
this.subprocess = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch() {
|
||||||
|
this.subprocess = spawn(this.path, ["start"]);
|
||||||
|
this.subprocess.stdout.on("data", data => console.log(`Daemon: ${data}`));
|
||||||
|
this.subprocess.stderr.on("data", data => console.error(`Daemon: ${data}`));
|
||||||
|
this.subprocess.on("exit", () => this.fire("exit"));
|
||||||
|
this.subprocess.on("error", error =>
|
||||||
|
console.error(`Daemon error: ${error}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
quit() {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
try {
|
||||||
|
execSync(`taskkill /pid ${this.subprocess.pid} /t /f`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.subprocess.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Follows the publish/subscribe pattern
|
||||||
|
|
||||||
|
// Subscribe method
|
||||||
|
on(event, handler, context = handler) {
|
||||||
|
this.handlers.push({ event, handler: handler.bind(context) });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish method
|
||||||
|
fire(event, args) {
|
||||||
|
this.handlers.forEach(topic => {
|
||||||
|
if (topic.event === event) topic.handler(args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Daemon;
|
35
src/main/index.html
Normal file
35
src/main/index.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>LBRY Starter</title>
|
||||||
|
</head>
|
||||||
|
<style>
|
||||||
|
body: {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resolve {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
<h1>Hello world</h1>
|
||||||
|
<div class="content">
|
||||||
|
<div id="loading">Starting daemon...</div>
|
||||||
|
<div id="resolve">
|
||||||
|
<input id="resolve-input" />
|
||||||
|
<button id="resolve-button">Resolve</button>
|
||||||
|
<p id="resolve-help"></p>
|
||||||
|
|
||||||
|
<pre id="claim"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
require("../renderer/index.js");
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
57
src/main/index.js
Normal file
57
src/main/index.js
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Modules to control application life and create native browser window
|
||||||
|
const { app } = require("electron");
|
||||||
|
const path = require("path");
|
||||||
|
const findProcess = require("find-process");
|
||||||
|
const createWindow = require("./create-window");
|
||||||
|
const Daemon = require("./daemon");
|
||||||
|
const IS_DEV = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
|
console.log("starting?");
|
||||||
|
|
||||||
|
// Auto-reload when we make changes
|
||||||
|
if (IS_DEV) {
|
||||||
|
require("electron-reload")(__dirname, {
|
||||||
|
electron: path.join(__dirname, "node_modules", ".bin", "electron")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will be called when Electron has finished
|
||||||
|
// initialization and is ready to create browser windows.
|
||||||
|
// Some APIs can only be used after this event occurs.
|
||||||
|
app.on("ready", function() {
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
const processListArgs =
|
||||||
|
process.platform === "win32" ? "lbrynet" : "lbrynet start";
|
||||||
|
findProcess("name", processListArgs).then(processList => {
|
||||||
|
const isDaemonRunning = processList.length > 0;
|
||||||
|
|
||||||
|
if (!isDaemonRunning) {
|
||||||
|
daemon = new Daemon();
|
||||||
|
daemon.on("exit", () => {
|
||||||
|
if (!isDev) {
|
||||||
|
daemon = null;
|
||||||
|
if (!appState.isQuitting) {
|
||||||
|
dialog.showErrorBox(
|
||||||
|
"Daemon has Exited",
|
||||||
|
"The daemon may have encountered an unexpected error, or another daemon instance is already running. \n\n" +
|
||||||
|
"For more information please visit: \n" +
|
||||||
|
"https://lbry.io/faq/startup-troubleshooting"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
daemon.launch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Quit when all windows are closed.
|
||||||
|
app.on("window-all-closed", function() {
|
||||||
|
// On OS X it is common for applications and their menu bar
|
||||||
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
|
if (process.platform !== "darwin") {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
47
src/renderer/index.js
Normal file
47
src/renderer/index.js
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
const { Lbry } = require("lbry-redux");
|
||||||
|
|
||||||
|
Lbry.connect().then(checkDaemonStarted);
|
||||||
|
|
||||||
|
function checkDaemonStarted() {
|
||||||
|
Lbry.status().then(status => {
|
||||||
|
if (status.is_running) {
|
||||||
|
// Daemon is now running
|
||||||
|
const resolveWrapper = document.getElementById("resolve");
|
||||||
|
const loadingWrapper = document.getElementById("loading");
|
||||||
|
|
||||||
|
loadingWrapper.style.display = "none";
|
||||||
|
resolveWrapper.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
checkDaemonStarted();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolveInput = document.getElementById("resolve-input");
|
||||||
|
const resolveButton = document.getElementById("resolve-button");
|
||||||
|
const resolveHelp = document.getElementById("resolve-help");
|
||||||
|
const claimData = document.getElementById("claim");
|
||||||
|
|
||||||
|
resolveInput.addEventListener("input", e => {
|
||||||
|
const { value } = e.target;
|
||||||
|
const helpText = `Would resolve <b>lbry://${value}</b>`;
|
||||||
|
resolveHelp.innerHTML = helpText;
|
||||||
|
});
|
||||||
|
|
||||||
|
resolveButton.addEventListener("click", () => {
|
||||||
|
const value = resolveInput.value;
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
claimData.innerText = "Loading...";
|
||||||
|
Lbry.resolve({ uri: `lbry://${value}` })
|
||||||
|
.then(res => {
|
||||||
|
claimData.innerText = JSON.stringify(res.claim, null, 2);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
claimData.innerText = JSON.stringify(error, null, 2);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue