forked from tools/josh
1
0
Fork 0

Christen "josh" and add version number

Oh and make persistence a bit more manageable.
This commit is contained in:
Florine W. Dekker 2019-11-09 19:23:33 +01:00
parent f5713fdf31
commit 11523b5046
Signed by: FWDekker
GPG Key ID: B1B567AF58D6EE0F
7 changed files with 152 additions and 83 deletions

View File

@ -17,6 +17,18 @@ module.exports = grunt => {
files: [{expand: true, cwd: "src/main/", src: "**/*.css", dest: "build/"}] files: [{expand: true, cwd: "src/main/", src: "**/*.css", dest: "build/"}]
} }
}, },
replace: {
default: {
src: "./build/bundle.js",
replacements: [
{
from: "%%VERSION_NUMBER%%",
to: "<%= pkg.version %>"
}
],
overwrite: true
}
},
webpack: { webpack: {
options: { options: {
entry: "./src/main/js/Main.ts", entry: "./src/main/js/Main.ts",
@ -49,6 +61,7 @@ module.exports = grunt => {
grunt.loadNpmTasks("grunt-contrib-clean"); grunt.loadNpmTasks("grunt-contrib-clean");
grunt.loadNpmTasks("grunt-contrib-copy"); grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-text-replace");
grunt.loadNpmTasks("grunt-webpack"); grunt.loadNpmTasks("grunt-webpack");
grunt.registerTask("dev", [ grunt.registerTask("dev", [
@ -59,7 +72,9 @@ module.exports = grunt => {
"copy:html", "copy:html",
"copy:css", "copy:css",
// Compile // Compile
"webpack:dev" "webpack:dev",
// Post
"replace"
]); ]);
grunt.registerTask("deploy", [ grunt.registerTask("deploy", [
// Pre // Pre
@ -69,7 +84,9 @@ module.exports = grunt => {
"copy:html", "copy:html",
"copy:css", "copy:css",
// Compile JS // Compile JS
"webpack:deploy" "webpack:deploy",
// Post
"replace"
]); ]);
grunt.registerTask("default", ["dev"]); grunt.registerTask("default", ["dev"]);

BIN
package-lock.json generated

Binary file not shown.

View File

@ -1,6 +1,6 @@
{ {
"name": "fwdekker.com", "name": "fwdekker.com",
"version": "1.0.0", "version": "1.6.4",
"description": "The source code of [my personal website](https://fwdekker.com/).", "description": "The source code of [my personal website](https://fwdekker.com/).",
"author": "Felix W. Dekker", "author": "Felix W. Dekker",
"repository": { "repository": {
@ -26,6 +26,7 @@
"grunt-cli": "^1.3.2", "grunt-cli": "^1.3.2",
"grunt-contrib-clean": "^2.0.0", "grunt-contrib-clean": "^2.0.0",
"grunt-contrib-copy": "^1.0.0", "grunt-contrib-copy": "^1.0.0",
"grunt-text-replace": "^0.4.0",
"grunt-webpack": "^3.1.3", "grunt-webpack": "^3.1.3",
"mocha": "^6.2.2", "mocha": "^6.2.2",
"ts-loader": "^6.2.1", "ts-loader": "^6.2.1",

View File

@ -1,7 +1,7 @@
import * as Cookies from "js-cookie";
import "./Extensions" import "./Extensions"
import {Environment} from "./Environment"; import {Environment} from "./Environment";
import {Directory, File, FileSystem, Path} from "./FileSystem" import {Directory, File, FileSystem, Path} from "./FileSystem"
import {Persistence} from "./Persistence";
import {IllegalArgumentError, IllegalStateError} from "./Shared"; import {IllegalArgumentError, IllegalStateError} from "./Shared";
import {InputArgs} from "./Shell"; import {InputArgs} from "./Shell";
import {EscapeCharacters} from "./Terminal"; import {EscapeCharacters} from "./Terminal";
@ -229,8 +229,7 @@ export class Commands {
*/ */
execute(input: InputArgs): string { execute(input: InputArgs): string {
if (input.command === "factory-reset") { if (input.command === "factory-reset") {
Cookies.remove("files"); Persistence.reset();
Cookies.remove("env");
location.reload(); location.reload();
throw new Error("Goodbye"); throw new Error("Goodbye");
} }
@ -369,7 +368,7 @@ export class Commands {
<b>List of commands</b> <b>List of commands</b>
${commandEntries.join("\n")} ${commandEntries.join("\n")}
Write "help [COMMAND]" or click a command in the list above for more information on a command.\\\ Write "help [COMMAND]" or click a command in the list above for more information.\\\
`.trimMultiLines(); `.trimMultiLines();
} }
} }
@ -476,12 +475,9 @@ export class Commands {
if (userName === "") if (userName === "")
throw new IllegalStateError("Cannot execute `poweroff` while not logged in."); throw new IllegalStateError("Cannot execute `poweroff` while not logged in.");
Cookies.set("poweroff", "true", { Persistence.setPoweroff(true);
"expires": new Date(new Date().setSeconds(new Date().getSeconds() + 30)),
"path": "/"
});
setTimeout(() => location.reload(), 2000); setTimeout(() => location.reload(), 2000);
return `Shutdown NOW! return `Shutdown NOW!
*** FINAL System shutdown message from ${userName}@fwdekker.com *** *** FINAL System shutdown message from ${userName}@fwdekker.com ***

View File

@ -29,5 +29,5 @@ addOnLoad(() => {
// @ts-ignore: Ugly hack to execute it anyway // @ts-ignore: Ugly hack to execute it anyway
if (window.terminal.shell.environment.get("user") !== "") if (window.terminal.shell.environment.get("user") !== "")
window.terminal.processInput("ls"); window.execute("ls");
}); });

115
src/main/js/Persistence.ts Normal file
View File

@ -0,0 +1,115 @@
import * as Cookies from "js-cookie";
import {Environment} from "./Environment";
import {Directory, FileSystem, Node, Path} from "./FileSystem";
import {UserList} from "./UserList";
/**
* Manages persistence of state.
*/
export class Persistence {
/**
* Deserializes a file system from persistent storage, or returns the default file system if the deserialization
* failed.
*/
static getFileSystem(): FileSystem {
const filesString = Cookies.get("files");
let files: Directory | undefined = undefined;
if (filesString !== undefined) {
try {
const parsedFiles = Node.deserialize(filesString);
if (parsedFiles instanceof Directory)
files = parsedFiles;
else
console.warn("`files` cookie contains non-directory.");
} catch (error) {
console.warn("Failed to deserialize `files` cookie.", error);
}
}
return new FileSystem(files);
}
/**
* Persists the given file system.
*
* @param fileSystem the file system to persist
*/
static setFileSystem(fileSystem: FileSystem) {
Cookies.set("files", fileSystem.root, {
"expires": new Date(new Date().setFullYear(new Date().getFullYear() + 25)),
"path": "/"
});
}
/**
* Deserializes an environment from persistent storage, or returns the default environment if the deserialization
* failed.
*
* @param fileSystem the file system used to validate the `cwd` environment variable
* @param userList the list of users used to validate the `user` environment variable
*/
static getEnvironment(fileSystem: FileSystem, userList: UserList): Environment {
const environmentString = Cookies.get("env") ?? "{}";
let environment: Environment;
try {
environment = new Environment(["cwd", "home", "user"], JSON.parse(environmentString));
} catch (error) {
console.warn("Failed to set environment from cookie.");
environment = new Environment(["cwd", "home", "user"]);
}
// Check user in environment
if (!environment.has("user")) {
environment.set("user", "felix");
} else if (environment.get("user") !== "" && !userList.has(environment.get("user"))) {
console.warn(`Invalid user '${environment.get("user")}' in environment.`);
environment.set("user", "felix");
}
// Set home directory
environment.set("home", userList.get(environment.get("user"))?.home ?? "/");
// Check cwd in environment
if (!environment.has("cwd")) {
environment.set("cwd", environment.get("home"));
} else if (!fileSystem.has(new Path(environment.get("cwd")))) {
console.warn(`Invalid cwd '${environment.get("cwd")}' in environment.`);
environment.set("cwd", environment.get("home"));
}
return environment;
}
/**
* Persists the given environment.
*
* @param environment the environment to persist
*/
static setEnvironment(environment: Environment) {
Cookies.set("env", environment.variables, {"path": "/"});
}
/**
* Persists the "power off" setting.
*
* @param value the value to persist for the "power off" setting
*/
static setPoweroff(value: boolean) {
Cookies.set("poweroff", `${value}`, {
"expires": new Date(new Date().setSeconds(new Date().getSeconds() + 30)),
"path": "/"
});
}
/**
* Removes all persistent storage.
*/
static reset() {
Cookies.remove("files");
Cookies.remove("env");
Cookies.remove("poweroff");
}
}

View File

@ -1,8 +1,8 @@
import * as Cookies from "js-cookie";
import {Commands} from "./Commands"; import {Commands} from "./Commands";
import {Environment} from "./Environment"; import {Environment} from "./Environment";
import {Directory, File, FileSystem, Node, Path} from "./FileSystem"; import {Directory, File, FileSystem, Path} from "./FileSystem";
import {InputParser} from "./InputParser"; import {InputParser} from "./InputParser";
import {Persistence} from "./Persistence";
import {asciiHeaderHtml, IllegalStateError, stripHtmlTags} from "./Shared"; import {asciiHeaderHtml, IllegalStateError, stripHtmlTags} from "./Shared";
import {EscapeCharacters, InputHistory} from "./Terminal"; import {EscapeCharacters, InputHistory} from "./Terminal";
import {UserList} from "./UserList"; import {UserList} from "./UserList";
@ -48,8 +48,8 @@ export class Shell {
constructor(inputHistory: InputHistory) { constructor(inputHistory: InputHistory) {
this.inputHistory = inputHistory; this.inputHistory = inputHistory;
this.userList = new UserList(); this.userList = new UserList();
this.fileSystem = Shell.loadFileSystem(); this.fileSystem = Persistence.getFileSystem();
this.environment = Shell.loadEnvironment(this.fileSystem, this.userList); this.environment = Persistence.getEnvironment(this.fileSystem, this.userList);
this.commands = new Commands(this.environment, this.userList, this.fileSystem); this.commands = new Commands(this.environment, this.userList, this.fileSystem);
this.saveState(); this.saveState();
@ -71,6 +71,7 @@ export class Shell {
</span> </span>
Type "<a href="#" onclick="execute('help');">help</a>" for help. Type "<a href="#" onclick="execute('help');">help</a>" for help.
Welcome to josh v%%VERSION_NUMBER%%, the javascript online shell.
`.trimLines(); `.trimLines();
} }
@ -205,74 +206,13 @@ export class Shell {
/** /**
* Saves the shell's state in cookies. * Persists the shell's state.
*
* @see Persistence
*/ */
private saveState() { private saveState() {
Cookies.set("files", this.fileSystem.root, { Persistence.setFileSystem(this.fileSystem);
"expires": new Date(new Date().setFullYear(new Date().getFullYear() + 25)), Persistence.setEnvironment(this.environment);
"path": "/"
});
Cookies.set("env", this.environment.variables, {"path": "/"});
}
/**
* Returns the file system loaded from a cookie, or the default file system if no cookie is present or the cookie
* is invalid.
*/
private static loadFileSystem(): FileSystem {
let files: Directory | undefined = undefined;
const filesString = Cookies.get("files");
if (filesString !== undefined) {
try {
const parsedFiles = Node.deserialize(filesString);
if (parsedFiles instanceof Directory)
files = parsedFiles;
else
console.warn("`files` cookie contains non-directory.");
} catch (error) {
console.warn("Failed to deserialize `files` cookie.", error);
}
}
return new FileSystem(files);
}
/**
* Returns the environment loaded from a cookie, or the default environment if no cookie is present or the cookie
* is invalid.
*
* @param fileSystem the file system used to validate the `cwd` environment variable
* @param userList the list of users used to validate the `user` environment variable
*/
private static loadEnvironment(fileSystem: FileSystem, userList: UserList): Environment {
const environmentString = Cookies.get("env") ?? "{}";
let environment: Environment;
try {
environment = new Environment(["cwd", "home", "user"], JSON.parse(environmentString));
} catch (error) {
console.warn("Failed to set environment from cookie.");
environment = new Environment(["cwd", "home", "user"]);
}
// Check user in environment
if (!environment.has("user")) {
environment.set("user", "felix");
} else if (environment.get("user") !== "" && !userList.has(environment.get("user"))) {
console.warn(`Invalid user '${environment.get("user")}' in environment.`);
environment.set("user", "felix");
}
// Set home directory
environment.set("home", userList.get(environment.get("user"))?.home ?? "/");
// Check cwd in environment
if (!environment.has("cwd")) {
environment.set("cwd", environment.get("home"));
} else if (!fileSystem.has(new Path(environment.get("cwd")))) {
console.warn(`Invalid cwd '${environment.get("cwd")}' in environment.`);
environment.set("cwd", environment.get("home"));
}
return environment;
} }
} }