001package Torello.Browser;
002
003import static Torello.Java.C.BRED;
004import static Torello.Java.C.BCYAN;
005import static Torello.Java.C.RESET;
006
007import Torello.Browser.BrowserAPI.Network;
008import Torello.Browser.BrowserAPI.Page;
009import Torello.Browser.BrowserAPI.Target;
010
011import Torello.Java.StrIndent;
012
013import java.util.ArrayList;
014import java.util.Base64;
015import java.util.List;
016
017import java.nio.file.Files;
018import java.nio.file.Paths;
019
020/**
021 * Demonstrates several CDP browser features without using JavaScript evaluation.
022 * <EMBED CLASS='external-html' DATA-FILE-ID=EX03_EXAMPLE>
023 */
024public class Example03
025{
026    private Example03() { }
027
028    /** The URL used for demonstrating Network, Page, Screenshot, PDF and Cookie commands. */
029    protected static final String chineseURL =
030        "https://zh.wikipedia.org/wiki/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD";
031
032    /** The files generated by this example. */
033    protected static final String screenshotFile = "Example03-Screenshot.png";
034    protected static final String pdfFile        = "Example03-Page.pdf";
035
036    private static ConnRecord connRec = new ConnRecord();
037
038    static 
039    {
040        connRec.setEventHandler(Example03::eventHandler);
041        connRec.setRawTextReceiver(System.out);
042        connRec.setErrTextReceiver(System.out);
043    }
044
045
046
047    // ********************************************************************************************
048    // ********************************************************************************************
049    // Printing Helpers
050    // ********************************************************************************************
051    // ********************************************************************************************
052
053
054    /** Network URLs collected by the page-level handler. */
055    protected static final List<String> networkURLs = new ArrayList<>();
056
057    /** Page-level handler; this is where Network events become useful. */
058    static void eventHandler(BrowserEvent<?> be)
059    {
060        if (be instanceof Network.requestWillBeSent)
061        {
062            final Network.requestWillBeSent r = (Network.requestWillBeSent) be;
063
064            networkURLs.add(r.request.url);
065
066            System.out.println(
067                '\n' + BCYAN + "Example03.java: " + RESET +
068                BRED + "Network.requestWillBeSent" + RESET + '\n' +
069                "    " + r.request.method + " " + r.request.url
070            );
071        }
072
073        else if (be instanceof Network.responseReceived)
074        {
075            final Network.responseReceived r = (Network.responseReceived) be;
076
077            System.out.println(
078                '\n' + BCYAN + "Example03.java: " + RESET +
079                BRED + "Network.responseReceived" + RESET + '\n' +
080                "    " + r.response.status + " " + r.response.mimeType + '\n' +
081                "    " + r.response.url
082            );
083        }
084
085        else if (be instanceof Network.loadingFinished)
086        {
087            final Network.loadingFinished r = (Network.loadingFinished) be;
088
089            System.out.println(
090                '\n' + BCYAN + "Example03.java: " + RESET +
091                BRED + "Network.loadingFinished" + RESET + '\n' +
092                "    requestId: " + r.requestId + '\n' +
093                "    bytes:     " + r.encodedDataLength
094            );
095        }
096    };
097
098
099    // ********************************************************************************************
100    // ********************************************************************************************
101    // MAIN METHOD
102    // ********************************************************************************************
103    // ********************************************************************************************
104
105
106    /** This class is intended to be invoked from the Command Line. */
107    public static void main(String[] argv) throws Exception
108    {
109        STEP_01_initializeBrowserAndPage();
110
111        try
112        {
113            STEP_02_enablePageAndNetwork(connRec.pws);
114
115            STEP_03_navigateAndCollectNetworkTraffic(connRec.pws);
116
117            STEP_04_captureScreenshot(connRec.pws);
118
119            STEP_05_printToPDF(connRec.pws);
120
121            STEP_06_printCookies(connRec.pws);
122        }
123
124        finally
125        {
126            connRec.bws.disconnect();
127            connRec.pws.disconnect();
128        }
129    }
130
131
132    // ********************************************************************************************
133    // ********************************************************************************************
134    // The Steps
135    // ********************************************************************************************
136    // ********************************************************************************************
137
138
139    /** Open Chrome, close old tabs, create a new tab, and return both WebSocket senders. */
140    protected static void STEP_01_initializeBrowserAndPage() throws Exception
141    {
142        Printing.notice("Initialize BrowserConn, PageConn and WebSocketSender");
143
144        final BrowserConn browserConn = BrowserConn.getBrowserConn(9222, false);
145
146        System.out.println(
147            '\n' + BCYAN + "Example03.java: " + RESET +
148            BRED + "Opened Browser Connection:\n" + RESET + browserConn.toString()
149        );
150
151        final WebSocketSender bws = browserConn.createSender(connRec);
152
153        final Target.TargetInfo[] allTabs = Target
154            .getTargets(null /* FilterEntry[] */)
155            .exec(bws)
156            .await();
157
158        for (int i = 0; i < allTabs.length; i++)
159            if ("page".equals(allTabs[i].type))
160                Target.closeTarget(allTabs[i].targetId).exec(bws).await();
161
162        final String targetID = Target
163            .createTarget()
164            .accept("url", "about:blank")
165            .build()
166            .exec(bws)
167            .await();
168
169        final PageConn pageConn = PageConn
170            .getAllPageConn(9222, false)
171            .filter((PageConn pc) -> pc.id.equals(targetID))
172            .findFirst()
173            .orElseThrow(() -> new RuntimeException("The Page-Connection was Not Found"));
174
175        System.out.println(
176            '\n' + BCYAN + "Example03.java: " + RESET +
177            BRED + "Opened Page Connection:\n" + RESET + pageConn.toString()
178        );
179
180        final WebSocketSender pws = pageConn.createSender(connRec);
181
182        Thread.sleep(1000);
183
184        connRec.bws = bws;
185        connRec.pws = pws;
186    }
187
188    /** Enables the two CDP domains used throughout this example. */
189    protected static void STEP_02_enablePageAndNetwork(final WebSocketSender pws) throws Exception
190    {
191        Printing.notice("Enable Page and Network Domains");
192
193        System.out.println('\n' + BCYAN + "Example03.java: " + RESET + "Page.enable()");
194        Page.enable(null /* enableFileChooserOpenedEvent */).exec(connRec.pws).await();
195
196        System.out.println('\n' + BCYAN + "Example03.java: " + RESET + "Network.enable()");
197        Network
198            .enable(
199                null,   // maxTotalBufferSize
200                null,   // maxResourceBufferSize
201                null,   // maxPostDataSize,
202                null    // reportDirectSocketTraffic
203            )
204            .exec(connRec.pws)
205            .await();
206    }
207
208    /** Navigate to the target page and allow Network events to arrive through the handler. */
209    protected static void STEP_03_navigateAndCollectNetworkTraffic(final WebSocketSender pws)
210        throws Exception
211    {
212        Printing.notice("Navigate and Collect Network Traffic");
213
214        System.out.println(
215            '\n' + BCYAN + "Example03.java: " + RESET +
216            "Navigating To: " + chineseURL
217        );
218
219        Page
220            .navigate()
221            .accept("url", chineseURL)
222            .build()
223            .exec(connRec.pws)
224            .await();
225
226        Thread.sleep(5000);
227
228        System.out.println(
229            '\n' + BCYAN + "Example03.java: " + RESET +
230            BRED + "Total Network Request URL's Collected: " + RESET +
231            networkURLs.size()
232        );
233
234        for (int i = 0; i < networkURLs.size(); i++)
235            System.out.println("    " + networkURLs.get(i));
236    }
237
238    /** Capture the rendered browser page as a PNG file. */
239    protected static void STEP_04_captureScreenshot(final WebSocketSender pws) throws Exception
240    {
241        Printing.notice("Capture a PNG Screenshot");
242
243        final String pngBase64 = Page
244            .captureScreenshot()
245            .accept("format", "png")
246            .accept("fromSurface", true)
247            .build()
248            .exec(connRec.pws)
249            .await();
250
251        Files.write(Paths.get(screenshotFile), Base64.getDecoder().decode(pngBase64));
252
253        System.out.println(
254            '\n' + BCYAN + "Example03.java: " + RESET +
255            BRED + "Wrote Screenshot File: " + RESET + screenshotFile
256        );
257    }
258
259    /** Print the rendered browser page to a PDF file. */
260    protected static void STEP_05_printToPDF(final WebSocketSender pws) throws Exception
261    {
262        Printing.notice("Print the Page to a PDF File");
263
264        final Page.printToPDF$$RET pdf = Page
265            .printToPDF()
266            .accept("printBackground", true)
267            .build()
268            .exec(connRec.pws)
269            .await();
270
271        Files.write(Paths.get(pdfFile), Base64.getDecoder().decode(pdf.data));
272
273        System.out.println(
274            '\n' + BCYAN + "Example03.java: " + RESET +
275            BRED + "Wrote PDF File: " + RESET + pdfFile
276        );
277    }
278
279    /** Print the cookies visible to Chrome for the current page. */
280    protected static void STEP_06_printCookies(final WebSocketSender pws) throws Exception
281    {
282        Printing.notice("Read Browser Cookies for the Current Page");
283
284        final Network.Cookie[] cookies = Network
285            .getCookies(null /* String[] urls */)
286            .exec(connRec.pws)
287            .await();
288
289        System.out.println(
290            '\n' + BCYAN + "Example03.java: " + RESET +
291            BRED + "Cookies Returned: " + RESET + cookies.length
292        );
293
294        for (int i = 0; i < cookies.length; i++)
295            System.out.println(StrIndent.indent(cookies[i].toString(), 4));
296    }
297}