How to send a POST message from MQL4 to NodeJS? - javascript

webrequest.mq4
#property copyright "Copyright 2013, apla"
#property link "-"
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
// WebRequest
string cookie = NULL;
string headers = "Content-Type: application/x-www-form-urlencoded";
int res;
string url = "localhost:8080"; // url = localhost:8080
char post[], result[];
string signal = "account=" + AccountNumber() + "&balance=" + AccountBalance() + "&equity=" + AccountEquity();
StringToCharArray( signal, post );
Print( signal );
int timeout = 5000; // 5 sec
res = WebRequest( "POST",
url,
cookie,
NULL,
timeout,
post,
ArraySize( post ),
result,
headers
);
Print( "Status code: " , res, ", error: ", GetLastError() );
//----
return(0);
}
//+------------------------------------------------------------------+
I want to send a file from MetaTrader Terminal 4 webrequest.mq4 to a Node this Site section that can be given up, however.
MT4 >> Nodejs
??? POST[] ??? (JavaScript nodes)
account, balance, equity
how to convert file.php to nodejs
<?php
$myfile = fopen("newfile.txt", "w") or die("Unable to open file!");
$txt = "account ".$_POST['account']."\n";
fwrite($myfile, $txt);
$txt = "balance ".$_POST['balance']."\n";
fwrite($myfile, $txt);
$txt = "equity ".$_POST['equity']."\n";
fwrite($myfile, $txt);
fclose($myfile);
?>
For which I do not know how to get the POST.
writeFile.js
var http = require('http'); var fs = require('fs');
fs.writeFile("file.txt",??? POST[] ???, function(err,data) {
if (err) throw err;
console.log('The file was saved!');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('OK');
}).listen(8080);
console.log('Server running at http://localhost:8080/'); });

kindly be attentive to details:
Step 0 :MQL4 partshould follow the recent New-MQL4.56789copy/paste code fails
As a first sign of this, MetaTrader Terminal 4 code-base statically present on web does not reflect creeping syntax changes of MQL4 language. Recently MQL4 has moved closer to MQL5 ( reasoning for which is outside of this post, if interested, check other posts about New-MQL4.56789 ).
int start(){...} // cannot be used anymore,
// neither for EXPERT_ADVISOR
// nor for SCRIPT
Recent #property strict compilation mode imposes use of:
void OnTick(){ ...} // for EXPERT_ADVISOR type of MQL4-code
void OnStart(){ ...} // for SCRIPT type of MQL4-code
int OnCalculate(...){ ...} // for CUSTOM_INDICATOR type of MQL4-code,
// while,
// CUSTOM_INDICATOR has explicitly
// FORBIDDEN any attempt
// call to a WebRequest( ... ) et al
This said, your MQL4-part of the code shall be modified in it's principal structure so as to reflect these facts.
For any further tasks, related to MQL4, rather use localhost installed Help-service from the IDE, searching for "help" on web will most of all become a misleading source for un-edited copy/paste attempts due to above presented reasons.
Step 1 :POST http-syntax constructionought be conformant to RFC 7231, Section 4.3.3
as a minimum, your constructed text, being stored into a string signal ought look something like this:
User-Agent: aplaHTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 54
account=123456789&balance=1234567.89&equity=1234567.89
Step 2 :Node.js partparse received parameters for whatever further post-processing
Similarly, the node.js part shall decipher the parameters delivered inside POST-url-encoded http-message.
And the job is done.
Welcome to the Wild Worlds of MQL4

Related

Why does client.recv(1024) return an empty byte literal in this bare-bones WebSocket Server implementation?

