Initial support for OpenSCAD's customizer #477
@@ -43,6 +43,7 @@ RUN wget https://github.com/CadQuery/cq-cli/releases/download/v2.2-beta.2/cq-cli
|
||||
RUN unzip cq-cli-Linux-x86_64.zip
|
||||
|
||||
RUN chmod +x cq-cli/cq-cli
|
||||
RUN echo "cadhub-concat-split" > /var/task/cadhub-concat-split
|
||||
|
||||
COPY cadquery/*.js /var/task/
|
||||
COPY common/*.js /var/common/
|
||||
|
||||
@@ -31,7 +31,6 @@ const stl = async (req, _context, callback) => {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify({
|
||||
url: getObjectUrl(params, s3, tk),
|
||||
consoleMessage: previousAsset.consoleMessage,
|
||||
}),
|
||||
}
|
||||
callback(null, response)
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
const { makeFile, runCommand } = require('../common/utils')
|
||||
const { writeFiles, runCommand } = require('../common/utils')
|
||||
const { nanoid } = require('nanoid')
|
||||
|
||||
module.exports.runCQ = async ({
|
||||
file,
|
||||
settings: { deflection = 0.3 } = {},
|
||||
} = {}) => {
|
||||
const tempFile = await makeFile(file, '.py', nanoid)
|
||||
const fullPath = `/tmp/${tempFile}/output.stl`
|
||||
const tempFile = await writeFiles(
|
||||
[{ file, fileName: 'main.py' }],
|
||||
'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug:
|
||||
)
|
||||
const fullPath = `/tmp/${tempFile}/output.gz`
|
||||
const stlPath = `/tmp/${tempFile}/output.stl`
|
||||
const command = [
|
||||
`cq-cli/cq-cli`,
|
||||
`--codec stl`,
|
||||
`--infile /tmp/${tempFile}/main.py`,
|
||||
`--outfile ${fullPath}`,
|
||||
`--outfile ${stlPath}`,
|
||||
`--outputopts "deflection:${deflection};angularDeflection:${deflection};"`,
|
||||
`&& gzip ${fullPath}`,
|
||||
].join(' ')
|
||||
console.log('command', command)
|
||||
|
||||
try {
|
||||
const consoleMessage = await runCommand(command, 30000)
|
||||
await writeFiles(
|
||||
[
|
||||
{
|
||||
file: JSON.stringify({
|
||||
consoleMessage,
|
||||
}),
|
||||
fileName: 'metadata.json',
|
||||
},
|
||||
],
|
||||
tempFile
|
||||
)
|
||||
await runCommand(
|
||||
`cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`,
|
||||
15000
|
||||
)
|
||||
return { consoleMessage, fullPath }
|
||||
} catch (error) {
|
||||
return { error, fullPath }
|
||||
|
|
||||
|
||||
@@ -3,24 +3,19 @@ const { promises } = require('fs')
|
||||
const { writeFile } = promises
|
||||
const { createHash } = require('crypto')
|
||||
|
||||
const CONSOLE_MESSAGE_KEY = 'console-message-b64'
|
||||
function putConsoleMessageInMetadata(consoleMessage) {
|
||||
return {
|
||||
[CONSOLE_MESSAGE_KEY]: Buffer.from(consoleMessage, 'utf-8').toString(
|
||||
'base64'
|
||||
),
|
||||
async function writeFiles(files = [], tempFile) {
|
||||
|
Removed code to store things in s3 metadata. Removed code to store things in s3 metadata.
|
||||
console.log(`file to write: ${files.length}`)
|
||||
|
||||
try {
|
||||
await runCommand(`mkdir /tmp/${tempFile}`)
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
function getConsoleMessageFromMetadata(metadata) {
|
||||
return Buffer.from(metadata[CONSOLE_MESSAGE_KEY], 'base64').toString('utf-8')
|
||||
}
|
||||
|
||||
async function makeFile(file, extension = '.scad', makeHash) {
|
||||
const tempFile = 'a' + makeHash() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug:
|
||||
console.log(`file to write: ${file}`)
|
||||
|
||||
await runCommand(`mkdir /tmp/${tempFile}`)
|
||||
await writeFile(`/tmp/${tempFile}/main${extension}`, file)
|
||||
await Promise.all(
|
||||
files.map(({ file, fileName }) =>
|
||||
writeFile(`/tmp/${tempFile}/${fileName}`, file)
|
||||
)
|
||||
)
|
||||
return tempFile
|
||||
}
|
||||
|
||||
@@ -54,10 +49,8 @@ function makeHash(script) {
|
||||
|
||||
async function checkIfAlreadyExists(params, s3) {
|
||||
try {
|
||||
const objectHead = await s3.headObject(params).promise()
|
||||
const consoleMessage = getConsoleMessageFromMetadata(objectHead.Metadata)
|
||||
console.log('consoleMessage', consoleMessage)
|
||||
return { isAlreadyInBucket: true, consoleMessage }
|
||||
await s3.headObject(params).promise()
|
||||
return { isAlreadyInBucket: true }
|
||||
} catch (e) {
|
||||
console.log("couldn't find it", e)
|
||||
return { isAlreadyInBucket: false }
|
||||
@@ -117,7 +110,7 @@ async function storeAssetAndReturnUrl({
|
||||
let buffer
|
||||
|
||||
try {
|
||||
buffer = await readFile(`${fullPath}.gz`)
|
||||
buffer = await readFile(fullPath)
|
||||
} catch (e) {
|
||||
console.log('read file error', e)
|
||||
const response = {
|
||||
@@ -136,7 +129,6 @@ async function storeAssetAndReturnUrl({
|
||||
CacheControl: `max-age=${FiveDays}`, // browser caching to stop downloads of the same part
|
||||
ContentType: 'text/stl',
|
||||
ContentEncoding: 'gzip',
|
||||
Metadata: putConsoleMessageInMetadata(consoleMessage),
|
||||
})
|
||||
.promise()
|
||||
console.log('stored object', storedRender)
|
||||
@@ -146,7 +138,6 @@ async function storeAssetAndReturnUrl({
|
||||
statusCode: 200,
|
||||
body: JSON.stringify({
|
||||
url,
|
||||
consoleMessage,
|
||||
}),
|
||||
}
|
||||
callback(null, response)
|
||||
@@ -156,7 +147,7 @@ async function storeAssetAndReturnUrl({
|
||||
|
||||
module.exports = {
|
||||
runCommand,
|
||||
makeFile,
|
||||
writeFiles,
|
||||
makeHash,
|
||||
checkIfAlreadyExists,
|
||||
getObjectUrl,
|
||||
|
||||
@@ -6,10 +6,12 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update -qq
|
||||
# double check this below, I'm not sure we need inkscape etc
|
||||
RUN apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb imagemagick unzip inkscape
|
||||
RUN add-apt-repository ppa:openscad/releases
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -y -qq openscad
|
||||
RUN apt-get install -y curl wget
|
||||
RUN touch /etc/apt/sources.list.d/openscad.list
|
||||
RUN echo "deb https://download.opensuse.org/repositories/home:/t-paul/xUbuntu_20.04/ ./" >> /etc/apt/sources.list.d/openscad.list
|
||||
RUN wget -qO - https://files.openscad.org/OBS-Repository-Key.pub | apt-key add -
|
||||
RUN apt-get update -qq
|
||||
RUN apt-get install -y openscad-nightly
|
||||
|
||||
# install node14, see comment at the to of node14source_setup.sh
|
||||
ADD common/node14source_setup.sh /nodesource_setup.sh
|
||||
|
Im replacing the release with the nightly build to keep things simple @t-paul, I didn't want to have to try and figure out to support multiple version right now. Im replacing the release with the nightly build to keep things simple @t-paul, I didn't want to have to try and figure out to support multiple version right now.
Yep, keeping it simpler for now seems a good idea. This version is actively used by people (including myself) so it should be reasonably stable. Yep, keeping it simpler for now seems a good idea. This version is actively used by people (including myself) so it should be reasonably stable.
|
||||
@@ -44,7 +46,9 @@ RUN echo "OPENSCADPATH=/var/task/openscad" >>/etc/profile && \
|
||||
wget -P /var/task/openscad/ https://github.com/Irev-Dev/Round-Anything/archive/refs/tags/1.0.4.zip && \
|
||||
unzip /var/task/openscad/1.0.4
|
||||
# Add our own theming (based on DeepOcean with a different "background" and "opencsg-face-back")
|
||||
COPY openscad/cadhubtheme.json /usr/share/openscad/color-schemes/render/
|
||||
COPY openscad/cadhubtheme.json /usr/share/openscad-nightly/color-schemes/render/
|
||||
|
||||
RUN echo "cadhub-concat-split" > /var/task/cadhub-concat-split
|
||||
|
||||
COPY openscad/*.js /var/task/
|
||||
COPY common/*.js /var/common/
|
||||
|
||||
@@ -57,8 +57,6 @@ const preview = async (req, _context, callback) => {
|
||||
s3,
|
||||
tk
|
||||
),
|
||||
consoleMessage:
|
||||
previousAsset.consoleMessage || previousAssetPng.consoleMessage,
|
||||
type,
|
||||
}),
|
||||
}
|
||||
@@ -67,7 +65,10 @@ const preview = async (req, _context, callback) => {
|
||||
}
|
||||
|
||||
const { file, settings } = JSON.parse(eventBody)
|
||||
const { error, consoleMessage, fullPath } = await runScad({ file, settings })
|
||||
const { error, consoleMessage, fullPath, customizerPath } = await runScad({
|
||||
file,
|
||||
settings,
|
||||
})
|
||||
await storeAssetAndReturnUrl({
|
||||
error,
|
||||
callback,
|
||||
@@ -100,14 +101,16 @@ const stl = async (req, _context, callback) => {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify({
|
||||
url: getObjectUrl({ ...params }, s3, tk),
|
||||
consoleMessage: previousAsset.consoleMessage,
|
||||
}),
|
||||
}
|
||||
callback(null, response)
|
||||
return
|
||||
}
|
||||
const { file } = JSON.parse(eventBody)
|
||||
const { error, consoleMessage, fullPath } = await stlExport({ file })
|
||||
const { file, settings } = JSON.parse(eventBody)
|
||||
const { error, consoleMessage, fullPath, customizerPath } = await stlExport({
|
||||
file,
|
||||
settings,
|
||||
})
|
||||
await storeAssetAndReturnUrl({
|
||||
error,
|
||||
callback,
|
||||
@@ -121,6 +124,6 @@ const stl = async (req, _context, callback) => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
stl: middy(stl).use(cors()),
|
||||
stl: middy(loggerWrap(stl)).use(cors()),
|
||||
preview: middy(loggerWrap(preview)).use(cors()),
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
const { makeFile, runCommand } = require('../common/utils')
|
||||
const { writeFiles, runCommand } = require('../common/utils')
|
||||
const { nanoid } = require('nanoid')
|
||||
const { readFile } = require('fs/promises')
|
||||
|
||||
const OPENSCAD_COMMON = `xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" openscad`
|
||||
const OPENSCAD_COMMON = `xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" openscad-nightly`
|
||||
|
||||
/** Removes our generated/hash filename with just "main.scad", so that it's a nice message in the IDE */
|
||||
const cleanOpenScadError = (error) =>
|
||||
@@ -11,6 +12,7 @@ module.exports.runScad = async ({
|
||||
file,
|
||||
settings: {
|
||||
size: { x = 500, y = 500 } = {},
|
||||
parameters,
|
||||
camera: {
|
||||
position = { x: 40, y: 40, z: 40 },
|
||||
rotation = { x: 55, y: 0, z: 25 },
|
||||
@@ -18,46 +20,113 @@ module.exports.runScad = async ({
|
||||
} = {},
|
||||
} = {}, // TODO add view settings
|
||||
} = {}) => {
|
||||
const tempFile = await makeFile(file, '.scad', nanoid)
|
||||
const tempFile = await writeFiles(
|
||||
[
|
||||
{ file, fileName: 'main.scad' },
|
||||
{
|
||||
file: JSON.stringify({
|
||||
parameterSets: { default: parameters },
|
||||
fileFormatVersion: '1',
|
||||
}),
|
||||
fileName: 'params.json',
|
||||
},
|
||||
],
|
||||
'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug:
|
||||
)
|
||||
const { x: rx, y: ry, z: rz } = rotation
|
||||
const { x: px, y: py, z: pz } = position
|
||||
const cameraArg = `--camera=${px},${py},${pz},${rx},${ry},${rz},${dist}`
|
||||
const fullPath = `/tmp/${tempFile}/output.png`
|
||||
const fullPath = `/tmp/${tempFile}/output.gz`
|
||||
const imPath = `/tmp/${tempFile}/output.png`
|
||||
const customizerPath = `/tmp/${tempFile}/customizer.param`
|
||||
const command = [
|
||||
OPENSCAD_COMMON,
|
||||
`-o ${fullPath}`,
|
||||
`-o ${customizerPath}`,
|
||||
`-o ${imPath}`,
|
||||
`-p /tmp/${tempFile}/params.json -P default`,
|
||||
cameraArg,
|
||||
`--imgsize=${x},${y}`,
|
||||
`--colorscheme CadHub`,
|
||||
`/tmp/${tempFile}/main.scad`,
|
||||
`&& gzip ${fullPath}`,
|
||||
].join(' ')
|
||||
console.log('command', command)
|
||||
|
||||
try {
|
||||
const consoleMessage = await runCommand(command, 15000)
|
||||
return { consoleMessage, fullPath }
|
||||
const params = JSON.parse(
|
||||
await readFile(customizerPath, { encoding: 'ascii' })
|
||||
).parameters
|
||||
await writeFiles(
|
||||
[
|
||||
{
|
||||
file: JSON.stringify({
|
||||
customizerParams: params,
|
||||
consoleMessage,
|
||||
}),
|
||||
fileName: 'metadata.json',
|
||||
},
|
||||
],
|
||||
tempFile
|
||||
)
|
||||
await runCommand(
|
||||
`cat ${imPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`,
|
||||
15000
|
||||
)
|
||||
return { consoleMessage, fullPath, customizerPath }
|
||||
} catch (dirtyError) {
|
||||
const error = cleanOpenScadError(dirtyError)
|
||||
return { error }
|
||||
return { error: cleanOpenScadError(dirtyError) }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.stlExport = async ({ file } = {}) => {
|
||||
const tempFile = await makeFile(file, '.scad', nanoid)
|
||||
const fullPath = `/tmp/${tempFile}/output.stl`
|
||||
module.exports.stlExport = async ({ file, settings: { parameters } } = {}) => {
|
||||
const tempFile = await writeFiles(
|
||||
[
|
||||
{ file, fileName: 'main.scad' },
|
||||
{
|
||||
file: JSON.stringify({
|
||||
parameterSets: { default: parameters },
|
||||
fileFormatVersion: '1',
|
||||
}),
|
||||
fileName: 'params.json',
|
||||
},
|
||||
],
|
||||
'a' + nanoid() // 'a' ensure nothing funny happens if it start with a bad character like "-", maybe I should pick a safer id generator :shrug:
|
||||
)
|
||||
const fullPath = `/tmp/${tempFile}/output.gz`
|
||||
const stlPath = `/tmp/${tempFile}/output.stl`
|
||||
const customizerPath = `/tmp/${tempFile}/customizer.param`
|
||||
const command = [
|
||||
OPENSCAD_COMMON,
|
||||
`--export-format=binstl`,
|
||||
`-o ${fullPath}`,
|
||||
// `--export-format=binstl`,
|
||||
`-o ${customizerPath}`,
|
||||
`-o ${stlPath}`,
|
||||
`-p /tmp/${tempFile}/params.json -P default`,
|
||||
`/tmp/${tempFile}/main.scad`,
|
||||
`&& gzip ${fullPath}`,
|
||||
].join(' ')
|
||||
|
||||
try {
|
||||
// lambda will time out before this, we might need to look at background jobs if we do git integration stl generation
|
||||
const consoleMessage = await runCommand(command, 60000)
|
||||
return { consoleMessage, fullPath }
|
||||
const params = JSON.parse(
|
||||
await readFile(customizerPath, { encoding: 'ascii' })
|
||||
).parameters
|
||||
await writeFiles(
|
||||
[
|
||||
{
|
||||
file: JSON.stringify({
|
||||
customizerParams: params,
|
||||
consoleMessage,
|
||||
}),
|
||||
fileName: 'metadata.json',
|
||||
},
|
||||
],
|
||||
tempFile
|
||||
)
|
||||
await runCommand(
|
||||
`cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`,
|
||||
15000
|
||||
)
|
||||
return { consoleMessage, fullPath, customizerPath }
|
||||
} catch (error) {
|
||||
return { error, fullPath }
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.0.0",
|
||||
"@heroicons/react": "^1.0.4",
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@monaco-editor/react": "^4.0.11",
|
||||
"@react-three/drei": "^7.3.1",
|
||||
|
||||
@@ -271,7 +271,7 @@ function parseParams(script){
|
||||
caption = caption.substring(0,idx).trim()
|
||||
}
|
||||
defs.push({name, type: 'group', caption, ...def.options})
|
||||
|
||||
|
||||
}else{
|
||||
const idx = line.indexOf('/')
|
||||
if(idx === -1){
|
||||
@@ -316,7 +316,7 @@ function parseComment(comment, line){
|
||||
const prefix = comment.substring(0,2)
|
||||
if(prefix === '//') comment = comment.substring(2)
|
||||
if(prefix === '/*') comment = comment.substring(2, comment.length-2)
|
||||
|
||||
|
||||
comment = comment.trim()
|
||||
|
||||
const ret = {}
|
||||
@@ -331,7 +331,7 @@ function parseComment(comment, line){
|
||||
}
|
||||
comment = comment.substring(0,idx).trim()
|
||||
}
|
||||
|
||||
|
||||
ret.caption = comment
|
||||
|
||||
return ret
|
||||
@@ -347,7 +347,7 @@ function parseDef(code, line){
|
||||
return {name:code, type:'text'}
|
||||
}else{
|
||||
let initial = code.substring(idx+1).trim()
|
||||
|
||||
|
||||
const ret = {type:'text', name:code.substring(0,idx).trim()}
|
||||
|
||||
if(initial === 'true' || initial === 'false'){
|
||||
@@ -394,7 +394,7 @@ const makeScriptWorker = ({callback, convertToSolids})=>{
|
||||
solids = []
|
||||
function flatten(arr){
|
||||
if(arr){
|
||||
if(arr instanceof Array)
|
||||
if(arr instanceof Array)
|
||||
arr.forEach(flatten)
|
||||
else
|
||||
solids.push(arr)
|
||||
@@ -454,7 +454,6 @@ const makeScriptWorker = ({callback, convertToSolids})=>{
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log('paramsDef', paramsDef)
|
||||
if(paramsDef.length) callback({action:'parameterDefinitions', worker:'main', data:paramsDef})
|
||||
|
||||
runMain(params)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Listbox, Transition } from '@headlessui/react'
|
||||
import { CheckIcon, SelectorIcon } from '@heroicons/react/solid'
|
||||
|
||||
import { useRender } from 'src/components/IdeWrapper/useRender'
|
||||
import { useIdeContext } from 'src/helpers/hooks/useIdeContext'
|
||||
import { Switch } from '@headlessui/react'
|
||||
@@ -6,6 +9,8 @@ import {
|
||||
CadhubStringParam,
|
||||
CadhubBooleanParam,
|
||||
CadhubNumberParam,
|
||||
CadhubStringChoiceParam,
|
||||
CadhubNumberChoiceParam,
|
||||
} from './customizerConverter'
|
||||
|
||||
const Customizer = () => {
|
||||
@@ -79,13 +84,22 @@ const Customizer = () => {
|
||||
{customizerParams.map((param, index) => {
|
||||
const otherProps = {
|
||||
value: currentParameters[param.name],
|
||||
onChange: (value) => updateCustomizerParam(param.name, value),
|
||||
onChange: (value) =>
|
||||
updateCustomizerParam(
|
||||
param.name,
|
||||
param.type == 'number' ? Number(value) : value
|
||||
),
|
||||
}
|
||||
if (param.type === 'string') {
|
||||
if (
|
||||
param.input === 'choice-string' ||
|
||||
param.input === 'choice-number'
|
||||
) {
|
||||
return <ChoiceParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.input === 'default-string') {
|
||||
return <StringParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.type === 'number') {
|
||||
} else if (param.input === 'default-number') {
|
||||
return <NumberParam key={index} param={param} {...otherProps} />
|
||||
} else if (param.type === 'boolean') {
|
||||
} else if (param.input === 'default-boolean') {
|
||||
return <BooleanParam key={index} param={param} {...otherProps} />
|
||||
}
|
||||
return <div key={index}>{JSON.stringify(param)}</div>
|
||||
@@ -128,7 +142,7 @@ function BooleanParam({
|
||||
}: {
|
||||
param: CadhubBooleanParam
|
||||
value: any
|
||||
onChange: Function
|
||||
onChange: (value: any) => void
|
||||
}) {
|
||||
return (
|
||||
<CustomizerParamBase name={param.name} caption={param.caption}>
|
||||
@@ -158,7 +172,7 @@ function StringParam({
|
||||
}: {
|
||||
param: CadhubStringParam
|
||||
value: any
|
||||
onChange: Function
|
||||
onChange: (value: any) => void
|
||||
}) {
|
||||
return (
|
||||
<CustomizerParamBase name={param.name} caption={param.caption}>
|
||||
@@ -173,6 +187,79 @@ function StringParam({
|
||||
)
|
||||
}
|
||||
|
||||
function ChoiceParam({
|
||||
param,
|
||||
value,
|
||||
onChange,
|
||||
}: {
|
||||
param: CadhubStringChoiceParam | CadhubNumberChoiceParam
|
||||
value: any
|
||||
onChange: (value: any) => void
|
||||
}) {
|
||||
return (
|
||||
<CustomizerParamBase name={param.name} caption={param.caption}>
|
||||
<Listbox value={value} onChange={onChange}>
|
||||
<div className="relative mt-1">
|
||||
<Listbox.Button className="relative w-full h-8 text-left cursor-default focus:outline-none focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-white focus-visible:ring-offset-orange-300 focus-visible:ring-offset-2 focus-visible:border-indigo-500 sm:text-sm border border-ch-gray-300 px-2 text-sm">
|
||||
<span className="block truncate">{value}</span>
|
||||
<span className="absolute inset-y-0 right-0 flex items-center pr-1 pointer-events-none">
|
||||
<SelectorIcon
|
||||
className="w-5 h-5 text-gray-300"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
</Listbox.Button>
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options className="absolute w-full py-1 mt-1 bg-ch-gray-600 bg-opacity-80 overflow-auto text-base rounded-sm shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||
{param.options.map((option, optionIdx) => (
|
||||
<Listbox.Option
|
||||
key={optionIdx}
|
||||
className={({ active }) =>
|
||||
`${
|
||||
active
|
||||
? 'text-ch-blue-600 bg-ch-gray-700'
|
||||
: 'text-ch-gray-300'
|
||||
}
|
||||
cursor-default select-none relative py-2 pl-10 pr-4`
|
||||
}
|
||||
value={option.value}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={`${
|
||||
selected ? 'font-medium' : 'font-normal'
|
||||
} block truncate`}
|
||||
>
|
||||
{option.name}
|
||||
</span>
|
||||
{selected ? (
|
||||
<span
|
||||
className={`${
|
||||
active ? 'text-ch-blue-600' : 'text-ch-gray-300'
|
||||
}
|
||||
absolute inset-y-0 left-0 flex items-center pl-3`}
|
||||
>
|
||||
<CheckIcon className="w-5 h-5" aria-hidden="true" />
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</Listbox>
|
||||
</CustomizerParamBase>
|
||||
)
|
||||
}
|
||||
|
||||
function NumberParam({
|
||||
param,
|
||||
value,
|
||||
@@ -180,10 +267,10 @@ function NumberParam({
|
||||
}: {
|
||||
param: CadhubNumberParam
|
||||
value: any
|
||||
onChange: Function
|
||||
onChange: (value: any) => void
|
||||
}) {
|
||||
const [isFocused, isFocusedSetter] = React.useState(false)
|
||||
const [localValue, localValueSetter] = React.useState(0)
|
||||
const [localValue, localValueSetter] = React.useState(value)
|
||||
const [isLocked, isLockedSetter] = React.useState(false)
|
||||
const [pixelsDragged, pixelsDraggedSetter] = React.useState(0)
|
||||
const step = param.step || 1
|
||||
|
||||
@@ -1,24 +1,45 @@
|
||||
// CadHub
|
||||
|
||||
type CadhubTypeNames = 'number' | 'string' | 'boolean'
|
||||
type CadhubInputNames =
|
||||
| 'default-number'
|
||||
| 'default-string'
|
||||
| 'default-boolean'
|
||||
| 'choice-string'
|
||||
| 'choice-number'
|
||||
|
||||
export interface CadhubStringOption {
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface CadhubNumberOption {
|
||||
name: string
|
||||
value: number
|
||||
}
|
||||
|
||||
interface CadhubParamBase {
|
||||
type: CadhubTypeNames
|
||||
caption: string
|
||||
name: string
|
||||
input: CadhubInputNames
|
||||
}
|
||||
|
||||
export interface CadhubStringParam extends CadhubParamBase {
|
||||
type: 'string'
|
||||
input: 'default-string'
|
||||
initial: string
|
||||
placeholder?: string
|
||||
maxLength?: number
|
||||
}
|
||||
export interface CadhubBooleanParam extends CadhubParamBase {
|
||||
type: 'boolean'
|
||||
input: 'default-boolean'
|
||||
initial?: boolean
|
||||
}
|
||||
export interface CadhubNumberParam extends CadhubParamBase {
|
||||
type: 'number'
|
||||
input: 'default-number'
|
||||
initial: number
|
||||
min?: number
|
||||
max?: number
|
||||
@@ -26,95 +47,22 @@ export interface CadhubNumberParam extends CadhubParamBase {
|
||||
decimal?: number
|
||||
}
|
||||
|
||||
export interface CadhubStringChoiceParam extends CadhubParamBase {
|
||||
type: 'string'
|
||||
input: 'choice-string'
|
||||
initial: string
|
||||
options: Array<CadhubStringOption>
|
||||
}
|
||||
export interface CadhubNumberChoiceParam extends CadhubParamBase {
|
||||
type: 'number'
|
||||
input: 'choice-number'
|
||||
initial: number
|
||||
options: Array<CadhubNumberOption>
|
||||
}
|
||||
|
||||
export type CadhubParams =
|
||||
| CadhubStringParam
|
||||
| CadhubBooleanParam
|
||||
| CadhubNumberParam
|
||||
|
||||
// OpenSCAD
|
||||
const openscadValues = `
|
||||
// slider widget for number with max. value
|
||||
sliderWithMax =34; // [50]
|
||||
|
||||
// slider widget for number in range
|
||||
sliderWithRange =34; // [10:100]
|
||||
|
||||
//step slider for number
|
||||
stepSlider=2; //[0:5:100]
|
||||
|
||||
// slider widget for number in range
|
||||
sliderCentered =0; // [-10:0.1:10]
|
||||
|
||||
// spinbox with step size 1
|
||||
Spinbox= 5;
|
||||
|
||||
// Text box for string
|
||||
String="hello";
|
||||
|
||||
// Text box for string with length 8
|
||||
String2="length"; //8
|
||||
|
||||
//description
|
||||
Variable = true;
|
||||
`
|
||||
|
||||
const openscadConverted: CadhubParams[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderWithMax',
|
||||
caption: 'slider widget for number with max. value',
|
||||
initial: 34,
|
||||
step: 1,
|
||||
max: 50,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderWithRange',
|
||||
caption: 'slider widget for number in range',
|
||||
initial: 34,
|
||||
step: 1,
|
||||
min: 10,
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'stepSlider',
|
||||
caption: 'step slider for number',
|
||||
initial: 2,
|
||||
step: 5,
|
||||
min: 0,
|
||||
max: 100,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'sliderCentered',
|
||||
caption: 'slider widget for number in range',
|
||||
initial: 0,
|
||||
step: 0.1,
|
||||
min: -10,
|
||||
max: 10,
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'Spinbox',
|
||||
caption: 'spinbox with step size 1',
|
||||
initial: 5,
|
||||
step: 1,
|
||||
},
|
||||
|
||||
{
|
||||
type: 'string',
|
||||
name: 'String',
|
||||
caption: 'Text box for string',
|
||||
initial: 'hello',
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'String2',
|
||||
caption: 'Text box for string with length 8',
|
||||
initial: 'length',
|
||||
maxLength: 8,
|
||||
},
|
||||
|
||||
{ type: 'boolean', name: 'Variable', caption: 'description', initial: true },
|
||||
]
|
||||
| CadhubStringChoiceParam
|
||||
| CadhubNumberChoiceParam
|
||||
|
||||
@@ -22,7 +22,7 @@ const IdeConsole = () => {
|
||||
{time?.toLocaleString()}
|
||||
</div>
|
||||
<div className={(type === 'error' ? 'text-red-400' : '') + ' pl-4'}>
|
||||
{message.split('\n').map((line, index) => {
|
||||
{(message || '').split('\n').map((line, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
{line.startsWith('ECHO:') ? (
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
timeoutErrorMessage,
|
||||
RenderArgs,
|
||||
DefaultKernelExport,
|
||||
splitGziped,
|
||||
} from './common'
|
||||
|
||||
export const render: DefaultKernelExport['render'] = async ({
|
||||
@@ -41,11 +42,19 @@ export const render: DefaultKernelExport['render'] = async ({
|
||||
return createUnhealthyResponse(new Date(), timeoutErrorMessage)
|
||||
}
|
||||
const data = await response.json()
|
||||
const geometry = await stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage } = splitGziped(text)
|
||||
return {
|
||||
data: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type: 'geometry',
|
||||
data: geometry,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
})
|
||||
} catch (e) {
|
||||
|
||||
@@ -13,8 +13,8 @@ export const stlToGeometry = (url) =>
|
||||
|
||||
export interface RenderArgs {
|
||||
code: State['code']
|
||||
parameters?: RawCustomizerParams
|
||||
settings: {
|
||||
parameters?: RawCustomizerParams
|
||||
camera: State['camera']
|
||||
viewerSize: State['viewerSize']
|
||||
quality: State['objectData']['quality']
|
||||
@@ -103,3 +103,16 @@ export type RenderResponse = HealthyResponse | ErrorResponse
|
||||
export interface DefaultKernelExport {
|
||||
render: (arg: RenderArgs) => Promise<RenderResponse>
|
||||
}
|
||||
|
||||
export const splitGziped = (text: string) => {
|
||||
const concatSplitStr = 'cadhub-concat-split'
|
||||
const splitIndex = text.indexOf(concatSplitStr)
|
||||
const json = text.slice(splitIndex + concatSplitStr.length)
|
||||
|
||||
try {
|
||||
return JSON.parse(json)
|
||||
} catch (e) {
|
||||
console.log(json, e)
|
||||
return {}
|
||||
}
|
||||
|
This is what splits and pulls the json meta off the concatenated file. This is what splits and pulls the json meta off the concatenated file.
it is ok for now, you control both sides, so It can be improved later it is ok for now, you control both sides, so It can be improved later
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DefaultKernelExport } from './common'
|
||||
import type { CadPackage } from 'src/helpers/hooks/useIdeState'
|
||||
|
||||
import openscad from './openScadController'
|
||||
import openscad from './openScad/openScadController'
|
||||
import cadquery from './cadQueryController'
|
||||
import jscad from './jsCad/jsCadController'
|
||||
|
||||
|
||||
@@ -130,7 +130,6 @@ const workerHelper = new WorkerHelper()
|
||||
|
||||
export const render: DefaultKernelExport['render'] = async ({
|
||||
code,
|
||||
parameters,
|
||||
settings,
|
||||
}: RenderArgs) => {
|
||||
if (!scriptWorker) {
|
||||
@@ -169,11 +168,11 @@ export const render: DefaultKernelExport['render'] = async ({
|
||||
}
|
||||
})
|
||||
|
||||
workerHelper.resolver()
|
||||
workerHelper.resolver(null)
|
||||
scriptWorker.postMessage({ action: 'init', baseURI, alias: [] })
|
||||
}
|
||||
|
||||
return workerHelper.render(code, parameters)
|
||||
return workerHelper.render(code, settings.parameters)
|
||||
}
|
||||
|
||||
const jsCadController: DefaultKernelExport = {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { CadhubParams } from 'src/components/Customizer/customizerConverter'
|
||||
import {
|
||||
CadhubNumberChoiceParam,
|
||||
CadhubNumberOption,
|
||||
CadhubParams,
|
||||
CadhubStringChoiceParam,
|
||||
CadhubStringOption,
|
||||
} from 'src/components/Customizer/customizerConverter'
|
||||
|
||||
type JscadTypeNames =
|
||||
| 'group'
|
||||
@@ -19,6 +25,7 @@ interface JscadParamBase {
|
||||
type: JscadTypeNames
|
||||
caption: string
|
||||
name: string
|
||||
initial?: number | string | boolean
|
||||
}
|
||||
interface JscadGroupParam extends JscadParamBase {
|
||||
type: 'group'
|
||||
@@ -81,14 +88,18 @@ type JsCadParams =
|
||||
export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
return input
|
||||
.map((param): CadhubParams => {
|
||||
const common: { caption: string; name: string } = {
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
}
|
||||
switch (param.type) {
|
||||
case 'slider':
|
||||
case 'number':
|
||||
case 'int':
|
||||
return {
|
||||
type: 'number',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
input: 'default-number',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
min: param.min,
|
||||
max: param.max,
|
||||
@@ -103,8 +114,8 @@ export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
case 'date':
|
||||
return {
|
||||
type: 'string',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
input: 'default-string',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
placeholder:
|
||||
param.type === 'text' ||
|
||||
@@ -120,10 +131,39 @@ export function jsCadToCadhubParams(input: JsCadParams[]): CadhubParams[] {
|
||||
case 'checkbox':
|
||||
return {
|
||||
type: 'boolean',
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
input: 'default-boolean',
|
||||
...common,
|
||||
initial: !!param.initial,
|
||||
}
|
||||
case 'choice':
|
||||
case 'radio':
|
||||
if (typeof param.values[0] === 'number') {
|
||||
const options: Array<CadhubNumberOption> = []
|
||||
const captions = param.captions || param.values
|
||||
param.values.forEach((value, i) => {
|
||||
options[i] = { name: String(captions[i]), value: Number(value) }
|
||||
})
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'choice-number',
|
||||
...common,
|
||||
initial: Number(param.initial),
|
||||
options,
|
||||
}
|
||||
} else {
|
||||
const options: Array<CadhubStringOption> = []
|
||||
const captions = param.captions || param.values
|
||||
param.values.forEach((value, i) => {
|
||||
options[i] = { name: String(captions[i]), value: String(value) }
|
||||
})
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'choice-string',
|
||||
...common,
|
||||
initial: String(param.initial),
|
||||
options,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter((a) => a)
|
||||
|
||||
@@ -5,7 +5,9 @@ import {
|
||||
createUnhealthyResponse,
|
||||
timeoutErrorMessage,
|
||||
RenderArgs,
|
||||
} from './common'
|
||||
splitGziped,
|
||||
} from '../common'
|
||||
import { openScadToCadhubParams } from './openScadParams'
|
||||
|
||||
export const render = async ({ code, settings }: RenderArgs) => {
|
||||
const pixelRatio = window.devicePixelRatio || 1
|
||||
@@ -17,6 +19,7 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
||||
const body = JSON.stringify({
|
||||
settings: {
|
||||
size,
|
||||
parameters: settings.parameters,
|
||||
camera: {
|
||||
// rounding to give our caching a chance to sometimes work
|
||||
...settings.camera,
|
||||
@@ -56,15 +59,25 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
||||
}
|
||||
const data = await response.json()
|
||||
const type = data.type !== 'stl' ? 'png' : 'geometry'
|
||||
const newData =
|
||||
data.type !== 'stl'
|
||||
? fetch(data.url).then((a) => a.blob())
|
||||
: stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage, customizerParams } = splitGziped(text)
|
||||
return {
|
||||
data:
|
||||
data.type !== 'stl'
|
||||
? blob
|
||||
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
customizerParams,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type,
|
||||
data: await newData,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
customizerParams: openScadToCadhubParams(newData.customizerParams || []),
|
||||
})
|
||||
} catch (e) {
|
||||
return createUnhealthyResponse(new Date())
|
||||
@@ -93,12 +106,22 @@ export const stl = async ({ code, settings }: RenderArgs) => {
|
||||
return createUnhealthyResponse(new Date(), timeoutErrorMessage)
|
||||
}
|
||||
const data = await response.json()
|
||||
const geometry = await stlToGeometry(data.url)
|
||||
const newData = await fetch(data.url).then(async (a) => {
|
||||
const blob = await a.blob()
|
||||
const text = await new Response(blob).text()
|
||||
const { consoleMessage, customizerParams } = splitGziped(text)
|
||||
return {
|
||||
data: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||
consoleMessage,
|
||||
customizerParams,
|
||||
}
|
||||
})
|
||||
return createHealthyResponse({
|
||||
type: 'geometry',
|
||||
data: geometry,
|
||||
consoleMessage: data.consoleMessage,
|
||||
data: newData.data,
|
||||
consoleMessage: newData.consoleMessage,
|
||||
date: new Date(),
|
||||
customizerParams: openScadToCadhubParams(newData.customizerParams || []),
|
||||
})
|
||||
} catch (e) {
|
||||
return createUnhealthyResponse(new Date())
|
||||
102
app/web/src/helpers/cadPackages/openScad/openScadParams.ts
Normal file
102
app/web/src/helpers/cadPackages/openScad/openScadParams.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { CadhubParams } from 'src/components/Customizer/customizerConverter'
|
||||
|
||||
interface OpenScadParamsBase {
|
||||
caption: string
|
||||
name: string
|
||||
group: string
|
||||
initial: number | string | boolean | number[]
|
||||
type: 'string' | 'number' | 'boolean'
|
||||
}
|
||||
|
||||
interface OpenScadNumberParam extends OpenScadParamsBase {
|
||||
type: 'number'
|
||||
initial: number | number[]
|
||||
max?: number
|
||||
min?: number
|
||||
step?: number
|
||||
options?: { name: string; value: number }[]
|
||||
}
|
||||
interface OpenScadStringParam extends OpenScadParamsBase {
|
||||
type: 'string'
|
||||
initial: string
|
||||
maxLength?: number
|
||||
options?: { name: string; value: string }[]
|
||||
}
|
||||
interface OpenScadBooleanParam extends OpenScadParamsBase {
|
||||
type: 'boolean'
|
||||
initial: boolean
|
||||
}
|
||||
|
||||
export type OpenScadParams =
|
||||
| OpenScadNumberParam
|
||||
| OpenScadStringParam
|
||||
| OpenScadBooleanParam
|
||||
|
||||
export function openScadToCadhubParams(
|
||||
input: OpenScadParams[]
|
||||
): CadhubParams[] {
|
||||
return input
|
||||
.map((param): CadhubParams => {
|
||||
const common: { caption: string; name: string } = {
|
||||
caption: param.caption,
|
||||
name: param.name,
|
||||
}
|
||||
switch (param.type) {
|
||||
case 'boolean':
|
||||
return {
|
||||
type: 'boolean',
|
||||
input: 'default-boolean',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
}
|
||||
case 'string':
|
||||
if (!Array.isArray(param?.options)) {
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'default-string',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
maxLength: param.maxLength,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: 'string',
|
||||
input: 'choice-string',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
options: param.options,
|
||||
}
|
||||
}
|
||||
case 'number':
|
||||
if (
|
||||
!Array.isArray(param?.options) &&
|
||||
!Array.isArray(param?.initial)
|
||||
) {
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'default-number',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
min: param.min,
|
||||
max: param.max,
|
||||
step: param.step,
|
||||
}
|
||||
} else if (
|
||||
Array.isArray(param?.options) &&
|
||||
!Array.isArray(param?.initial)
|
||||
) {
|
||||
return {
|
||||
type: 'number',
|
||||
input: 'choice-number',
|
||||
...common,
|
||||
initial: param.initial,
|
||||
options: param.options,
|
||||
}
|
||||
} // TODO else vector
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
})
|
||||
.filter((a) => a)
|
||||
}
|
||||
@@ -51,21 +51,21 @@ show_object(result)
|
||||
|
||||
const jscad = require('@jscad/modeling')
|
||||
// https://openjscad.xyz/docs/module-modeling_primitives.html
|
||||
const { circle, rectangle, cube, cuboid, sphere, cylinder } = jscad.primitives
|
||||
const { cuboid, cylinder } = jscad.primitives
|
||||
|
||||
const { rotate, scale, translate } = jscad.transforms
|
||||
const { rotate, translate } = jscad.transforms
|
||||
const { degToRad } = jscad.utils // because jscad uses radians for rotations
|
||||
const { colorize } = jscad.colors
|
||||
// https://openjscad.xyz/docs/module-modeling_booleans.html
|
||||
const { union, intersect, subtract } = jscad.booleans
|
||||
const { subtract } = jscad.booleans
|
||||
|
||||
function main({//@jscad-params
|
||||
// Box example
|
||||
width=40, // Width
|
||||
length=20, // Length
|
||||
length=20, // Length
|
||||
height=10, // Height
|
||||
hole=3,// Hole for cables diameter (0=no hole)
|
||||
wall=1, // wall {min:0.5, step:0.5}
|
||||
flip=0, // print orientation {type: 'choice', values: [0, 90, 180]}
|
||||
}){
|
||||
|
||||
let wallOffset = wall * 2
|
||||
@@ -77,8 +77,8 @@ function main({//@jscad-params
|
||||
model = subtract( model,
|
||||
translate([width/2-wall/2], rotate([0, degToRad(90), 0 ], cylinder({radius:hole/2, height:wall})))
|
||||
)
|
||||
}
|
||||
return rotate([0,0, degToRad(90)], model)
|
||||
}
|
||||
return rotate([degToRad(flip), 0, degToRad(90)], model)
|
||||
}
|
||||
|
||||
module.exports = {main}
|
||||
@@ -281,8 +281,8 @@ export const requestRender = ({
|
||||
: cadPackages[state.ideType].render
|
||||
return renderFn({
|
||||
code,
|
||||
parameters,
|
||||
settings: {
|
||||
parameters,
|
||||
camera,
|
||||
viewerSize,
|
||||
quality,
|
||||
|
||||
@@ -1917,6 +1917,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.2.0.tgz#e48652bfce82ddf73d7f331faeb9db6526ee6874"
|
||||
integrity sha512-19DkLz8gDgbi+WvkoTzi9vs0NK9TJf94vbYhMzB4LYJo03Kili0gmvXT9CiKZoxXZ7YAvy/b1U1oQKEnjWrqxw==
|
||||
|
||||
"@heroicons/react@^1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.4.tgz#11847eb2ea5510419d7ada9ff150a33af0ad0863"
|
||||
integrity sha512-3kOrTmo8+Z8o6AL0rzN82MOf8J5CuxhRLFhpI8mrn+3OqekA6d5eb1GYO3EYYo1Vn6mYQSMNTzCWbEwUInb0cQ==
|
||||
|
||||
"@iarna/toml@^2.2.5":
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c"
|
||||
|
||||
Reference in New Issue
Block a user
I had been storing the output logs from running CQ and OpenSCAD in s3 as metadata, and had planned to do the same thing with the customizer params, but realised this wasn't going to work since there is a tiny 2kb limit and that was already causing problems https://github.com/Irev-Dev/cadhub/issues/476
So now instead I'm concatenating the gzip file with and metadata (params and logs), its a little messy to split them apart in the browser but its working.
/var/task/cadhub-concat-splithas a unique string that I sue to split at.why not use https://www.npmjs.com/package/fflate
I started using it recently (to create 3mf export in my jscad prototype)
no temp file needed, lib is tiny, you can name the files when compressing, and decompressing and will likely be useful in the frontend in the future, so it will not be a bloat :)
... I would not stop this PR because of it, better not do too many things in a single PR. ... but maybe open an issue, so it is in the pipeline for later :)
I was trying to stick to native browser ungziping things when the request arrives with the correct headers. But something like this might be better
I am not too concerned about finding an optimum solution right now since the next thing on my todo list is investigate performance, and I have a feeling that a lot of backend things might change in the process. Thanks for the lib recommendation.