Search in sources :

Example 1 with StatusSession

use of qz.printer.status.StatusSession in project tray by qzind.

the class PrintSocketClient method processMessage.

/**
 * Determine which method was called from web API
 *
 * @param session WebSocket session
 * @param json    JSON received from web API
 */
private void processMessage(Session session, JSONObject json, SocketConnection connection, RequestState request) throws JSONException, SerialPortException, DeviceException, IOException, ListenerNotFoundException {
    String UID = json.optString("uid");
    SocketMethod call = SocketMethod.findFromCall(json.optString("call"));
    JSONObject params = json.optJSONObject("params");
    if (params == null) {
        params = new JSONObject();
    }
    if (call == SocketMethod.INVALID && (UID == null || UID.isEmpty())) {
        // incorrect message format, likely incompatible qz version
        session.close(4003, "Connected to incompatible " + Constants.ABOUT_TITLE + " version");
        return;
    }
    String prompt = call.getDialogPrompt();
    if (call == SocketMethod.PRINT) {
        // special formatting for print dialogs
        JSONObject pr = params.optJSONObject("printer");
        if (pr != null) {
            prompt = String.format(prompt, pr.optString("name", pr.optString("file", pr.optString("host", "an undefined location"))));
        } else {
            sendError(session, UID, "A printer must be specified before printing");
            return;
        }
    }
    if (call.isDialogShown() && !allowedFromDialog(request, prompt, findDialogPosition(session, json.optJSONObject("position")))) {
        sendError(session, UID, "Request blocked");
        return;
    }
    if (call != SocketMethod.GET_VERSION) {
        trayManager.voidIdleActions();
    }
    // used in usb calls
    DeviceOptions dOpts = new DeviceOptions(params, DeviceOptions.DeviceMode.parse(call.getCallName()));
    // call appropriate methods
    switch(call) {
        case PRINTERS_GET_DEFAULT:
            sendResult(session, UID, PrintServiceLookup.lookupDefaultPrintService() == null ? null : PrintServiceLookup.lookupDefaultPrintService().getName());
            break;
        case PRINTERS_FIND:
            if (params.has("query")) {
                String name = PrintServiceMatcher.findPrinterName(params.getString("query"));
                if (name != null) {
                    sendResult(session, UID, name);
                } else {
                    sendError(session, UID, "Specified printer could not be found.");
                }
            } else {
                JSONArray services = PrintServiceMatcher.getPrintersJSON();
                JSONArray names = new JSONArray();
                for (int i = 0; i < services.length(); i++) {
                    names.put(services.getJSONObject(i).getString("name"));
                }
                sendResult(session, UID, names);
            }
            break;
        case PRINTERS_DETAIL:
            sendResult(session, UID, PrintServiceMatcher.getPrintersJSON());
            break;
        case PRINTERS_START_LISTENING:
            if (!connection.hasStatusListener()) {
                connection.startStatusListener(new StatusSession(session));
            }
            StatusMonitor.startListening(connection, params.getJSONArray("printerNames"));
            sendResult(session, UID, null);
            break;
        case PRINTERS_GET_STATUS:
            if (connection.hasStatusListener()) {
                StatusMonitor.sendStatuses(connection);
            } else {
                sendError(session, UID, "No printer listeners started for this client.");
            }
            sendResult(session, UID, null);
            break;
        case PRINTERS_STOP_LISTENING:
            if (connection.hasStatusListener()) {
                connection.stopStatusListener();
            }
            sendResult(session, UID, null);
            break;
        case PRINT:
            PrintingUtilities.processPrintRequest(session, UID, params);
            break;
        case SERIAL_FIND_PORTS:
            sendResult(session, UID, SerialUtilities.getSerialPortsJSON());
            break;
        case SERIAL_OPEN_PORT:
            SerialUtilities.setupSerialPort(session, UID, connection, params);
            break;
        case SERIAL_SEND_DATA:
            {
                SerialOptions opts = null;
                // properties param is deprecated legacy here and will be overridden by options if provided
                if (!params.isNull("properties")) {
                    opts = new SerialOptions(params.optJSONObject("properties"), false);
                }
                if (!params.isNull("options")) {
                    opts = new SerialOptions(params.optJSONObject("options"), false);
                }
                SerialIO serial = connection.getSerialPort(params.optString("port"));
                if (serial != null) {
                    serial.sendData(params, opts);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("Serial port [%s] must be opened first.", params.optString("port")));
                }
                break;
            }
        case SERIAL_CLOSE_PORT:
            {
                SerialIO serial = connection.getSerialPort(params.optString("port"));
                if (serial != null) {
                    serial.close();
                    connection.removeSerialPort(params.optString("port"));
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("Serial port [%s] is not open.", params.optString("port")));
                }
                break;
            }
        case SOCKET_OPEN_PORT:
            SocketUtilities.setupSocket(session, UID, connection, params);
            break;
        case SOCKET_SEND_DATA:
            {
                String location = String.format("%s:%s", params.optString("host"), params.optInt("port"));
                SocketIO socket = connection.getNetworkSocket(location);
                if (socket != null) {
                    socket.sendData(params);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("Socket [%s] is not open.", location));
                }
                break;
            }
        case SOCKET_CLOSE_PORT:
            {
                String location = String.format("%s:%s", params.optString("host"), params.optInt("port"));
                SocketIO socket = connection.getNetworkSocket(location);
                if (socket != null) {
                    socket.close();
                    connection.removeNetworkSocket(location);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("Socket [%s] is not open.", location));
                }
                break;
            }
        case USB_LIST_DEVICES:
            sendResult(session, UID, UsbUtilities.getUsbDevicesJSON(params.getBoolean("includeHubs")));
            break;
        case USB_LIST_INTERFACES:
            sendResult(session, UID, UsbUtilities.getDeviceInterfacesJSON(dOpts));
            break;
        case USB_LIST_ENDPOINTS:
            sendResult(session, UID, UsbUtilities.getInterfaceEndpointsJSON(dOpts));
            break;
        case HID_LIST_DEVICES:
            if (SystemUtilities.isWindows()) {
                sendResult(session, UID, PJHA_HidUtilities.getHidDevicesJSON());
            } else {
                sendResult(session, UID, H4J_HidUtilities.getHidDevicesJSON());
            }
            break;
        case HID_START_LISTENING:
            if (!connection.isDeviceListening()) {
                if (SystemUtilities.isWindows()) {
                    connection.startDeviceListening(new PJHA_HidListener(session));
                } else {
                    connection.startDeviceListening(new H4J_HidListener(session));
                }
                sendResult(session, UID, null);
            } else {
                sendError(session, UID, "Already listening HID device events");
            }
            break;
        case HID_STOP_LISTENING:
            if (connection.isDeviceListening()) {
                connection.stopDeviceListening();
                sendResult(session, UID, null);
            } else {
                sendError(session, UID, "Not already listening HID device events");
            }
            break;
        case USB_CLAIM_DEVICE:
        case HID_CLAIM_DEVICE:
            {
                if (connection.getDevice(dOpts) == null) {
                    DeviceIO device;
                    if (call == SocketMethod.USB_CLAIM_DEVICE) {
                        device = new UsbIO(dOpts);
                    } else {
                        if (SystemUtilities.isWindows()) {
                            device = new PJHA_HidIO(dOpts);
                        } else {
                            device = new H4J_HidIO(dOpts);
                        }
                    }
                    if (session.isOpen()) {
                        connection.openDevice(device, dOpts);
                    }
                    if (device.isOpen()) {
                        sendResult(session, UID, null);
                    } else {
                        sendError(session, UID, "Failed to open connection to device");
                    }
                } else {
                    sendError(session, UID, String.format("USB Device [v:%s p:%s] is already claimed.", params.opt("vendorId"), params.opt("productId")));
                }
                break;
            }
        case USB_CLAIMED:
        case HID_CLAIMED:
            {
                sendResult(session, UID, connection.getDevice(dOpts) != null);
                break;
            }
        case USB_SEND_DATA:
        case HID_SEND_FEATURE_REPORT:
        case HID_SEND_DATA:
            {
                DeviceIO usb = connection.getDevice(dOpts);
                if (usb != null) {
                    if (call == SocketMethod.HID_SEND_FEATURE_REPORT) {
                        usb.sendFeatureReport(DeviceUtilities.getDataBytes(params, null), dOpts.getEndpoint());
                    } else {
                        usb.sendData(DeviceUtilities.getDataBytes(params, null), dOpts.getEndpoint());
                    }
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("USB Device [v:%s p:%s] must be claimed first.", params.opt("vendorId"), params.opt("productId")));
                }
                break;
            }
        case USB_READ_DATA:
        case HID_GET_FEATURE_REPORT:
        case HID_READ_DATA:
            {
                DeviceIO usb = connection.getDevice(dOpts);
                if (usb != null) {
                    byte[] response;
                    if (call == SocketMethod.HID_GET_FEATURE_REPORT) {
                        response = usb.getFeatureReport(dOpts.getResponseSize(), dOpts.getEndpoint());
                    } else {
                        response = usb.readData(dOpts.getResponseSize(), dOpts.getEndpoint());
                    }
                    JSONArray hex = new JSONArray();
                    for (byte b : response) {
                        hex.put(UsbUtil.toHexString(b));
                    }
                    sendResult(session, UID, hex);
                } else {
                    sendError(session, UID, String.format("USB Device [v:%s p:%s] must be claimed first.", params.opt("vendorId"), params.opt("productId")));
                }
                break;
            }
        case USB_OPEN_STREAM:
        case HID_OPEN_STREAM:
            {
                StreamEvent.Stream stream = (call == SocketMethod.USB_OPEN_STREAM ? StreamEvent.Stream.USB : StreamEvent.Stream.HID);
                UsbUtilities.setupUsbStream(session, UID, connection, dOpts, stream);
                break;
            }
        case USB_CLOSE_STREAM:
        case HID_CLOSE_STREAM:
            {
                DeviceIO usb = connection.getDevice(dOpts);
                if (usb != null && usb.isStreaming()) {
                    usb.setStreaming(false);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("USB Device [v:%s p:%s] is not streaming data.", params.opt("vendorId"), params.opt("productId")));
                }
                break;
            }
        case USB_RELEASE_DEVICE:
        case HID_RELEASE_DEVICE:
            {
                DeviceIO usb = connection.getDevice(dOpts);
                if (usb != null) {
                    usb.close();
                    connection.removeDevice(dOpts);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, String.format("USB Device [v:%s p:%s] is not claimed.", params.opt("vendorId"), params.opt("productId")));
                }
                break;
            }
        case FILE_START_LISTENING:
            {
                FileParams fileParams = new FileParams(params);
                Path absPath = FileUtilities.getAbsolutePath(params, request, true);
                FileIO fileIO = new FileIO(session, params, fileParams.getPath(), absPath);
                if (connection.getFileListener(absPath) == null && !fileIO.isWatching()) {
                    connection.addFileListener(absPath, fileIO);
                    FileUtilities.setupListener(fileIO);
                    sendResult(session, UID, null);
                } else {
                    sendError(session, UID, "Already listening to path events");
                }
                break;
            }
        case FILE_STOP_LISTENING:
            {
                if (params.isNull("path")) {
                    connection.removeAllFileListeners();
                    sendResult(session, UID, null);
                } else {
                    Path absPath = FileUtilities.getAbsolutePath(params, request, true);
                    FileIO fileIO = connection.getFileListener(absPath);
                    if (fileIO != null) {
                        fileIO.close();
                        FileWatcher.deregisterWatch(fileIO);
                        connection.removeFileListener(absPath);
                        sendResult(session, UID, null);
                    } else {
                        sendError(session, UID, "Not already listening to path events");
                    }
                }
                break;
            }
        case FILE_LIST:
            {
                Path absPath = FileUtilities.getAbsolutePath(params, request, true);
                if (Files.exists(absPath)) {
                    if (Files.isDirectory(absPath)) {
                        ArrayList<String> files = new ArrayList<>();
                        Files.list(absPath).forEach(file -> files.add(file.getFileName().toString()));
                        sendResult(session, UID, new JSONArray(files));
                    } else {
                        log.error("Failed to list '{}' (not a directory)", absPath);
                        sendError(session, UID, "Path is not a directory");
                    }
                } else {
                    log.error("Failed to list '{}' (does not exist)", absPath);
                    sendError(session, UID, "Path does not exist");
                }
                break;
            }
        case FILE_READ:
            {
                Path absPath = FileUtilities.getAbsolutePath(params, request, false);
                if (Files.exists(absPath)) {
                    if (Files.isReadable(absPath)) {
                        sendResult(session, UID, new String(Files.readAllBytes(absPath)));
                    } else {
                        log.error("Failed to read '{}' (not readable)", absPath);
                        sendError(session, UID, "Path is not readable");
                    }
                } else {
                    log.error("Failed to read '{}' (does not exist)", absPath);
                    sendError(session, UID, "Path does not exist");
                }
                break;
            }
        case FILE_WRITE:
            {
                FileParams fileParams = new FileParams(params);
                Path absPath = FileUtilities.getAbsolutePath(params, request, false);
                Files.write(absPath, fileParams.getData(), StandardOpenOption.CREATE, fileParams.getAppendMode());
                FileUtilities.inheritParentPermissions(absPath);
                sendResult(session, UID, null);
                break;
            }
        case FILE_REMOVE:
            {
                Path absPath = FileUtilities.getAbsolutePath(params, request, false);
                if (Files.exists(absPath)) {
                    Files.delete(absPath);
                    sendResult(session, UID, null);
                } else {
                    log.error("Failed to remove '{}' (does not exist)", absPath);
                    sendError(session, UID, "Path does not exist");
                }
                break;
            }
        case NETWORKING_DEVICE_LEGACY:
            JSONObject networkDevice = NetworkUtilities.getDeviceJSON(params);
            JSONObject legacyDevice = new JSONObject();
            legacyDevice.put("ipAddress", networkDevice.optString("ip", null));
            legacyDevice.put("macAddress", networkDevice.optString("mac", null));
            sendResult(session, UID, legacyDevice);
            break;
        case NETWORKING_DEVICE:
            sendResult(session, UID, NetworkUtilities.getDeviceJSON(params));
            break;
        case NETWORKING_DEVICES:
            sendResult(session, UID, NetworkUtilities.getDevicesJSON(params));
            break;
        case GET_VERSION:
            sendResult(session, UID, Constants.VERSION);
            break;
        case WEBSOCKET_STOP:
            log.info("Another instance of {} is asking this to close", Constants.ABOUT_TITLE);
            String challenge = json.optString("challenge", "");
            if (SystemUtilities.validateSaltedChallenge(challenge)) {
                log.info("Challenge validated: {}, honoring shutdown request", challenge);
                session.close(SingleInstanceChecker.REQUEST_INSTANCE_TAKEOVER);
                try {
                    server.stop();
                } catch (Exception ignore) {
                }
                trayManager.exit(0);
            } else {
                log.warn("A valid challenge was not provided: {}, ignoring request to close", challenge);
            }
            break;
        case INVALID:
        default:
            sendError(session, UID, "Invalid function call: " + json.optString("call", "NONE"));
            break;
    }
}
Also used : TrayManager(qz.common.TrayManager) WebSocketException(org.eclipse.jetty.websocket.api.WebSocketException) StatusMonitor(qz.printer.status.StatusMonitor) SerialPortException(jssc.SerialPortException) qz.communication(qz.communication) TimeoutException(java.util.concurrent.TimeoutException) HashMap(java.util.HashMap) java.nio.file(java.nio.file) UsbUtil(javax.usb.util.UsbUtil) ArrayList(java.util.ArrayList) org.eclipse.jetty.websocket.api.annotations(org.eclipse.jetty.websocket.api.annotations) Locale(java.util.Locale) Session(org.eclipse.jetty.websocket.api.Session) Constants(qz.common.Constants) Server(org.eclipse.jetty.server.Server) CloseException(org.eclipse.jetty.websocket.api.CloseException) StatusSession(qz.printer.status.StatusSession) RequestState(qz.auth.RequestState) Semaphore(java.util.concurrent.Semaphore) JSONObject(org.codehaus.jettison.json.JSONObject) JSONArray(org.codehaus.jettison.json.JSONArray) Certificate(qz.auth.Certificate) IOException(java.io.IOException) Reader(java.io.Reader) CertificateException(java.security.cert.CertificateException) EOFException(java.io.EOFException) qz.utils(qz.utils) java.awt(java.awt) IOUtils(org.apache.commons.io.IOUtils) PrintServiceMatcher(qz.printer.PrintServiceMatcher) Logger(org.apache.logging.log4j.Logger) JSONException(org.codehaus.jettison.json.JSONException) ListenerNotFoundException(javax.management.ListenerNotFoundException) PrintServiceLookup(javax.print.PrintServiceLookup) LogManager(org.apache.logging.log4j.LogManager) StatusSession(qz.printer.status.StatusSession) JSONArray(org.codehaus.jettison.json.JSONArray) ArrayList(java.util.ArrayList) WebSocketException(org.eclipse.jetty.websocket.api.WebSocketException) SerialPortException(jssc.SerialPortException) TimeoutException(java.util.concurrent.TimeoutException) CloseException(org.eclipse.jetty.websocket.api.CloseException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException) EOFException(java.io.EOFException) JSONException(org.codehaus.jettison.json.JSONException) ListenerNotFoundException(javax.management.ListenerNotFoundException) JSONObject(org.codehaus.jettison.json.JSONObject)

Aggregations

java.awt (java.awt)1 EOFException (java.io.EOFException)1 IOException (java.io.IOException)1 Reader (java.io.Reader)1 java.nio.file (java.nio.file)1 CertificateException (java.security.cert.CertificateException)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Locale (java.util.Locale)1 Semaphore (java.util.concurrent.Semaphore)1 TimeoutException (java.util.concurrent.TimeoutException)1 ListenerNotFoundException (javax.management.ListenerNotFoundException)1 PrintServiceLookup (javax.print.PrintServiceLookup)1 UsbUtil (javax.usb.util.UsbUtil)1 SerialPortException (jssc.SerialPortException)1 IOUtils (org.apache.commons.io.IOUtils)1 LogManager (org.apache.logging.log4j.LogManager)1 Logger (org.apache.logging.log4j.Logger)1 JSONArray (org.codehaus.jettison.json.JSONArray)1 JSONException (org.codehaus.jettison.json.JSONException)1