UNPKG

3.53 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow strict-local
8 * @format
9 */
10
11'use strict';
12
13const Blob = require('Blob');
14const BlobRegistry = require('BlobRegistry');
15const {BlobModule} = require('NativeModules');
16
17import type {BlobData, BlobOptions} from 'BlobTypes';
18
19/*eslint-disable no-bitwise */
20/*eslint-disable eqeqeq */
21
22/**
23 * Based on the rfc4122-compliant solution posted at
24 * http://stackoverflow.com/questions/105034
25 */
26function uuidv4(): string {
27 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
28 const r = (Math.random() * 16) | 0,
29 v = c == 'x' ? r : (r & 0x3) | 0x8;
30 return v.toString(16);
31 });
32}
33
34/**
35 * Module to manage blobs. Wrapper around the native blob module.
36 */
37class BlobManager {
38 /**
39 * If the native blob module is available.
40 */
41 static isAvailable = !!BlobModule;
42
43 /**
44 * Create blob from existing array of blobs.
45 */
46 static createFromParts(
47 parts: Array<Blob | string>,
48 options?: BlobOptions,
49 ): Blob {
50 const blobId = uuidv4();
51 const items = parts.map(part => {
52 if (
53 part instanceof ArrayBuffer ||
54 (global.ArrayBufferView && part instanceof global.ArrayBufferView)
55 ) {
56 throw new Error(
57 "Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported",
58 );
59 }
60 if (part instanceof Blob) {
61 return {
62 data: part.data,
63 type: 'blob',
64 };
65 } else {
66 return {
67 data: String(part),
68 type: 'string',
69 };
70 }
71 });
72 const size = items.reduce((acc, curr) => {
73 if (curr.type === 'string') {
74 return acc + global.unescape(encodeURI(curr.data)).length;
75 } else {
76 return acc + curr.data.size;
77 }
78 }, 0);
79
80 BlobModule.createFromParts(items, blobId);
81
82 return BlobManager.createFromOptions({
83 blobId,
84 offset: 0,
85 size,
86 type: options ? options.type : '',
87 lastModified: options ? options.lastModified : Date.now(),
88 });
89 }
90
91 /**
92 * Create blob instance from blob data from native.
93 * Used internally by modules like XHR, WebSocket, etc.
94 */
95 static createFromOptions(options: BlobData): Blob {
96 BlobRegistry.register(options.blobId);
97 return Object.assign(Object.create(Blob.prototype), {data: options});
98 }
99
100 /**
101 * Deallocate resources for a blob.
102 */
103 static release(blobId: string): void {
104 BlobRegistry.unregister(blobId);
105 if (BlobRegistry.has(blobId)) {
106 return;
107 }
108 BlobModule.release(blobId);
109 }
110
111 /**
112 * Inject the blob content handler in the networking module to support blob
113 * requests and responses.
114 */
115 static addNetworkingHandler(): void {
116 BlobModule.addNetworkingHandler();
117 }
118
119 /**
120 * Indicate the websocket should return a blob for incoming binary
121 * messages.
122 */
123 static addWebSocketHandler(socketId: number): void {
124 BlobModule.addWebSocketHandler(socketId);
125 }
126
127 /**
128 * Indicate the websocket should no longer return a blob for incoming
129 * binary messages.
130 */
131 static removeWebSocketHandler(socketId: number): void {
132 BlobModule.removeWebSocketHandler(socketId);
133 }
134
135 /**
136 * Send a blob message to a websocket.
137 */
138 static sendOverSocket(blob: Blob, socketId: number): void {
139 BlobModule.sendOverSocket(blob.data, socketId);
140 }
141}
142
143module.exports = BlobManager;