1
0
mirror of https://github.com/falk-werner/webfuse-provider synced 2026-03-02 04:09:18 +00:00

project structure changed

This commit is contained in:
Falk Werner
2019-02-10 14:19:15 +01:00
parent fa5e89c64f
commit cf1b57e86e
59 changed files with 36 additions and 31 deletions

22
example/www/index.html Normal file
View File

@@ -0,0 +1,22 @@
<html>
<head>
<title>LWS Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="style/main.css">
<script type="text/javascript" src="js/connection.js"></script>
<script type="text/javascript" src="js/connection_view.js"></script>
<script type="text/javascript" src="js/filesystem.js"></script>
<script type="text/javascript" src="js/filesystem_handler.js"></script>
<script type="text/javascript" src="js/startup.js"></script>
</head>
<body>
<div class="page">
<div class="window">
<div class="title">Connection</div>
<div id="connection"></div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,36 @@
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();
}
}

View File

@@ -0,0 +1,42 @@
class ConnectionView {
constructor(connection) {
this.connection = connection;
this.connection.onclose = () => { this.onConnectionClosed(); };
this.connection.onopen = () => { this.onConnectionOpened(); };
this.element = document.createElement('div');
let urlLabel = document.createElement('span');
urlLabel.textContent = 'URL:';
this.element.appendChild(urlLabel);
this.urlTextbox = document.createElement('input');
this.urlTextbox.type = 'text';
this.urlTextbox.value = window.location.href.replace(/^http/, "ws");
this.element.appendChild(this.urlTextbox);
this.connectButton = document.createElement('input');
this.connectButton.type = 'button';
this.connectButton.value = 'connect';
this.connectButton.addEventListener('click', () => { this.onConnectButtonClicked(); });
this.element.appendChild(this.connectButton);
}
onConnectButtonClicked() {
if (!this.connection.isConnected) {
let url = this.urlTextbox.value;
this.connection.connectTo(url);
}
else {
this.connection.close();
}
}
onConnectionOpened() {
this.connectButton.value = 'disconnect';
}
onConnectionClosed() {
this.connectButton.value = 'connect';
}
}

View File

@@ -0,0 +1,128 @@
class FileSystem {
static get GOOD() { return 0; }
static get BAD() { return 1; }
static get BAD_NOTIMPLEMENTED() { return 2; }
static get BAD_TIMEOUT() { return 3; }
static get BAD_FORMAT() { return 4; }
static get BAD_NOENTRY() { return 101; }
static get BAD_NOACCESS() { return 102; }
static get O_ACCMODE() { return 0x003; }
static get O_RDONLY() { return 0x000; }
static get O_WRONLY() { return 0x001; }
static get O_RDWR() { return 0x002; }
static get O_CREAT() { return 0x040; }
static get O_EXCL() { return 0x080; }
static get O_TRUNK() { return 0x200; }
static get O_APPEND() { return 0x400; }
constructor(root) {
this.root = root;
this._inodes = { };
this._walk(this.root, (entry) => { this._inodes[entry.inode] = entry; });
}
_walk(node, callback) {
callback(node);
const entries = node.entries;
if (entries) {
for(let entry of Object.entries(entries)) {
this._walk(entry[1], callback);
}
}
}
lookup(parent, name) {
const parentEntry = this._inodes[parent];
const entry = (parentEntry && parentEntry.entries && parentEntry.entries[name]) || null;
if (entry) {
return {
inode: entry.inode,
mode: entry.mode || parseInt("755", 8),
type: entry.type || 'file',
size: entry.size || (entry.contents && entry.contents.length) || 0,
atime: entry.atime || 0,
mtime: entry.mtime || 0,
ctime: entry.ctime || 0
};
}
else {
return FileSystem.BAD_NOENTRY;
}
}
getattr(inode) {
let entry = this._inodes[inode];
if (entry) {
return {
mode: entry.mode || parseInt("755", 8),
type: entry.type || 'file',
size: entry.size || (entry.contents && entry.contents.length) || 0,
atime: entry.atime || 0,
mtime: entry.mtime || 0,
ctime: entry.ctime || 0
};
}
else {
return FileSystem.BAD_NOENTRY;
}
}
readdir(inode) {
let result = FileSystem.BAD_NOENTRY;
let entry = this._inodes[inode];
if ((entry) && ("dir" === entry.type)) {
result = [
{name: '.', inode: entry.inode},
{name: '..', inode: entry.inode}
];
for(let subdir of Object.entries(entry.entries)) {
const name = subdir[0];
const inode = subdir[1].inode;
result.push({name: name, inode: inode});
}
}
return result;
}
open(inode, mode) {
let result = FileSystem.BAD_NOENTRY;
let entry = this._inodes[inode];
if (entry.type == "file") {
result = ((mode & FileSystem.O_ACCMODE) == FileSystem.O_RDONLY) ? {handle: 1337} : FileSystem.BAD_NOACCESS;
}
return result;
}
close(inode, handle, mode) {
// do nothing
return true;
}
read(inode, handle, offset, length) {
let result = FileSystem.BAD_NOENTRY;
let entry = this._inodes[inode];
if (entry.type == "file") {
let end = Math.min(offset + length, entry.contents.length);
let data = (offset < entry.contents.length) ? entry.contents.substring(offset, end) : "";
result = {
data: data,
format: "identity",
count: data.length
};
}
return result;
}
}

View File

@@ -0,0 +1,87 @@
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); }
};
}

62
example/www/js/startup.js Normal file
View File

@@ -0,0 +1,62 @@
function 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 "getattr":
result = fs.getattr(request.params[0]);
break;
case "readdir":
result = fs.readdir(request.params[0]);
break;
case "open":
result = fs.open(request.params[0], request.params[1]);
break;
case "read":
result = fs.read(request.params[0], request.params[1], request.params[2]);
break;
default:
break;
}
if ("number" !== typeof(result)) {
response = {result: result, id: request.id};
}
else {
response = {error: {code: result}, id: request.id};
}
console.log(response);
ws.send(JSON.stringify(response));
}
}
catch (ex) { console.log(ex, message); }
};
function startup() {
let connection = new Connection();
let connectionView = new ConnectionView(connection);
document.getElementById('connection').appendChild(connectionView.element);
let fs = new FileSystem({
inode: 1,
mode: 0755,
type: "dir",
entries: {
"hello.txt" : { inode: 2, mode: 0444, type: "file", contents: "Hello, World!"},
"say_hello.sh": { inode: 3, mode: 0555, type: "file", contents: "#!/bin/sh\necho hello\n"}
}
});
let handler = new FileSystemHandler(fs, connection);
}
window.onload = startup;

View File

@@ -0,0 +1,47 @@
html, body {
font-family: monospace;
background-color: #c0c0c0;
}
.page {
margin-left: 50px;
margin-right: 50px;
width: auto;
}
.window {
border: 1px solid black;
background-color: black;
border-radius: 5px;
padding: 10px;
margin-bottom: 25px;
color: white;
}
.window .title {
text-align: center;
color: #dba329;
font-weight: bold;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #dba329;
}
.commands {
text-align: right;
}
.content {
column-count: 2;
column-width: 50%;
}
.content > div {
display: inline-block;
width: 100%;
}
#connection {
text-align: center;
}