#node.js #cloudkit #cloudkit-web-services #cloudkit-js
#node.js #cloudkit #cloudkit-веб-сервисы #cloudkit-js
Вопрос:
Я хочу использовать cloudkit js от сервера к серверу. чтобы сохранить запись с полем активов.
поле активов — это аудио формата m4a. после сохранения аудиофайл поврежден для воспроизведения
В документе Apple неясно, что касается поля активов.
В записи, которая сохраняется в базе данных, значением поля активов должно быть окно.Тип большого двоичного объекта. В приведенном выше фрагменте кода тип переменной assetFile — window.File .
Документы: https://developer.apple.com/documentation/cloudkitjs/cloudkit/database/1628735-saverecords
но в nodejs нет большого двоичного объекта или .File, я заполнил его буфером, подобным этому коду:
var dstFile = path.join(__dirname,"../test.m4a");
var data = fs.readFileSync(dstFile);
let buffer = Buffer.from(data);
var rec = {
recordType: "MyAttachment",
fields: {
ext: { value: ".m4a" },
file: { value: buffer }
}
}
//console.debug(rec);
mydatabase.newRecordsBatch().create(rec).commit().then(function (response) {
if (response.hasErrors) {
console.log(">>> saveAttachFile record failed");
console.warn(response.errors[0]);
} else {
var createdRecord = response.records[0];
console.log(">>> saveAttachFile record success:", createdRecord);
}
});
Запись успешно сохранена.
Но когда я загружаю аудио из icloud.developer.apple.com/dashboard .
аудиофайл поврежден для воспроизведения.
Что в этом плохого. спасибо за ответ.
Комментарии:
1. Вы решили проблему?
2. нет. Документ Apple настолько ограничен. и нет полного источника cloudkit.js чтобы разобраться в этом. 😂
Ответ №1:
У меня была такая же проблема, и я нашел рабочее решение!
Помня, что CloudKitJS требует, чтобы вы определили свой собственный fetch
метод, я внедрил пользовательский, чтобы посмотреть, что происходит. Затем я подключил отладчик к пользовательскому fetch
интерфейсу для проверки данных, которые проходили через него.
Пройдя через вызывающего абонента, я обнаружил, что все значения активов преобразуются с использованием его toString()
метода только тогда, когда библиотека встроена в NodeJS. Это определяется отсутствием глобального window
объекта.
При toString()
вызове a Buffer
его содержимое кодируется в UTF-8 (по умолчанию), что приводит к искажению двоичных активов. Если вы используете node-fetch
для своей fetch
реализации, он поддерживает Buffer
и stream.Readable
, поэтому этот toString()
вызов не приносит ничего, кроме вреда.
Самое незаметное исправление, которое я нашел, — это поменять toString()
метод на любой Buffer
или stream.Readable
экземпляры, переданные в качестве значений поля активов. Кстати, вам, вероятно, следует использовать stream.Readable
, чтобы не загружать весь ресурс в память при загрузке.
В любом случае, вот как это выглядит на практике:
// Put this somewhere in your implementation
const swizzleBuffer = (buffer) => {
buffer.toString = () => buffer;
return buffer;
};
// Use this asset value instead
{ asset: swizzleBuffer(fs.readFileSync(path)) }
Пожалуйста, имейте в виду, что это обходное Buffer
решение уродливо изменяет a (поскольку Buffer
, по-видимому, не может быть расширено). Вероятно, хорошей идеей будет разработать API, который не использует Buffer
аргументы, чтобы вы могли изменять экземпляры, которые только вы создаете сами, чтобы избежать непреднамеренных побочных эффектов где-либо еще в вашем коде.
Кроме того, обязательно укажите поставщика (создайте локальную копию) CloudKitJS в своем проекте, так как поведение может измениться в будущем.
ОРИГИНАЛЬНЫЙ ОТВЕТ
Я столкнулся с той же проблемой и решил ее, закодировав свои данные с помощью Base64. Похоже, что в их SDK есть ошибка, которая искажает Buffer
экземпляры, содержащие символы, отличные от ascii (что, гм, кажется проблематичным).
В любом случае, попробуйте что-то вроде этого:
const assetField = { value: Buffer.from(data.toString('base64')), 'ascii') }
Примечание:
Перед их использованием вам необходимо расшифровать активы на устройстве. Невозможно сделать это эффективно, не написав свои собственные процедуры, поскольку методы, включенные в Data
/ NSData
instances, требуют, чтобы все данные были в памяти.
Это проблема с CloudKitJS (а не с собственным клиентом / сервисом CloudKit), поэтому другой вариант — написать собственную процедуру для загрузки ресурсов.
Ни один из этих вариантов не кажется особенно замечательным, но, по крайней мере, развертывание собственного означает, что клиентам не нужно предпринимать дополнительных шагов для использования ресурса.
Комментарии:
1. Спасибо за ваш ответ, я не могу проверить ваш ответ сейчас, но звучит здорово. поэтому я принимаю это. другой друг может это проверить.
2. Спасибо, Майки, очень полезно. Ваш первоначальный ответ помог мне, который заключался в сжатии строки с помощью zlib в base64 и отправке ее в CK в качестве ресурса. Мне не нужно было делать это с помощью функции swizzler.