All files / src/services connection-service.ts

100% Statements 24/24
100% Branches 7/7
100% Functions 10/10
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187          2x                                                                                                                                                                                                                       2x                           10x     9x                       9x 9x     10x   10x 10x 10x 10x     1x     4x     3x 3x 3x 2x   2x   1x   3x     6x     2x         1x   2x        
import { Base64 } from '../utils/base64';
import { Cryptography } from '../utils/cryptography';
import { Logger } from '../utils/logger';
import { Utf8 } from '../utils/utf8';
import { CallService } from './call-service';
import {
    Connection,
    ConnectionInternal,
    ConnectionState,
    getConnection,
    translateConnection,
} from './connection/connection';
import { IceServer } from './connection/ice-server';
import { WebRTC } from './connection/web-rtc';
import { SessionService } from './session-service';
import { TimeService } from './time-service';
 
/**
 * Configuration interface for the connection service.
 * Defines callbacks and configuration options for managing peer connections.
 */
export type ConnectionServiceConfig = {
    /**
     * Callback triggered when a new incoming connection is established.
     * Allows the application to react to peer connection attempts.
     *
     * @param connection - The new incoming connection that was established
     */
    onIncomingConnection?: (connection: Connection) => void;
 
    /**
     * Array of ICE server configurations for WebRTC connections.
     * Used to assist in traversing NATs and establishing peer connections.
     */
    iceServers?: IceServer[];
};
 
/**
 * Extended configuration interface with additional properties for internal use.
 * Includes all properties from ConnectionServiceConfig plus WebRTC dependencies.
 */
type ConnectionServiceEffectiveConfig = ConnectionServiceConfig & {
    /**
     * WebRTC interface implementations.
     */
    webRTC: WebRTC;
};
 
/**
 * Service interface for managing peer-to-peer connections.
 * Provides methods for creating, accessing, and managing WebRTC connections.
 */
export interface ConnectionService {
    /**
     * Initializes the connection service with the provided configuration.
     * Sets up callbacks and default configuration for WebRTC connections.
     *
     * @param config - Configuration with callbacks and WebRTC settings
     */
    initialize(config: ConnectionServiceEffectiveConfig): void;
 
    /**
     * Gets all active connections managed by the service.
     *
     * @returns Array of all connection objects
     */
    get connections(): ConnectionInternal[];
 
    /**
     * Retrieves a connection by the peer's public key.
     *
     * @param publicKey - Public key of the peer to find
     * @returns The connection if found, or undefined if no connection exists
     */
    getConnection(publicKey: string): ConnectionInternal | undefined;
 
    /**
     * Creates a new incoming connection with the specified peer.
     *
     * @param peerSigningPublicKey - Public key of the peer initiating the connection
     * @returns The newly created connection object
     */
    createIncoming(peerSigningPublicKey: string): ConnectionInternal;
 
    /**
     * Creates a new outgoing connection to the specified peer.
     *
     * @param peerSigningPublicKey - Public key of the peer to connect to
     * @returns The newly created connection object
     */
    createOutgoing(peerSigningPublicKey: string): ConnectionInternal;
 
    /**
     * Terminates and removes a connection with the specified peer.
     *
     * @param publicKey - Public key of the peer whose connection should be removed
     */
    deleteConnection(publicKey: string): void;
}
 
/**
 * Factory function that creates and returns an implementation of the ConnectionService interface.
 * Manages the lifecycle of peer-to-peer WebRTC connections.
 *
 * @param logger - Logger instance for error and debugging information
 * @param timeService - Service for managing time synchronization
 * @param callService - Service for making signaling calls
 * @param sessionService - Service for accessing session information
 * @param base64 - Utility for Base64 encoding/decoding
 * @param utf8 - Utility for UTF-8 encoding/decoding
 * @param cryptography - Cryptography service for encryption operations
 * @returns An implementation of the ConnectionService interface
 */
export function getConnectionService(
    logger: Logger,
    timeService: TimeService,
    callService: CallService,
    sessionService: SessionService,
    base64: Base64,
    utf8: Utf8,
    cryptography: Cryptography,
): ConnectionService {
    let onIncomingConnection: ((connection: Connection) => void) | undefined;
    let iceServers: IceServer[] | undefined;
    let webRTC: WebRTC;
    let connections: {
        [publicKey: string]: ConnectionInternal;
    } = {};
 
    function createConnection(publicKey: string): ConnectionInternal {
        const connection = getConnection(
            publicKey,
            logger,
            timeService,
            callService,
            sessionService,
            base64,
            utf8,
            cryptography,
            webRTC,
            iceServers,
        );
        connections[publicKey] = connection;
        return connection;
    }
 
    return {
        initialize(config: ConnectionServiceEffectiveConfig): void {
            onIncomingConnection = config.onIncomingConnection;
            iceServers = config.iceServers;
            webRTC = config.webRTC;
            logger.debug('[connection-service] Initialized.');
        },
        get connections(): ConnectionInternal[] {
            return Object.values(connections);
        },
        getConnection(publicKey: string): ConnectionInternal | undefined {
            return connections[publicKey];
        },
        createIncoming(publicKey: string): ConnectionInternal {
            const connection = createConnection(publicKey);
            new Promise<void>((resolve) => {
                if (onIncomingConnection) {
                    onIncomingConnection(translateConnection(connection));
                }
                resolve();
            }).catch((err) => {
                logger.error('[connection-service] On incoming connection callback error.', err);
            });
            return connection;
        },
        createOutgoing(publicKey: string): ConnectionInternal {
            return createConnection(publicKey);
        },
        deleteConnection(publicKey: string) {
            if (
                connections[publicKey]?.state !== undefined &&
                connections[publicKey]?.state !== null &&
                connections[publicKey].state !== ConnectionState.Closed
            ) {
                connections[publicKey].close();
            }
            delete connections[publicKey];
        },
    };
}