ews-javascript-api icon indicating copy to clipboard operation
ews-javascript-api copied to clipboard

Connection.isOpen returns false after timeout for the first connection, but always returns true for other connections resulting in no detection for OnDisconnect event for the rest connections.

Open KeaganFerrao1998 opened this issue 4 years ago • 2 comments
trafficstars

const { WellKnownFolderName,
    Mailbox,
    FolderId,
    EventType,
    StreamingSubscriptionConnection,
    ExchangeService,
    WebCredentials,
    ExchangeVersion,
    Uri } = require("ews-javascript-api");
const { getMeetings } = require("../controllers/EWSController");

const streamConnections = [];

const setUpdateListner = async (credentials, resource_url, socket, io) => {
    console.log(`Setting update listner for EWS Stream notifications, Resource: ${resource_url}`)

    var isManualClose = false;
    var mailbox = new Mailbox(resource_url);
    var calenderFolderID = new FolderId(WellKnownFolderName.Calendar, mailbox);

    var service = new ExchangeService(ExchangeVersion.Exchange2010_SP1);
    service.Credentials = new WebCredentials(credentials.username, credentials.password);
    service.Url = new Uri(credentials.ews_url);

    try {
        let streamingSubscription = await service.SubscribeToStreamingNotifications(
            [calenderFolderID],
            EventType.Created,
            EventType.Deleted,
            EventType.Modified,
            EventType.FreeBusyChanged
        )
        let connection = new StreamingSubscriptionConnection(service, 30);

        streamConnections.push({
            socket,
            connection,
            streamingSubscription
        })

        connection.AddSubscription(streamingSubscription);

        //Send data once at startup.
        getMeetings(resource_url).then(data => io.to(socket.id).emit("calenderUpdate", data))

        connection.OnNotificationEvent.push(async (o, a) => {
            console.log(` --------------------------- Notification received for : ${resource_url} ---------------------------------`);

            let data = await getMeetings(resource_url);
            //TODO: Send Data here to clients subscribed to socket
        });

        connection.OnDisconnect.push((sender, subscriptionErrorEventArgsInstance) => {
            console.log(`subscribeStreamNotification: Disconnected for ${resource_url}`);      
console.log(`subscribeStreamNotification: Disconnected for ${resource_url}`);

        // If the connection was closed manually by the programmer, do not open the connection again. 
        if (isManualClose === false) {
            try {
                sender.Open();
                console.log(`subscribeStreamNotification: Connected for ${resource_url}`);
            }
            catch (error) {
                console.log("Connection already Open.", error)
            }
        }
        })

        connection.OnSubscriptionError.push((a,o) => {
            console.error(`subscribeStreamNotification: Subscription Error Occured for ${resource_url}`, o.Exception.Message);
        })

        connection.Open();

        socket.on("disconnect", async () => {
            console.log(`Socket connection for resource --${resource_url}-- is disconnected, SocketID: ${socket.id}`);
            try {
                isManualClose = true;
                connection.Close();
                console.log("Stream Connection Closed.");
            }
            catch (error) {
                console.log(`Connection ${socket.id} already closed.`)
            }

            connection.RemoveSubscription(streamingSubscription);
            await streamingSubscription.Unsubscribe();
            console.log("Stream Subscription removed.");

            connection.Dispose();
            console.log("Stream connection disposed.");
        })

        //Check connection status every status
        setInterval(() => {
            console.log(connection.IsOpen + " for " + resource_url)
        }, 10000);
    }
    catch (error) {
        console.log(`Error in try block for ${resource_url}`, error)
    }
}

module.exports = {
    setUpdateListner,
    streamConnections
}

Code Explanation: - Here "setUpdateListner" function is called on every socket connection made by different client side applications, each using different mailboxes and data is sent to clients on notification event for their specific calendar events. After the timeout of 30 mins, the connection is opened again for each client and the process continues.

ISSUE: "setInterval" is used to check the connection status of each separate connection made. It prints TRUE for all connections until the timeout of 30 mins. After 30 mins it should ideally print FALSE for all the different connections made by clients. BUT, it prints FALSE only for the first connection made by client to the server, and for all the rest connections, "connection.IsOpen" always prints TRUE, resulting in the ONDICONNECT event not triggering and connection not reconnecting for the rest.

KeaganFerrao1998 avatar Sep 04 '21 12:09 KeaganFerrao1998

are you able to debug further and point out which code block may be problematic? a PR may be helpful.

gautamsi avatar Sep 05 '21 08:09 gautamsi

connection.OnDisconnect.push((sender, subscriptionErrorEventArgsInstance) => { console.log(subscribeStreamNotification: Disconnected for ${resource_url});
console.log(subscribeStreamNotification: Disconnected for ${resource_url});

    // If the connection was closed manually by the programmer, do not open the connection again. 
    if (isManualClose === false) {
        try {
            sender.Open();
            console.log(`subscribeStreamNotification: Connected for ${resource_url}`);
        }
        catch (error) {
            console.log("Connection already Open.", error)
        }
    }
    })

The connection.OnDisconnect is only triggered for the first connection I make, and not for the rest. I printed the connection status for each connection and found that the other connections don't show a FASLE value for connection.IsOpen property, only the first connection I make does. It is always TRUE hence OnDisconnect not trigerring

setInterval(() => { console.log(connection.IsOpen + " for " + resource_url) }, 10000);

KeaganFerrao1998 avatar Sep 05 '21 08:09 KeaganFerrao1998