-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathbridge.ios.ts
More file actions
144 lines (131 loc) · 5.35 KB
/
bridge.ios.ts
File metadata and controls
144 lines (131 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
import { HeaderType } from './common';
import { NativeBridgeDefinition, WebSocketBridgeConnectOptions } from './websocket.definition';
@NativeClass
class RCTSRWebSocketDelegateImpl extends NSObject implements RCTSRWebSocketDelegate {
public static ObjCProtocols = [RCTSRWebSocketDelegate];
public static initWithOwner(owner: NativeBridge) {
const instance = <RCTSRWebSocketDelegateImpl>RCTSRWebSocketDelegateImpl.new();
instance.owner = new WeakRef(owner);
return instance;
}
public owner!: WeakRef<NativeBridge>;
webSocketDidCloseWithCodeReasonWasClean?(webSocket: RCTSRWebSocket, code: number, reason: string, wasClean: boolean): void {
this.owner.get()?._websocketClosed(code, reason, wasClean);
}
webSocketDidFailWithError?(webSocket: RCTSRWebSocket, error: NSError): void {
this.owner.get()?._websocketFailed(error);
}
webSocketDidOpen(webSocket: RCTSRWebSocket): void {
this.owner.get()?._websocketOpen();
}
webSocketDidReceiveMessage(webSocket: RCTSRWebSocket, message: unknown): void {
this.owner.get()?._websocketMessage(message);
}
webSocketDidReceivePong?(webSocket: RCTSRWebSocket, pongPayload: NSData): void {
this.owner.get()?._websocketPong(pongPayload);
}
}
export class NativeBridge extends NativeBridgeDefinition {
nativeSocket!: RCTSRWebSocket;
// store the delegate so it isn't garbage collected
// TODO: fix the iOS runtime so we don't need this
delegate!: RCTSRWebSocketDelegateImpl;
connect({ url, protocols, headers, pinnedCertificates }: WebSocketBridgeConnectOptions): void {
const nativeUrl = NSURL.URLWithString(url);
const request = NSMutableURLRequest.requestWithURL(nativeUrl);
// NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
// We load cookies from sharedHTTPCookieStorage (shared with XHR and
// fetch). To get secure cookies for wss URLs, replace wss with https
// in the URL.
const components = NSURLComponents.componentsWithURLResolvingAgainstBaseURL(nativeUrl, true);
// NSURLComponents *components = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:true];
if (components.scheme.toLocaleLowerCase() === 'wss') {
components.scheme = 'https';
}
// Load and set the cookie header.
const cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookiesForURL(components.URL);
request.allHTTPHeaderFields = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies);
// Load supplied headers
for (const k of Object.keys(headers.headers)) {
request.addValueForHTTPHeaderField(`${headers.headers[k]}`, k);
}
if (pinnedCertificates) {
const sslArray = NSMutableArray.new();
for (const c of pinnedCertificates) {
// convert from pem to der (base64)
const der = c
.replace(/-----BEGIN CERTIFICATE-----/g, '')
.replace(/-----END CERTIFICATE-----/g, '')
.replace(/\r?\n/g, '');
const cert = SecCertificateCreateWithData(null, NSData.alloc().initWithBase64EncodedStringOptions(der, NSDataBase64DecodingOptions.IgnoreUnknownCharacters));
if (cert) {
sslArray.addObject(cert);
} else {
console.warn('Unable to create certificate from pem');
}
}
request.RCTSR_SSLPinnedCertificates = sslArray;
}
const webSocket = RCTSRWebSocket.alloc().initWithURLRequestProtocols(request, protocols);
this.nativeSocket = webSocket;
this.delegate = RCTSRWebSocketDelegateImpl.initWithOwner(this);
webSocket.setDelegateDispatchQueue(dispatch_get_current_queue() as unknown as NSObject);
webSocket.delegate = this.delegate;
webSocket.open();
}
send(data: string | ArrayBuffer | ArrayBufferView | Blob): void {
// if (data instanceof Blob) {
// invariant(
// BlobManager.isAvailable,
// 'Native module BlobModule is required for blob support',
// );
// BlobManager.sendOverSocket(data, this._socketId);
// return;
// }
if (typeof data === 'string') {
this.nativeSocket.send(data);
// NativeWebSocketModule.send(data, this._socketId);
return;
}
if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
this.nativeSocket.send(data);
// NativeWebSocketModule.sendBinary(binaryToBase64(data), this._socketId);
return;
}
throw new Error('Unsupported data type');
}
closeWithCodeReason(statusCode: number, closeReason: string) {
this.nativeSocket.closeWithCodeReason(statusCode, closeReason);
}
sendPing() {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.nativeSocket.sendPing(null!);
}
_websocketOpen() {
this.ws._websocketOpen(this.nativeSocket.protocol);
}
_websocketClosed(code: number, reason: string, wasClean: boolean) {
this.ws._websocketClosed(code, reason, wasClean);
}
_websocketMessage(message: unknown) {
if (message instanceof NSData) {
message = interop.bufferFromData(message);
}
this.ws._websocketMessage(message as string | ArrayBuffer);
}
_websocketPong(pongPayload: NSData) {
//
}
_websocketFailed(error: NSError) {
this.ws._websocketFailed(error.localizedDescription);
}
}