import { IncomingResponseMessage, OutgoingRequestMessage } from "../messages"; import { Transport } from "../transport"; import { Transaction } from "./transaction"; import { TransactionState } from "./transaction-state"; import { ClientTransactionUser } from "./transaction-user"; /** * Client Transaction. * @remarks * The client transaction provides its functionality through the * maintenance of a state machine. * * The TU communicates with the client transaction through a simple * interface. When the TU wishes to initiate a new transaction, it * creates a client transaction and passes it the SIP request to send * and an IP address, port, and transport to which to send it. The * client transaction begins execution of its state machine. Valid * responses are passed up to the TU from the client transaction. * https://tools.ietf.org/html/rfc3261#section-17.1 * @public */ export abstract class ClientTransaction extends Transaction { private static makeId(request: OutgoingRequestMessage): string { if (request.method === "CANCEL") { if (!request.branch) { throw new Error("Outgoing CANCEL request without a branch."); } return request.branch; } else { return "z9hG4bK" + Math.floor(Math.random() * 10000000); } } protected constructor( private _request: OutgoingRequestMessage, transport: Transport, protected user: ClientTransactionUser, state: TransactionState, loggerCategory: string, ) { super( transport, user, ClientTransaction.makeId(_request), state, loggerCategory ); // The Via header field indicates the transport used for the transaction // and identifies the location where the response is to be sent. A Via // header field value is added only after the transport that will be // used to reach the next hop has been selected (which may involve the // usage of the procedures in [4]). // https://tools.ietf.org/html/rfc3261#section-8.1.1.7 _request.setViaHeader(this.id, transport.protocol); } /** The outgoing request the transaction handling. */ get request(): OutgoingRequestMessage { return this._request; } /** * Receive incoming responses from the transport which match this transaction. * Responses will be delivered to the transaction user as necessary. * @param response - The incoming response. */ public abstract receiveResponse(response: IncomingResponseMessage): void; /** * A 408 to non-INVITE will always arrive too late to be useful ([3]), * The client already has full knowledge of the timeout. The only * information this message would convey is whether or not the server * believed the transaction timed out. However, with the current design * of the NIT, a client cannot do anything with this knowledge. Thus, * the 408 is simply wasting network resources and contributes to the * response bombardment illustrated in [3]. * https://tools.ietf.org/html/rfc4320#section-4.1 */ protected onRequestTimeout(): void { if (this.user.onRequestTimeout) { this.user.onRequestTimeout(); } } }