Skip to content

Commit

Permalink
feat: add js deamon file
Browse files Browse the repository at this point in the history
  • Loading branch information
akitaSummer committed Jan 19, 2024
1 parent c4b7442 commit 212f229
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 90 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,4 @@ packages/downloader/test/nginx.conf
# napi-rs generate wrong type ignore for tmp
packages/binding/index.d.ts
.DS_Store
package-lock.json
50 changes: 30 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"dl:nydusd": "bash scripts/download_nydusd.sh",
"cp:binary": "node scripts/prepareBootstrap.js",
"build": "npm run build:binary && npm run build:binding && npm run dl:nydusd && npm run cp:binary",
"build:binary": "cargo build --package nydus-rs --release",
"build:binary": "cargo build --package nydus-rs --release && cargo build --package rapid_deamon --release",
"build:binding": "npm run build-release --workspace @cnpmjs/binding",
"clean": "rm -rf mochawesome-reports coverage",
"lint": "eslint integration/**/*.test.js packages/cli/bin packages/cli/lib packages/cli/test/**/*.test.js",
Expand Down
153 changes: 153 additions & 0 deletions packages/cli/lib/deamon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
const urllib = require('urllib');
const AutoLaunch = require('auto-launch');
const path = require('node:path');
const fs = require('node:fs/promises');
const { chmodSync } = require('node:fs');
const {
rsBindingPath,
nydusd,
nydusdConfigFile,
nydusdMnt,
socketPath,
nydusdLogFile,
} = require('@cnpmjs/binding');
const execa = require('execa');

const {
baseRapidModeDir,
} = require('../constants');

const deamonDir = path.join(baseRapidModeDir(), 'project');

const metadataDir = path.join(deamonDir, 'metadata');

const rapidDeamon = rsBindingPath
? path.join(rsBindingPath, 'rapid_deamon')
: undefined;

const daemonPoint = 'http://localhost:33889';
const aliveUrl = `${daemonPoint}/alive`;
const delUrl = `${daemonPoint}/del-project`;
const addUrl = `${daemonPoint}/add-project`;

const checkDeamonAlive = async () => {
try {
const result = await urllib.request(`${aliveUrl}`, {
method: 'GET',
});
return result.status === 200;
} catch (_) {
return false;
}
};

const delProject = async projectName => {
let config;
try {
await fs.stat(metadataDir);
const configPath = path.join(metadataDir, `${projectName}.json`);
const configBuffer = await fs.readFile(configPath);

config = JSON.parse(configBuffer.toString());
await fs.rm(`${projectName}.json`);
} catch (_) {
return true;
}

try {
const result = await urllib.request(`${delUrl}`, {
method: 'POST',
data: { projectPath: config.projectPath },
});
return result.status === 200;
} catch (_) {
return false;
}
};

const addProject = async config => {
try {
await fs.mkdir(metadataDir, { recursive: true });
await fs.writeFile(path.join(metadataDir, `${config.projectName}.json`), JSON.stringify(config, null, 2));
const result = await urllib.request(`${addUrl}`, {
method: 'POST',
data: config,
});
return result.status === 200;
} catch (_) {
return false;
}
};

const initDeamon = async () => {
const isRunning = await checkDeamonAlive();
if (isRunning) {
console.info('[rapid] rapid daemon is running already.');
return;
}
await fs.mkdir(deamonDir, { recursive: true });

await fs.mkdir(nydusdMnt, { recursive: true });

const destinationFilePath = path.join(deamonDir, 'rapid_deamon');

try {
await fs.stat(destinationFilePath);
await execa.command(destinationFilePath);
} catch (_) {

const nydusConfigPath = path.join(deamonDir, 'nydus_config.json');

await fs.writeFile(nydusConfigPath, JSON.stringify({
nydusdBin: nydusd,
nydusdConfigFile,
nydusdMnt,
socketPath,
nydusdLogFile,
}, null, 2));

const logConfigPath = path.join(deamonDir, 'log4rs.yaml');

await fs.writeFile(logConfigPath, `
refresh_rate: 86400 seconds
appenders:
file:
kind: file
path: "logs/rapid-deamon-output.log"
encoder:
pattern: "{d} - {l} - {m}{n}"
root:
level: info
appenders:
- file
`);

await fs.copyFile(rapidDeamon, destinationFilePath);

chmodSync(destinationFilePath, '755');

const deamonAutoLauncher = new AutoLaunch({
name: 'rapid_deamon',
path: destinationFilePath,
mac: {
useLaunchAgent: true,
},
});

deamonAutoLauncher.enable();

try {
const isEnabled = deamonAutoLauncher.isEnabled();
if (isEnabled) return;
deamonAutoLauncher.enable();
} catch (e) {
console.log(e);
}
}
};

