UNPKG

clumsy-graphics

Version:

a tool for rapidly developing animations where frames are described using svg elements à la react 🙃

246 lines (245 loc) 14.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.clientServerEventHandlerSaga = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const IO = __importStar(require("io-ts")); const path_1 = __importDefault(require("path")); const server_1 = __importDefault(require("react-dom/server")); const decodeData_1 = require("../../helpers/decodeData"); const storeEffects_1 = require("../helpers/storeEffects"); const GraphicsRendererProcessStateRequestQueryParams_1 = require("../models/GraphicsRendererProcessStateRequestQueryParams"); function* clientServerEventHandlerSaga(api) { const { clientServerEventChannel, generatedAssetsDirectoryPath, animationModulePath, numberOfFrameRendererWorkers, clientPageBundle, localStorageSessionCacheId, } = api; while (true) { const someClientServerEvent = yield* (0, storeEffects_1.takeEvent)(clientServerEventChannel); switch (someClientServerEvent.eventType) { case 'clientServerListening': break; case 'clientRequestsGraphicsRendererProcessState': yield* (0, storeEffects_1.spawn)(clientRequestsGraphicsRendererProcessStateHandler, { generatedAssetsDirectoryPath, animationModulePath, numberOfFrameRendererWorkers, clientRequest: someClientServerEvent.eventPayload.clientRequest, serverResponse: someClientServerEvent.eventPayload.serverResponse, }); break; case 'clientRequestsGraphicAsset': yield* (0, storeEffects_1.spawn)(clientRequestsGraphicAssetHandler, { clientRequest: someClientServerEvent.eventPayload.clientRequest, serverResponse: someClientServerEvent.eventPayload.serverResponse, }); break; case 'clientRequestsPage': yield* (0, storeEffects_1.spawn)(clientRequestsPageHandler, { clientPageBundle, localStorageSessionCacheId, serverResponse: someClientServerEvent.eventPayload.serverResponse, }); break; } } } exports.clientServerEventHandlerSaga = clientServerEventHandlerSaga; function* clientRequestsGraphicsRendererProcessStateHandler(api) { const { serverResponse, clientRequest, generatedAssetsDirectoryPath, animationModulePath, numberOfFrameRendererWorkers, } = api; const currentAnimationModuleBundlerState = yield* (0, storeEffects_1.select)((currentAnimationDevelopmentState) => currentAnimationDevelopmentState.animationModuleBundlerState); try { switch (currentAnimationModuleBundlerState.bundlerStatus) { case 'bundlerInitializing': serverResponse.sendStatus(204); break; case 'bundlerActive': const { graphicsRendererProcessStateRequestQueryParams } = yield* (0, storeEffects_1.call)(getGraphicsRendererProcessStateRequestQueryParams, { clientRequestQueryData: clientRequest.query, }); const { specifiedClientGraphicsRendererProcessState } = getSpecifiedClientGraphicsRendererProcessState({ currentAnimationModuleBundlerState, graphicsRendererProcessStateRequestQueryParams, }); serverResponse.statusCode = 200; serverResponse.setHeader('Content-Type', 'application/json'); serverResponse.send(JSON.stringify(specifiedClientGraphicsRendererProcessState)); if (specifiedClientGraphicsRendererProcessState.buildStatus === 'validBuild' && specifiedClientGraphicsRendererProcessState.graphicsRendererProcessStatus === 'processInitializing') { const { graphicsRendererProcessCommandString, graphicAssetPathKey, graphicAssetPath, graphicAssetUrlResult, } = getPartialSpawnGraphicsRendererProcessActionPayload({ generatedAssetsDirectoryPath, animationModulePath, numberOfFrameRendererWorkers, graphicsRendererProcessStateRequestQueryParams, currentBundleSessionVersion: currentAnimationModuleBundlerState.buildVersion, }); yield* (0, storeEffects_1.put)({ type: 'spawnGraphicsRendererProcess', actionPayload: { graphicsRendererProcessCommandString, graphicAssetPathKey, graphicAssetPath, graphicAssetUrlResult, buildVersion: currentAnimationModuleBundlerState.buildVersion, graphicsRendererProcessKey: graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey, }, }); } break; } } catch (queryParamsError) { if (queryParamsError instanceof Error) { serverResponse.statusCode = 400; serverResponse.send(`${queryParamsError}`); } else { serverResponse.sendStatus(500); } } } async function getGraphicsRendererProcessStateRequestQueryParams(api) { const { clientRequestQueryData } = api; const graphicsRendererProcessStateRequestQueryParams = await (0, decodeData_1.decodeData)({ targetCodec: GraphicsRendererProcessStateRequestQueryParams_1.GraphicsRendererProcessStateRequestQueryParamsCodec, inputData: clientRequestQueryData, }); return { graphicsRendererProcessStateRequestQueryParams }; } function getPartialSpawnGraphicsRendererProcessActionPayload(api) { const { generatedAssetsDirectoryPath, animationModulePath, graphicsRendererProcessStateRequestQueryParams, currentBundleSessionVersion, numberOfFrameRendererWorkers, } = api; const generatedAssetsDirectoryAbsolutePath = path_1.default.resolve(generatedAssetsDirectoryPath); const animationModuleAbsolutePath = path_1.default.resolve(animationModulePath); if (graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey.startsWith('animation')) { const animationAssetFilename = `${currentBundleSessionVersion}.mp4`; const animationMp4OutputPath = path_1.default.join(generatedAssetsDirectoryAbsolutePath, animationAssetFilename); return { graphicAssetPathKey: animationAssetFilename, graphicAssetPath: animationMp4OutputPath, graphicAssetUrlResult: `/asset/${animationAssetFilename}`, graphicsRendererProcessCommandString: `_clumsy-graphics renderAnimation --animationModulePath=${animationModuleAbsolutePath} --animationMp4OutputPath=${animationMp4OutputPath} --numberOfFrameRendererWorkers=${numberOfFrameRendererWorkers}`, }; } else if (graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey.startsWith('frame')) { const frameIndex = Number(graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey.replace('frame/', '')); const frameAssetFilename = `${currentBundleSessionVersion}_${frameIndex}.png`; const frameFileOutputPath = path_1.default.join(generatedAssetsDirectoryAbsolutePath, frameAssetFilename); return { graphicAssetPathKey: frameAssetFilename, graphicAssetPath: frameFileOutputPath, graphicsRendererProcessCommandString: `_clumsy-graphics renderAnimationFrame --animationModulePath=${animationModuleAbsolutePath} --frameIndex=${frameIndex} --frameFileOutputPath=${frameFileOutputPath}`, graphicAssetUrlResult: `/asset/${frameAssetFilename}`, }; } else { throw new Error('wtf? getPartialSpawnGraphicsRendererProcessActionPayload'); } } function getSpecifiedClientGraphicsRendererProcessState(api) { const { graphicsRendererProcessStateRequestQueryParams, currentAnimationModuleBundlerState, } = api; const specifiedGraphicsRendererProcessState = currentAnimationModuleBundlerState.graphicsRendererProcessStates[graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey]; if (currentAnimationModuleBundlerState.buildStatus === 'validBuild' && !specifiedGraphicsRendererProcessState) { const { getFrameDescription, ...clientAnimationModule } = currentAnimationModuleBundlerState.animationModule; return { specifiedClientGraphicsRendererProcessState: { buildVersion: currentAnimationModuleBundlerState.buildVersion, buildStatus: currentAnimationModuleBundlerState.buildStatus, graphicsRendererProcessKey: graphicsRendererProcessStateRequestQueryParams.graphicsRendererProcessKey, animationModule: clientAnimationModule, graphicsRendererProcessStatus: 'processInitializing', graphicsRendererProcessStdoutLog: '', }, }; } else if (currentAnimationModuleBundlerState.buildStatus === 'validBuild' && specifiedGraphicsRendererProcessState) { const { spawnedGraphicsRendererProcess, ...someSpecifiedClientGraphicsRendererProcessState } = specifiedGraphicsRendererProcessState; const { getFrameDescription, ...clientAnimationModule } = currentAnimationModuleBundlerState.animationModule; return { specifiedClientGraphicsRendererProcessState: { ...someSpecifiedClientGraphicsRendererProcessState, buildVersion: currentAnimationModuleBundlerState.buildVersion, buildStatus: currentAnimationModuleBundlerState.buildStatus, animationModule: clientAnimationModule, }, }; } else if (currentAnimationModuleBundlerState.buildStatus === 'invalidBuild') { return { specifiedClientGraphicsRendererProcessState: { buildVersion: currentAnimationModuleBundlerState.buildVersion, buildStatus: currentAnimationModuleBundlerState.buildStatus, buildErrorMessage: currentAnimationModuleBundlerState.buildErrorMessage, }, }; } else { throw new Error('wtf? getSpecifiedClientGraphicsRendererProcessState'); } } function* clientRequestsGraphicAssetHandler(api) { const { clientRequest, serverResponse } = api; const clientRequestRouteParams = yield* (0, storeEffects_1.call)(() => (0, decodeData_1.decodeData)({ targetCodec: IO.exact(IO.type({ assetFilename: IO.string, })), inputData: clientRequest.params, })); const currentAvailableAssetsFilePathMap = yield* (0, storeEffects_1.select)((currentAnimationDevelopmentState) => currentAnimationDevelopmentState.availableAssetsFilePathMap); const targetAssetFilepath = currentAvailableAssetsFilePathMap[clientRequestRouteParams.assetFilename]; if (targetAssetFilepath) { const targetAssetMimeType = getTargetAssetMimeType({ targetAssetFilepath, }); serverResponse.setHeader('Content-Type', targetAssetMimeType); serverResponse.sendFile(targetAssetFilepath); } else { serverResponse.sendStatus(404); } } function getTargetAssetMimeType(api) { const { targetAssetFilepath } = api; const assetType = targetAssetFilepath.split(/\.(svg|png|mp4|gif)$/, 2)[1]; switch (assetType) { case 'svg': return 'image/svg+xml'; case 'png': return 'image/png'; case 'mp4': return 'video/mp4'; case 'gif': return 'image/gif'; default: throw new Error('wtf? getTargetAssetMimeType'); } } function* clientRequestsPageHandler(api) { const { serverResponse, localStorageSessionCacheId, clientPageBundle } = api; serverResponse.statusCode = 200; serverResponse.setHeader('Content-Type', 'text/html'); serverResponse.send(server_1.default.renderToStaticMarkup((0, jsx_runtime_1.jsxs)("html", Object.assign({ lang: 'en' }, { children: [(0, jsx_runtime_1.jsxs)("head", { children: [(0, jsx_runtime_1.jsx)("meta", { charSet: 'utf-8' }, void 0), (0, jsx_runtime_1.jsx)("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }, void 0), (0, jsx_runtime_1.jsx)("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }, void 0), (0, jsx_runtime_1.jsx)("link", { rel: "preconnect", href: "https://fonts.gstatic.com" }, void 0), (0, jsx_runtime_1.jsx)("link", { href: "https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap", rel: "stylesheet" }, void 0)] }, void 0), (0, jsx_runtime_1.jsx)("body", { children: (0, jsx_runtime_1.jsx)("script", { id: 'client-page-bundle-script', "data-local-storage-session-cache-id": localStorageSessionCacheId, dangerouslySetInnerHTML: { __html: clientPageBundle, } }, void 0) }, void 0)] }), void 0))); }