wip: root can add directories to itself
This commit is contained in:
@ -2,11 +2,10 @@ import { Permissions } from "./rfwfs/main"
|
|||||||
|
|
||||||
import rfwfs from "./rfwfs/main"
|
import rfwfs from "./rfwfs/main"
|
||||||
|
|
||||||
const time_now = (Date.now()/1000)|0
|
const time_now = (Date.now()/1000) | 0
|
||||||
|
|
||||||
const fs = new rfwfs([
|
const fs = new rfwfs()
|
||||||
rfwfs.directory("bin", Permissions.r, fs, time_now)
|
|
||||||
])
|
|
||||||
|
|
||||||
|
fs.add_file(default_name, default_permissions)
|
||||||
|
|
||||||
export default fs
|
export default fs
|
@ -1,5 +1,5 @@
|
|||||||
import { ReadStatus, PushStatus, ExecuteStatus } from "./enum/status"
|
import { ReadStatus, PushStatus, ExecuteStatus } from "./enum/status"
|
||||||
import { wrap_entry, wrap_none, type WrapResultEntry, type WrapResultNone, type WrapBinary, wrap_binary } from "./wrap"
|
import { wrap_entry, wrap_none, wrap_binary, type WrapResultEntry, type WrapResultNone, type WrapBinary } from "./wrap"
|
||||||
|
|
||||||
import directory_search from "./index"
|
import directory_search from "./index"
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ const enum Permissions {
|
|||||||
x = 1<<2,
|
x = 1<<2,
|
||||||
none = 1<<3,
|
none = 1<<3,
|
||||||
}
|
}
|
||||||
|
const enum ROOT_ID { TRUNK = "/" }
|
||||||
|
|
||||||
type FileInner = string | number
|
type FileInner = string | number
|
||||||
type BinaryError = string
|
type BinaryError = string
|
||||||
@ -26,15 +27,6 @@ type Directory<T extends Entry> = EntryCollection<T>
|
|||||||
type DirectoryAny = EntryCollection<Entry>
|
type DirectoryAny = EntryCollection<Entry>
|
||||||
type DirectoryAnyDepth = EntryCollection<DirectoryAny>
|
type DirectoryAnyDepth = EntryCollection<DirectoryAny>
|
||||||
|
|
||||||
interface Root<T extends Entry> {
|
|
||||||
readonly type: EntryType,
|
|
||||||
inner: T[],
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RootFile<T extends Entry> extends Root<T> {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EntryStripped {
|
interface EntryStripped {
|
||||||
readonly type: EntryType,
|
readonly type: EntryType,
|
||||||
permissions: Permissions,
|
permissions: Permissions,
|
||||||
@ -42,8 +34,8 @@ interface EntryStripped {
|
|||||||
name: EntryValue<string>,
|
name: EntryValue<string>,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Entry extends EntryStripped {
|
interface Entry<T = DirectoryAny | null> extends EntryStripped {
|
||||||
parent: DirectoryAny,
|
parent: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EntryFile extends Entry {
|
interface EntryFile extends Entry {
|
||||||
@ -59,6 +51,15 @@ interface EntryBinary extends Entry {
|
|||||||
inner: RfwfsBinary
|
inner: RfwfsBinary
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Root<T extends Entry> {
|
||||||
|
readonly type: EntryType,
|
||||||
|
readonly permissions: Permissions,
|
||||||
|
readonly timestamp: EntryValueRoot<number>,
|
||||||
|
readonly parent: null,
|
||||||
|
readonly inner: RfwfsRootDirectory<T>,
|
||||||
|
readonly name: ROOT_ID.TRUNK,
|
||||||
|
}
|
||||||
|
|
||||||
function strip_entry<T extends Entry>(entry: T): EntryStripped {
|
function strip_entry<T extends Entry>(entry: T): EntryStripped {
|
||||||
return {
|
return {
|
||||||
type: entry.type,
|
type: entry.type,
|
||||||
@ -68,15 +69,53 @@ function strip_entry<T extends Entry>(entry: T): EntryStripped {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fs_dir_clone<T extends Entry>(directory: T[], file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
const clone_find = directory_search(directory, file_name)
|
||||||
|
if (clone_find) {
|
||||||
|
return wrap_entry(ReadStatus.Ok, { ...clone_find.result })
|
||||||
|
}
|
||||||
|
return wrap_entry(ReadStatus.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fs_dir_find<T extends Entry>(directory: T[], file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
const file_search = directory_search(directory, file_name)
|
||||||
|
if (file_search) {
|
||||||
|
return wrap_entry(ReadStatus.Ok, file_search.result)
|
||||||
|
}
|
||||||
|
return wrap_entry(ReadStatus.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fs_dir_push<T extends Entry, E extends T>(directory: T[], entry: E) {
|
||||||
|
const no_duplicates = directory_search(directory, entry.name.inner)
|
||||||
|
if (!no_duplicates) {
|
||||||
|
directory.push(entry)
|
||||||
|
directory.sort()
|
||||||
|
return wrap_none(PushStatus.Ok)
|
||||||
|
}
|
||||||
|
return wrap_none(PushStatus.Duplicate)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fs_dir_pop<T extends Entry>(directory: T[], file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
const pop_find = directory_search(directory, file_name)
|
||||||
|
if (pop_find) {
|
||||||
|
directory.splice(pop_find.status, 1)
|
||||||
|
return wrap_entry(ReadStatus.Ok, pop_find.result)
|
||||||
|
}
|
||||||
|
return wrap_entry(ReadStatus.NotFound)
|
||||||
|
}
|
||||||
|
|
||||||
class EntryValue<T> {
|
class EntryValue<T> {
|
||||||
public inner: T;
|
public inner: T;
|
||||||
protected entry: Entry
|
protected entry: Entry;
|
||||||
|
|
||||||
constructor(entry: Entry, inner_default: T) {
|
constructor(entry: Entry, inner_default: T) {
|
||||||
this.inner = inner_default
|
this.inner = inner_default
|
||||||
this.entry = entry
|
this.entry = entry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Safe write
|
||||||
|
*/
|
||||||
public write<I extends T>(item: I): boolean {
|
public write<I extends T>(item: I): boolean {
|
||||||
if (rfwfs.write_access(this.entry.permissions)) {
|
if (rfwfs.write_access(this.entry.permissions)) {
|
||||||
this.inner = item
|
this.inner = item
|
||||||
@ -99,6 +138,18 @@ class EntryValue<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EntryValueRoot<T> {
|
||||||
|
protected inner: T;
|
||||||
|
|
||||||
|
constructor(inner: T) {
|
||||||
|
this.inner = inner
|
||||||
|
}
|
||||||
|
|
||||||
|
public read(): T {
|
||||||
|
return this.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RfwfsDirectory<T extends Entry> {
|
class RfwfsDirectory<T extends Entry> {
|
||||||
public directory: T[];
|
public directory: T[];
|
||||||
protected entry: Entry;
|
protected entry: Entry;
|
||||||
@ -114,52 +165,61 @@ class RfwfsDirectory<T extends Entry> {
|
|||||||
|
|
||||||
public clone(file_name: string): WrapResultEntry<T, ReadStatus> {
|
public clone(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
if (rfwfs.read_write_access(this.entry.permissions)) {
|
if (rfwfs.read_write_access(this.entry.permissions)) {
|
||||||
const clone_find = directory_search(this.directory, file_name)
|
return fs_dir_clone(this.directory, file_name)
|
||||||
if (clone_find) {
|
|
||||||
return wrap_entry(ReadStatus.Ok, { ...clone_find.result })
|
|
||||||
}
|
|
||||||
return wrap_entry(ReadStatus.NotFound)
|
|
||||||
}
|
}
|
||||||
return wrap_entry(ReadStatus.Denied)
|
return wrap_entry(ReadStatus.Denied)
|
||||||
}
|
}
|
||||||
|
|
||||||
public find(file_name: string): WrapResultEntry<T, ReadStatus> {
|
public find(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
if (rfwfs.read_write_access(this.entry.permissions)) {
|
if (rfwfs.read_write_access(this.entry.permissions)) {
|
||||||
const file_search = directory_search(this.directory, file_name)
|
return fs_dir_find(this.directory, file_name)
|
||||||
if (file_search) {
|
|
||||||
return wrap_entry(ReadStatus.Ok, file_search.result)
|
|
||||||
}
|
|
||||||
return wrap_entry(ReadStatus.NotFound)
|
|
||||||
}
|
}
|
||||||
return wrap_entry(ReadStatus.Denied)
|
return wrap_entry(ReadStatus.Denied)
|
||||||
}
|
}
|
||||||
|
|
||||||
public push<E extends T>(entry: E): WrapResultNone<PushStatus> {
|
public push<E extends T>(entry: E): WrapResultNone<PushStatus> {
|
||||||
if (rfwfs.read_write_access(this.entry.permissions)) {
|
if (rfwfs.read_write_access(this.entry.permissions)) {
|
||||||
const no_duplicates = directory_search(this.directory, entry.name.inner)
|
return fs_dir_push(this.directory, entry)
|
||||||
if (!no_duplicates) {
|
|
||||||
this.directory.push(entry)
|
|
||||||
this.directory.sort()
|
|
||||||
return wrap_none(PushStatus.Ok)
|
|
||||||
}
|
|
||||||
return wrap_none(PushStatus.Duplicate)
|
|
||||||
}
|
}
|
||||||
return wrap_none(PushStatus.Denied)
|
return wrap_none(PushStatus.Denied)
|
||||||
}
|
}
|
||||||
|
|
||||||
public pop(file_name: string): WrapResultEntry<T, ReadStatus> {
|
public pop(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
if (rfwfs.read_write_access(this.entry.permissions)) {
|
if (rfwfs.read_write_access(this.entry.permissions)) {
|
||||||
const pop_find = directory_search(this.directory, file_name)
|
fs_dir_pop(this.directory, file_name)
|
||||||
if (pop_find) {
|
|
||||||
this.directory.splice(pop_find.status, 1)
|
|
||||||
return wrap_entry(ReadStatus.Ok, pop_find.result)
|
|
||||||
}
|
|
||||||
return wrap_entry(ReadStatus.NotFound)
|
|
||||||
}
|
}
|
||||||
return wrap_entry(ReadStatus.Denied)
|
return wrap_entry(ReadStatus.Denied)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RfwfsRootDirectory<T extends Entry> {
|
||||||
|
public directory: T[];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.directory = []
|
||||||
|
}
|
||||||
|
|
||||||
|
public sort() {
|
||||||
|
this.directory.sort((a,z) => a.name.inner.localeCompare(z.name.inner))
|
||||||
|
}
|
||||||
|
|
||||||
|
public clone(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
return fs_dir_clone(this.directory, file_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
public find(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
return fs_dir_find(this.directory, file_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
public push<E extends T>(entry: E): WrapResultNone<PushStatus> {
|
||||||
|
return fs_dir_push(this.directory, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
public pop(file_name: string): WrapResultEntry<T, ReadStatus> {
|
||||||
|
return fs_dir_pop(this.directory, file_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RfwfsBinary {
|
class RfwfsBinary {
|
||||||
public lambda: BinaryLambda;
|
public lambda: BinaryLambda;
|
||||||
protected entry: Entry;
|
protected entry: Entry;
|
||||||
@ -182,7 +242,10 @@ class RfwfsBinary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class rfwfs_static {
|
class rfwfs_lib {
|
||||||
|
public static is_root<T extends Entry>(entry: T): boolean {
|
||||||
|
return entry.type === EntryType.Root
|
||||||
|
}
|
||||||
public static is_dir<T extends Entry>(entry: T): boolean {
|
public static is_dir<T extends Entry>(entry: T): boolean {
|
||||||
return entry.type === EntryType.Directory
|
return entry.type === EntryType.Directory
|
||||||
}
|
}
|
||||||
@ -192,9 +255,6 @@ class rfwfs_static {
|
|||||||
public static is_binary<T extends Entry>(entry: T): boolean {
|
public static is_binary<T extends Entry>(entry: T): boolean {
|
||||||
return entry.type === EntryType.Binary
|
return entry.type === EntryType.Binary
|
||||||
}
|
}
|
||||||
public static is_root<T extends Entry>(entry: Root<T>): boolean {
|
|
||||||
return entry.type === EntryType.Root
|
|
||||||
}
|
|
||||||
|
|
||||||
public static read_access(permissions: Permissions): boolean {
|
public static read_access(permissions: Permissions): boolean {
|
||||||
return (permissions & Permissions.r) !== 0
|
return (permissions & Permissions.r) !== 0
|
||||||
@ -210,28 +270,24 @@ class rfwfs_static {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class rfwfs<T extends Entry> extends rfwfs_static {
|
class rfwfs<T extends Entry> extends rfwfs_lib {
|
||||||
public root: Root<T>;
|
public root: Root<T>;
|
||||||
|
|
||||||
constructor(inner: T[]) {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.root = { type: EntryType.Root, inner: inner }
|
this.root = {
|
||||||
|
type: EntryType.Root,
|
||||||
|
permissions: Permissions.r | Permissions.w,
|
||||||
|
timestamp: new EntryValueRoot((Date.now()/1000) | 0),
|
||||||
|
parent: null,
|
||||||
|
inner: new RfwfsRootDirectory(),
|
||||||
|
name: ROOT_ID.TRUNK,
|
||||||
|
} as Root<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
public add_file(
|
public push_directory_into_root<T extends Entry>(dir: EntryCollection<T>): EntryCollection<T> {
|
||||||
default_name: string,
|
this.root.inner.push(dir)
|
||||||
default_permissions: Permissions,
|
return dir
|
||||||
default_timestamp?: number,
|
|
||||||
default_inner?: FileInner
|
|
||||||
): EntryFile {
|
|
||||||
const file = { type: EntryType.File } as EntryFile
|
|
||||||
file.hash = "0"
|
|
||||||
file.permissions = default_permissions
|
|
||||||
file.parent = this.root
|
|
||||||
file.timestamp = new EntryValue(file, default_timestamp ? default_timestamp : (Date.now()/1000)|0)
|
|
||||||
file.inner = new EntryValue(file, default_inner ? default_inner : "")
|
|
||||||
file.name = new EntryValue(file, default_name)
|
|
||||||
return file
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static file(
|
public static file(
|
||||||
@ -245,7 +301,7 @@ class rfwfs<T extends Entry> extends rfwfs_static {
|
|||||||
file.hash = "0"
|
file.hash = "0"
|
||||||
file.permissions = default_permissions
|
file.permissions = default_permissions
|
||||||
file.parent = default_parent
|
file.parent = default_parent
|
||||||
file.timestamp = new EntryValue(file, default_timestamp ? default_timestamp : (Date.now()/1000)|0)
|
file.timestamp = new EntryValue(file, default_timestamp ? default_timestamp : (Date.now()/1000) | 0)
|
||||||
file.inner = new EntryValue(file, default_inner ? default_inner : "")
|
file.inner = new EntryValue(file, default_inner ? default_inner : "")
|
||||||
file.name = new EntryValue(file, default_name)
|
file.name = new EntryValue(file, default_name)
|
||||||
return file
|
return file
|
||||||
@ -261,7 +317,7 @@ class rfwfs<T extends Entry> extends rfwfs_static {
|
|||||||
const directory = { type: EntryType.Directory } as EntryCollection<T>
|
const directory = { type: EntryType.Directory } as EntryCollection<T>
|
||||||
directory.parent = default_parent
|
directory.parent = default_parent
|
||||||
directory.permissions = default_permissions
|
directory.permissions = default_permissions
|
||||||
directory.timestamp = new EntryValue(directory, default_timestamp ? default_timestamp : (Date.now()/1000)|0)
|
directory.timestamp = new EntryValue(directory, default_timestamp ? default_timestamp : (Date.now()/1000) | 0)
|
||||||
directory.inner = new RfwfsDirectory(directory, default_inner ? default_inner : [])
|
directory.inner = new RfwfsDirectory(directory, default_inner ? default_inner : [])
|
||||||
directory.name = new EntryValue(directory, default_name)
|
directory.name = new EntryValue(directory, default_name)
|
||||||
return directory
|
return directory
|
||||||
@ -277,7 +333,7 @@ class rfwfs<T extends Entry> extends rfwfs_static {
|
|||||||
const binary = { type: EntryType.Binary } as EntryBinary
|
const binary = { type: EntryType.Binary } as EntryBinary
|
||||||
binary.parent = default_parent
|
binary.parent = default_parent
|
||||||
binary.permissions = default_permissions
|
binary.permissions = default_permissions
|
||||||
binary.timestamp = new EntryValue(binary, default_timestamp ? default_timestamp : (Date.now()/1000)|0)
|
binary.timestamp = new EntryValue(binary, default_timestamp ? default_timestamp : (Date.now()/1000) | 0)
|
||||||
binary.inner = new RfwfsBinary(binary, default_inner ? default_inner : () => {})
|
binary.inner = new RfwfsBinary(binary, default_inner ? default_inner : () => {})
|
||||||
binary.name = new EntryValue(binary, default_name)
|
binary.name = new EntryValue(binary, default_name)
|
||||||
return binary
|
return binary
|
||||||
@ -286,8 +342,8 @@ class rfwfs<T extends Entry> extends rfwfs_static {
|
|||||||
|
|
||||||
export default rfwfs
|
export default rfwfs
|
||||||
export {
|
export {
|
||||||
type EntryCollection,
|
|
||||||
type DirectoryAnyDepth,
|
type DirectoryAnyDepth,
|
||||||
|
type EntryCollection,
|
||||||
type RfwfsDirectory,
|
type RfwfsDirectory,
|
||||||
type DirectoryAny,
|
type DirectoryAny,
|
||||||
type BinaryError,
|
type BinaryError,
|
||||||
@ -297,4 +353,5 @@ export {
|
|||||||
type Entry,
|
type Entry,
|
||||||
Permissions,
|
Permissions,
|
||||||
EntryType,
|
EntryType,
|
||||||
|
ROOT_ID,
|
||||||
}
|
}
|
Reference in New Issue
Block a user