Files
win32.run/src/lib/fs.js
2023-02-13 19:32:10 +07:00

399 lines
10 KiB
JavaScript

import { queueProgram, clipboard, selectingItems, hardDrive, clipboard_op } from './store';
import { recycle_bin_id, protected_items } from './system';
import * as utils from './utils';
import { get } from 'svelte/store';
import short from 'short-uuid';
import * as util from './utils';
import * as idb from 'idb-keyval';
import * as finder from './finder';
import {Buffer} from 'buffer';
export function copy(){
clipboard_op.set('copy');
clipboard.set(get(selectingItems));
console.log('copy');
}
export function cut(){
clipboard_op.set('cut');
clipboard.set(get(selectingItems));
console.log('cut');
}
export function paste(id, new_id=null){
console.log('paste to', id);
console.log('clipboard_op', get(clipboard_op));
console.log(get(hardDrive)[id]);
if(get(hardDrive)[id] == null || get(hardDrive)[id].type == 'file'){
console.log('target is not a dir');
return;
}
if(get(clipboard).length == 0){
console.log('clipboard is empty');
return;
}
for(let fs_id of get(clipboard)){
clone_fs(fs_id, id, new_id);
if(get(clipboard_op) == 'cut'){
del_fs(fs_id);
}
}
clipboard_op.set('copy')
clipboard.set([]);
}
export function del_fs(id){
if(protected_items.includes(id)){
console.log(id, 'is protected');
return;
}
let obj = get(hardDrive)[id];
let child_ids = [
...obj.files,
...obj.folders
]
if(get(hardDrive)[obj.parent] != null){
console.log('delete from parent', obj.parent)
hardDrive.update(data => {
data[obj.parent].files = data[obj.parent].files.filter(el => el != obj.id);
data[obj.parent].folders = data[obj.parent].folders.filter(el => el != obj.id);
return data;
})
}
hardDrive.update(data => {
delete data[id];
return data;
})
for(let child_id of child_ids){
del_fs(child_id);
}
}
export function clone_fs(obj_current_id, parent_id, new_id=null){
let obj = {...get(hardDrive)[obj_current_id]};
if(new_id == null){
obj.id = short.generate();
} else {
obj.id = new_id;
}
obj.parent = parent_id;
let parent_items_names = [
...get(hardDrive)[parent_id].files.map(el => get(hardDrive)[el].name),
...get(hardDrive)[parent_id].folders.map(el => get(hardDrive)[el].name),
]
let appendix = 2;
let basename = obj.basename;
while(parent_items_names.includes(basename + obj.ext)){
basename = obj.basename + ' ' + appendix;
appendix++;
}
obj.basename = basename;
obj.name = basename + obj.ext;
//backup files & folders
console.log(obj)
let files = [...obj.files];
let folders = [...obj.folders];
obj.files = [];
obj.folders = [];
//save to hard drive
hardDrive.update(data => {
data[obj.id] = obj;
return data;
})
console.log('cloning', obj.id)
if(obj.type == 'file'){
hardDrive.update(data => {
data[parent_id].files.push(obj.id);
return data;
})
} else if(obj.type == 'folder'){
hardDrive.update(data => {
data[parent_id].folders.push(obj.id);
return data;
})
}
//recursively clone child items
for(let child of [...files, ...folders]){
clone_fs(child, obj.id);
}
}
export async function new_fs_item(type, ext, seedname, parent_id, file=null){
if(type == null || seedname == null || parent_id == null){
return;
}
let item = {
"id": short.generate(),
"type": type,
"path": "",
"name": "",
"storage_type": "local",
"url": short.generate(),
"ext": ext,
"level": 0,
"parent": parent_id,
"size": 1,
"files": [],
"folders": [],
"basename": ""
}
let files = get(hardDrive)[parent_id].files.map(el => get(hardDrive)[el]);
let folders = get(hardDrive)[parent_id].folders.map(el => get(hardDrive)[el]);
let parent_items_names = [
...files.map(el => el.name),
...folders.map(el => el.name)
]
let appendix = 2;
seedname = utils.sanitize_filename(seedname);
let basename = seedname;
while(parent_items_names.includes(basename + ext)){
basename = seedname + ' ' + appendix;
appendix++;
}
item.basename = basename;
item.name = basename + item.ext;
if(file != null){
await idb.set(item.url, file);
item.size = Math.ceil(file.size/1024);
} else if(type == 'file'){
console.log('fetch empty file')
file = await file_from_url(`/empty/empty${item.ext}`, item.name);
await idb.set(item.url, file);
item.size = Math.ceil(file.size/1024);
} else {
item.url = '';
}
hardDrive.update(data => {
data[item.id] = item;
return data;
})
if(type == 'file'){
hardDrive.update(data => {
data[parent_id].files.push(item.id);
return data;
})
} else if (type == 'folder'){
hardDrive.update(data => {
data[parent_id].folders.push(item.id);
return data;
})
}
return item.id;
}
export async function new_fs_item_raw(item, parent_id){
if(parent_id == null){
return;
}
item.id = short.generate();
item.parent = parent_id;
if(!['file', 'folder'].includes(item.type)){
item.type = 'file';
}
if(item.storage_type == null){
item.storage_type = 'local'
}
if(item.ext == null){
item.ext = '';
}
if(item.icon == null){
item.icon = '/images/xp/icons/ApplicationWindow.png'
}
if(item.files == null){
item.files = [];
}
if(item.folders == null){
item.folders = [];
}
let files = get(hardDrive)[parent_id].files.map(el => get(hardDrive)[el]);
let folders = get(hardDrive)[parent_id].folders.map(el => get(hardDrive)[el]);
let parent_items_names = [
...files.map(el => el.name),
...folders.map(el => el.name)
]
let appendix = 2;
let seedname = utils.sanitize_filename(item.basename);
let basename = seedname;
while(parent_items_names.includes(basename + item.ext)){
basename = seedname + ' ' + appendix;
appendix++;
}
item.basename = basename;
item.name = basename + item.ext;
if(item.file != null){
item.url = short.generate();
await idb.set(item.url, item.file);
item.size = Math.ceil(file.size/1024);
delete item.file;
} else if(item.executable){
item.url = './programs/webapp.svelte';
}
hardDrive.update(data => {
data[item.id] = item;
return data;
})
if(item.type == 'file'){
hardDrive.update(data => {
data[parent_id].files.push(item.id);
return data;
})
} else if (item.type == 'folder'){
hardDrive.update(data => {
data[parent_id].folders.push(item.id);
return data;
})
}
return item.id;
}
export function get_path(id){
return finder.to_url(id);
}
export async function save_file(fs_id, file){
if(get(hardDrive)[fs_id] == null){
console.log(fs_id, 'not exist');
return;
}
let url = short.generate();
await idb.set(url, file);
hardDrive.update(data => {
data[fs_id].url = url;
data[fs_id].storage_type = 'local';
return data;
})
}
export async function save_file_as(basename, ext, file, parent_id, new_id=null){
ext = ext.toLowerCase();
if(util.extname(basename) == ext){
basename = util.basename(basename, ext);
}
let url = short.generate();
await idb.set(url, file);
if(new_id == null){
new_id = short.generate();
}
let obj = {
"id": new_id,
"type": 'file',
"path": "",
"name": basename + ext,
"storage_type": "local",
"url": url,
"ext": ext,
"level": 0,
"parent": parent_id,
"size": Math.round(file.size/1024),
"files": [],
"folders": [],
"basename": basename
}
let parent_items_names = [
...get(hardDrive)[parent_id].files.map(el => get(hardDrive)[el].name),
...get(hardDrive)[parent_id].folders.map(el => get(hardDrive)[el].name),
]
let appendix = 2;
basename = obj.basename;
while(parent_items_names.includes(basename + obj.ext)){
basename = obj.basename + ' ' + appendix;
appendix++;
}
obj.basename = basename;
obj.name = basename + obj.ext;
hardDrive.update(data => {
data[obj.id] = obj;
data[parent_id].files.push(obj.id);
return data;
})
}
export async function get_file(id){
let fs_item = get(hardDrive)[id];
let file;
if(fs_item.storage_type == 'remote'){
file = await file_from_url(fs_item.url);
} else if(fs_item.storage_type == 'local') {
file = await idb.get(fs_item.url);
console.log(file);
}
file = new File([file], fs_item.name, {type: file.type})
return file;
}
export async function get_url(id){
let fs_item = get(hardDrive)[id];
if(fs_item.storage_type == 'remote'){
return fs_item.url;
} else if(fs_item.storage_type == 'local') {
let file = await idb.get(fs_item.url);
return URL.createObjectURL(file);
}
}
export async function file_from_url(url, name, defaultType = 'image/jpeg'){
try {
const response = await fetch(url);
const data = await response.blob();
return new File([data], name, {
type: data.type || defaultType,
});
} catch (error) {
return new File([''], 'empty.txt', {
type: 'text/plain'
})
}
}
export async function array_buffer_from_url(url){
let file = await file_from_url(url);
return await file.arrayBuffer();
}
export async function buffer_from_url(url){
let array_buffer = await array_buffer_from_url(url);
console.log(array_buffer)
return Buffer.from(array_buffer);
}