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}