I need a web socket client server exchange between Python and JavaScript on an air-gapped network, so I'm limited to what I can read and type up (believe me I'd love to be able to run pip install websockets). Here's a bare-bones RFC 6455 WebSocket client-server relationship between Python and JavaScript. Below the code, I'll pinpoint a specific issue with client.recv(1024) returning an empty byte literal, causing the WebSocket Server implementation to abort the connection.
Client:
<script>
const message = {
name: "ping",
data: 0
}
const socket = new WebSocket("ws://localhost:8000")
socket.addEventListener("open", (event) => {
console.log("socket connected to server")
socket.send(JSON.stringify(message))
})
socket.addEventListener("message", (event) => {
console.log("message from socket server:", JSON.parse(event))
})
</script>
Server, found here (minimal implementation of RFC 6455):
import array
import time
import socket
import hashlib
import sys
from select import select
import re
import logging
from threading import Thread
import signal
from base64 import b64encode
class WebSocket(object):
handshake = (
"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
"Upgrade: WebSocket\r\n"
"Connection: Upgrade\r\n"
"WebSocket-Origin: %(origin)s\r\n"
"WebSocket-Location: ws://%(bind)s:%(port)s/\r\n"
"Sec-Websocket-Accept: %(accept)s\r\n"
"Sec-Websocket-Origin: %(origin)s\r\n"
"Sec-Websocket-Location: ws://%(bind)s:%(port)s/\r\n"
"\r\n"
)
def __init__(self, client, server):
self.client = client
self.server = server
self.handshaken = False
self.header = ""
self.data = ""
def feed(self, data):
if not self.handshaken:
self.header += str(data)
if self.header.find('\\r\\n\\r\\n') != -1:
parts = self.header.split('\\r\\n\\r\\n', 1)
self.header = parts[0]
if self.dohandshake(self.header, parts[1]):
logging.info("Handshake successful")
self.handshaken = True
else:
self.data += data.decode("utf-8", "ignore")
playloadData = data[6:]
mask = data[2:6]
unmasked = array.array("B", playloadData)
for i in range(len(playloadData)):
unmasked[i] = unmasked[i] ^ mask[i % 4]
self.onmessage(bytes(unmasked).decode("utf-8", "ignore"))
def dohandshake(self, header, key=None):
logging.debug("Begin handshake: %s" % header)
digitRe = re.compile(r'[^0-9]')
spacesRe = re.compile(r'\s')
part = part_1 = part_2 = origin = None
for line in header.split('\\r\\n')[1:]:
name, value = line.split(': ', 1)
if name.lower() == "sec-websocket-key1":
key_number_1 = int(digitRe.sub('', value))
spaces_1 = len(spacesRe.findall(value))
if spaces_1 == 0:
return False
if key_number_1 % spaces_1 != 0:
return False
part_1 = key_number_1 / spaces_1
elif name.lower() == "sec-websocket-key2":
key_number_2 = int(digitRe.sub('', value))
spaces_2 = len(spacesRe.findall(value))
if spaces_2 == 0:
return False
if key_number_2 % spaces_2 != 0:
return False
part_2 = key_number_2 / spaces_2
elif name.lower() == "sec-websocket-key":
part = bytes(value, 'UTF-8')
elif name.lower() == "origin":
origin = value
if part:
sha1 = hashlib.sha1()
sha1.update(part)
sha1.update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11".encode('utf-8'))
accept = (b64encode(sha1.digest())).decode("utf-8", "ignore")
handshake = WebSocket.handshake % {
'accept': accept,
'origin': origin,
'port': self.server.port,
'bind': self.server.bind
}
#handshake += response
else:
logging.warning("Not using challenge + response")
handshake = WebSocket.handshake % {
'origin': origin,
'port': self.server.port,
'bind': self.server.bind
}
logging.debug("Sending handshake %s" % handshake)
self.client.send(bytes(handshake, 'UTF-8'))
return True
def onmessage(self, data):
logging.info("Got message: %s" % data)
def send(self, data):
logging.info("Sent message: %s" % data)
self.client.send("\x00%s\xff" % data)
def close(self):
self.client.close()
class WebSocketServer(object):
def __init__(self, bind, port, cls):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind((bind, port))
self.bind = bind
self.port = port
self.cls = cls
self.connections = {}
self.listeners = [self.socket]
def listen(self, backlog=5):
self.socket.listen(backlog)
logging.info("Listening on %s" % self.port)
self.running = True
while self.running:
# upon first connection rList = [784] and the other two are empty
rList, wList, xList = select(self.listeners, [], self.listeners, 1)
for ready in rList:
if ready == self.socket:
logging.debug("New client connection")
client, address = self.socket.accept()
fileno = client.fileno()
self.listeners.append(fileno)
self.connections[fileno] = self.cls(client, self)
else:
logging.debug("Client ready for reading %s" % ready)
client = self.connections[ready].client
data = client.recv(1024) # currently, this results in: b''
fileno = client.fileno()
if data: # data = b''
self.connections[fileno].feed(data)
else:
logging.debug("Closing client %s" % ready)
self.connections[fileno].close()
del self.connections[fileno]
self.listeners.remove(ready)
for failed in xList:
if failed == self.socket:
logging.error("Socket broke")
for fileno, conn in self.connections:
conn.close()
self.running = False
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s")
server = WebSocketServer("localhost", 8000, WebSocket)
server_thread = Thread(target=server.listen, args=[5])
server_thread.start()
# Add SIGINT handler for killing the threads
def signal_handler(signal, frame):
logging.info("Caught Ctrl+C, shutting down...")
server.running = False
sys.exit()
signal.signal(signal.SIGINT, signal_handler)
while True:
time.sleep(100)
server side logs:
INFO - Hanshake successful
DEBUG - Client ready for reading 664
DEBUG - Closing client 664
and on the client side I get
WebSocket connection to 'ws://localhost:8000' failed: Unknown Reason
The problem is traced here:
if data:
self.connections[fileno].feed(data)
else: # this is being triggered on the server side
logging.debug("Closing client %s" % ready)
So researching this I found a potential problem in the Python documentation for select used to retrieve rlist, wlist, xlist
select.select(rlist, wlist, xlist[, timeout]) This is a
straightforward interface to the Unix select() system call. The first
three arguments are iterables of ‘waitable objects’: either integers
representing file descriptors or objects with a parameterless method
named fileno() returning such an integer:
rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition” (see the manual page for
what your system considers such a condition)
Seeing that the feature is based on the Unix system call, I realized this code might not support Windows, which is my environment. I checked the values of rlist, wlist, xlist and found they're all empty lists on the first iteration rList = [784] (or another number, such as 664) and the other two are empty, after which the connection is closed.
The documentation goes on to note:
Note: File objects on Windows are not acceptable, but sockets are. On Windows, the underlying select() function is provided by the
WinSock library, and does not handle file descriptors that don’t
originate from WinSock.
But I'm not clear on the exact meaning of this.
So in the code logic, I did some logging and traced the issue here:
rList, wList, xList = select(self.listeners, [], self.listeners, 1)
for ready in rList: # rList = [836] or some other number
# and then we check if ready (so the 836 int) == self.socket
# but if we log self.socket we get this:
# <socket.socket fd=772, family=AddressFamily.AF_INET,
# type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8000)>
# so of course an integer isn't going to be equivalent to that
if ready == self.socket:
logging.debug("New client connection")
#so lets skip this code and see what the other condition does
else:
logging.debug("Client ready for reading %s" % ready)
client = self.connections[ready].client
data = client.recv(1024) # currently, this results in: b''
fileno = client.fileno()
if data: # data = b'', so this is handled as falsy
self.connections[fileno].feed(data)
else:
logging.debug("Closing client %s" % ready)
And as to why client.recv(1024) returns an empty binary string, I have no idea. I don't know if rList was supposed to contain more than an integer, or if the protocol is working as intended up until recv
Can anyone explain what's causing the broken .recv call here? Is the client side JavaScript WebSocket protocol not sending whatever data should be expected? Or is the WebSocket Server at fault, and what's wrong with it?
I tried running your example and it seem to be working as expected. At least server logs end with the following line:
INFO - Got message: {"name":"ping","data":0}
My environment:
OS: Arch Linux;
WebSocket client: Chromium/85.0.4183.121 running the JS-code you provided;
WebSocket server: Python/3.8.5 running the Python code you provided;
select.select docstring indeed states that
On Windows, only sockets are supported
but most likely the OS is irrelevant since the server code uses only sockets as select.select arguments.
recv returns an empty byte string when the reading end of a socket is closed. From recv(3) man:
If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0.
An interesting thing is a message about a successful handshake in server logs you got:
INFO - Hanshake successful
It means that in your case the connection between the client and the server has been established and some data has flown in both directions. After that the socket got closed. Looking at the server code I see no reason for the server to stop the connection. So I assume that the client you are using is to blame.
To find out exactly what is going wrong, try intercepting the network traffic using tcpdump or wireshark and running the following Python WebSocket client script that reproduces the actions my browser did when I was testing:
import socket
SERVER = ("localhost", 8000)
HANDSHAKE = (
b"GET /chat HTTP/1.1\r\n"
b"Host: server.example.com\r\n"
b"Upgrade: websocket\r\n"
b"Connection: Upgrade\r\n"
b"Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
b"Sec-WebSocket-Protocol: chat, superchat\r\n"
b"Sec-WebSocket-Version: 13\r\n"
b"Origin: http://example.com\r\n"
b"\r\n\r\n"
)
# a frame with `{"name":"ping","data":0}` payload
MESSAGE = b"\x81\x983\x81\xde\x04H\xa3\xb0e^\xe4\xfc>\x11\xf1\xb7jT\xa3\xf2&W\xe0\xaae\x11\xbb\xeey"
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(SERVER)
n = s.send(HANDSHAKE)
assert n != 0
data = s.recv(1024)
print(data.decode())
n = s.send(MESSAGE)
assert n != 0

