Initial commit

This commit is contained in:
Viet An
2026-03-02 09:45:33 +07:00
commit d17a9e2588
415 changed files with 92113 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
import { getViewerToken } from '../utils/aps.js';
export default defineEventHandler(getViewerToken);

View File

@@ -0,0 +1,25 @@
export default defineEventHandler(async (event) => {
const urn = getRouterParam(event, 'urn');
const manifest = await getManifest(urn);
if (!manifest)
return { status: 'n/a' };
let messages = [];
if (manifest.derivatives) {
for (const derivative of manifest.derivatives) {
messages = messages.concat(derivative.messages || []);
if (derivative.children) {
for (const child of derivative.children) {
messages.concat(child.messages || []);
}
}
}
}
return {
status: manifest.status,
progress: manifest.progress,
messages
};
})

View File

@@ -0,0 +1,37 @@
export default defineEventHandler(async (event) => {
if (event.method === 'GET') {
const objects = await listObjects();
return objects.map((o) => ({
name: o.objectKey,
urn: urnify(o.objectId),
}));
}
if (event.method === 'POST') {
const formData = await readMultipartFormData(event);
if (!formData) {
throw createError({
statusCode: 400,
statusMessage: `formData should not be ${formData}`,
})
}
const file = formData[0];
try {
const obj = await uploadObject(file.filename, file.data);
await translateObject(urnify(obj.objectId), req.fields['model-zip-entrypoint']);
return {
name: obj.objectKey,
urn: urnify(obj.objectId),
}
} catch (error) {
throw createError({
statusCode: 400,
statusMessage: 'Upload file failed',
error,
})
}
}
})

View File

@@ -0,0 +1,9 @@
export default defineEventHandler((event) => {
const originalUrl = event.node.req.url || "";
if (originalUrl.startsWith("/product:")) {
const rewritten = originalUrl.replace("/product:", "/product/");
event.node.req.url = rewritten;
event._path = rewritten;
}
});

3
server/tsconfig.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

101
server/utils/aps.js Normal file
View File

@@ -0,0 +1,101 @@
import { AuthenticationClient, Scopes } from '@aps_sdk/authentication';
import { ModelDerivativeClient, View, OutputType } from '@aps_sdk/model-derivative';
import { OssClient, Region, PolicyKey } from '@aps_sdk/oss';
const apsClientId = 'PkqB8KlPGekLGKElPSjPhC9C2NGyXMN64QVhPSaqUhV46zEn';
const apsClientSecret = 'Jr70CpXFaV2PRd9lux3ZXBKpSMwFsyO6xq1Y7AJy1Q4xcK6nZMLq20KB8SlipC4Z';
const apsBucket = `${apsClientId.toLowerCase()}-basic-app`;
const authenticationClient = new AuthenticationClient();
const ossClient = new OssClient();
const modelDerivativeClient = new ModelDerivativeClient();
async function getInternalToken() {
const credentials = await authenticationClient.getTwoLeggedToken(
apsClientId,
apsClientSecret,
[Scopes.DataRead, Scopes.DataCreate, Scopes.DataWrite, Scopes.BucketCreate, Scopes.BucketRead],
);
return credentials.access_token;
}
export const getViewerToken = async () => {
return await authenticationClient.getTwoLeggedToken(apsClientId, apsClientSecret, [
Scopes.ViewablesRead,
]);
};
export const ensureBucketExists = async (bucketKey) => {
const accessToken = await getInternalToken();
try {
await ossClient.getBucketDetails(bucketKey, { accessToken });
} catch (err) {
if (err.axiosError.response.status === 404) {
await ossClient.createBucket(
Region.Us,
{ bucketKey: bucketKey, policyKey: PolicyKey.Persistent },
{ accessToken },
);
} else {
throw err;
}
}
};
export const listObjects = async () => {
await ensureBucketExists(apsBucket);
const accessToken = await getInternalToken();
let resp = await ossClient.getObjects(apsBucket, { limit: 64, accessToken });
let objects = resp.items;
while (resp.next) {
const startAt = new URL(resp.next).searchParams.get('startAt');
resp = await ossClient.getObjects(apsBucket, { limit: 64, startAt, accessToken });
objects = objects.concat(resp.items);
}
return objects;
};
export const uploadObject = async (objectName, buffer) => {
await ensureBucketExists(apsBucket);
const accessToken = await getInternalToken();
const obj = await ossClient.uploadObject(apsBucket, objectName, buffer, { accessToken });
return obj;
};
export const translateObject = async (urn, rootFilename) => {
const accessToken = await getInternalToken();
const job = await modelDerivativeClient.startJob(
{
input: {
urn,
compressedUrn: !!rootFilename,
rootFilename,
},
output: {
formats: [
{
views: [View._2d, View._3d],
type: OutputType.Svf2,
},
],
},
},
{ accessToken },
);
return job.result;
};
export const getManifest = async (urn) => {
const accessToken = await getInternalToken();
try {
const manifest = await modelDerivativeClient.getManifest(urn, { accessToken });
return manifest;
} catch (err) {
if (err.axiosError.response.status === 404) {
return null;
} else {
throw err;
}
}
};
export const urnify = (id) => Buffer.from(id).toString('base64').replace(/=/g, '');