1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package Torello.Browser;

import static Torello.Java.C.BYELLOW;
import static Torello.Java.C.RESET;

import Torello.HTML.Scrape;
import Torello.JSON.RJArrIntoStream;

import java.util.stream.Stream;
import java.net.URL;
import java.net.MalformedURLException;
import java.io.StringReader;
import javax.json.Json;
import javax.json.JsonArray;

// ================================================================================================
// PCBuilder.java
// ================================================================================================
// This internal-use-only builder class is responsible for retrieving the list of open pages
// (i.e., Chrome Tabs) from a running Chrome browser instance that was started with the
// `--remote-debugging-port=9222` flag.
//
// It communicates with the `/json/list` endpoint exposed by Chrome, which returns a JSON array
// of metadata objects — each describing an open tab or page in the current browser session.
//
// The sole method in this class:
//     getAllPageConn(Integer port, boolean quiet)
// performs the following:
// 
//   1. Connects to Chrome's /json/list URL on localhost, port 9222 (or another port if specified)
//   2. Downloads the resulting JSON array string via a utility scraper
//   3. Parses that string into a `JsonArray`
//   4. Uses a functional-constructor pattern to build one `PageConn` instance per entry
//   5. Returns a Java Stream<PageConn> — one for each open tab
//
// As with `BCBuilder`, this class is not part of the public API. It exists solely to isolate
// and encapsulate the network communication, JSON parsing, and error handling logic involved in
// constructing `PageConn` instances.
//
// --------------------------------------------------------------------------------
// DEVELOPER NOTES (Written by a Real Human):
//
// - This class is structured to cleanly separate out all possible failure cases that might
//   occur when connecting to the remote browser and interpreting the response.
//
// - All failure modes (bad URL, connection issues, malformed JSON, conversion failure)
//   are isolated in separate try-catch blocks, each with an intentional and instructive error
//   message for easier debugging.
//
// - If you want to know what could go wrong in this process, just read through the catch blocks.
// ================================================================================================
// 
// Above Crapola was written by Chat-GPT on August 5th, 2025.  It looks great, so I'm going to 
// leave it alone!  Hope it makes sense!  It was written by "A.I."  (A.I. brings the fun back into
// writing software... sort of...)
// 
// IMPORTANT NOTE:
//      The part where it says "Written by a Real Human" - it is lying to you!  Chat-GPT also wrote
//      that chunk-o-stuff too.  It is trying to copy the notes that I wrote for "BCBuilder" -
//      where I added an addendum, mentioning that a human wrote all of the stuff at the end.

class PCBuilder
{
    static Stream<PageConn> getAllPageConn(Integer port, final boolean quiet)
    {
        if (port == null) port = 9222;

        final String    urlStr = "http://127.0.0.1:" + port + "/json/list";
        final URL       url;

        try 
            { url = new URL(urlStr); }

        catch (MalformedURLException e)
        {
            throw new RDPException(
                "An Internal-Error has occurred.  Unable to instantiate URL.\n" +
                "    URL: " + urlStr + "\n" +
                "    Exception: " + e.getClass().getSimpleName() + " - " + e.getMessage() + '\n' +
                "Please see cause-exception for details.",
                e
            );
        }

        if (! quiet) System.out.println(
            "\nQuerying Page-Level WebSocket URL:\n\t" +
            BYELLOW + urlStr + RESET
        );

        final String json;

        try 
            { json = Scrape.scrapePage(url); }

        catch (Exception e)
        {
            // Wordng Generated by Chat-GPT
            throw new RDPException(
                "Problem while Querying Page-Level WebSocket URL:\n" +
                "    URL: " + url + "\n" +
                "    Exception: " + e.getClass().getSimpleName() + " - " + e.getMessage() + '\n' +
                "Please See Cause-Exception for Details.",
                e
            );
        }

        final StringReader sr = new StringReader(json);

        if (! quiet) System.out.println("Page-Level JSON Response:\n" + json);

        final JsonArray jArr;

        try
            { jArr = Json.createReader(sr).readArray(); }

        catch (Exception e)
        {
            throw new RDPException(
                "Play it again, Sam. Failed to parse JSON array from Chrome's response:\n" +
                "    Source: java.io.StringReader\n" +
                "    Exception: " + e.getClass().getSimpleName() + " - " + e.getMessage() + '\n' +
                "Please See Cause-Exception for Details.",
                e
            );
        }

        if (jArr == null) throw new RDPException
            ("Null JsonArray was extracted while querying the browser's list-pages endpoint.");

        try 
        {
            return RJArrIntoStream.objArr(
                jArr,           // Input Json-Array
                null,           // Default-Value,
                0,              // JFlags
                PageConn::new,  // Object-Builder, Function<JsonObject,​ BRDPC.PageConn>
                PageConn.class  // Strean-Contents Class / Type
            );
        }

        catch (Exception e)
        {
            throw new RDPException(
                "Failed to convert JsonArray into Stream<BRDPC.PageConn>:\n" +
                "    Exception: " + e.getClass().getSimpleName() + " - " + e.getMessage() + '\n' +
                "Please see cause-exception for full stack trace.",
                e
            );
        }
    }
}