Skip to content

Commit

Permalink
Store 1000 history lines for shell app (#1219)
Browse files Browse the repository at this point in the history
* Store 100 history lines for shell app

* Store 100 history lines for shell app

* Remove unused dep

* ok lets use 1000
  • Loading branch information
Apollon77 authored Sep 21, 2024
1 parent 71c7d15 commit cad50a6
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 24 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The main work (all changes without a GitHub username in brackets in the below li
- @matter.js/nodejs-shell:
- Feature: Added new shell command "tlv" with TLV decoding and structure logging tooling
- Enhancement: Added option to specify if attributes are loaded from remote or locally
- Enhancement: The shell now saves a 100 history of commands and restores this on startup

- @matter.js/protocol:
- Info: Low-level Matter logic previously defined in `@project-chip/matter.js` now resides in `@matter.js/protocol`. This includes network communication, fabric management and cluster invocation, read/write, events, etc.
Expand Down
168 changes: 159 additions & 9 deletions package-lock.json

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

1 change: 0 additions & 1 deletion packages/nodejs-shell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
"@project-chip/matter.js": "*",
"@matter.js/tools": "*",
"child_process": "^1.0.2",
"readline": "^1.3.0",
"yargs": "^17.7.2"
},
"engines": {
Expand Down
4 changes: 2 additions & 2 deletions packages/nodejs-shell/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import yargs from "yargs/yargs";
import { MatterNode } from "./MatterNode.js";
import { Shell } from "./shell/Shell";

const PROMPT = "matter-node> ";
const PROMPT = "matter> ";
const logger = Logger.get("Shell");
if (process.stdin?.isTTY) Logger.format = LogFormat.ANSI;

Expand Down Expand Up @@ -110,7 +110,7 @@ async function main() {
}
setLogLevel("default", await theNode.Store.get<string>("LogLevel", "info"));

const theShell = new Shell(theNode, PROMPT);
const theShell = new Shell(theNode, nodeNum, PROMPT);

if (bleHciId !== undefined) {
await theNode.Store.set("BleHciId", bleHciId);
Expand Down
60 changes: 48 additions & 12 deletions packages/nodejs-shell/src/shell/Shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
*/

import { MatterError } from "@matter.js/general";
import readline from "readline";
import type { Argv } from "yargs";
import { createWriteStream, readFileSync } from "fs";
import readline from "node:readline";
import yargs from "yargs/yargs";
import { MatterNode } from "../MatterNode.js";
import { exit } from "../app";
Expand All @@ -23,6 +23,8 @@ import cmdSession from "./cmd_session.js";
import cmdSubscribe from "./cmd_subscribe.js";
import cmdTlv from "./cmd_tlv";

const MAX_HISTORY_SIZE = 1000;

function exitCommand() {
return {
command: "exit",
Expand All @@ -39,36 +41,67 @@ function exitCommand() {
* Class to process and dispatch shell commands.
*/
export class Shell {
configExecPassthrough = false;
readline?: readline.Interface;
yargsInstance?: Argv;
writeStream?: NodeJS.WritableStream;

/**
* Construct a new Shell object.
*
* @param {MatterNode} theNode MatterNode object to use for all commands.
* @param {string} prompt Prompt string to use for each command line.
*/
constructor(
public theNode: MatterNode,
public nodeNum: number,
public prompt: string,
) {}

start() {
const history = new Array<string>();
const fileName = `.matter-shell-${this.nodeNum}.history`;
try {
const historyData = readFileSync(fileName, "utf8");
history.push(
...historyData
.split("\n")
.map(line => line.trim())
.filter(line => line.length),
);
history.splice(0, -MAX_HISTORY_SIZE);
console.log(`Loaded ${history.length} history entries from ${fileName}`);
} catch (e) {
if (e instanceof Error && "code" in e && e.code !== "ENOENT") {
process.stderr.write(`Error happened during history file read: ${e}\n`);
}
}
try {
this.writeStream = createWriteStream(fileName, { flags: "w" });
this.writeStream.write(`${history.join("\n")}\n`);
} catch (e) {
process.stderr.write(`Error happened during history file write: ${e}\n`);
}

this.readline = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
prompt: this.prompt,
history: history.reverse(),
historySize: MAX_HISTORY_SIZE,
});
this.readline
.on("line", cmd => {
this.onReadLine(cmd.trim()).catch(e => {
process.stderr.write(`Read error: ${e}\n`);
process.exit(1);
});
cmd = cmd.trim();
this.onReadLine(cmd)
.then(result => result && cmd.length && this.writeStream?.write(`${cmd}\n`))
.catch(e => {
process.stderr.write(`Read error: ${e}\n`);
process.exit(1);
});
})
.on("close", () => {
try {
this.writeStream?.end();
} catch (e) {
process.stderr.write(`Error happened during history file write: ${e}\n`);
}
exit()
.then(() => process.exit(0))
.catch(e => {
Expand All @@ -86,13 +119,14 @@ export class Shell {
* @param {string} line
*/
async onReadLine(line: string) {
let result = true;
if (line) {
let args;
try {
args = commandlineParser(line);
} catch (error) {
process.stderr.write(`Error happened during command parsing: ${error}\n`);
return;
return false;
}
const yargsInstance = yargs(args)
.command([
Expand Down Expand Up @@ -140,9 +174,11 @@ export class Shell {
}
if (!(error instanceof MatterError)) {
yargsInstance.showHelp();
result = false;
}
}
}
this.readline?.prompt();
return result;
}
}

0 comments on commit cad50a6

Please sign in to comment.