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

BIN
package-lock.json generated

Binary file not shown.

View File

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

View File

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

View File

@ -29,5 +29,5 @@ addOnLoad(() => {
// @ts-ignore: Ugly hack to execute it anyway
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 {Environment} from "./Environment";
import {Directory, File, FileSystem, Node, Path} from "./FileSystem";
import {Directory, File, FileSystem, Path} from "./FileSystem";
import {InputParser} from "./InputParser";
import {Persistence} from "./Persistence";
import {asciiHeaderHtml, IllegalStateError, stripHtmlTags} from "./Shared";
import {EscapeCharacters, InputHistory} from "./Terminal";
import {UserList} from "./UserList";
@ -48,8 +48,8 @@ export class Shell {
constructor(inputHistory: InputHistory) {
this.inputHistory = inputHistory;
this.userList = new UserList();
this.fileSystem = Shell.loadFileSystem();
this.environment = Shell.loadEnvironment(this.fileSystem, this.userList);
this.fileSystem = Persistence.getFileSystem();
this.environment = Persistence.getEnvironment(this.fileSystem, this.userList);
this.commands = new Commands(this.environment, this.userList, this.fileSystem);
this.saveState();
@ -71,6 +71,7 @@ export class Shell {
</span>
Type "<a href="#" onclick="execute('help');">help</a>" for help.
Welcome to josh v%%VERSION_NUMBER%%, the javascript online shell.
`.trimLines();
}
@ -205,74 +206,13 @@ export class Shell {
/**
* Saves the shell's state in cookies.
* Persists the shell's state.
*
* @see Persistence
*/
private saveState() {
Cookies.set("files", this.fileSystem.root, {
"expires": new Date(new Date().setFullYear(new Date().getFullYear() + 25)),
"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;
Persistence.setFileSystem(this.fileSystem);
Persistence.setEnvironment(this.environment);
}
}