mirror of
https://github.com/linux-odyssey/linux-odyssey.git
synced 2026-11-08 11:30:12 +08:00
feat: collect 2 level files info when ls
* change cli dir to /usr/local/lib/cli * refactor cli to multiple files * add handleCommand and listeners pattern
This commit is contained in:
1 parent
e6d6036cd0
commit
41a12c9aa8
8 files changed
+157
-81
No files matched your search
+25
-77
@@ -1,82 +1,8 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
|
||||||
/* eslint-disable no-restricted-syntax */
|
/* eslint-disable no-restricted-syntax */
|
||||||
const fs = require('fs').promises
|
const fs = require('fs').promises
|
||||||
const { exit } = require('process')
|
const { exit } = require('process')
|
||||||
const readline = require('readline')
|
const { colorize, printResponses } = require('./print.js')
|
||||||
|
const discoverFiles = require('./discover.js')
|
||||||
const RETURN_SYMBOL = '\u21B5'
|
|
||||||
|
|
||||||
// ANSI color map
|
|
||||||
const ANSI_COLORS = {
|
|
||||||
black: 30,
|
|
||||||
red: 31,
|
|
||||||
green: 32,
|
|
||||||
yellow: 33,
|
|
||||||
blue: 34,
|
|
||||||
magenta: 35,
|
|
||||||
cyan: 36,
|
|
||||||
white: 37,
|
|
||||||
}
|
|
||||||
|
|
||||||
function colorize(content, color) {
|
|
||||||
const colorCode = ANSI_COLORS[color]
|
|
||||||
if (!colorCode) return content
|
|
||||||
return `\x1b[${colorCode}m${content}\x1b[0m`
|
|
||||||
}
|
|
||||||
|
|
||||||
process.stdin.setRawMode(true)
|
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: process.stdin,
|
|
||||||
output: process.stdout,
|
|
||||||
terminal: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
function waitForEnter() {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
rl.once('line', resolve)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function printLine(content, delay, color) {
|
|
||||||
const printContent = `${colorize(content, color)}${RETURN_SYMBOL}`
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
let i = 0
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
process.stdout.write(printContent[i])
|
|
||||||
i += 1
|
|
||||||
if (i >= printContent.length) {
|
|
||||||
clearInterval(timer)
|
|
||||||
waitForEnter().then(resolve)
|
|
||||||
}
|
|
||||||
}, delay)
|
|
||||||
|
|
||||||
waitForEnter().then(() => {
|
|
||||||
clearInterval(timer)
|
|
||||||
process.stdout.write(printContent.slice(i))
|
|
||||||
process.stdout.write('\n')
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function printResponses(responses, delay = 100) {
|
|
||||||
for (const response of responses) {
|
|
||||||
const { type, content, speaker, color } = response
|
|
||||||
if (type === 'narrative') {
|
|
||||||
for (const line of content) {
|
|
||||||
await printLine(line, delay, color || 'white')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type === 'dialogue') {
|
|
||||||
console.log(`${speaker}:`)
|
|
||||||
for (const line of content) {
|
|
||||||
await printLine(`\t${line}`, delay, color || 'green')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rl.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function readOrNone(file) {
|
async function readOrNone(file) {
|
||||||
try {
|
try {
|
||||||
@@ -86,6 +12,25 @@ async function readOrNone(file) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseCommand(command) {
|
||||||
|
const [name, ...args] = command.trim().split(' ')
|
||||||
|
return { name, args }
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandListeners = {
|
||||||
|
ls: [discoverFiles],
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleCommand(command) {
|
||||||
|
const { name, args } = parseCommand(command)
|
||||||
|
const listeners = commandListeners[name]
|
||||||
|
if (!listeners) return {}
|
||||||
|
return listeners.reduce(async (result, listener) => {
|
||||||
|
const res = await listener(name, args)
|
||||||
|
return { ...res, ...result }
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const {
|
const {
|
||||||
API_ENDPOINT,
|
API_ENDPOINT,
|
||||||
@@ -98,6 +43,8 @@ async function main() {
|
|||||||
} = process.env
|
} = process.env
|
||||||
if (!CMD_NAME) exit(0)
|
if (!CMD_NAME) exit(0)
|
||||||
|
|
||||||
|
const additionalData = await handleCommand(CMD_NAME)
|
||||||
|
|
||||||
const output = await readOrNone(CMD_OUTPUT_FILE)
|
const output = await readOrNone(CMD_OUTPUT_FILE)
|
||||||
const error = await readOrNone(CMD_ERROR_FILE)
|
const error = await readOrNone(CMD_ERROR_FILE)
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -107,6 +54,7 @@ async function main() {
|
|||||||
exit_code: CMD_EXIT_CODE,
|
exit_code: CMD_EXIT_CODE,
|
||||||
token: TOKEN,
|
token: TOKEN,
|
||||||
pwd: PWD,
|
pwd: PWD,
|
||||||
|
...additionalData,
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_ENDPOINT}/api/v1/commands`, {
|
const res = await fetch(`${API_ENDPOINT}/api/v1/commands`, {
|
||||||
@@ -133,4 +81,4 @@ async function main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main().then(exit).catch(console.error)
|
main().then(exit)
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const fs = require('fs').promises
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
async function collectFilesInfo(directoryPath, level = 0) {
|
||||||
|
const entries = await fs.readdir(directoryPath, { withFileTypes: true })
|
||||||
|
|
||||||
|
const promises = entries.map(async (entry) => {
|
||||||
|
const filePath = path.join(directoryPath, entry.name)
|
||||||
|
const isDirectory = entry.isDirectory()
|
||||||
|
const discovered = level === 0 && !entry.name.startsWith('.')
|
||||||
|
|
||||||
|
const file = {
|
||||||
|
path: filePath,
|
||||||
|
name: entry.name,
|
||||||
|
type: isDirectory ? 'folder' : 'file',
|
||||||
|
discovered,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDirectory && level < 2) {
|
||||||
|
// Get up to two levels deep
|
||||||
|
const subFilesInfo = await collectFilesInfo(filePath, level + 1)
|
||||||
|
return [file, ...subFilesInfo]
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
|
})
|
||||||
|
|
||||||
|
const results = await Promise.all(promises)
|
||||||
|
return results.flat()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function discoverFiles(name, args) {
|
||||||
|
let targetPath = args[0] || '.'
|
||||||
|
targetPath = path.resolve(process.cwd(), targetPath)
|
||||||
|
return { discover: await collectFilesInfo(targetPath) }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = discoverFiles
|
||||||
@@ -3,5 +3,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {}
|
"dependencies": {
|
||||||
|
"chokidar": "^3.5.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/* eslint-disable no-restricted-syntax */
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
const readline = require('readline')
|
||||||
|
|
||||||
|
const RETURN_SYMBOL = '\u21B5'
|
||||||
|
|
||||||
|
// ANSI color map
|
||||||
|
const ANSI_COLORS = {
|
||||||
|
black: 30,
|
||||||
|
red: 31,
|
||||||
|
green: 32,
|
||||||
|
yellow: 33,
|
||||||
|
blue: 34,
|
||||||
|
magenta: 35,
|
||||||
|
cyan: 36,
|
||||||
|
white: 37,
|
||||||
|
}
|
||||||
|
|
||||||
|
function colorize(content, color) {
|
||||||
|
const colorCode = ANSI_COLORS[color]
|
||||||
|
if (!colorCode) return content
|
||||||
|
return `\x1b[${colorCode}m${content}\x1b[0m`
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdin.setRawMode(true)
|
||||||
|
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout,
|
||||||
|
terminal: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
function waitForEnter() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
rl.once('line', resolve)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function printLine(content, delay, color) {
|
||||||
|
const printContent = `${colorize(content, color)}${RETURN_SYMBOL}`
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let i = 0
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
process.stdout.write(printContent[i])
|
||||||
|
i += 1
|
||||||
|
if (i >= printContent.length) {
|
||||||
|
clearInterval(timer)
|
||||||
|
waitForEnter().then(resolve)
|
||||||
|
}
|
||||||
|
}, delay)
|
||||||
|
|
||||||
|
waitForEnter().then(() => {
|
||||||
|
clearInterval(timer)
|
||||||
|
process.stdout.write(printContent.slice(i))
|
||||||
|
process.stdout.write('\n')
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function printResponses(responses, delay = 100) {
|
||||||
|
for (const response of responses) {
|
||||||
|
const { type, content, speaker, color } = response
|
||||||
|
if (type === 'narrative') {
|
||||||
|
for (const line of content) {
|
||||||
|
await printLine(line, delay, color || 'white')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type === 'dialogue') {
|
||||||
|
console.log(`${speaker}:`)
|
||||||
|
for (const line of content) {
|
||||||
|
await printLine(`\t${line}`, delay, color || 'green')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rl.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
printResponses,
|
||||||
|
colorize,
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const chokidar = require('chokidar')
|
||||||
|
|
||||||
|
// One-liner for current directory
|
||||||
|
chokidar.watch('.').on('all', (event, path) => {
|
||||||
|
console.log(event, path)
|
||||||
|
})
|
||||||
@@ -14,6 +14,6 @@ WORKDIR /home/rudeus
|
|||||||
|
|
||||||
COPY ./server/quests/helloworld/home /home/rudeus/
|
COPY ./server/quests/helloworld/home /home/rudeus/
|
||||||
|
|
||||||
COPY ./packages/cli/cli.js /usr/local/bin/cli.js
|
COPY ./packages/cli /usr/local/lib/cli
|
||||||
|
|
||||||
CMD [ "/bin/zsh" ]
|
CMD [ "/bin/zsh" ]
|
||||||
@@ -29,7 +29,7 @@ precmd() {
|
|||||||
export CMD_ERROR_FILE=/tmp/cmd.error
|
export CMD_ERROR_FILE=/tmp/cmd.error
|
||||||
|
|
||||||
# Now run your Node.js script with the result as an argument
|
# Now run your Node.js script with the result as an argument
|
||||||
node /usr/local/bin/cli.js
|
node /usr/local/lib/cli/cli.js
|
||||||
|
|
||||||
rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null # cleanup
|
rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null # cleanup
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const containerOptions = {
|
|||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
`${projectPath}/server/quests/helloworld/home:/home/rudeus`,
|
`${projectPath}/server/quests/helloworld/home:/home/rudeus`,
|
||||||
`${projectPath}/packages/cli/cli.js:/usr/local/bin/cli.js`,
|
`${projectPath}/packages/cli:/usr/local/lib/cli`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user