Autodesk 模型衍生翻译作业导致“TranslationWorker-InternalFailure”响应?
Autodesk model derivative translation job results in `TranslationWorker-InternalFailure` response?
我正在尝试使用 Autodesk 的 Model Derivative API 将 .zip
文件转换为 .svf
清单。我能够成功创建一个存储桶,使用分块上传将 zip 放入存储桶中,并使用相应的端点(所有端点 return 200)开始翻译作业。当我来检查作业的翻译进度时,它停在“0% 完成”,最终 return 显示 TranslationWorker-InternalFailure
的失败消息。
这一切都是在 Node.js 和超级代理堆栈上以编程方式完成的,以发出 HTTP 请求。我可以通过使用 Paw 手动翻译来确认文件本身是有效的;并使用我们正在更换的旧工具对其进行翻译。
请参阅下文了解我的代码的具体部分。
Autodesk 翻译作业 (Endpoint)
translate: async function(accessToken, obj) {
return await request.post('https://developer.api.autodesk.com/modelderivative/v2/designdata/job')
.set("Authorization", "Bearer " + accessToken)
.set("Content-Type", "application/json")
.set('x-ads-force', true)
.send({
input: {
urn: obj.base64Urn,
compressedUrn: true,
rootFilename: obj.parentFile
},
output: {
formats: [
{
type: "thumbnail"
},
{
type: "svf",
views: ["2d", "3d"]
}
]
}
});
}
在上面的代码中,变量具有以下值:
obj.base64Urn
是由Autodesk提供的URN通过以下函数动态转换而来:
base64Urn: function() {
// https://tools.ietf.org/html/rfc7515#appendix-C
return this.getDataValue("urn") != null ? (new Buffer(this.getDataValue("urn"))).toString('base64').replace(/=+$/g, "").replace(/\+/g, "-").replace(/[\/]/g, "_") : null;
}
obj.parentFile
采用 "160728 Small Test Project.rvt"
的形式
Autodesk 翻译进度 (Endpoint)
getTranslationProgressAndDerivatives: function(accessToken, obj) {
return request.get('https://developer.api.autodesk.com/modelderivative/v2/designdata/' + obj.base64Urn + '/manifest')
.set('Authorization', "Bearer " + accessToken);
}
当然,obj 有时必须放在 Autodesk 的服务器上。这是通过这段代码完成的:
Autodesk 将对象放入桶中 (Endpoint)
class HttpAutodeskPutObjectWriteStream extends stream.Writable {
/**
* Constructor sets all the properties for the instance.
*
* @param {string} accessToken - The OAuth2 access token needed for server authentication to engage with Autodesk's API.
* @param {Obj} obj
*/
constructor(accessToken, bucket) {
super();
this.accessToken = accessToken;
this.obj = obj;
this._bytesTransferred = 0;
this._putHttpUrl = 'https://developer.api.autodesk.com/oss/v2/buckets/' + this.obj.name + '/objects/' + this.obj.name + '/resumable';
}
/**
* Return a bytes transferred statement.
*
* @private
*
* @param chunk - The chunk currently being transferred.
*
* @returns {string}
*/
_bytesTransferredStatement(chunk) {
return `bytes ${this._bytesTransferred}-${this._bytesTransferred+chunk.byteLength-1}/${this.obj.zipFileSize}`;
};
/**
* Writes data to the stream. Note the use of the serialize method in the request.
*
* @private
*
* @param chunk - The chunk currently being transferred.
* @param encoding - The encoding of the chunk data.
* @param callback - The function to be called on chunk completion (success or otherwise).
*
* @returns {Promise.<void>}
*/
async _write(chunk, encoding, callback) {
try {
let stmt = this._bytesTransferredStatement(chunk);
this._bytesTransferred += chunk.byteLength;
let response = await request.put(this._putHttpUrl)
.set("Authorization", "Bearer " + this.accessToken)
.set("Session-Id", this.bucket.key)
.set("Content-Length", chunk.byteLength)
.set("Content-Range", stmt)
.serialize(function(d) { return d; })
.send(chunk.toString());
if (response.status === 200) {
this.urn = response.body.objectId;
}
callback(null);
} catch (e) {
callback(e);
}
};
}
然后在此处调用:
put: function(accessToken, bucketEntity) {
return new Promise(async (resolve, reject) => {
const maximalChunkedTransferSize = 2*1024*1024; // 2MB (Minimum amount, Autodesk recommends 5MB).
const objStorageLocation = (await config.get())[process.env.NODE_ENV].objStorageLocation;
const pathToFile = path.join(__dirname, "../../", objStorageLocation, obj.name + ".zip");
let readFileStream = fs.createReadStream(pathToFile, { highWaterMark: maximalChunkedTransferSize });
let ws = new HttpAutodeskPutObjectWriteStream(accessToken, obj);
readFileStream.pipe(ws);
ws.on("finish", () => resolve(ws.urn));
ws.on("error", () => reject());
});
}
当作业失败时...
一旦失败,这是我从翻译进度端点收到的响应:
{
"type": "manifest",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"region": "US",
"urn": "<redacted>",
"version": "1.0",
"derivatives": [
{
"name": "LMV Bubble",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"messages": [
{
"type": "error",
"message": "Translation failure",
"code": "TranslationWorker-InternalFailure"
}
],
"outputType": "svf"
}
]
}
我在这里做错了什么会导致尝试翻译文件时 100% 的失败率吗?
当然,在 Whosebug 上发帖会让您从不同的角度审视您的代码。问题出在我上传文件时,特别是最后一个链接方法:
let response = await request.put(this._putHttpUrl)
.set("Authorization", "Bearer " + this.accessToken)
.set("Session-Id", this.bucket.key)
.set("Content-Length", chunk.byteLength)
.set("Content-Range", stmt)
.serialize(function(d) { return d; })
.send(chunk.toString()); // HERE
在块上调用 .toString()
是不正确的。
我正在尝试使用 Autodesk 的 Model Derivative API 将 .zip
文件转换为 .svf
清单。我能够成功创建一个存储桶,使用分块上传将 zip 放入存储桶中,并使用相应的端点(所有端点 return 200)开始翻译作业。当我来检查作业的翻译进度时,它停在“0% 完成”,最终 return 显示 TranslationWorker-InternalFailure
的失败消息。
这一切都是在 Node.js 和超级代理堆栈上以编程方式完成的,以发出 HTTP 请求。我可以通过使用 Paw 手动翻译来确认文件本身是有效的;并使用我们正在更换的旧工具对其进行翻译。
请参阅下文了解我的代码的具体部分。
Autodesk 翻译作业 (Endpoint)
translate: async function(accessToken, obj) {
return await request.post('https://developer.api.autodesk.com/modelderivative/v2/designdata/job')
.set("Authorization", "Bearer " + accessToken)
.set("Content-Type", "application/json")
.set('x-ads-force', true)
.send({
input: {
urn: obj.base64Urn,
compressedUrn: true,
rootFilename: obj.parentFile
},
output: {
formats: [
{
type: "thumbnail"
},
{
type: "svf",
views: ["2d", "3d"]
}
]
}
});
}
在上面的代码中,变量具有以下值:
obj.base64Urn
是由Autodesk提供的URN通过以下函数动态转换而来:base64Urn: function() { // https://tools.ietf.org/html/rfc7515#appendix-C return this.getDataValue("urn") != null ? (new Buffer(this.getDataValue("urn"))).toString('base64').replace(/=+$/g, "").replace(/\+/g, "-").replace(/[\/]/g, "_") : null; }
obj.parentFile
采用"160728 Small Test Project.rvt"
的形式
Autodesk 翻译进度 (Endpoint)
getTranslationProgressAndDerivatives: function(accessToken, obj) {
return request.get('https://developer.api.autodesk.com/modelderivative/v2/designdata/' + obj.base64Urn + '/manifest')
.set('Authorization', "Bearer " + accessToken);
}
当然,obj 有时必须放在 Autodesk 的服务器上。这是通过这段代码完成的:
Autodesk 将对象放入桶中 (Endpoint)
class HttpAutodeskPutObjectWriteStream extends stream.Writable {
/**
* Constructor sets all the properties for the instance.
*
* @param {string} accessToken - The OAuth2 access token needed for server authentication to engage with Autodesk's API.
* @param {Obj} obj
*/
constructor(accessToken, bucket) {
super();
this.accessToken = accessToken;
this.obj = obj;
this._bytesTransferred = 0;
this._putHttpUrl = 'https://developer.api.autodesk.com/oss/v2/buckets/' + this.obj.name + '/objects/' + this.obj.name + '/resumable';
}
/**
* Return a bytes transferred statement.
*
* @private
*
* @param chunk - The chunk currently being transferred.
*
* @returns {string}
*/
_bytesTransferredStatement(chunk) {
return `bytes ${this._bytesTransferred}-${this._bytesTransferred+chunk.byteLength-1}/${this.obj.zipFileSize}`;
};
/**
* Writes data to the stream. Note the use of the serialize method in the request.
*
* @private
*
* @param chunk - The chunk currently being transferred.
* @param encoding - The encoding of the chunk data.
* @param callback - The function to be called on chunk completion (success or otherwise).
*
* @returns {Promise.<void>}
*/
async _write(chunk, encoding, callback) {
try {
let stmt = this._bytesTransferredStatement(chunk);
this._bytesTransferred += chunk.byteLength;
let response = await request.put(this._putHttpUrl)
.set("Authorization", "Bearer " + this.accessToken)
.set("Session-Id", this.bucket.key)
.set("Content-Length", chunk.byteLength)
.set("Content-Range", stmt)
.serialize(function(d) { return d; })
.send(chunk.toString());
if (response.status === 200) {
this.urn = response.body.objectId;
}
callback(null);
} catch (e) {
callback(e);
}
};
}
然后在此处调用:
put: function(accessToken, bucketEntity) {
return new Promise(async (resolve, reject) => {
const maximalChunkedTransferSize = 2*1024*1024; // 2MB (Minimum amount, Autodesk recommends 5MB).
const objStorageLocation = (await config.get())[process.env.NODE_ENV].objStorageLocation;
const pathToFile = path.join(__dirname, "../../", objStorageLocation, obj.name + ".zip");
let readFileStream = fs.createReadStream(pathToFile, { highWaterMark: maximalChunkedTransferSize });
let ws = new HttpAutodeskPutObjectWriteStream(accessToken, obj);
readFileStream.pipe(ws);
ws.on("finish", () => resolve(ws.urn));
ws.on("error", () => reject());
});
}
当作业失败时...
一旦失败,这是我从翻译进度端点收到的响应:
{
"type": "manifest",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"region": "US",
"urn": "<redacted>",
"version": "1.0",
"derivatives": [
{
"name": "LMV Bubble",
"hasThumbnail": "false",
"status": "failed",
"progress": "complete",
"messages": [
{
"type": "error",
"message": "Translation failure",
"code": "TranslationWorker-InternalFailure"
}
],
"outputType": "svf"
}
]
}
我在这里做错了什么会导致尝试翻译文件时 100% 的失败率吗?
当然,在 Whosebug 上发帖会让您从不同的角度审视您的代码。问题出在我上传文件时,特别是最后一个链接方法:
let response = await request.put(this._putHttpUrl)
.set("Authorization", "Bearer " + this.accessToken)
.set("Session-Id", this.bucket.key)
.set("Content-Length", chunk.byteLength)
.set("Content-Range", stmt)
.serialize(function(d) { return d; })
.send(chunk.toString()); // HERE
在块上调用 .toString()
是不正确的。