All files / src/Ice ConnectRequestHandler.js

74.07% Statements 100/135
81.81% Branches 18/22
87.5% Functions 7/8
74.07% Lines 100/135

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 13641x 41x 41x 41x 41x 41x 41x 41x 3553x 3553x 3553x 3553x 3553x 3553x 3553x 41x 41x 4788x 3568x 3568x 4788x 4788x 3568x 3568x 3568x 1220x 4788x 41x 41x                             41x 41x 25x 25x 25x 25x 25x 25x       25x 41x 41x 41x 41x 41x 1504x 1504x 1504x 1504x 1504x 1504x 1504x 1504x 8x 8x 8x 8x     8x 8x 1496x 1496x 1496x 1504x 41x 41x 2049x 2049x 2049x 2049x 2049x 2049x 2049x 2049x 2049x 41x 41x 4788x 1220x 1220x 4774x 3568x               3568x 3568x 3568x 3568x 4788x 41x 41x 1504x 1504x 1504x 1519x 1519x 1519x                   1519x 1504x 1504x 1504x 1504x 1504x 1504x 41x  
// Copyright (c) ZeroC, Inc.
 
import { AsyncStatus } from "./AsyncStatus.js";
import { LocalException } from "./LocalException.js";
import { RetryException } from "./RetryException.js";
 
export class ConnectRequestHandler {
    constructor(reference) {
        this._reference = reference;
        this._response = reference.isTwoway;
        this._initialized = false;
        this._connection = null;
        this._exception = null;
        this._requests = [];
    }
 
    sendAsyncRequest(out) {
        if (!this._initialized) {
            out.cancelable(this); // This will throw if the request is canceled
        }
 
        if (!this.initialized()) {
            this._requests.push(out);
            return AsyncStatus.Queued;
        }
        return out.invokeRemote(this._connection, this._response);
    }
 
    asyncRequestCanceled(out, ex) {
        if (this._exception !== null) {
            return; // The request has been notified of a failure already.
        }

        if (!this.initialized()) {
            const i = this._requests.indexOf(out);
            // The request has to be queued if it timed out and we're not initialized yet.
            console.assert(i != -1);
            out.completedEx(ex);
            this._requests.splice(i, 1);
        } else {
            this._connection.asyncRequestCanceled(out, ex);
        }
    }
 
    getConnection() {
        // First check for the connection, it's important otherwise the user could first get a connection
        // and then the exception if he tries to obtain the proxy cached connection multiple times (the
        // exception can be set after the connection is set if the flush of pending requests fails).
        if (this._connection !== null) {
            return this._connection;
        } else if (this._exception !== null) {
            throw this._exception;
        }
        return null;
    }
 
    //
    // Implementation of Reference_GetConnectionCallback
    //
    async setConnection(connection) {
        console.assert(this._exception === null && this._connection === null);
 
        this._connection = connection;
 
        // If this proxy is for a non-local object, and we are using a router, then add this proxy to the router info
        // object.
        const ri = this._reference.getRouterInfo();
        if (ri !== null) {
            try {
                await ri.addProxy(this._reference);
                this.flushRequests();
            } catch (ex) {
                this.setException(ex);
            }
            return; // The request handler will be initialized once addProxy completes.
        }
 
        // We can now send the queued requests.
        this.flushRequests();
    }
 
    setException(ex) {
        console.assert(!this._initialized && this._exception === null);
 
        this._exception = ex;
 
        for (const request of this._requests) {
            request.completedEx(this._exception);
        }
        this._requests.length = 0;
    }
 
    initialized() {
        if (this._initialized) {
            console.assert(this._connection !== null);
            return true;
        } else {
            if (this._exception !== null) {
                if (this._connection !== null) {
                    // Only throw if the connection didn't get established. If it died after being established, we allow
                    // the caller to retry the connection establishment by not throwing here (the connection will throw
                    // RetryException).
                    return true;
                }
                throw this._exception;
            } else {
                return this._initialized;
            }
        }
    }
 
    flushRequests() {
        console.assert(this._connection !== null && !this._initialized);
        let exception = null;
        for (const request of this._requests) {
            try {
                request.invokeRemote(this._connection, this._response);
            } catch (ex) {
                if (ex instanceof RetryException) {
                    exception = ex.inner;
                    request.retryException();
                } else {
                    console.assert(ex instanceof LocalException, ex);
                    exception = ex;
                    request.out.completedEx(ex);
                }
            }
        }
        this._requests.length = 0;
 
        console.assert(!this._initialized);
        this._exception = exception;
        this._initialized = this._exception === null;
    }
}