Initial work to support curv #578
3
.vscode/settings.json
vendored
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Cadhub",
|
"Cadhub",
|
||||||
|
"cadquery",
|
||||||
|
"curv",
|
||||||
"Customizer",
|
"Customizer",
|
||||||
"Hutten",
|
"Hutten",
|
||||||
"cadquery",
|
|
||||||
"jscad",
|
"jscad",
|
||||||
"openscad",
|
"openscad",
|
||||||
"sendmail"
|
"sendmail"
|
||||||
|
|||||||
@@ -34,8 +34,12 @@ const makeRequest = (route, port) => [
|
|||||||
|
|
||||||
app.post(...makeRequest('/openscad/preview', 5052))
|
app.post(...makeRequest('/openscad/preview', 5052))
|
||||||
app.post(...makeRequest('/openscad/stl', 5053))
|
app.post(...makeRequest('/openscad/stl', 5053))
|
||||||
|
|
||||||
app.post(...makeRequest('/cadquery/stl', 5060))
|
app.post(...makeRequest('/cadquery/stl', 5060))
|
||||||
|
|
||||||
|
app.post(...makeRequest('/curv/preview', 5070))
|
||||||
|
app.post(...makeRequest('/curv/stl', 5071))
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Example app listening at http://localhost:${port}`)
|
console.log(`Example app listening at http://localhost:${port}`)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,17 +2,27 @@ FROM public.ecr.aws/lts/ubuntu:20.04_stable
|
|||||||
|
|
|||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN apt-get update --fix-missing -qq
|
RUN apt-get update --fix-missing -qq
|
||||||
RUN apt-get -y -qq install git software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb unzip maim clang cmake git-core libboost-all-dev libopenexr-dev libtbb-dev libglm-dev libpng-dev libeigen3-dev dbus-x11 libxcursor-dev libxinerama-dev libxrandr-dev libglu1-mesa-dev libgles2-mesa-dev libgl1-mesa-dev libxi-dev
|
RUN apt-get update --fix-missing && apt-get -y -qq install software-properties-common dirmngr apt-transport-https lsb-release ca-certificates xvfb
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN git clone https://github.com/curv3d/curv.git
|
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN cd curv
|
RUN apt-get update -qq
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN git submodule init && git submodule update
|
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN mkdir build
|
RUN apt-get -y -qq install git
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN cd build
|
RUN apt-get update --fix-missing && apt-get -y --fix-broken install python-pycurl python-apt
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN sed -i 's/set(LEAN_BUILD 0)/set(LEAN_BUILD 1)/' ../CMakeLists.txt
|
RUN apt-get -y -qq --fix-broken install software-properties-common
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN cmake ..
|
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN make
|
RUN apt-get -y -qq install xvfb unzip maim clang cmake
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
RUN make install
|
RUN apt-get -y -qq install git-core libboost-all-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libopenexr-dev libtbb-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libglm-dev libpng-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libeigen3-dev dbus-x11
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libxcursor-dev libxinerama-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libxrandr-dev libglu1-mesa-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libgles2-mesa-dev libgl1-mesa-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN apt-get -y -qq install libxi-dev
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
RUN git clone --recursive https://github.com/curv3d/curv; cd curv; make; make install
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
|
||||||
# install node14, see comment at the top of node14source_setup.sh
|
# install node14, see comment at the top of node14source_setup.sh
|
||||||
ADD src/docker/common/node14source_setup.sh /nodesource_setup.sh
|
ADD src/docker/common/node14source_setup.sh /nodesource_setup.sh
|
||||||
@@ -46,7 +56,7 @@ RUN echo "cadhub-concat-split" > /var/task/cadhub-concat-split
|
|||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
|
|
||||||
# using built javascript from dist
|
# using built javascript from dist
|
||||||
# run `yarn rw build` before bulding this image
|
# run `yarn rw build` before bulding this image
|
||||||
COPY dist/docker/openscad/* /var/task/js/
|
COPY dist/docker/curv/* /var/task/js/
|
||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
COPY dist/docker/common/* /var/task/common/
|
COPY dist/docker/common/* /var/task/common/
|
||||||
COPY src/docker/common/entrypoint.sh /entrypoint.sh
|
COPY src/docker/common/entrypoint.sh /entrypoint.sh
|
||||||
RUN ["chmod", "+x", "/entrypoint.sh"]
|
RUN ["chmod", "+x", "/entrypoint.sh"]
|
||||||
|
|||||||
|
built from source? better way to do this? built from source? better way to do this?
built from source? better way to do this? built from source? better way to do this?
|
|||||||
@@ -1,21 +1,5 @@
|
|||||||
import { writeFiles, runCommand } from '../common/utils'
|
import { writeFiles, runCommand } from '../common/utils'
|
||||||
import { nanoid } from 'nanoid'
|
import { nanoid } from 'nanoid'
|
||||||
const { readFile } = require('fs/promises')
|
|
||||||
const fs = require('fs');
|
|
||||||
const { spawn } = require('child_process');
|
|
||||||
|
|
||||||
function* getXDisplayNumber() {
|
|
||||||
const startValue = 99;
|
|
||||||
let i = startValue;
|
|
||||||
while(true) {
|
|
||||||
i -= 1;
|
|
||||||
|
|
||||||
// Never hit zero since 0 is usually used by desktop users.
|
|
||||||
if (i <= 0) i = startValue;
|
|
||||||
yield ':' + i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const runCurv = async ({
|
export const runCurv = async ({
|
||||||
file,
|
file,
|
||||||
@@ -54,61 +38,23 @@ export const runCurv = async ({
|
|||||||
const fullPath = `/tmp/${tempFile}/output.gz`
|
const fullPath = `/tmp/${tempFile}/output.gz`
|
||||||
const imPath = `/tmp/${tempFile}/output.png`
|
const imPath = `/tmp/${tempFile}/output.png`
|
||||||
const customizerPath = `/tmp/${tempFile}/customizer.param`
|
const customizerPath = `/tmp/${tempFile}/customizer.param`
|
||||||
const summaryPath = `/tmp/${tempFile}/summary.json` // contains camera info
|
|
||||||
|
|
||||||
const code = file;
|
|
||||||
const DISPLAY = getXDisplayNumber().next().value;
|
|
||||||
|
|
||||||
const xvfbProcess = spawn(
|
|
||||||
'Xvfb',
|
|
||||||
[DISPLAY, '-ac', '-nocursor', '-screen', '0', '480x500x24'],
|
|
||||||
);
|
|
||||||
|
|
||||||
const curvProcess = spawn(
|
|
||||||
'curv',
|
|
||||||
['-' ],
|
|
||||||
{ env: Object.assign({}, process.env, { DISPLAY, PATH: '/usr/local/bin' }) }
|
|
||||||
);
|
|
||||||
|
|
||||||
curvProcess.stdin.write(code);
|
|
||||||
curvProcess.stdin.end();
|
|
||||||
|
|
||||||
let statusSet = false;
|
|
||||||
let contentTypeSet = false;
|
|
||||||
|
|
||||||
curvProcess.stderr.on('data', (buf) => {
|
|
||||||
const data = buf.toString('utf8');
|
|
||||||
if (data.indexOf('shape') >= 0) {
|
|
||||||
setTimeout(() => {
|
|
||||||
const screenshotProcess = spawn('maim', ['--hidecursor', imPath], { env: { DISPLAY } });
|
|
||||||
screenshotProcess.on('close', () => {
|
|
||||||
curvProcess.kill();
|
|
||||||
xvfbProcess.kill();
|
|
||||||
});
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.indexOf('ERROR') < 0) { return; }
|
|
||||||
curvProcess.kill();
|
|
||||||
xvfbProcess.kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const command = [
|
||||||
|
'xvfb-run --auto-servernum --server-args "-screen 0 1024x768x24" curv',
|
||||||
|
`-o ${imPath}`,
|
||||||
|
`-O xsize=${x}`,
|
||||||
|
`-O ysize=${y}`,
|
||||||
|
`-O bg=webRGB[26,26,29]`, // #1A1A1D
|
||||||
|
`/tmp/${tempFile}/main.curv`,
|
||||||
|
].join(' ')
|
||||||
|
console.log('command', command)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const files: string[] = await Promise.all(
|
const consoleMessage = await runCommand(command, 15000)
|
||||||
[customizerPath, summaryPath].map((path) =>
|
|
||||||
readFile(path, { encoding: 'ascii' })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
const [params, cameraInfo] = files.map((fileStr: string) =>
|
|
||||||
JSON.parse(fileStr)
|
|
||||||
)
|
|
||||||
await writeFiles(
|
await writeFiles(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
file: JSON.stringify({
|
file: JSON.stringify({
|
||||||
cameraInfo: viewAll ? cameraInfo.camera : undefined,
|
|
||||||
customizerParams: params.parameters,
|
|
||||||
consoleMessage,
|
consoleMessage,
|
||||||
type: 'png',
|
type: 'png',
|
||||||
}),
|
}),
|
||||||
@@ -143,7 +89,6 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => {
|
|||||||
)
|
)
|
||||||
const fullPath = `/tmp/${tempFile}/output.gz`
|
const fullPath = `/tmp/${tempFile}/output.gz`
|
||||||
const stlPath = `/tmp/${tempFile}/output.stl`
|
const stlPath = `/tmp/${tempFile}/output.stl`
|
||||||
const customizerPath = `/tmp/${tempFile}/customizer.param`
|
|
||||||
const command = [
|
const command = [
|
||||||
'curv',
|
'curv',
|
||||||
'-o', stlPath,
|
'-o', stlPath,
|
||||||
@@ -155,14 +100,10 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => {
|
|||||||
try {
|
try {
|
||||||
// lambda will time out before this, we might need to look at background jobs if we do git integration stl generation
|
// 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)
|
const consoleMessage = await runCommand(command, 60000)
|
||||||
const params = JSON.parse(
|
|
||||||
await readFile(customizerPath, { encoding: 'ascii' })
|
|
||||||
).parameters
|
|
||||||
await writeFiles(
|
await writeFiles(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
file: JSON.stringify({
|
file: JSON.stringify({
|
||||||
customizerParams: params,
|
|
||||||
consoleMessage,
|
consoleMessage,
|
||||||
type: 'stl',
|
type: 'stl',
|
||||||
}),
|
}),
|
||||||
@@ -175,7 +116,7 @@ export const stlExport = async ({ file, settings: { parameters } } = {}) => {
|
|||||||
`cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`,
|
`cat ${stlPath} /var/task/cadhub-concat-split /tmp/${tempFile}/metadata.json | gzip > ${fullPath}`,
|
||||||
15000
|
15000
|
||||||
)
|
)
|
||||||
return { consoleMessage, fullPath, customizerPath }
|
return { consoleMessage, fullPath }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { error, fullPath }
|
return { error, fullPath }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,11 +53,20 @@ services:
|
|||||||
command: js/curv.preview
|
command: js/curv.preview
|
||||||
# Adding volumes so that the containers can be restarted for js only changes in local dev
|
# Adding volumes so that the containers can be restarted for js only changes in local dev
|
||||||
volumes:
|
volumes:
|
||||||
- ../../dist/docker/openscad:/var/task/js/
|
- ../../dist/docker/curv:/var/task/js/
|
||||||
- ../../dist/docker/common:/var/task/common/
|
- ../../dist/docker/common:/var/task/common/
|
||||||
ports:
|
ports:
|
||||||
- "5052:8080"
|
- "5070:8080"
|
||||||
environment:
|
curv-stl:
|
||||||
AWS_SECRET_ACCESS_KEY: "${DEV_AWS_SECRET_ACCESS_KEY}"
|
build:
|
||||||
AWS_ACCESS_KEY_ID: "${DEV_AWS_ACCESS_KEY_ID}"
|
context: ../../
|
||||||
BUCKET: "${DEV_BUCKET}"
|
dockerfile: ./src/docker/curv/Dockerfile
|
||||||
|
image: curv
|
||||||
|
command: js/curv.stl
|
||||||
|
# Adding volumes so that the containers can be restarted for js only changes in local dev
|
||||||
|
volumes:
|
||||||
|
- ../../dist/docker/curv:/var/task/js/
|
||||||
|
- ../../dist/docker/common:/var/task/common/
|
||||||
|
ports:
|
||||||
|
- "5071:8080"
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = (config, { env }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
test: /\.(md|jscad\.js|py|scad)$/i,
|
test: /\.(md|jscad\.js|py|scad|curv)$/i,
|
||||||
use: 'raw-loader',
|
use: 'raw-loader',
|
||||||
});
|
});
|
||||||
return config
|
return config
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const IdeEditor = ({ Loading }) => {
|
|||||||
cadquery: 'python',
|
cadquery: 'python',
|
||||||
openscad: 'cpp',
|
openscad: 'cpp',
|
||||||
jscad: 'javascript',
|
jscad: 'javascript',
|
||||||
curv: 'javascript',
|
curv: 'python',
|
||||||
INIT: '',
|
INIT: '',
|
||||||
}
|
}
|
||||||
const monaco = useMonaco()
|
const monaco = useMonaco()
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import {
|
|||||||
RenderArgs,
|
RenderArgs,
|
||||||
splitGziped,
|
splitGziped,
|
||||||
} from '../common'
|
} from '../common'
|
||||||
import { CurvToCadhubParams } from './openScadParams'
|
|
||||||
import type { XYZ, Camera } from 'src/helpers/hooks/useIdeState'
|
|
||||||
|
|
||||||
export const render = async ({ code, settings }: RenderArgs) => {
|
export const render = async ({ code, settings }: RenderArgs) => {
|
||||||
const pixelRatio = window.devicePixelRatio || 1
|
const pixelRatio = window.devicePixelRatio || 1
|
||||||
@@ -61,21 +59,8 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
|||||||
}
|
}
|
||||||
const blob = await response.blob()
|
const blob = await response.blob()
|
||||||
const text = await new Response(blob).text()
|
const text = await new Response(blob).text()
|
||||||
const { consoleMessage, customizerParams, type, cameraInfo } =
|
const { consoleMessage, type } =
|
||||||
splitGziped(text)
|
splitGziped(text)
|
||||||
const vecArray2Obj = (arr: number[]): XYZ => ({
|
|
||||||
x: arr[0],
|
|
||||||
y: arr[1],
|
|
||||||
z: arr[2],
|
|
||||||
})
|
|
||||||
const camera: Camera = cameraInfo
|
|
||||||
? {
|
|
||||||
dist: cameraInfo?.distance,
|
|
||||||
position: vecArray2Obj(cameraInfo?.translation),
|
|
||||||
rotation: vecArray2Obj(cameraInfo?.rotation),
|
|
||||||
isScadUpdate: true,
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
return createHealthyResponse({
|
return createHealthyResponse({
|
||||||
type: type !== 'stl' ? 'png' : 'geometry',
|
type: type !== 'stl' ? 'png' : 'geometry',
|
||||||
data:
|
data:
|
||||||
@@ -83,9 +68,7 @@ export const render = async ({ code, settings }: RenderArgs) => {
|
|||||||
? blob
|
? blob
|
||||||
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||||
consoleMessage,
|
consoleMessage,
|
||||||
camera,
|
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
customizerParams: curvToCadhubParams(customizerParams || []),
|
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return createUnhealthyResponse(new Date())
|
return createUnhealthyResponse(new Date())
|
||||||
@@ -115,7 +98,7 @@ export const stl = async ({ code /*settings*/ }: RenderArgs) => {
|
|||||||
}
|
}
|
||||||
const blob = await response.blob()
|
const blob = await response.blob()
|
||||||
const text = await new Response(blob).text()
|
const text = await new Response(blob).text()
|
||||||
const { consoleMessage, customizerParams, type } = splitGziped(text)
|
const { consoleMessage, type } = splitGziped(text)
|
||||||
return createHealthyResponse({
|
return createHealthyResponse({
|
||||||
type: type !== 'stl' ? 'png' : 'geometry',
|
type: type !== 'stl' ? 'png' : 'geometry',
|
||||||
data:
|
data:
|
||||||
@@ -124,7 +107,6 @@ export const stl = async ({ code /*settings*/ }: RenderArgs) => {
|
|||||||
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
: await stlToGeometry(window.URL.createObjectURL(blob)),
|
||||||
consoleMessage,
|
consoleMessage,
|
||||||
date: new Date(),
|
date: new Date(),
|
||||||
customizerParams: openScadToCadhubParams(customizerParams || []),
|
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return createUnhealthyResponse(new Date())
|
return createUnhealthyResponse(new Date())
|
||||||
|
|||||||
built from source? better way to do this?
built from source? better way to do this?