refactor: no more buffer juggling!!!
This commit is contained in:
parent
a54b9b8230
commit
592b3e9ba1
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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} />
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
});
|
||||
|
|
|
@ -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$/);
|
||||
|
|
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -82,7 +82,7 @@ const Particle = ({
|
|||
Emit particles
|
||||
</button>
|
||||
<Entity.Component
|
||||
buffer={Buffer.from(JSON.stringify(particle))}
|
||||
resource={particle}
|
||||
path={path}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -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,
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user