Randomly occuring Unexpected end of JSON on GET request

I'm developing a simple web project where one of the features (Related to the error) will display a quote, credit and source. This feature works as intended using setInterval every 12seconds to call a function which will make a connection to my XAMPP hosted MYSQL server and return a random row as a JSON object which I can use to display on the page. below is the Quote retrieval script and PHP:
quotes.js
(function() {
ajax = new XMLHttpRequest();
var method = "GET";
var url = "data.php";
var asynchronous = true; // revise asynchronous
var quoteContainer = document.getElementById("quote");
var authorContainer = document.getElementById("author");
function getQuote() {
ajax.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200) {
var data = JSON.parse(this.responseText);
console.log(data)
quoteContainer.innerHTML = "\"" + data.Quote + "\""
authorContainer.innerHTML = data.Author + " - " + "<a href='"+ data.Source +"' target='_blank'>source</a>";
}
}
ajax.open(method,url,asynchronous);
ajax.send();
}
getQuote();
setInterval(getQuote,12000); //set to 100 for testing
}());
Data.php
<?php
// write secondry query for seasonal messages
$conn = mysqli_connect("localhost","root","","quotes_db");
$sql = "SELECT * FROM quote_table ORDER BY RAND() LIMIT 1;";
$result = mysqli_query($conn,$sql);
$data= mysqli_fetch_assoc($result);
echo json_encode($data);
?>
The issue is that on random occasions while this is running the server returns a 'null' packet (with the titled error) I have checked the network data using Chromes developer console and the effected packets are empty and take slightly longer to return. I have checked my database table for special characters and it all seems normal. due to the packet returning null the page is left empty
How can I stop this error appearing, so that I can get a continuous stream of random rows from my table?
If the answer is not an obvious one what bug-testing steps should I take to find a fix?
If more information is needed I can update this post.
Error log
This usually happens when the data returned is undefined or is not in a valid format. That is when JSON.parse() would fail. You can consider putting try-catch block.
try {
var data = JSON.parse(this.responseText);
} catch(e) {
console.log('Unable to parse the string.')
}
Also, consider wrapping the JSON.parse() statement in an if condition, if server sends an empty response.
You can do some kind of error handling to achieve your goal.
ajax.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200) {
try
{
var data = JSON.parse(this.responseText);
}
catch (error)
{
if (error instanceof SyntaxError)
{
// unable to parse the result to json
// maybe retry?
// do some kind of errer handling
}
}
}
Using the try-catch statement you simply catch the error instead of stopping the script from executing so you are able to handle errors yourself.
Best regards.
EDIT:
setInterval(function ()
{
var found = false;
var attemptCount = 0;
var allowedAttempts = 10; // your exit condition, so you wont get stuck in an infinite loop if the server is broken or something
while (!found && attemptCount < allowedAttempts)
{
try
{
getQuote();
}
catch (error)
{
if (error instanceof SyntaxError)
{
attemptCount++;
continue;
}
}
found = true;
}
}, 12e3);
EDIT No.2: (based on your comment on another answer)
If you want to do some server-side validation, you have to modify the PHP-Code:
$data = []; // set a default return value
$result = mysqli_query($conn,$sql);
if (mysqli_num_rows($result) === 1) // we found a result
{
$data= mysqli_fetch_assoc($result);
}
echo json_encode($data);
So, if you combine both, the client- and server-side validation you should be fine for sure:
What did we do?
we implemented a server side validation, so the result that is returned to the client should never throw an error when going through JSON.parse(). To make this work you have to implement a client-side validation on the result of JSON.parse() to make sure that you got a valid result (because it could be an empty array).
if any errors occur on the server (for whatever reason) and the returned result cannot be parsed, we simply retry the entire process for n times.
Best regards.
The issue is caused by your encoding: Jean de La Bruyère is transmitted as Jean de La Bruy�re by MySQL.
PHP json_encode() is not able to deal with the encoding of the French character as shown in this print_r() output of the mysqli_fetch_assoc() result:
Array
(
[QuoteID] => 6
[Quote] => Those who make the worst use of their time are the first to complain of its brevity.
[Author] => Jean de La Bruy�re
[Source] => https://www.goodreads.com/author/show/778012.Jean_de_La_Bruy_re
)
As json_encode() is only accepting UTF-8 encoded strings ("All string data must be UTF-8 encoded.", cf. PHP Documentation), you can tell MySQL to return every result in UTF-8 encoding by simply executing the following query once after opening the connection:
mysqli_query($conn, "SET NAMES 'utf8'");

