@blocklet/uploader-server
Version:
blocklet upload server
157 lines (156 loc) • 4.7 kB
JavaScript
import { existsSync } from "fs";
import { join, basename } from "path";
import config from "@blocklet/sdk/lib/config";
import { getResources } from "@blocklet/sdk/lib/component";
import joinUrl from "url-join";
import component from "@blocklet/sdk/lib/component";
import {
setPDFDownloadHeader,
logger,
calculateCacheControl,
serveResource,
scanDirectory,
getFileNameFromReq
} from "../utils.js";
import { ImageBinDid } from "../constants.js";
const ImgResourceType = "imgpack";
let skipRunningCheck = false;
let resourceTypes = [
{
type: ImgResourceType,
did: ImageBinDid,
folder: ""
// can be string or string[]
}
];
let resourcesMap = /* @__PURE__ */ new Map();
let canUseResources = [];
export const getCanUseResources = () => canUseResources;
export const mappingResource = async () => {
try {
const resources = getResources({
types: resourceTypes,
skipRunningCheck
});
canUseResources = resources.map((resource) => {
const originDir = resource.path;
const resourceType = resourceTypes.find(({ type }) => originDir.endsWith(type));
if (!existsSync(originDir) || !resourceType) {
return false;
}
const folders = Array.isArray(resourceType.folder) ? resourceType.folder : [resourceType.folder || ""];
return folders.map((folder) => ({
originDir,
dir: join(originDir, folder),
blockletInfo: resource,
whitelist: resourceType.whitelist,
blacklist: resourceType.blacklist
}));
}).filter(Boolean).flat();
resourcesMap.clear();
for (const resource of canUseResources) {
const { dir, whitelist, blacklist, originDir, blockletInfo } = resource;
if (existsSync(dir)) {
try {
const dirResourceMap = scanDirectory(dir, {
whitelist,
blacklist,
originDir,
blockletInfo
});
for (const [key, value] of dirResourceMap.entries()) {
resourcesMap.set(key, value);
}
} catch (err) {
logger.error(`Error scanning directory ${dir}:`, err);
}
}
}
logger.info("Mapping resources: files count:", resourcesMap.size, "directories count:", canUseResources.length);
return canUseResources;
} catch (error) {
logger.error(error);
}
return false;
};
const { events, Events } = config;
events.on(Events.componentAdded, () => mappingResource());
events.on(Events.componentRemoved, () => mappingResource());
events.on(Events.componentStarted, () => mappingResource());
events.on(Events.componentStopped, () => mappingResource());
events.on(Events.componentUpdated, () => mappingResource());
export const initStaticResourceMiddleware = ({
options = {},
resourceTypes: _resourceTypes = resourceTypes,
express,
skipRunningCheck: _skipRunningCheck
} = {}) => {
skipRunningCheck = !!_skipRunningCheck;
const { cacheControl, cacheControlImmutable } = calculateCacheControl(
options.maxAge || "365d",
options.immutable !== false
);
if (_resourceTypes?.length > 0) {
resourceTypes = _resourceTypes.map((item) => {
if (typeof item === "string") {
return {
type: item,
did: ImageBinDid,
// not set did, default is ImageBinDid
folder: ""
// not set folder, default is root
};
}
return item;
});
}
mappingResource();
return (req, res, next) => {
const fileName = getFileNameFromReq(req);
try {
const resource = resourcesMap.get(fileName);
if (resource) {
serveResource(req, res, next, resource, {
...options,
cacheControl,
cacheControlImmutable
});
} else {
next();
}
} catch (error) {
logger.error("Error serving static file:", error);
next();
}
};
};
export const initProxyToMediaKitUploadsMiddleware = ({ options, express } = {}) => {
return async (req, res, next) => {
if (!component.getComponentWebEndpoint(ImageBinDid)) {
return next();
}
setPDFDownloadHeader(req, res);
try {
const { data, status, headers } = await component.call({
name: ImageBinDid,
path: joinUrl("/uploads", basename(req.url)),
responseType: "stream",
method: "GET"
});
if (data && status >= 200 && status < 400) {
Object.keys(headers).forEach((key) => {
res.set(key, headers[key]);
});
data.on("error", (err) => {
next();
}).pipe(res).on("error", (err) => {
next();
});
} else {
next();
}
} catch (error) {
next();
}
};
};