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
|
8 | * @format
|
9 | */
|
10 |
|
11 | ;
|
12 |
|
13 | import type {BlobData, BlobOptions} from 'BlobTypes';
|
14 |
|
15 | /**
|
16 | * Opaque JS representation of some binary data in native.
|
17 | *
|
18 | * The API is modeled after the W3C Blob API, with one caveat
|
19 | * regarding explicit deallocation. Refer to the `close()`
|
20 | * method for further details.
|
21 | *
|
22 | * Example usage in a React component:
|
23 | *
|
24 | * class WebSocketImage extends React.Component {
|
25 | * state = {blob: null};
|
26 | * componentDidMount() {
|
27 | * let ws = this.ws = new WebSocket(...);
|
28 | * ws.binaryType = 'blob';
|
29 | * ws.onmessage = (event) => {
|
30 | * if (this.state.blob) {
|
31 | * this.state.blob.close();
|
32 | * }
|
33 | * this.setState({blob: event.data});
|
34 | * };
|
35 | * }
|
36 | * componentUnmount() {
|
37 | * if (this.state.blob) {
|
38 | * this.state.blob.close();
|
39 | * }
|
40 | * this.ws.close();
|
41 | * }
|
42 | * render() {
|
43 | * if (!this.state.blob) {
|
44 | * return <View />;
|
45 | * }
|
46 | * return <Image source={{uri: URL.createObjectURL(this.state.blob)}} />;
|
47 | * }
|
48 | * }
|
49 | *
|
50 | * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob
|
51 | */
|
52 | class Blob {
|
53 | _data: ?BlobData;
|
54 |
|
55 | /**
|
56 | * Constructor for JS consumers.
|
57 | * Currently we only support creating Blobs from other Blobs.
|
58 | * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
|
59 | */
|
60 | constructor(parts: Array<Blob | string> = [], options?: BlobOptions) {
|
61 | const BlobManager = require('BlobManager');
|
62 | this.data = BlobManager.createFromParts(parts, options).data;
|
63 | }
|
64 |
|
65 | /*
|
66 | * This method is used to create a new Blob object containing
|
67 | * the data in the specified range of bytes of the source Blob.
|
68 | * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice
|
69 | */
|
70 | set data(data: ?BlobData) {
|
71 | this._data = data;
|
72 | }
|
73 |
|
74 | get data(): BlobData {
|
75 | if (!this._data) {
|
76 | throw new Error('Blob has been closed and is no longer available');
|
77 | }
|
78 |
|
79 | return this._data;
|
80 | }
|
81 |
|
82 | slice(start?: number, end?: number): Blob {
|
83 | const BlobManager = require('BlobManager');
|
84 | let {offset, size} = this.data;
|
85 |
|
86 | if (typeof start === 'number') {
|
87 | if (start > size) {
|
88 | start = size;
|
89 | }
|
90 | offset += start;
|
91 | size -= start;
|
92 |
|
93 | if (typeof end === 'number') {
|
94 | if (end < 0) {
|
95 | end = this.size + end;
|
96 | }
|
97 | size = end - start;
|
98 | }
|
99 | }
|
100 | return BlobManager.createFromOptions({
|
101 | blobId: this.data.blobId,
|
102 | offset,
|
103 | size,
|
104 | });
|
105 | }
|
106 |
|
107 | /**
|
108 | * This method is in the standard, but not actually implemented by
|
109 | * any browsers at this point. It's important for how Blobs work in
|
110 | * React Native, however, since we cannot de-allocate resources automatically,
|
111 | * so consumers need to explicitly de-allocate them.
|
112 | *
|
113 | * Note that the semantics around Blobs created via `blob.slice()`
|
114 | * and `new Blob([blob])` are different. `blob.slice()` creates a
|
115 | * new *view* onto the same binary data, so calling `close()` on any
|
116 | * of those views is enough to deallocate the data, whereas
|
117 | * `new Blob([blob, ...])` actually copies the data in memory.
|
118 | */
|
119 | close() {
|
120 | const BlobManager = require('BlobManager');
|
121 | BlobManager.release(this.data.blobId);
|
122 | this.data = null;
|
123 | }
|
124 |
|
125 | /**
|
126 | * Size of the data contained in the Blob object, in bytes.
|
127 | */
|
128 | get size(): number {
|
129 | return this.data.size;
|
130 | }
|
131 |
|
132 | /*
|
133 | * String indicating the MIME type of the data contained in the Blob.
|
134 | * If the type is unknown, this string is empty.
|
135 | */
|
136 | get type(): string {
|
137 | return this.data.type || '';
|
138 | }
|
139 | }
|
140 |
|
141 | module.exports = Blob;
|