parent
f22a1dfd5e
commit
85ae74a57a
@ -1,36 +0,0 @@
|
|||||||
export class Connection {
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.ws = null;
|
|
||||||
this.isConnected = false;
|
|
||||||
this.onopen = () => {};
|
|
||||||
this.onclose = () => {};
|
|
||||||
this.onmessage = () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
connectTo(url) {
|
|
||||||
if (this.ws) { this.close(); }
|
|
||||||
|
|
||||||
this.ws = new WebSocket(url, "fs");
|
|
||||||
this.ws.onopen = () => {
|
|
||||||
this.isConnected = true;
|
|
||||||
this.onopen();
|
|
||||||
};
|
|
||||||
this.ws.onclose = () => {
|
|
||||||
this.isConnected = false;
|
|
||||||
this.onclose();
|
|
||||||
};
|
|
||||||
this.ws.onmessage = (message) => {
|
|
||||||
this.onmessage(message);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
send(message) {
|
|
||||||
this.ws.send(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.ws.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
/* eslint no-console: "off" */
|
|
||||||
|
|
||||||
export class FileSystemHandler {
|
|
||||||
|
|
||||||
constructor(filesystem, connection) {
|
|
||||||
this._fs = filesystem;
|
|
||||||
this._connection = connection;
|
|
||||||
this._connection.onmessage = (message) => {
|
|
||||||
this._onmessage(message);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_onmessage(message) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
let request = JSON.parse(message.data);
|
|
||||||
let result = -42;
|
|
||||||
let response;
|
|
||||||
|
|
||||||
console.log(request);
|
|
||||||
if (("string" === typeof(request.method)) &&
|
|
||||||
("number" === typeof(request.id)) &&
|
|
||||||
(request.params)) {
|
|
||||||
switch(request.method)
|
|
||||||
{
|
|
||||||
case "lookup":
|
|
||||||
{
|
|
||||||
const parent = request.params[0];
|
|
||||||
const name = request.params[1];
|
|
||||||
result = this._fs.lookup(parent, name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "getattr":
|
|
||||||
{
|
|
||||||
const inode = request.params[0];
|
|
||||||
result = this._fs.getattr(inode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "readdir":
|
|
||||||
{
|
|
||||||
const inode = request.params[0];
|
|
||||||
result = this._fs.readdir(inode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "open":
|
|
||||||
{
|
|
||||||
const inode = request.params[0];
|
|
||||||
const mode = request.params[1];
|
|
||||||
result = this._fs.open(inode, mode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "close":
|
|
||||||
{
|
|
||||||
const inode = request.params[0];
|
|
||||||
const handle = request.params[1];
|
|
||||||
const mode = request.params[2];
|
|
||||||
this._fs.close(inode, handle, mode);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "read":
|
|
||||||
{
|
|
||||||
const inode = request.params[0];
|
|
||||||
const handle = request.params[1];
|
|
||||||
const offset = request.params[2];
|
|
||||||
const length = request.params[3];
|
|
||||||
result = this._fs.read(inode, handle, offset, length);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("number" == typeof(request.id))
|
|
||||||
{
|
|
||||||
if ("number" !== typeof(result)) {
|
|
||||||
response = {result: result, id: request.id};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
response = {error: {code: result}, id: request.id};
|
|
||||||
}
|
|
||||||
console.log(response);
|
|
||||||
this._connection.send(JSON.stringify(response));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ex) { console.log(ex, message); }
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,15 @@
|
|||||||
|
export class BadState extends Error {
|
||||||
|
static get BAD() { return 1; }
|
||||||
|
|
||||||
|
static get NOT_IMPLEMENTED() { return 2; }
|
||||||
|
static get TIMEOUT() { return 3; }
|
||||||
|
static get FORMAT() { return 4; }
|
||||||
|
|
||||||
|
static get NO_ENTRY() { return 101; }
|
||||||
|
static get NO_ACCESS() { return 102; }
|
||||||
|
|
||||||
|
constructor(code) {
|
||||||
|
super("Bad State");
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
import { BadState } from "./bad_state.js";
|
||||||
|
|
||||||
|
export class Client {
|
||||||
|
static get _PROTOCOL() { return "fs"; }
|
||||||
|
|
||||||
|
constructor(provider) {
|
||||||
|
this._provider = provider;
|
||||||
|
this._ws = null;
|
||||||
|
this.isConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectTo(url) {
|
||||||
|
this.disconnect();
|
||||||
|
|
||||||
|
this._ws = new WebSocket(url, Client._PROTOCOL);
|
||||||
|
this._ws.onopen = () => {
|
||||||
|
this.isConnected = true;
|
||||||
|
this._provider.connected();
|
||||||
|
};
|
||||||
|
this._ws.onclose = () => {
|
||||||
|
this.isConnected = false;
|
||||||
|
this._provider.disconnected();
|
||||||
|
};
|
||||||
|
this._ws.onmessage = (message) => {
|
||||||
|
this._onmessage(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (this._ws) {
|
||||||
|
this._ws.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onmessage(message) {
|
||||||
|
try {
|
||||||
|
const request = JSON.parse(message.data);
|
||||||
|
const method = request.method;
|
||||||
|
const id = request.id;
|
||||||
|
const params = request.params;
|
||||||
|
|
||||||
|
if ("string" !== typeof(method)) {
|
||||||
|
throw new Error("parse error: missing field: \"method\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
throw new Error("parse error: missing field: \"params\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("number" === typeof(request.id)) {
|
||||||
|
this._invoke(method, params, id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this._notify(method, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
// swallow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_invoke(method, params, id) {
|
||||||
|
this._invokeAsync(method, params).then((result) => {
|
||||||
|
const response = { result, id };
|
||||||
|
this._ws.send(JSON.stringify(response));
|
||||||
|
}).
|
||||||
|
catch((ex) => {
|
||||||
|
const code = ex.code || BadState.BAD;
|
||||||
|
const response = {error: {code}, id};
|
||||||
|
this._ws.send(JSON.stringify(response));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async _invokeAsync(method, params) {
|
||||||
|
switch(method)
|
||||||
|
{
|
||||||
|
case "lookup":
|
||||||
|
return this._lookup(params);
|
||||||
|
case "getattr":
|
||||||
|
return this._getattr(params);
|
||||||
|
case "readdir":
|
||||||
|
return this._readdir(params);
|
||||||
|
case "open":
|
||||||
|
return this._open(params);
|
||||||
|
case "read":
|
||||||
|
return this._read(params);
|
||||||
|
default:
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_notify(method, params) {
|
||||||
|
switch(method) {
|
||||||
|
case 'close':
|
||||||
|
this._close(params);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Invalid method: "${method}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _lookup(params) {
|
||||||
|
const parent = params[0];
|
||||||
|
const name = params[1];
|
||||||
|
|
||||||
|
return this._provider.lookup(parent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getattr(params) {
|
||||||
|
const inode = params[0];
|
||||||
|
|
||||||
|
return this._provider.getattr(inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _readdir(params) {
|
||||||
|
const inode = params[0];
|
||||||
|
|
||||||
|
return this._provider.readdir(inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _open(params) {
|
||||||
|
const inode = params[0];
|
||||||
|
const mode = params[1];
|
||||||
|
|
||||||
|
return this._provider.open(inode, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
_close(params) {
|
||||||
|
const inode = params[0];
|
||||||
|
const handle = params[1];
|
||||||
|
const mode = params[2];
|
||||||
|
|
||||||
|
this._provider.close(inode, handle, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _read(params) {
|
||||||
|
const inode = params[0];
|
||||||
|
const handle = params[1];
|
||||||
|
const offset = params[2];
|
||||||
|
const length = params[3];
|
||||||
|
|
||||||
|
const data = await this._provider.read(inode, handle, offset, length);
|
||||||
|
|
||||||
|
if ("string" === typeof(data)) {
|
||||||
|
return {
|
||||||
|
data: btoa(data),
|
||||||
|
format: "base64",
|
||||||
|
count: data.length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new BadState(BadState.BAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
export class FileMode {
|
||||||
|
static get ACCESS_MODE() { return 0x003; }
|
||||||
|
static get READONLY() { return 0x000; }
|
||||||
|
static get WRITEONLY() { return 0x001; }
|
||||||
|
static get READWRITE() { return 0x002; }
|
||||||
|
static get CREATE() { return 0x040; }
|
||||||
|
static get EXCLUSIVE() { return 0x080; }
|
||||||
|
static get TRUNKATE() { return 0x200; }
|
||||||
|
static get APPEND() { return 0x400; }
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
|
||||||
|
|
||||||
|
import { BadState } from "./bad_state.js";
|
||||||
|
|
||||||
|
export class Provider {
|
||||||
|
|
||||||
|
connected() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnected() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
async lookup(_parent, _name) {
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getattr(_inode) {
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
async readdir(_inode) {
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(_inode, _mode) {
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(_inode, _handle, _mode) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
async read(_inode, _handle, _offset, _length) {
|
||||||
|
throw new BadState(BadState.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue