Subversion Repositories SmartDukaan

Rev

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;
    }
}