Blame | Last modification | View Log | RSS feed
package com.spice.profitmandi.service.lms;import com.spice.profitmandi.dao.entity.auth.AuthUser;import com.spice.profitmandi.dao.entity.user.LeadCall;import com.spice.profitmandi.dao.enumuration.dtr.LeadCallProvider;import java.io.InputStream;/*** The seam between the LMS and whichever telephony vendor actually places the call.** <p>Exists because the two candidate providers work in opposite directions: Vonage's Client SDK* places the call <em>from the browser</em> once we hand it a token, while Knowlarity places it* <em>from the server</em> and rings the agent's handset first. {@link Handshake} is what lets the* LMS front-end treat both the same — it either receives a token to dial with, or is told the call is* already on its way.** <p>Everything else in the LMS (the {@code user.lead_call} history, DND, disposition binding, the* recording gate) is provider-agnostic and sits above this interface, so swapping vendors — which the* India VoIP position may yet force — does not reach into the lead record.*/public interface LmsDialerProvider {/** How a call gets started, from the browser's point of view. */enum Mode {/** Browser dials over WebRTC using {@link Handshake#token}. */WEBRTC,/** Server already placed the call; the agent's own handset will ring. */SERVER_PLACED}/** What the browser needs in order to start, or the reason it cannot. */class Handshake {public final boolean ok;public final Mode mode;/** Client credential for WEBRTC mode; null otherwise. Treat as a secret. */public final String token;/** Vonage application id, or the vendor's equivalent, when the client SDK needs it. */public final String applicationId;public final String reason;private Handshake(boolean ok, Mode mode, String token, String applicationId, String reason) {this.ok = ok;this.mode = mode;this.token = token;this.applicationId = applicationId;this.reason = reason;}public static Handshake webrtc(String token, String applicationId) {return new Handshake(true, Mode.WEBRTC, token, applicationId, null);}public static Handshake serverPlaced() {return new Handshake(true, Mode.SERVER_PLACED, null, null, null);}/** Refuse with a reason the agent can act on — never a bare failure. */public static Handshake refuse(String reason) {return new Handshake(false, null, null, null, reason);}}/*** Place the call server-side. Only meaningful for {@link Mode#SERVER_PLACED} providers — a* WebRTC provider dials from the browser and refuses this.** @return the vendor's call id, stored so state can be polled and the recording found later*/String placeCall(AuthUser agent, String agentEndpoint, String toNumber) throws Exception;LeadCallProvider provider();/** False when credentials are absent, so the UI can hide the dialer rather than fail mid-call. */boolean isConfigured();/** Prepare this agent to place a call. Never throws for an unprovisioned agent — refuses instead. */Handshake prepare(AuthUser agent);/*** Open the vendor's copy of a call recording for archival. The caller owns the stream and must* close it. Returns null when the vendor has no recording for this call.*/InputStream fetchRecording(LeadCall call) throws Exception;/** A recording the vendor holds, before we have copied it anywhere. */class RecordingRef {/** The vendor's recording id, stored on {@code lead_call.recording_uuid}. */public final String id;public final int durationSeconds;public RecordingRef(String id, int durationSeconds) {this.id = id;this.durationSeconds = durationSeconds;}}/*** Find the vendor's recording for a finished call, or null if there is not one (yet).** <p>Needed by providers that place calls server-side: they get no recording webhook, so the only* way a recording is ever attached to a lead is by asking after the fact. The default returns null* for webhook-driven providers, which are told about their recordings and have nothing to look up.*/default RecordingRef findRecording(LeadCall call) {return null;}}