How can I pass parameters when calling a Node.js script from PHP exec()?

I'm trying to implement iOS push notifications. My PHP version stopped working and I haven't been able to get it working again. However, I have a node.js script that works perfectly, using Apple's new Auth Key. I am able to call that from PHP using:
chdir("../apns");
exec("node app.js &", $output);
However, I would like to be able to pass the deviceToken and message to it. Is there any way to pass parameters to the script?
Here's the script I'm trying to run (app.js):
var apn = require('apn');
var apnProvider = new apn.Provider({
token: {
key: 'apns.p8', // Path to the key p8 file
keyId: '<my key id>', // The Key ID of the p8 file (available at https://developer.apple.com/account/ios/certificate/key)
teamId: '<my team id>', // The Team ID of your Apple Developer Account (available at https://developer.apple.com/account/#/membership/)
},
production: false // Set to true if sending a notification to a production iOS app
});
var deviceToken = '<my device token>';
var notification = new apn.Notification();
notification.topic = '<my app>';
notification.expiry = Math.floor(Date.now() / 1000) + 3600;
notification.badge = 3;
notification.sound = 'ping.aiff';
notification.alert = 'This is a test notification \u270C';
notification.payload = {id: 123};
apnProvider.send(notification, deviceToken).then(function(result) {
console.log(result);
process.exit(0)
});
You can pass parameters as you would pass it to any other script.
node index.js param1 param2 paramN
You can access the arguments through process.argv
The process.argv property returns an array containing the command line
arguments passed when the Node.js process was launched. The first
element will be process.execPath. See process.argv0 if access to the
original value of argv[0] is needed. The second element will be the
path to the JavaScript file being executed. The remaining elements
will be any additional command line arguments.
exec("node app.js --token=my-token --mesage=\"my message\" &", $output);
app.js
console.log(process.argv);
/*
Output:
[ '/usr/local/bin/node',
'/your/path/app.js',
'--token=my-token',
'--mesage=my message' ]
*/
You can use minimist to parse the arguments for you:
const argv = require('minimist')(process.argv.slice(2));
console.log(argv);
/*
Output
{
_: [],
token: 'my-token',
mesage: 'my message'
}
*/
console.log(argv.token) //my-token
console.log(argv.message) //my-message
After a lot of work, I have a solution. I am using a local web UI to send and receive data to/from Arduino
using AJAX, the php script is:
<?php
/**
* It is already not necessary to go to Device Manager> Ports (COM & LPT)>Arduino XXX (COMXX)>right, NO, the script PruebaCOMRetrieve.bat detect the COM port Arduino is connected to.
* click>Properties>
* Port Settings>Advanced>uncheck "use FIFO buffers ........."
* In other hand, remeber that the Tx speed has to be the same in writeandread.js as in
* Arduino sketch and in the COM
* properties in Device manager, I selected 115200 b/s.
*
*/
$t = $_POST['text1'];
include 'PruebaBatchCOM.php';
$puerto = escapeshellarg($usbCOM);
$dato = escapeshellarg($t);
exec("node C:\\xampp\\htdocs\\DisenoWEBTerminados\\BatteryTesterFinal\\Scripts\\writeandread.js
{$puerto} {$dato} 2>&1", $output1);
$str = implode($output1);
$str1 = explode(",",$str);
$myJSON = json_encode($str1);
echo $myJSON;
?>
PruebaBatchCOM.php
<?php
$puerto = array();
$file111 = "PruebaCOMRetrieve.bat";
exec($file111, $puerto);
$usbCOM = implode(",",$puerto);
?>
PruebaCOMRetrieve.bat
#echo off
setlocal
for /f "tokens=1* delims==" %%I in ('wmic path win32_pnpentity get caption
/format:list ^| find "Arduino Uno"') do (
call :setCOM "%%~J"
)
:: end main batch
goto :EOF
:setCOM <WMIC_output_line>
:: sets _COM#=line
setlocal
set "str=%~1"
set "num=%str:*(COM=%"
set "num=%num:)=%"
set port=COM%num%
echo %port%
The Node Js script is:
//writeandread.js
var portName = process.argv[2];
var dato = process.argv[3];
var SerialPort = require("serialport");
var Readline = require('#serialport/parser-readline');
var serialport = new SerialPort(portName, { baudRate: 115200 });
// Look for return and newline at the end of each data packet
var parser = serialport.pipe(new Readline({ delimiter: '\n' }));
serialport.on('open', function(err) {
// A timeout is necessary to wait the port to open (if not working, try to
increase the milliseconds value)
setTimeout(function() {
serialport.write(dato);
}, 1700);
if(err) {
console.log('Error when trying to open:' + err);
}
parser.on('data', function(data) {
console.log(data);
serialport.close(function (err) {
if(err){
console.log('port closed', err);
}
});
});
});
serialport.on('close', () => {
console.log('Bye');
});
With this scripts one can send and receive data from Arduino and pass it to AJAX script in the client side and do what one wants. Now I am adding a script to php firt one to detect programmatically the COM port Arduino is connected to.
enjoy.