exports.initDeamon = initDeamon;
exports.delProject = delProject;
exports.addProject = addProject;
67 changes: 60 additions & 7 deletions packages/cli/lib/nydusd/fuse_mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
const fs = require('node:fs/promises');
const os = require('node:os');
const path = require('node:path');
const crypto = require('node:crypto');
const execa = require('execa');
const {
tarBucketsDir,
unionfs,
BOOTSTRAP_BIN,
socketPath,
} = require('../constants');
const {
wrapSudo,
Expand All @@ -18,35 +20,63 @@ const {
} = require('../util');
const nydusdApi = require('./nydusd_api');
const { Bar } = require('../logger');
const { addProject, delProject, initDeamon } = require('../deamon');

const getProjectName = cwd => {
const folderName = path.basename(cwd);
const hash = crypto.createHash('md5').update(folderName).digest('hex');
const hashedFolderName = `${folderName}_${hash}`;

return hashedFolderName;
};

async function startNydusFs(cwd, pkg) {
await initDeamon();

await nydusdApi.initDaemon();

const deamonConfig = {
projectName: getProjectName(cwd),
projectPath: cwd,
};

console.log('[rapid] generate bootstrap');
await generateBootstrapFile(cwd, pkg);
await generateBootstrapFile(cwd, pkg, deamonConfig);

console.log('[rapid] mount nydusd');
await mountNydus(cwd, pkg);
await mountNydus(cwd, pkg, deamonConfig);

console.log('[rapid] mount overlay, it may take a few seconds');
await mountOverlay(cwd, pkg);
await mountOverlay(cwd, pkg, deamonConfig);

await addProject(deamonConfig);
}

async function generateBootstrapFile(cwd, pkg) {
async function generateBootstrapFile(cwd, pkg, config) {
const allPkgs = await getAllPkgPaths(cwd, pkg);
const bar = new Bar({ type: 'bootstrap', total: allPkgs.length });
const bootstraps = [];
await Promise.all(allPkgs.map(async pkgPath => {
const { bootstrap, tarIndex, nodeModulesDir } = await getWorkdir(cwd, pkgPath);
await fs.mkdir(path.dirname(bootstrap), { recursive: true });
await execa.command(`${BOOTSTRAP_BIN} --stargz-config-path=${tarIndex} --stargz-dir=${tarBucketsDir} --bootstrap=${bootstrap}`);
bootstraps.push({
bootstrapBin: BOOTSTRAP_BIN,
stargzConfigPath: tarIndex,
stargzDir: tarBucketsDir,
bootstrap,
});
bar.update(nodeModulesDir);
}));
bar.stop();
config.bootstraps = bootstraps;
}

async function mountNydus(cwd, pkg) {
async function mountNydus(cwd, pkg, config) {
const allPkgs = await getAllPkgPaths(cwd, pkg);

const mounts = [];

const bar = new Bar({
type: 'mount',
total: allPkgs.length,
Expand All @@ -56,17 +86,25 @@ async function mountNydus(cwd, pkg) {
for (const pkgPath of allPkgs) {
const { dirname, bootstrap } = await getWorkdir(cwd, pkgPath);
await nydusdApi.mount(`/${dirname}`, cwd, bootstrap);
mounts.push({
mountpoint: dirname,
socketPath,
bootstrap,
nydusdConfig: nydusdApi.nydusdConfig,
});
bar.update(dirname);
}
bar.stop();
config.nydusdApiMount = mounts;
}

async function mountOverlay(cwd, pkg) {
async function mountOverlay(cwd, pkg, config) {
const allPkgs = await getAllPkgPaths(cwd, pkg);
const bar = new Bar({
type: 'overlay',
total: allPkgs.length,
});
const overlays = [];
await Promise.all(allPkgs.map(async pkgPath => {
const {
upper,
Expand Down Expand Up @@ -103,29 +141,44 @@ async function mountOverlay(cwd, pkg) {
}
await fs.mkdir(upper, { recursive: true });
await fs.mkdir(workdir, { recursive: true });

let overlayConfig = {};
let shScript = wrapSudo(`mount \
-t overlay overlay \
-o lowerdir=${mnt},upperdir=${upper},workdir=${workdir} \
${nodeModulesDir}`);
overlayConfig = {
workdir,
upper,
mnt,
nodeModulesDir,
};

if (os.type() === 'Darwin') {
shScript = `${unionfs} \
-o cow,max_files=32768 \
-o allow_other,use_ino,suid,dev,nobrowse \
${upper}=RW:${mnt}=RO \
${nodeModulesDir}`;
overlayConfig = {
unionfs,
upper,
mnt,
nodeModulesDir,
};
}
// console.log('[rapid] mountOverlay: `%s`', shScript);
await execa.command(shScript);
bar.update(nodeModulesDir);
overlays.push(overlayConfig);
}));
bar.stop();
config.overlays = overlays;
}

async function endNydusFs(cwd, pkg, force = true) {
const allPkgs = await getAllPkgPaths(cwd, pkg);
const umountCmd = force ? 'umount -f' : 'umount';
await delProject(getProjectName(cwd));
await Promise.all(allPkgs.map(async pkgPath => {
const { dirname, overlay, baseDir, nodeModulesDir } = await getWorkdir(
cwd,
Expand Down
1 change: 1 addition & 0 deletions packages/cli/lib/nydusd/nydusd_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,4 @@ exports.exitDaemon = exitDaemon;
exports.forceExitDaemon = forceExitDaemon;
exports.isDaemonRunning = isDaemonRunning;
exports.list = list;
exports.nydusdConfig = nydusdConfig;
Loading

0 comments on commit 212f229

Please sign in to comment.