pubnub
Version:
Publish & Subscribe Real-time Messaging with PubNub
266 lines (224 loc) • 7.63 kB
text/typescript
/* global File, FileReader */
/**
* React Native {@link PubNub} File object module.
*/
import { PubNubFileInterface } from '../../core/types/file';
// --------------------------------------------------------
// ------------------------ Types -------------------------
// --------------------------------------------------------
// region Types
/**
* File path-based file.
*/
type FileUri = { uri: string; name: string; mimeType?: string };
/**
* Asynchronously fetched file content.
*/
type ReadableFile = { arrayBuffer: () => Promise<ArrayBuffer>; blob: () => Promise<Blob>; text: () => Promise<string> };
/**
* PubNub File instance creation parameters.
*/
export type PubNubFileParameters =
| File
| FileUri
| ReadableFile
| { data: string | Blob | ArrayBuffer | ArrayBufferView; name: string; mimeType?: string };
// endregion
export class PubNubFile implements PubNubFileInterface {
// region Class properties
/**
* Whether {@link Blob} data supported by platform or not.
*/
static supportsBlob = typeof Blob !== 'undefined';
/**
* Whether {@link File} data supported by platform or not.
*/
static supportsFile = typeof File !== 'undefined';
/**
* Whether {@link Buffer} data supported by platform or not.
*/
static supportsBuffer = false;
/**
* Whether {@link Stream} data supported by platform or not.
*/
static supportsStream = false;
/**
* Whether {@link String} data supported by platform or not.
*/
static supportsString = true;
/**
* Whether {@link ArrayBuffer} supported by platform or not.
*/
static supportsArrayBuffer = true;
/**
* Whether {@link PubNub} File object encryption supported or not.
*/
static supportsEncryptFile = false;
/**
* Whether `File Uri` data supported by platform or not.
*/
static supportsFileUri = true;
// endregion
// region Instance properties
/**
* File object content source.
*/
readonly data: File | FileUri | ReadableFile;
/**
* File object content length.
*/
contentLength?: number;
/**
* File object content type.
*/
mimeType: string;
/**
* File object name.
*/
name: string;
// endregion
static create(file: PubNubFileParameters) {
return new PubNubFile(file);
}
constructor(file: PubNubFileParameters) {
let fileData: PubNubFile['data'] | undefined;
let contentLength: number | undefined;
let fileMimeType: string | undefined;
let fileName: string | undefined;
if (file instanceof File) {
fileData = file;
fileName = file.name;
fileMimeType = file.type;
contentLength = file.size;
} else if ('data' in file) {
const contents = file.data;
fileMimeType = file.mimeType;
fileName = file.name;
fileData = new File([contents], fileName, { type: fileMimeType });
contentLength = fileData.size;
} else if ('uri' in file) {
fileMimeType = file.mimeType;
fileName = file.name;
fileData = {
uri: file.uri,
name: file.name,
type: file.mimeType!,
};
} else throw new Error("Couldn't construct a file out of supplied options. URI or file data required.");
if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options.");
if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one.");
if (contentLength) this.contentLength = contentLength;
this.mimeType = fileMimeType!;
this.data = fileData;
this.name = fileName;
}
/**
* Convert {@link PubNub} File object content to {@link Buffer}.
*
* @throws Error because {@link Buffer} not available in React Native environment.
*/
async toBuffer() {
throw new Error('This feature is only supported in Node.js environments.');
}
/**
* Convert {@link PubNub} File object content to {@link ArrayBuffer}.
*
* @returns Asynchronous results of conversion to the {@link ArrayBuffer}.
*
* @throws Error if provided {@link PubNub} File object content is not supported for this
* operation.
*/
async toArrayBuffer(): Promise<ArrayBuffer> {
if (this.data && this.data instanceof File) {
const data = this.data;
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener('load', () => {
if (reader.result instanceof ArrayBuffer) return resolve(reader.result);
});
reader.addEventListener('error', () => reject(reader.error));
reader.readAsArrayBuffer(data);
});
} else if (this.data && 'uri' in this.data) {
throw new Error('This file contains a file URI and does not contain the file contents.');
} else if (this.data) {
let result: ArrayBuffer | undefined;
try {
result = await this.data.arrayBuffer();
} catch (error) {
throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${error}`);
}
return result;
}
throw new Error('Unable convert provided file content type to ArrayBuffer');
}
/**
* Convert {@link PubNub} File object content to {@link string}.
*
* @returns Asynchronous results of conversion to the {@link string}.
*/
async toString(): Promise<string> {
if (this.data && 'uri' in this.data) return JSON.stringify(this.data);
else if (this.data && this.data instanceof File) {
const data = this.data;
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.addEventListener('load', () => {
if (typeof reader.result === 'string') return resolve(reader.result);
});
reader.addEventListener('error', () => reject(reader.error));
reader.readAsBinaryString(data);
});
}
return this.data.text();
}
/**
* Convert {@link PubNub} File object content to {@link Readable} stream.
*
* @throws Error because {@link Readable} stream not available in React Native environment.
*/
async toStream() {
throw new Error('This feature is only supported in Node.js environments.');
}
/**
* Convert {@link PubNub} File object content to {@link File}.
*
* @returns Asynchronous results of conversion to the {@link File}.
*
* @throws Error if provided {@link PubNub} File object content is not supported for this
* operation.
*/
async toFile() {
if (this.data instanceof File) return this.data;
else if ('uri' in this.data)
throw new Error('This file contains a file URI and does not contain the file contents.');
else return this.data.blob();
}
/**
* Convert {@link PubNub} File object content to file `Uri`.
*
* @returns Asynchronous results of conversion to file `Uri`.
*
* @throws Error if provided {@link PubNub} File object content is not supported for this
* operation.
*/
async toFileUri() {
if (this.data && 'uri' in this.data) return this.data;
throw new Error('This file does not contain a file URI');
}
/**
* Convert {@link PubNub} File object content to {@link Blob}.
*
* @returns Asynchronous results of conversion to the {@link Blob}.
*
* @throws Error if provided {@link PubNub} File object content is not supported for this
* operation.
*/
async toBlob() {
if (this.data instanceof File) return this.data;
else if (this.data && 'uri' in this.data)
throw new Error('This file contains a file URI and does not contain the file contents.');
else return this.data.blob();
}
}
export default PubNubFile;