NodeJS Email Alias Server

The scenario is simple:
I own several domains
I want to run email on those domains
I wantthem all to deliver to the same address regardless of who they where
sent to or on which domain
I want them to retain the original headers
specifically the to field
For this project i need use NodeJS
I have tried several things to no avail, I'm pretty proficient in node, but have no idea what I'm doing when it comes to emails.
I have all the domains pointed to the correct place, including the MX records, and using simplesmtp, i am able to receive the emails, i just can't figure out how to deliver them without trashing the headers or forwarding them in which case they show up at their destination as two emails.
Any suggestions or guidance is much appreciated
Regards,
David
Since we all love code here is the relevant stuff
var simplesmtp = require("simplesmtp"),
MailParser = require("mailparser").MailParser,
mailparser = new MailParser(),
nodemailer = require("nodemailer"),
gmail = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "***",
pass: "***"
}
}),
fs = require("fs"),
smtp = simplesmtp.createServer();
// Setup the listener
smtp.listen(25);
// runs when the email is initially recieved
smtp.on("startData", function(connection){
// log out some basic stuff
console.log("Message from:", connection.from);
console.log("Message to:", connection.to);
// start the write stream
connection.saveStream = fs.createWriteStream("/path/message.txt");
});
// each chunk of data that is received
smtp.on("data", function(connection, chunk){
// continue the write stream
connection.saveStream.write(chunk);
});
// email completly received
smtp.on("dataReady", function(connection, callback){
// end the write stream
connection.saveStream.end();
// log some more stuff
console.log("Incoming message saved to /path/message.txt");
// start a readstream to forward out the message
fs.createReadStream("/path/message.txt").pipe(mailparser);
//
callback(null, "ABC1"); // ABC1 is the queue id to be advertised to the client
// callback(new Error("Rejected as spam!")); // reported back to the client
});
// Parse the email
mailparser.on("end", function(email){
// now lets forward the mail
// for now everything goes back to *****,
// eventually ill be setting up some configs to handle other addresses
// console.log(email.headers); */
// email.headers['X-Forwarded-To'] = "*****";
// email.to = "*****";
delete email.headers.received;
delete email.text;
// delete email.headers.X-Received;
email.to = email.to + ', ' + "*****";
email.headers.to = email.to + ', ' + "*****";
console.log(email.headers);
gmail.sendMail(email, function(err, response){
if(err)
console.log(err);
// now clean up that message file
fs.rename('/path/message.txt', 'emails/'+new Date().toJSON()+email.subject+'.eml', function(err){
if(err) console.log(err);
fs.unlink('/path/message.txt', function(){console.log('clenaed up');});
})
// final logging
console.log('sent');
});
});
You can set the envelope sender for the email using nodemailer so that it contains the forwarding address:
email.envelope = {
from: email.from
to: "user#example.com"
}
Some SMTP services will not let you set the envelope sender (MAIL FROM). You may have trouble with Gmail.
See also:
Email forwarding - Wikipedia, the free encyclopedia
email - What's the difference between Sender, From and Return-Path? - Stack Overflow

