Как сохранить записи с помощью поля активов, используя сервер-сервер cloudkit.js

#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.