client.connect(1234, 'localhost', function(err, sock) { console.log("connected " + num); sock.dataHandler(function(buffer) { console.log("received " + received); received++; }); sock.write("X"); num++; if (num < numConns) { vertx.runOnContext(function() { connect(num) }); } });
this._buffer.forEach(function (item) { var str = item[0], callback = item[1]; vertx.runOnContext(function () { self._write(str, callback); if (--msgsToWrite === 0) { // Last of the buffer messages written, when "flush" was called. // In the meantime, more messages might have piled up in the buffer, // so flush these synchronously. self._buffer.forEach(function (item) { var str = item[0], callback = item[1]; self._write(str, callback); }); // Truncate the buffer again self._buffer.length = 0; // Emitting flush triggers a callback, which sets the "opening" flag // to false self.emit('flush'); } }); });
this.nextTick = function(callback, args) { vertx.runOnContext(function() { callback(args); }); };
Mailer.prototype.sendSeq = function (sendData, callback) { var smtpClient; // Underlying SMTP client var mailOpts; // Mail client options var fromAddr; // "from" address as a Java object var toAddrs; // Array of "to" addresses as Java objects var ccAddrs; // Array of "cc" addresses as Java objects var bccAddrs; // Array of "bcc" addresses as Java objects var addressInfo; // Address info for the message var sendError; // Error in the course of the send method var sendResult; // Result of send operation var sendContentSubtype; // MIME subtype for this send request var sendTimeoutTimer; // Timer for send timeouts var self = this; /* * Reusable function to return and error */ function returnError (err) { if (sendTimeoutTimer) { vertx.cancelTimer(sendTimeoutTimer); } if (smtpClient) { try { smtpClient.close(); } catch (ignore) {} smtpClient = undefined; } callback(err); } // END: returnError // =========== // Initialize // =========== // Should be allowed to be called without callback callback = callback || function () {return;}; sendError = null; sendResult = {}; // ================ // Check arguments // ================ if (!sendData) { returnError(new Error('a-mailer.send: Missing send data')); return; } if (!sendData.from) { returnError(new Error('a-mailer.send: Missing "from" field')); return; } if (!sendData.to) { returnError(new Error('a-mailer.send: Missing "to" field')); return; } if (!sendData.subject) { returnError(new Error('a-mailer.send: Missing "subject" field')); return; } sendContentSubtype = this.textContentSubtype; if (sendData.content_type === 'text/html') { sendContentSubtype = 'html'; } else if (sendData.content_type === 'text/plain') { sendContentSubtype = 'plain'; } // ============================ // Check sender and recipients // ============================ try { fromAddr = InternetAddress.parse(sendData.from)[0]; } catch (parseErr) { returnError(new Error('a-mailer.send: Illegal "from" address: ' + parseErr.toString())); return; } try { toAddrs = parseAddresses(sendData.to); if (toAddrs.length === 0) { throw new Error('Missing "to" address'); } } catch (parseErr) { returnError(new Error('a-mailer.send: Illegal "to" address: ' + parseErr.toString())); return; } try { ccAddrs = parseAddresses(sendData.cc || []); } catch (parseErr) { returnError(new Error('a-mailer.send: Illegal "cc" address: ' + parseErr.toString())); return; } try { bccAddrs = parseAddresses(sendData.bcc || []); } catch (parseErr) { returnError(new Error('a-mailer.send: Illegal "bcc" address: ' + parseErr.toString())); return; } // =================== // Set up mail client // =================== if (this._smtpClient) { // We already have a client if (!this._isIdle) { // If not idle, "sendSeq" was called before its callback // returned with success => error returnError(new Error('a-mailer.send: SMTP client not idle')); return; } this._isIdle = false; smtpClient = this._smtpClient; smtpClient.removeAllListeners(); // By emitting the "idle" event with the "next tick" we make sure that // the event handlers below are attached first vertx.runOnContext(function () { smtpClient.emit('idle'); }); } else { // No current client in this._smtpClient => create a new one mailOpts = { ignoreTLS: true, debug: this.debug }; if (this.auth) { mailOpts.auth = {}; mailOpts.auth.user = this.username; mailOpts.auth.pass = this.password; } if (this.ssl) { mailOpts.secureConnection = true; } smtpClient = getSmtpClient(this.port, this.host, mailOpts); if (this.debug) { this.emit("debug", 'Smtp client created'); } this._smtpClient = smtpClient; // Set the "_isIdle" flag initially to false, so that subsequent calls // to "sendSeq" return an error until the flag is set to true after // sending a message this._isIdle = false; } if (this.sendTimeout) { sendTimeoutTimer = vertx.setTimer(this.sendTimeout, function() { sendTimeoutTimer = undefined; returnError(new Error('A-Mailer: Send timeout')); }); } // ======================================================================== // Set event handlers // // NOTE: The sequence of setting the handlers below does not affect the // program logic, BUT changing the order will make the unit tests fail, // because those tests rely on a certain order. This is kind of stupid, // but I did not find a different way to ensure that the event handlers // get called with the right arguments. // ======================================================================== // ======================= // Set exception handlers // ======================= // Sets the "send error", which has a "toString" method // and optionally the properties "name", "data", "code". smtpClient.on('error', function(err){ sendError = err; // "close" triggers the emittance of the "end" event and destroys // the client returnError(sendError); }); smtpClient.on('rcptFailed', function(failedAddresses){ sendResult.rcptFailedAdrs = failedAddresses; }); // Optionally set a debug handler if (this.debug) { smtpClient.on('debug', function (msg) { self.emit("debug", msg); }); } // ========================== // Set control flow handlers // ========================== addressInfo = { 'fromAddr': fromAddr, 'toAddrs': toAddrs, 'ccAddrs': ccAddrs, 'bccAddrs': bccAddrs }; smtpClient.once('idle', function () { sendEnvelope(smtpClient, addressInfo); }); smtpClient.on('message', function () { try { // Send the message smtpClient.end(composeMsg(addressInfo, sendData, sendContentSubtype)); } catch (msgError) { sendError = msgError; // "close" triggers the emittance of the "end" event and destroys // the client returnError(sendError); } }); smtpClient.on('ready', function (success, response) { if (!success) { sendError = new Error(response); // "close" triggers the emittance of the "end" event and destroys // the client returnError(sendError); return; } // Successful server response sendResult.response = response; // NOTE: This handler relies on implicit implementation knowledge of // the smtp client from client.js, namely: The "ready" event is // always followed by an "idle" event, which is emitted, AFTER this // "ready" handler has finished (by using "vertx.runOnContext(...)" smtpClient.once('idle', function () { if (sendTimeoutTimer) { vertx.cancelTimer(sendTimeoutTimer); } self._isIdle = true; callback(undefined, sendResult); }); }); // NOTE // We do not implement an "end" handler in this case because the callback // is either triggerd by the "ready" handler in case of success or directly // in case of an error }; // END: sendSeq()