@react-native-oh-tpl/react-native-tcp-socket
Version:
React Native TCP socket API for HarmonyOS with SSL/TLS support
220 lines (198 loc) • 7.58 kB
text/typescript
import { TurboModule, RNOHError, TurboModuleContext } from '@rnoh/react-native-openharmony/ts';
import { TM } from "@rnoh/react-native-openharmony/generated/ts"
import { TcpEventListener } from "./TcpEventListener"
import { connection } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { TcpSocket } from './TcpSocket'
import Logger from './Logger'
import { TcpSocketClient } from './TcpSocketClient'
import { TcpSocketServer } from './TcpSocketServer'
import { util } from '@kit.ArkTS';
import { Context } from '@kit.AbilityKit';
export class TcpSocketTurboModule extends TurboModule implements TM.TcpSocketModule.Spec {
private socketMap: Map<number, TcpSocket> = new Map<number, TcpSocket>();
private pendingTLS: Map<number, Object> = new Map<number, Object>();
private mNetworkMap: Map<string, connection.ConnectionProperties> =
new Map<string, connection.ConnectionProperties>();
private tcpEvtListener?: TcpEventListener;
private currentNetwork?: connection.ConnectionProperties;
private context: Context;
constructor(ctx: TurboModuleContext) {
super(ctx)
this.tcpEvtListener = new TcpEventListener(ctx);
this.context = ctx.uiAbilityContext
}
private getTcpClient(cid: number): TcpSocketClient | undefined {
let socket: TcpSocket | undefined = this.socketMap.get(cid);
if (socket && (socket instanceof TcpSocketClient)) {
return socket as TcpSocketClient;
}
return undefined;
}
private getTcpServer(cid: number): TcpSocketServer | undefined {
let socket: TcpSocket | undefined = this.socketMap.get(cid);
if (socket && (socket instanceof TcpSocketServer)) {
return socket as TcpSocketServer;
}
return undefined;
}
private async requestNetwork(transportType: number, iotDeviceHost: string): Promise<void> {
if (!iotDeviceHost || "localhost" === iotDeviceHost) {
this.getDefaultNetInfo();
} else {
let netHandles = connection.getAllNetsSync();
for (const netHandle of netHandles) {
let conpro = connection.getNetCapabilitiesSync(netHandle);
if (conpro.bearerTypes.includes(transportType)) {
await connection.setAppNet(netHandle, (error: BusinessError, data: void) => {
if (error) {
Logger.error(`setAppNet error. Code:${error.code}, message:${error.message}`);
return;
}
Logger.info("setAppNet Succeeded");
this.currentNetwork = connection.getConnectionPropertiesSync(netHandle);
});
}
}
}
}
private getDefaultNetInfo() {
if (!connection.hasDefaultNetSync()) {
Logger.info("has not default net")
return;
}
let netHandle: connection.NetHandle = connection.getDefaultNetSync();
this.currentNetwork = connection.getConnectionPropertiesSync(netHandle);
}
private async selectNetwork(ipAddress: string, iface: string, iotDeviceHost: string): Promise<void> {
if (!iface) {
return;
}
if (ipAddress) {
let cachedNetwork = this.mNetworkMap.get(iface + ipAddress);
if (cachedNetwork) {
this.currentNetwork = cachedNetwork;
}
}
switch (iface) {
case 'wifi':
await this.requestNetwork(connection.NetBearType.BEARER_WIFI, iotDeviceHost);
break;
case 'cellular':
await this.requestNetwork(connection.NetBearType.BEARER_CELLULAR, iotDeviceHost);
break;
case 'ethernet':
await this.requestNetwork(connection.NetBearType.BEARER_ETHERNET, iotDeviceHost);
break;
}
if (!this.currentNetwork) {
throw new Error("Interface " + iface + " unreachable");
} else {
this.mNetworkMap.set(iface + ipAddress, this.currentNetwork);
}
}
async connect(cId: number, host: string, port: number, options: Object): Promise<void> {
if (this.socketMap.get(cId)) {
this.tcpEvtListener?.onError(cId, "connect() called twice with the same id.");
return;
}
try {
let localAddress: string = options['localAddress'];
let iface: string = options['interface'];
let iotDeviceHost: string = options['host'];
this.selectNetwork(localAddress, iface, iotDeviceHost);
let client: TcpSocketClient = new TcpSocketClient(this.tcpEvtListener, cId);
this.socketMap.set(cId, client);
let tlsOptions = this.pendingTLS.get(cId);
await client.connect(host, port, options, tlsOptions);
this.tcpEvtListener?.onConnect(cId, client);
} catch (err) {
this.tcpEvtListener?.onError(cId, err?.message);
}
}
startTLS(cId: number, tlsOptions: Object): void {
let socketClient: TcpSocketClient = this.socketMap.get(cId) as TcpSocketClient;
if (!socketClient) {
this.pendingTLS.set(cId, tlsOptions);
} else {
try {
socketClient.startTLS(tlsOptions);
} catch (e) {
this.tcpEvtListener?.onError(cId, JSON.stringify(e));
}
}
}
listen(cId: number, options: Object): void {
let tcpSocketServer = new TcpSocketServer(this.socketMap, this.tcpEvtListener, cId, options);
this.socketMap.set(cId, tcpSocketServer);
this.tcpEvtListener.onListen(cId, tcpSocketServer);
}
close(cid: number): void {
let socketServer: TcpSocketServer = this.getTcpServer(cid);
socketServer?.close();
let socketClient: TcpSocketClient = this.getTcpClient(cid);
socketClient?.destroy();
this.socketMap.delete(cid);
}
destroy(cid: number): void {
this.end(cid);
}
end(cid: number): void {
let socketClient = this.getTcpClient(cid);
socketClient?.destroy();
this.socketMap.delete(cid);
}
pause(cid: number): void {
let socketClient = this.getTcpClient(cid);
socketClient?.pause();
}
resume(cid: number): void {
let socketClient = this.getTcpClient(cid);
socketClient?.resume();
}
write(cId: number, base64String: string, msgId: number): void {
let socketClient = this.getTcpClient(cId);
let base64Helper = new util.Base64Helper;
let uint8Array = base64Helper.decodeSync(base64String)
let buffer = uint8Array.buffer as ArrayBuffer;
socketClient?.write(msgId, buffer);
}
setNoDelay(cId: number, noDelay: boolean): void {
try {
let socketClient = this.getTcpClient(cId);
socketClient?.setNoDelay(noDelay);
} catch (e) {
this.tcpEvtListener?.onError(cId, JSON.stringify(e));
}
}
setKeepAlive(cId: number, enable: boolean, initialDelay: number): void {
try {
let socketClient: TcpSocketClient = this.getTcpClient(cId);
socketClient?.setKeepAlive(enable);
} catch (e) {
this.tcpEvtListener?.onError(cId, JSON.stringify(e));
}
}
getPeerCertificate(cId: number): Promise<string> {
try {
let socketClient = this.getTcpClient(cId);
return socketClient?.getPeerCertificate();
} catch (e) {
this.tcpEvtListener?.onError(cId, JSON.stringify(e));
return new Promise<string>(() => {
return ""
});
}
}
getCertificate(cId: number): Promise<string> {
try {
let socketClient = this.getTcpClient(cId);
return socketClient?.getCertificate();
} catch (e) {
this.tcpEvtListener?.onError(cId, JSON.stringify(e));
return new Promise<string>(() => {
return ""
});
}
}
}