Node JS taking long time in sending initial data

I am facing an issue with NodeJS. Initially it takes a long time about 4-5 seconds before I get any update. Node JS Server is publicly accessible and it is not patched through any proxy or anything. But once initial connection has been established - updates are instantaneous.
I dug deep using network tools from Chrome - it says it is waiting for data. see the attached image
I am also pasting the code for my app.js (node application) for your reference.
var http = require('http'),
url = require('url'),
fs = require('fs'),
amqp = require('amqp'),
sys = require(process.binding('natives').util ? 'util' : 'sys');
var exchangeName = 'conferenceTest';
send404 = function (res) {
res.writeHead(404);
res.write('404');
res.end();
};
server = http.createServer(function (req, res) {
var path = url.parse(req.url).pathname;
switch (path) {
case '/':
fs.readFile(__dirname + "/index.html", function (err, data) {
if (err) {
return send404(res);
} else {
res.writeHead(200, {
'Content-Type': 'application/zip',
'Connection': 'close',
'content-encoding': 'gzip'
});
res.write(data, 'utf8');
res.end();
}
});
break;
}
});
// listen to the http server for socket connections
var io = require('socket.io').listen(server);
var connection = amqp.createConnection({
host: 'localhost'
});
connection.on('ready', function () {
var exchange = connection.exchange(exchangeName, { // create exchange
type: 'direct',
durable: true
});
io.sockets.on('connection', function (client) {
console.log("client connected");
client.on('changeview', function (data) {
var queue = connection.queue(data.queueName, { //create queue
durable: true,
autoDelete: false
});
var plaintext = "Put any kind of meat on a stick and roast it over a flame and it immediately becomes food fit for gods. No country understands this sacred rule of seared meat like Turkey.Turkish kebabs are the incarnation of the meat lovers most exotic fantasies, with grilled lamb, beef and chicken as skewer MVPs.Most kebab restaurants also have a long list of Turkish starters called meze that are as delicious as the main dishes.Turkeys best alcoholic complement for all that meat is raki -- an aniseed-flavored drink that s often diluted with water and chilled with ice. Frothy, yogurt-based ayran is a great non-alcoholic complement to heavy dishes. But who are we kidding -- you just want the meat. Heres where to get it in Turkey.";
io.sockets.emit('changeview', plaintext);
});
});
});
process.on('uncaughtException', function (err) {
console.log('Uncaught Exception: ' + err.message);
});
server.listen(18080);
Thanks
Your client is requesting some long numerical URI, but your handler is only accepting requests for / (for which it sends back index.html). Other requests (like for the numerical URI's) are just not handled at all, which means your browser will wait for some time and eventually give up.
To solve, add a default case and return a 404 error:
switch (path) {
case '/':
// your current code
break;
default:
send404(res);
}
Also: why are you setting those specific headers on the response for the index.html file? application/zip would mean that your index.html should be regarded as a ZIP file, and setting the content encoding to gzip would mean that the response is gzip'ed. Neither of which seem to be the case here.
On the client side - default connect timeout is 10 seconds
I have reduced it to 500 ms - it connects almost now in 2.92 seconds - previously it was taking up to 12.3 seconds
var conn = io.connect("http://myserver.com:myport/", { transports: transports, 'reconnect': true, 'connect timeout':500});
Hope it helps anyone else struggling with this issue

Categories

Resources