001package Torello.Browser;
002
003import Torello.Java.StringParse;
004
005import Torello.Java.Additional.AppendableSafe;
006
007import java.io.StringReader;
008import java.util.concurrent.ConcurrentHashMap;
009import java.util.function.Consumer;
010
011import javax.json.JsonObject;
012import javax.json.Json;
013
014import static Torello.Java.C.BCYAN_BKGND;
015import static Torello.Java.C.BCYAN;
016import static Torello.Java.C.BBLACK;
017import static Torello.Java.C.RESET;
018
019
020// ************************************************************************************************
021// ************************************************************************************************
022// Chat-GPT wrote the summary below: July 20th, 2025 - VERY ACCURATE!
023// ************************************************************************************************
024// ************************************************************************************************
025// 
026// 
027// Package-private class that serves as the main dispatcher for all incoming WebSocket messages
028// received from the browser. It determines whether each message is a response to a prior command,
029// a CDP event, or something else (like a malformed payload), and routes it appropriately.
030//
031// This class is the central entry point for JSON message handling logic. Depending on the shape of
032// the incoming JSON, it will forward the object to either HandleScriptResponse, HandleEvent, or 
033// log an error if the message is unrecognized.
034// 
035// 
036// ************************************************************************************************
037// ************************************************************************************************
038// My Points (after reading the above computer generated explanation)
039// ************************************************************************************************
040// ************************************************************************************************
041// 
042// class WebSocketSender is used as the "Connection Class" to the NeoVisionaries WebSocket Driver
043// Whenever NeoVisionaries has a "payload" or "message" to pass back to our code, it will be:
044// 
045//  * A "Command Response Message" with a "Response ID" that is tied to a previous Command
046// 
047//  * An "Event Message" that does not have a "Response ID" - but just (sort of) "Happened" inside
048//    of the Web-Browser and is being returned to us.
049// 
050// For either type of Message, the NeoVisionaries.WebSocket will invoke our WebSocketSender class
051// with a response message, and that class calls THIS CLASS to do analyze the Message, and decide
052// whether to invoke:
053// 
054// * HandleScriptResponse.java
055// * HandleEvent.java
056
057/**
058 * Top level dispatch handler for all messages received from the browser, via websocket.
059 */
060@Torello.JavaDoc.Annotations.StaticFunctional
061@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID="INTERNAL_USE_JDHBI")
062public class HandleDispatch 
063{
064    private HandleDispatch() { }
065
066    private static final String CTITLE =
067        BCYAN_BKGND + BBLACK + StringParse.rightSpacePad(" [Class HandleDispatch]", 30) + RESET;
068
069
070    // Top-Level Handler
071    // The Browser has sent a message about a particular Send-Request.  Report this response
072    // to the promise.
073
074    static void handle(
075            final String        message,
076            final ConnRecord    connRec,
077
078            @SuppressWarnings("rawtypes")
079            final ConcurrentHashMap<Integer, Promise> promises
080        )
081    {
082        final JsonObject jo = Json
083            .createReader(new StringReader(message))
084            .readObject();
085
086        final int       idReceived  = jo.getInt("id", -1);
087        final String    method      = jo.getString("method", null);
088
089        final String msg = 
090            CTITLE +
091            BCYAN + " Received Browser Message:\n" + RESET +
092            PrintUtil.json2(jo) + '\n';
093
094        connRec.app(msg);
095
096
097        // If the WebSocket Message had an ID, then that ID should map to one of the Promises
098        // stored in the TreeMap.
099        // 
100        // The '-1' is the "Default Value" that is assigned, above, in the JsonObjet.getInt
101        // Method.
102
103
104        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
105        // CASE: Command-Response Message
106        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
107
108        if (idReceived != -1)
109        {
110            final Promise<?> promise = promises.remove(idReceived);
111
112            if (promise == null)
113            {
114                final String errMsg = 
115                    "ID Received: [" + idReceived + "], is unknown, or already handled.\n" +
116                    "There was no 'Promise' Instance matching this ID.";
117
118                PrintUtil.ERR(CTITLE, connRec, errMsg, jo);
119                connRec.acceptRDPError(new RDPError(errMsg, jo));
120                return;
121            }
122
123            else HandleScriptResponse.handle(idReceived, promise, jo, connRec);
124        }
125
126
127        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
128        // CASE: Browser-Event Message
129        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
130
131        else if (method != null)
132            HandleEvent.handle(jo, method /* this is the 'eventName' */, connRec);
133
134
135        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
136        // CASE: Ooops / Unknown - Neither a "Command Response" nor an "Event" Message
137        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
138
139        else
140        {
141            final String errMsg = "Unrecognized Browser Message Received";
142            PrintUtil.ERR(CTITLE, connRec, errMsg, jo);
143            connRec.acceptRDPError(new RDPError(errMsg, jo));
144            return;
145        }
146    }
147}