refactor: no more buffer juggling!!!

This commit is contained in:
cha0s 2021-01-27 00:01:35 -06:00
parent a54b9b8230
commit 592b3e9ba1
13 changed files with 131 additions and 104 deletions

View File

@ -12,11 +12,10 @@ const Resource = ({uri, uuid}) => {
const latus = useLatus();
const resource = useSelector((state) => resourceSelector(state, `${uuid}${uri}`));
const {Component} = latus.get('%resource-controllers')(uri);
const buffer = Buffer.from(resource, 'base64');
return (
<div className="resource">
<UriContext.Provider value={uri}>
<Component buffer={buffer} />
<Component resource={resource} />
</UriContext.Provider>
</div>
);

View File

@ -1,8 +1,8 @@
import flatten from 'lodash.flatten';
import BinaryResource from './resource-controllers/binary';
import ImageResource from './resource-controllers/image';
import TextResource from './resource-controllers/text';
import BinaryResourceController from './resource-controllers/binary';
import ImageResourceController from './resource-controllers/image';
import TextResourceController from './resource-controllers/text';
import {projects, user} from './state';
export {default as Number} from './components/number';
@ -16,6 +16,12 @@ export {default as useProject} from './hooks/use-project';
export {default as useUri} from './hooks/use-uri';
export * from './state';
export {
BinaryResourceController,
ImageResourceController,
TextResourceController,
};
export default {
hooks: {
'@latus/core/config': () => ({
@ -24,9 +30,9 @@ export default {
'@latus/core/starting': async (latus) => {
const Controllers = flatten(await latus.invokeOrdered('@persea/core/resource-controllers'));
Controllers.push(
ImageResource,
TextResource,
BinaryResource,
ImageResourceController,
TextResourceController,
BinaryResourceController,
);
const Controller = (uri) => Controllers.find(({matcher}) => uri.match(matcher));
latus.set('%resource-controllers', Controller);

View File

@ -5,31 +5,32 @@ import {
import HexEditor from 'react-hex-editor';
import oneDarkPro from 'react-hex-editor/themes/oneDarkPro';
const BinaryComponent = ({buffer}) => (
<HexEditor
className="binary-renderer"
columns={0x10}
data={new Uint8Array(buffer.buffer)}
showAscii
showColumnLabels
showRowLabels
theme={{hexEditor: oneDarkPro}}
rows={Math.ceil(buffer.length / 0x10)}
/>
);
const BinaryComponent = ({resource}) => {
// eslint-disable-next-line no-use-before-define
const buffer = BinaryController.decode(resource);
return (
<HexEditor
className="binary-renderer"
columns={0x10}
data={new Uint8Array(buffer.buffer)}
showAscii
showColumnLabels
showRowLabels
theme={{hexEditor: oneDarkPro}}
rows={Math.ceil(buffer.length / 0x10)}
/>
);
};
BinaryComponent.propTypes = {
buffer: PropTypes.shape({
buffer: PropTypes.shape({}),
length: PropTypes.number,
}).isRequired,
resource: PropTypes.string.isRequired,
};
export default class BinaryController {
static Component({buffer}) {
static Component({resource}) {
return (
<BinaryComponent buffer={buffer} />
<BinaryComponent resource={resource} />
);
}

View File

@ -3,26 +3,30 @@ import {
React,
} from '@latus/react';
const ImageComponent = ({buffer}) => (
<div className="image-renderer">
<div
className="holder"
style={{backgroundImage: `url(data:;base64,${buffer.toString('base64')})`}}
/>
</div>
);
import BinaryController from '../binary';
ImageComponent.propTypes = {
buffer: PropTypes.shape({
toString: PropTypes.func,
}).isRequired,
const ImageComponent = ({resource}) => {
// eslint-disable-next-line no-use-before-define
const buffer = ImageController.decode(resource);
return (
<div className="image-renderer">
<div
className="holder"
style={{backgroundImage: `url(data:;base64,${buffer.toString('base64')})`}}
/>
</div>
);
};
export default class ImageController {
ImageComponent.propTypes = {
resource: PropTypes.string.isRequired,
};
static Component({buffer}) {
export default class ImageController extends BinaryController {
static Component({resource}) {
return (
<ImageComponent buffer={buffer} />
<ImageComponent resource={resource} />
);
}

View File

@ -3,26 +3,32 @@ import {
React,
} from '@latus/react';
const TextComponent = ({buffer}) => (
<div className="text-renderer">{buffer.toString()}</div>
const TextComponent = ({resource}) => (
<div className="text-renderer">{resource}</div>
);
TextComponent.propTypes = {
buffer: PropTypes.shape({
toString: PropTypes.func,
}).isRequired,
resource: PropTypes.string.isRequired,
};
export default class TextController {
static Component({buffer}) {
static Component({resource}) {
return (
<TextComponent buffer={buffer} />
<TextComponent resource={resource} />
);
}
static encode(buffer) {
return buffer.toString('utf8');
}
static get matcher() {
return /\.txt$/;
}
static decode(encoded) {
return Buffer.from(encoded, 'utf8');
}
}

View File

@ -25,11 +25,12 @@ export default {
}
next();
},
'@latus/redux/defaultState': async (req) => ({
'@latus/redux/defaultState': async (req, latus) => ({
projects: await projectsState(
req
? await req.user.projectsResourcePaths()
: {},
latus,
),
user: {
id: req

View File

@ -5,7 +5,7 @@ import {promisify} from 'util';
const readFile = promisify(fs.readFile).bind(fs);
const stat = promisify(fs.stat).bind(fs);
const projectResources = async (uuid, resourcePaths) => {
const projectResources = async (uuid, resourcePaths, latus) => {
const statPaths = await Promise.all(
resourcePaths
.map(async ([, path]) => {
@ -24,19 +24,20 @@ const projectResources = async (uuid, resourcePaths) => {
.filter(([stat]) => stat)
.map(([, path]) => path);
return filePaths
.reduce(async (r, path) => ({
...(await r),
[join(uuid, path)]: (
await readFile(join(process.cwd(), 'projects', uuid, path))
).toString('base64'),
}), {});
.reduce(async (r, path) => {
const {encode} = latus.get('%resource-controllers')(path);
return ({
...(await r),
[join(uuid, path)]: encode(await readFile(join(process.cwd(), 'projects', uuid, path))),
});
}, {});
};
const projectsResources = (projectsResourcePaths) => (
const projectsResources = (projectsResourcePaths, latus) => (
Object.entries(projectsResourcePaths)
.reduce(async (r, [uuid, resourcePaths]) => ({
...(await r),
...(await projectResources(uuid, resourcePaths)),
...(await projectResources(uuid, resourcePaths, latus)),
}), {})
);
@ -66,7 +67,7 @@ const projectsStructure = async (projectsResourcePaths) => (
)
);
export default async (projectsResourcePaths) => ({
export default async (projectsResourcePaths, latus) => ({
structure: await projectsStructure(projectsResourcePaths),
resources: await projectsResources(projectsResourcePaths),
resources: await projectsResources(projectsResourcePaths, latus),
});

View File

@ -2,7 +2,9 @@ import {basename, extname} from 'path';
import {camelCase} from '@latus/core';
import EntityController from './resource-controllers/entity';
import EntityResourceController from './resource-controllers/entity';
export {EntityResourceController};
export default {
hooks: {
@ -11,7 +13,7 @@ export default {
latus.set('%trait-renderers', TraitRenderers);
},
'@persea/core/resource-controllers': () => [
EntityController,
EntityResourceController,
],
'@persea/entity/trait-renderers': () => {
const context = require.context('./trait-renderers', false, /\.jsx$/);

View File

@ -4,6 +4,9 @@ import {
PropTypes,
React,
} from '@latus/react';
import {
JsonResourceController,
} from '@persea/json';
import {
Tab,
Tabs,
@ -15,53 +18,52 @@ import Traits from './traits';
import View from './view';
const EntityComponent = ({
buffer,
resource,
path,
}) => {
const json = JSON.parse(buffer.toString());
return (
<div className="entity-renderer">
<Tabs>
<div className="entity-renderer__workspacePanes">
<TabPanel>
<Traits
json={json.traits}
path={join(path, '/traits')}
/>
</TabPanel>
<TabPanel>
<View json={json} />
</TabPanel>
</div>
<div className="entity-renderer__workspaceTabs">
<TabList>
<Tab>Traits</Tab>
<Tab>View</Tab>
</TabList>
</div>
</Tabs>
</div>
);
};
}) => (
<div className="entity-renderer">
<Tabs>
<div className="entity-renderer__workspacePanes">
<TabPanel>
<Traits
json={resource.traits}
path={join(path, '/traits')}
/>
</TabPanel>
<TabPanel>
<View json={resource} />
</TabPanel>
</div>
<div className="entity-renderer__workspaceTabs">
<TabList>
<Tab>Traits</Tab>
<Tab>View</Tab>
</TabList>
</div>
</Tabs>
</div>
);
EntityComponent.defaultProps = {
path: '',
};
EntityComponent.propTypes = {
buffer: PropTypes.shape({}).isRequired,
resource: PropTypes.shape({
traits: PropTypes.shape({}),
}).isRequired,
path: PropTypes.string,
};
export default class EntityController {
export default class EntityController extends JsonResourceController {
static Component({
buffer,
resource,
path,
}) {
return (
<EntityComponent
buffer={buffer}
resource={resource}
path={path}
/>
);

View File

@ -82,7 +82,7 @@ const Particle = ({
Emit particles
</button>
<Entity.Component
buffer={Buffer.from(JSON.stringify(particle))}
resource={particle}
path={path}
/>
</div>

View File

@ -1,14 +1,16 @@
import JsonController from './resource-controllers/json';
import JsonResourceController from './resource-controllers/json';
import reducer from './state/reducer';
export {default as useJsonPatcher} from './hooks/use-json-patcher';
export * from './state';
export {JsonResourceController};
export default {
hooks: {
'@latus/redux/reducers': () => reducer,
'@persea/core/resource-controllers': () => [
JsonController,
JsonResourceController,
],
},
};

View File

@ -4,16 +4,24 @@ import {dark} from 'react-syntax-highlighter/dist/cjs/styles/prism';
export default class JsonController {
static Component({buffer}) {
static Component({resource}) {
return (
<SyntaxHighlighter language="json" style={dark}>
{JSON.stringify(JSON.parse(buffer.toString()), null, 2)}
{JSON.stringify(resource, null, 2)}
</SyntaxHighlighter>
);
}
static encode(buffer) {
return JSON.parse(buffer.toString('utf8'));
}
static get matcher() {
return /\.json$/;
}
static decode(encoded) {
return Buffer.from(JSON.stringify(encoded, null, 2), 'utf8');
}
}

View File

@ -1,4 +1,3 @@
import {JSONB} from '@avocado/resource';
import {createNextState} from '@latus/redux';
import {applyPatch} from 'fast-json-patch';
@ -10,10 +9,6 @@ export default (state, {payload, type}) => {
}
const {patch, project, uri} = payload;
return createNextState(state, (draft) => {
const buffer = Buffer.from(draft.projects.resources[`${project}${uri}`], 'base64');
const json = JSONB.parse(buffer);
applyPatch(json, patch);
// eslint-disable-next-line no-param-reassign
draft.projects.resources[`${project}${uri}`] = JSONB.bufferify(json).toString('base64');
applyPatch(draft.projects.resources[`${project}${uri}`], patch);
});
};