UNPKG

godprotocol

Version:
269 lines (209 loc) 7.72 kB
import fs from "fs"; import { hash } from "../utils/hash"; class Fs { constructor(oracle) { this.oracle = oracle; this.fs = fs; this.base = __dirname; } is_directory=async path=>{ if(!await this.exists(path, {pure:true}))return false; try { const stats = this.fs.statSync(`${this.base}/${path}`); return stats.isDirectory(); } catch (err) { // console.error(`Error checking path: ${err.message}`); return false; // Handle error, e.g., path doesn't exist } } exists = async (path, options={}) => { return this.fs.existsSync(`${this.base}/${path}`); }; mkdir = async (path) => { path = `${this.base}/${path}`; !(await this.exists(path, {pure:true})) && this.fs.mkdirSync(path, { recursive: true }); }; read = async(path)=>{ let content; try{ content = this.fs.readFileSync(`${this.base}/${path}`, {encoding:'utf-8'}) content = JSON.parse(content) }catch(e){} return content; } retrieve = async(path, options)=>{ let config, result; if (options.current){ config = {current: path} }else{ config = await this.read(`${path}/.config`) || {}; if (!config.current) { if (options.config){ return } } } if (options.sibling){ if (config.sibling){ let res = await this.read(`${config.sibling}`) result = res.content } }else{ if (config.current){ let res = await this.read(`${config.current}/.config`) let value = await this.read(`${config.current}/${res.index-1}`) if(!value && res.current && !res.current.includes('/')){ value = await this.read(`${config.current}/${res.current}`) } if(options.config){ result = typeof value.content === 'string'? JSON.parse(value.content): value.content; } } } return result } write = async(path, content, options={})=>{ let addr; if (options.config){ await this.mkdir(path); let conf_path = `${path}/.config` let hash = await this.oracle.hash(content) let conf = await this.read(conf_path) || {index: 0} let obj = {content, sibling: conf.current} let current = `${path}/${hash}` conf.current = current; await this.write(conf_path, JSON.stringify(conf)) await this.mkdir(current) let current_conff = `${current}/.config` let conff = await this.read(current_conff) || {index: 0} await this.write(`${current}/${conff.index}`, JSON.stringify(obj)) conff.index++ await this.write(current_conff, JSON.stringify(conff)) addr = current }else { this.fs.writeFileSync(`${this.base}/${path}`, content) addr = path; } return addr; } store = async(content, {path, type, hash: hash_, is_instance})=>{ if (!type) type = this.oracle.get_type(content) let result, hash = hash_; switch(type){ case 'array': hash = hash || await this.oracle.hash(content) let arr_path = `${path}/${hash}` await this.mkdir(arr_path) let arr = [] for (let i=0; i< content.length; i++){ let item = content[i] let item_path = `${arr_path}/${i}` await this.mkdir(item_path) item = await this.store(item, {path: item_path}) let conf = await this.read(`${item_path}/.config`) if(!conf) conf = {index:0} else conf.index++ await this.write(`${item_path}/${conf.index}`, item) await this.write(`${item_path}/.config`, JSON.stringify(conf)); arr.push(conf.index) } let aconf = await this.read(`${path}/.config`) || {} let arr_hash = await this.oracle.hash(arr) let arr_conf = await this.read(`${arr_path}/.config`) || {index: 0} await this.write(`${arr_path}/${arr_hash}`, JSON.stringify({content:arr, type: is_instance? 'instance': type, previous: arr_conf.current, indice: aconf.indice})) arr_conf.current = arr_hash arr_conf.sibling = aconf.current; await this.write(`${arr_path}/.config`, JSON.stringify(arr_conf)); aconf.current = arr_path; await this.write(`${path}/.config`, JSON.stringify(aconf)) result = arr_path break; case 'twain': hash = hash || await this.oracle.hash(content) let twa_path = `${path}/${hash}` await this.mkdir(twa_path) let twa = {} for (let prop in content){ let value = content[prop]; let p_hash = await this.oracle.hash(prop) let pair_path = `${twa_path}/${p_hash}` await this.mkdir(pair_path) let p_addr = await this.store(prop, {path: pair_path}) let val_addr = await this.store(value, {path: pair_path}) let pair = [p_addr, val_addr] let conf = await this.read(`${pair_path}/.config`) if (!conf){ conf = {index: 0} }else if (!Object.keys(conf).includes('index'))conf.index = 0 else { conf.index++ } await this.write(`${pair_path}/${conf.index}`, JSON.stringify(pair)) twa[p_hash] = conf.index; await this.write(`${pair_path}/.config`, JSON.stringify(conf)); } let pconf = await this.read(`${path}/.config`) || {} let twa_hash = await this.oracle.hash(twa) let twa_conf = await this.read(`${twa_path}/.config`) || {index: 0} await this.write(`${twa_path}/${twa_hash}`, JSON.stringify({content:twa, type: is_instance? 'instance': type, previous: twa_conf.current, indice: pconf.indice})) twa_conf.current = twa_hash twa_conf.sibling = pconf.current; await this.write(`${twa_path}/.config`, JSON.stringify(twa_conf)); pconf.current = twa_path; await this.write(`${path}/.config`, JSON.stringify(pconf)) result = twa_path break; case 'string': hash = await this.oracle.hash(content) result = await this.write(`${path}/${hash}`, content) break case 'number': hash = await this.oracle.hash(`0${content}`) result = await this.write(`${path}/${hash}`, JSON.stringify(content)) break case 'boolean': hash = await this.oracle.hash(`0${content}`) result = await this.write(`${path}/${hash}`, JSON.stringify(content)) break } return result; } } class Oracle { constructor(manager) { this.manager = manager; this.fs = new Fs(this); } read = async(path, options)=>{ let result = await this.fs.retrieve(path, options) return result; } write = async(path, content, options={})=>{ let type = this.get_type(content), addr; if(options.config){ return await this.fs.write(path, JSON.stringify(content), {config: true}) } if (options.hash) path = `${path}/${options.hash}` addr = await this.fs.store(content, {path, type, has_hash: options.hash, is_instance: options.is_instance}) return addr; } hash = async(value, alg)=>{ if (typeof value !== 'string')value = JSON.stringify(value) return hash(value, alg) } sync = async () => { this.manager.path = `${this.manager.trinity.game}/${this.manager.name}`; await this.fs.mkdir(this.manager.path) }; get_type = (content)=>{ let type = typeof content; if (content == null) return 'void' if (type === 'object'){ if (Array.isArray(content)) type = 'array' else if (!content) type = 'void' else type = 'twain' } return type; } } export default Oracle;