001package Torello.Browser;
002
003import static Torello.Java.C.BYELLOW;
004import static Torello.Java.C.RESET;
005
006import Torello.JSON.ReadJSON;
007import Torello.JavaDoc.Annotations.LinkJavaSource;
008import NeoVisionaries.WebSockets.WebSocketException;
009
010import java.util.Objects;
011import java.io.IOException;
012import javax.json.JsonObject;
013
014
015/**
016 * A Connection to a Browser, rather than an individual Page within the Browser. 
017 * 
018 * <BR /><BR />
019 * Represents a snapshot of metadata returned from Chrome’s
020 * <B STYLE='color:red;'>{@code /json/version}</B> End-Point. This
021 * includes protocol versioning, V8 details, and the root
022 * {@link NeoVisionaries.WebSockets.WebSocket WebSocket} {@code URL} for establishing DevTools
023 * sessions.
024 *
025 * <BR /><BR />
026 * Although this class offers a public constructor, the recommended way to build an instance is via
027 * the {@code static} method: <B>{@link #getBrowserConn getBrowserConn}</B>.  This instance
028 * contains a few informational fields that were scraped from the Json-Response to the above
029 * mentioned Chrome response object.
030 * 
031 * <BR /><BR /><B CLASS=JDDescLabel2>A {@link WebSocketSender} Instance:</B>
032 * 
033 * <BR />
034 * To begin sending CDP commands, it is mandatory to obtain an instance of the
035 * <B>{@link WebSocketSender}</B> class which has been connected to a Web Browser.  This instance
036 * should be passed as the sender to any of the available API methods offered by the Domain Classes
037 * in the packages
038 * <B><CODE><A HREF='BrowserAPI/package-summary.html'>BrowserAPI</A></CODE></B>
039 * and or the classes in
040 * <B><CODE><A HREF='JavaScriptAPI/package-summary.html'>JavaScriptAPI</A></CODE></B>.
041 * You should review the methods exported by each of the domains and classes within those packages,
042 * and note that the <B>{@link Script}</B> objects returned by them expose an
043 * <B>{@link Script#exec(WebSocketSender)}</B> method.
044 * 
045 * <BR /><BR />
046 * Obtaining the <B>{@link WebSocketSender}</B> instance can be achieved by invoking
047 * <B>{@link BrowserConn#createSender(ConnRecord) BrowserConn.createSender}</B>,
048 * a method offered by this class.  This method initializes a <B>{@link WebSocketSender}</B> which
049 * is connected to the associated <B>{@link #webSocketDebuggerUrl}</B>. That sender can be used to
050 * make invocations into all CDP Domains.
051 *
052 * <BR /><BR />
053 * The individual fields exported by this class are documented below, and within their respective
054 * documentation.  This class, itself, is largely a structured data holder with minimal logic.
055 * Mostly, it parses the Json which is returned by the Web-Browser endpoint
056 * <B STYLE='color:red;'>{@code /json/version}</B>.
057 *
058 * <EMBED CLASS='external-html' DATA-FILE-ID=PCBC_CHECKLIST>
059 */
060@Torello.JavaDoc.Annotations.CSSLinks(FileNames="BrowserAndPageConn.css")
061public class BrowserConn implements java.io.Serializable, Comparable<BrowserConn>, Cloneable
062{
063    /** <EMBED CLASS=external-html DATA-FILE-ID=SVUID> */
064    protected static final long serialVersionUID = 1;
065
066
067    // ********************************************************************************************
068    // ********************************************************************************************
069    // PUBLIC FIELDS
070    // ********************************************************************************************
071    // ********************************************************************************************
072
073
074    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_BROWSER> */
075    public final String browser;
076
077    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_PROT_VER> */
078    public final String protocolVersion;
079
080    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_USER_AGENT> */
081    public final String userAgent;
082
083    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_V8_VERSION> */
084    public final String v8Version;
085
086    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_WEBKIT_VER> */
087    public final String webkitVersion;
088
089    /** <EMBED CLASS='external-html' DATA-FILE-ID=BC_WS_DEBUG_URL> */
090    public final String webSocketDebuggerUrl;
091
092
093    // ********************************************************************************************
094    // ********************************************************************************************
095    // Constructors
096    // ********************************************************************************************
097    // ********************************************************************************************
098
099
100    /**
101     * Constructs an instance of this type.
102     * @throws NullPointerException if {@code 'webSocketDebuggerUrl'} is passed null.
103     */
104    public BrowserConn(
105            final String browser,
106            final String protocolVersion,
107            final String userAgent,
108            final String v8Version,
109            final String webkitVersion,
110            final String webSocketDebuggerUrl
111        )
112    {
113        Objects.requireNonNull(webSocketDebuggerUrl, "webSocketDebuggerUrl is null");
114
115        this.browser                = browser;
116        this.protocolVersion        = protocolVersion;
117        this.userAgent              = userAgent;
118        this.v8Version              = v8Version;
119        this.webkitVersion          = webkitVersion;
120        this.webSocketDebuggerUrl   = webSocketDebuggerUrl;
121    }
122
123    /**
124     * <EMBED CLASS='external-html' DATA-FILE-ID=PAGE_CONN>
125     * 
126     * @param jo The exact {@link JsonObject} that was generated by querying the HTTP End-Point
127     * <B STYLE='color:red;'>{@code /json/version}</B>.
128     * 
129     * @see ReadJSON#getString(JsonObject, String, boolean, boolean)
130     */
131    public BrowserConn(final JsonObject jo)
132    {
133        this.browser            = ReadJSON.getString(jo, "Browser",             false,  true);
134        this.protocolVersion    = ReadJSON.getString(jo, "Protocol-Version",    false,  true);
135        this.userAgent          = ReadJSON.getString(jo, "User-Agent",          false,  true);
136        this.v8Version          = ReadJSON.getString(jo, "V8-Version",          true,   false);
137        this.webkitVersion      = ReadJSON.getString(jo, "WebKit-Version",      true,   false);
138
139        this.webSocketDebuggerUrl =
140            ReadJSON.getString(jo, "webSocketDebuggerUrl", false,  true);
141    }
142
143
144    // ********************************************************************************************
145    // ********************************************************************************************
146    // Build Methods
147    // ********************************************************************************************
148    // ********************************************************************************************
149
150
151    /**
152     * Creates a {@link WebSocketSender} connected to the {@link #webSocketDebuggerUrl} for this
153     * tab.  This URL is the endpoint that speaks the Chrome DevTools Protocol (CDP).
154     * 
155     * @param connRec Messaging settings for this connection
156     */
157    public WebSocketSender createSender(final ConnRecord connRec)
158        throws IOException, WebSocketException
159    { return new WebSocketSender(this.webSocketDebuggerUrl, connRec); }
160
161    /**
162     * Retrieves the WebSocketDebugger URL for the main browser instance.
163     * This queries {@code /json/version} and parses the result into an instance.
164     *
165     * @param port  The DevTools port Chrome is listening on (default is 9222 if {@code null}).
166     * @param quiet If {@code false}, debug output is printed to the console.
167     * @return A {@code BrowserConn} instance representing the browser-level connection.
168     */
169    @LinkJavaSource(handle="BCBuilder")
170    public static BrowserConn getBrowserConn(Integer port, boolean quiet)
171    { return BCBuilder.getBrowserConn(port, quiet); }
172
173
174    // ********************************************************************************************
175    // ********************************************************************************************
176    // java.lang.Object Methods
177    // ********************************************************************************************
178    // ********************************************************************************************
179
180
181    @LinkJavaSource(handle="BCHelper", name="toString")
182    public String toString() { return BCHelper.toString(this); }
183
184    @LinkJavaSource(handle="BCHelper", name="hashCode")
185    public int hashCode() { return BCHelper.hashCode(this); }
186
187    @LinkJavaSource(handle="BCHelper", name="equals")
188    public boolean equals(Object o) { return BCHelper.equals(this, o); }
189
190    @LinkJavaSource(handle="BCHelper", name="clone")
191    public BrowserConn clone() { return BCHelper.clone(this); }
192
193    public int compareTo(BrowserConn other)
194    { return this.webSocketDebuggerUrl.compareTo(other.webSocketDebuggerUrl); }
195}