If i send A quickfix message using
FIX::Session::sendToTarget(FIX::Message, FIX::SessionID)
Then suppose in header of message:
sender Comp ID = s1, target CompID = t1
and in the SessionID variable:
sender Comp ID = s1, target CompID = t2
Will the message go to t1 or t2
It will use the session ID you specify in the sendToTarget call. From the QF source code...
bool Session::sendToTarget( Message& message, const SessionID& sessionID )
throw( SessionNotFound )
{
message.setSessionID( sessionID );
Session* pSession = lookupSession( sessionID );
if ( !pSession ) throw SessionNotFound();
return pSession->send( message );
}
Notice that the message session ID is immediately overwritten by the sessionID passed to the function.
Related
I want to use a get request to get optional path parameters in a single end point . For example :-
if user hit below api :-
/metric/monitor/:id
or
/metric/:id
here id is path parameter than i need to route to the same function in a single end point using get request. How can i do the same ?
You can specify a route using regular expressions.
Assuming the id is a number:
router.getWithRegex( "\\/metric(\\/monitor)?\\/(?<ID>\\d+)" ).respond( this::monitor );
and then read the value:
long id = Long.parseLong( ctx.pathParam( "ID" ) );
This is how I usually declare the route using Vert.x Web 4.3.1:
public class MyVerticle extends AbstractVerticle {
#Override
public void start(Promise<Void> startPromise) {
Router router = Router.router( vertx );
BodyHandler bodyHandler = BodyHandler.create();
router.post().handler( bodyHandler );
router.getWithRegex( "\\/metric(\\/monitor)?\\/(?<ID>\\d+)" ).respond( this::monitor );
// Keeping track of it so that I can close it later
this.httpServer = vertx.createHttpServer();
final Future<HttpServer> startHttpServer = httpServer
.requestHandler( router )
.listen( HTTP_PORT )
.onSuccess( v -> LOG.infof( "✅ HTTP server listening on port %s", HTTP_PORT ) );
startHttpServer
.onSuccess( s -> startPromise.complete() )
.onFailure( startPromise::fail );
}
private Future<Result> monitor(RoutingContext ctx) {
long id = Long.parseLong( ctx.pathParam( "ID" ) );
Result result = ... // Do something
return Future.succeededFuture(result);
}
More details about routing with regular expressions are available in the documentation.
But, to be fair, creating two separate entry points seems easier for this case:
router.get( "/metric/monitor/:id" ).respond( this::monitor );
router.get( "/metric/:id" ).respond( this::monitor );
this is a quiz channel and after joining I want to get all the users who joined all the quizzes
quiz channel
def join("quiz:" <> id, _params, socket) do
presence = Nuton.Presence.list("quiz:" <> id)
if presence == %{} do
send(self(), {:after_join_quiz, id})
response = %{message: "you can now listen"}
{:ok, response, socket}
else
quiz = "quiz:#{id}"
%{^quiz => %{metas: metas}} = presence
if Enum.count(metas) > 1 do
{:error, %{reason: "Some other user already accepted the invitation"}}
else
send(self(), {:after_join_quiz, id})
response = %{message: "you can now listen"}
:ok = ChannelWatcher.monitor(:quiz, self(), {__MODULE__, :leave, [id]})
{:ok, response, socket}
end
end
end
def handle_info({:after_join_quiz, id}, socket) do
presence = Presence.list(socket)
if presence == %{} do
{:ok, _} =
Presence.track(socket, "quiz:" <> id, %{
user_name: socket.assigns.current_user.username,
user_id: socket.assigns.current_user.id,
quiz_id: id
})
{:noreply, socket}
else
{:ok, _} =
Presence.track(socket, "quiz:" <> id, %{
user_name: socket.assigns.current_user.username,
user_id: socket.assigns.current_user.id,
quiz_id: id
})
Core.Endpoint.broadcast(
"user:all",
"invitation:decline",
%{message: "Some other user already accepted the invitation"}
)
{:noreply, socket}
end
end
with specific quiz_id I can get all the user who joined the channel but with all I cant is there any issue in my code plz check if it is
Controller
quiz_users = Nuton.Presence.list("quiz:all")
You'd need to cycle through all of the channels, somehow, to get that information. I believe there was a PR to get this info, before, actually, so you can cycle through all.
What would be better: if you have the socket join 2 channels, like a "lobby" or "all" channel and then each individual channel. When you track, you can specify the string for the topic instead of only putting in the socket:
track(socket, "quiz:all", socket.assigns.user.id,%{})
I'm writing a custom ejabberd module. When I send a custom IQ stanza using strophe js, ejabberd processes the request and returns the result IQ back to the sender.
Below is the IQ request I send using strophe js,
connection.sendIQ($iq({
to: 'john#localhost',
type: 'set',
id: 'abc1234567890'
})
.c('query', {
xmlns: 'jabber:iq:custom_module',
msg_id: 'xyz9876543210'
})
.tree());
and this is the ejabberd module code,
-module(mod_custom_module).
-behaviour(gen_mod).
-define(NS_CUSTOM_MODULE, <<"jabber:iq:custom_module">>).
-export([start/2, stop/1, depends/2, mod_options/1, process_sm_iq/1, decode_iq_subel/1]).
-include("xmpp.hrl").
-include("logger.hrl").
-include("ejabberd_sql_pt.hrl").
start(_Host, _Opts) ->
gen_iq_handler:add_iq_handler(ejabberd_sm, _Host, ?NS_CUSTOM_MODULE, ?MODULE, process_sm_iq, one_queue).
stop(_Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_sm, _Host, ?NS_CUSTOM_MODULE).
depends(_Host, _Opts) ->
[].
mod_options(_Host) ->
[].
-spec decode_iq_subel(xmpp_element()) -> xmpp_element();
(xmlel()) -> xmlel().
decode_iq_subel(El) ->
El.
-spec process_sm_iq(iq()) -> iq().
process_sm_iq(#iq{from = _From, to = _To, sub_els = _sub_els} = IQ) ->
% My module actions here...
[First | Rest] = _sub_els,
xmpp:make_iq_result(IQ, First).
After processing the IQ, I also want to notify the other user 'john#localhost' about the custom event. I tried to do this using ejabberd_router:route/3, but it did not work.
I don't know what I am doing wrong.
Update
When I use the following code, the other user is not receiving stanza.
NewIQ = #iq{id = _Id, type = result, to = _To, from = _From, sub_els = _sub_els},
ejabberd_router:route(xmpp:set_from_to(NewIQ, _From, _To)),
% or ejabberd_router:route(NewIQ),
% or ejabberd_sm:route(NewIQ),
And when I checked the debug console, it is showing the following message in it. Not sure whether this is relevant as it is just a debug type message and there is no other failure error message.
17:07:47.173 [debug] Dropping packet to unavailable resource:
#iq{id = <<"abc1234567890">>,type = result,lang = <<>>,
from = #jid{user = <<"nikhil">>,server = <<"localhost">>,
resource = <<"49230572059507447681762">>,luser = <<"nikhil">>,
lserver = <<"localhost">>,
lresource = <<"49230572059507447681762">>},
to = #jid{user = <<"john">>,server = <<"localhost">>,
resource = <<>>,luser = <<"john">>,
lserver = <<"localhost">>,lresource = <<>>},
sub_els = [#xmlel{name = <<"query">>,
attrs = [{<<"xmlns">>,<<"jabber:iq:custom_module">>},
{<<"msg_id">>,<<"xyz9876543210">>}],
children = []}],
meta = #{}}
Try this function. It sends a headline message to the destination account with some details about the original IQ.
process_sm_iq(#iq{from = From, to = To, sub_els = SubEls} = IQ) ->
[First | Rest] = SubEls,
MsgId = fxml:get_tag_attr_s(<<"msg_id">>, First),
Subject = "Event alert",
Body = "An IQ was received by custom_module with msg_id: "++MsgId,
Packet = #message{from = From,
to = To,
type = headline,
body = xmpp:mk_text(Body),
subject = xmpp:mk_text(Subject)},
ejabberd_router:route(Packet),
xmpp:make_iq_result(IQ, First).
I have an app that sends an email with image attachments thru an SMTP server (sendgrid).
When the application launches it initializes a Socket connection and authenticates the user(application. I see the following message returned from Sendgrid
SG ESMTP service ready at<foo..sendgrid.net
and I also get a successful authentication returned.
However, on sending an email I get the following 3 errors:
error 1 550 Unauthenticated senders not allowed
error 2 503 Must have sender before recipient
error 3 503 Must have valid receiver and originator
So this suggests to me that I must change the order of sender and recipient in my SMTP module. Internally I am taking an incoming ByteArray and converting to base64 string in order to send emails with attached files. So how would I change the following code excerpt?
writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
writeUTFBytes ("DATA\r\n");
writeUTFBytes ("From: "+pFrom+"\r\n");
writeUTFBytes ("To: "+pDest+"\r\n");
This is the entire class I am using. I call authenticate just once after the class is initialized and then sendAttachedMail when sending email with image attachments. And when testing using a local SMTP server WITHOUT authentication, everything works fine(emails and image attachments sent)
package org.bytearray.smtp.mailer
{
import flash.events.ProgressEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.getTimer;
import org.bytearray.smtp.crypto.MD5;
import org.bytearray.smtp.encoding.Base64;
import org.bytearray.smtp.events.SMTPEvent;
import org.bytearray.smtp.infos.SMTPInfos;
public class SMTPMailer extends Socket
{
private var sHost:String;
private var buffer:Array = new Array();
// regexp pattern
private var reg:RegExp = /^\d{3}/img;
// PNG, JPEG header values
private static const PNG:Number = 0x89504E47;
private static const JPEG:Number = 0xFFD8;
// common SMTP server response codes
// other codes could be added to add fonctionalities and more events
private static const ACTION_OK:Number = 0xFA;
private static const AUTHENTICATED:Number = 0xEB;
private static const DISCONNECTED:Number = 0xDD;
private static const READY:Number = 0xDC;
private static const DATA:Number = 0x162;
private static const BAD_SEQUENCE:Number = 0x1F7;
public function SMTPMailer ( pHost:String, pPort:int)
{
super ( pHost, pPort );
sHost = pHost;
addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler,false,0,true);
}
public function reset():void{
removeEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}
/*
* This method lets you authenticate, just pass a login and password
*/
public function authenticate ( pLogin:String, pPass:String ):void
{
writeUTFBytes ("EHLO "+sHost+"\r\n");
writeUTFBytes ("AUTH LOGIN\r\n");
writeUTFBytes (Base64.encode64String (pLogin)+"\r\n");
writeUTFBytes (Base64.encode64String (pPass)+"\r\n");
flush();
}
/*
* This method is used to send emails with attached files and HTML
* takes an incoming Bytearray and convert it to base64 string
* for instance pass a JPEG ByteArray stream to get a picture attached in the mail ;)
*/
public function sendAttachedMail ( pFrom:String, pDest:String, pSubject:String, pMess:String, pByteArray:ByteArray, pFileName:String ) :void
{
try {
writeUTFBytes ("HELO "+sHost+"\r\n");
writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
writeUTFBytes ("DATA\r\n");
writeUTFBytes ("From: "+pFrom+"\r\n");
writeUTFBytes ("To: "+pDest+"\r\n");
writeUTFBytes ("Date : "+new Date().toString()+"\r\n");
writeUTFBytes ("Subject: "+pSubject+"\r\n");
writeUTFBytes ("Mime-Version: 1.0\r\n");
var md5Boundary:String = MD5.hash ( String ( getTimer() ) );
writeUTFBytes ("Content-Type: multipart/mixed; boundary=------------"+md5Boundary+"\r\n");
writeUTFBytes("\r\n");
writeUTFBytes ("This is a multi-part message in MIME format.\r\n");
writeUTFBytes ("--------------"+md5Boundary+"\r\n");
writeUTFBytes ("Content-Type: text/html; charset=UTF-8; format=flowed\r\n");
writeUTFBytes("\r\n");
writeUTFBytes (pMess+"\r\n");
writeUTFBytes ("--------------"+md5Boundary+"\r\n");
writeUTFBytes ( readHeader (pByteArray, pFileName) );
writeUTFBytes ("Content-Transfer-Encoding: base64\r\n");
writeUTFBytes ("\r\n");
var base64String:String = Base64.encode64 ( pByteArray, true );
writeUTFBytes ( base64String+"\r\n");
writeUTFBytes ("--------------"+md5Boundary+"-\r\n");
writeUTFBytes (".\r\n");
flush();
} catch ( pError:Error )
{
trace("Error : Socket error, please check the sendAttachedMail() method parameters");
trace("Arguments : " + arguments );
}
}
/*
* This method is used to send HTML emails
* just pass the HTML string to pMess
*/
public function sendHTMLMail ( pFrom:String, pDest:String, pSubject:String, pMess:String ):void
{
try
{
writeUTFBytes ("HELO "+sHost+"\r\n");
writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
writeUTFBytes ("RCPT TO: <"+pDest+">\r\n");
writeUTFBytes ("DATA\r\n");
writeUTFBytes ("From: "+pFrom+"\r\n");
writeUTFBytes ("To: "+pDest+"\r\n");
writeUTFBytes ("Subject: "+pSubject+"\r\n");
writeUTFBytes ("Mime-Version: 1.0\r\n");
writeUTFBytes ("Content-Type: text/html; charset=UTF-8; format=flowed\r\n");
writeUTFBytes("\r\n");
writeUTFBytes (pMess+"\r\n");
writeUTFBytes (".\r\n");
flush();
} catch ( pError:Error )
{
trace("Error : Socket error, please check the sendHTMLMail() method parameters");
trace("Arguments : " + arguments );
}
}
/*
* This method automatically detects the header of the binary stream and returns appropriate headers (jpg, png)
* classic application/octet-stream content type is added for different kind of files
*/
private function readHeader ( pByteArray:ByteArray, pFileName:String ):String
{
pByteArray.position = 0;
var sOutput:String = null;
if ( pByteArray.readUnsignedInt () == SMTPMailer.PNG )
{
sOutput = "Content-Type: image/png; name="+pFileName+"\r\n";
sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";
return sOutput;
}
pByteArray.position = 0;
if ( pByteArray.readUnsignedShort() == SMTPMailer.JPEG )
{
sOutput = "Content-Type: image/jpeg; name="+pFileName+"\r\n";
sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";
return sOutput;
}
sOutput = "Content-Type: application/octet-stream; name="+pFileName+"\r\n";
sOutput += "Content-Disposition: attachment filename="+pFileName+"\r\n";
return sOutput;
}
// check SMTP response and dispatch proper events
// Keep in mind SMTP servers can have different result messages the detection can be modified to match some specific SMTP servers
private function socketDataHandler ( pEvt:ProgressEvent ):void
{
var response:String = pEvt.target.readUTFBytes ( pEvt.target.bytesAvailable );
buffer.length = 0;
var result:Array = reg.exec(response);
while (result != null)
{
buffer.push (result[0]);
result = reg.exec(response);
}
var smtpReturn:Number = buffer[buffer.length-1];
var smtpInfos:SMTPInfos = new SMTPInfos ( smtpReturn, response );
if ( smtpReturn == SMTPMailer.READY )
dispatchEvent ( new SMTPEvent ( SMTPEvent.CONNECTED, smtpInfos ) );
else if ( smtpReturn == SMTPMailer.ACTION_OK && (response.toLowerCase().indexOf ("queued") != -1 || response.toLowerCase().indexOf ("accepted") != -1 ||
response.toLowerCase().indexOf ("qp") != -1) ) dispatchEvent ( new SMTPEvent ( SMTPEvent.MAIL_SENT, smtpInfos ) );
else if ( smtpReturn == SMTPMailer.AUTHENTICATED )
dispatchEvent ( new SMTPEvent ( SMTPEvent.AUTHENTICATED, smtpInfos ) );
else if ( smtpReturn == SMTPMailer.DISCONNECTED )
dispatchEvent ( new SMTPEvent ( SMTPEvent.DISCONNECTED, smtpInfos ) );
else if ( smtpReturn == SMTPMailer.BAD_SEQUENCE )
dispatchEvent ( new SMTPEvent ( SMTPEvent.BAD_SEQUENCE, smtpInfos ) );
else if ( smtpReturn != SMTPMailer.DATA )
dispatchEvent ( new SMTPEvent ( SMTPEvent.MAIL_ERROR, smtpInfos ) );
}
}
}
So this suggests to me that I must change the order of sender and recipient in my SMTP module.
The order of your commands is correct. Instead, you should look at the first error message for the real cause of the problem:
error 1 550 Unauthenticated senders not allowed
This tells you that the server requires authentication from the sender, i.e. use of the SMTP AUTH command with user credentials. Attempts to send mail from an unauthenticated sender will be rejected. As such, if MAIL FROM fails, then RCPT TO fails. If RCPT TO fails, then DATA fails. And so on.
Use the SMTP EHLO command to discover the AUTH schemes (and other capabilities) that the server supports, and then send the appropriate AUTH command before sending MAIL FROM.
UPDATE: sorry, I had not examined your class carefully. You already have an authenticate method and it does what it should. So, apparently, while you think that you're calling it, either it isn't getting called, or it fails.
So check carefully that the connection you're authenticating in and the connection you're sending mail in are actually the same connection, and you are not maybe unwittingly re-creating a new, unauthenticated connection.
Also, you really need to check the results of the operations you conduct - in this case, the authentication. Is it really successful?
Old answer
From your example and what little documentation I found, you need - or at least appear to need - two authentications. Probably with the same username and password.
The first one you're doing right, it is the 'XML socket connection' that gets you to the SMTP layer.
Now you need the second authentication. Otherwise all commands will fail and the errors will pancake one into the other, while the 'real' error, as Steffen Ulrich noticed, is the first.
writeUTFBytes ("HELO "+sHost+"\r\n");
// Inner authentication
writeUTFBytes ("AUTH LOGIN\r\n");
writeUTFBytes (Base64.encode64 (username) + "\r\n");
writeUTFBytes (Base64.encode64 (password) + "\r\n");
// HERE you really should read the stream and ensure it says
// "Authentication OK" -- or something to that effect.
writeUTFBytes ("MAIL FROM: <"+pFrom+">\r\n");
This line indicates the error:
error 1 550 Unauthenticated senders not allowed
May it be that you have to register your sender email address in sendgrid first? See https://sendgrid.com/docs/User_Guide/Marketing_Campaigns/senders.html#-Create-Your-Sender-Identity
If you have already done this, what does the email activity page tells you? (See https://sendgrid.com/docs/User_Guide/email_activity.html)
I have an app which is already on the app store,
I also have a server that sends push notification to the iphone.
My problem is that sometimes, the notification does not arrive to the iphone,
and this only happened after there was no apns communication to the apple push server after 2 or 3 hours, but after timeout, it would start working again. it was really random.
At first i though the problem was a timeout, then i tried to print out the return value of my ssl_wrap.send() functions, and it did return the length of the strings that was supposed to be sent, meaning, Apple APNS received all my json strings. it is just not broadcasting them to the client phone.
I need to keep firing the apns server until it timeouts before making the push notification work again, this is not right.
Any ideas?
class PushSender:
def __init__(self):
_sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
_sock.settimeout(2)
self.ssl_sock = ssl.wrap_socket( _sock, certfile = theCertfile )
self.ssl_sock.settimeout(1)
self.ssl_sock.connect( theHost )
self.counter = 0
self.lastPush = time()
def reset(self):
Log("Reset APNS");
self.ssl_sock.close()
_sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
_sock.settimeout(2)
self.ssl_sock = ssl.wrap_socket( _sock, certfile = theCertfile )
self.ssl_sock.settimeout(1)
self.ssl_sock.connect( theHost )
self.counter = self.counter + 1;
self.lastPush = time()
def send(self,token, message, badge, sound):
#Log("INIT APNS")
payload = {}
aps = {}
aps["alert"] = str(message)
aps["badge"] = badge
aps["sound"] = str(sound)
payload["aps"] = aps
if time() - self.lastPush> 60*30 : # 30 minutes idle reconnect
self.reset()
try:
#Log("Making Message APNS")
tokenh = binascii.unhexlify(token)
payloadstr = json.dumps(payload, separators=(',',':'))
payloadLen = len(payloadstr)
fmt = "!cH32sH%ds" % payloadLen
command = '\x00'
msg = struct.pack(fmt, command, 32, tokenh, payloadLen, payloadstr)
except:
Log("APNS Data Error " +token+" " +message);
return;
try:
#Log(msg)
sent = 0;
while sent < len(msg):
msg2 = msg[sent:];
justSent = self.ssl_sock.write( msg2 )
#Log(str(len(msg)) + " " + str(justSent))
sent += justSent
if justSent==0 :
raise socket.error(0,"Send failed")
except socket.error, err:
Log( "APNS Error: "+str(self.counter)+" "+ str(err) )
self.reset()
if self.counter<=2 : self.send(token,message,badge,sound)
Log( "APNS DONE"+ str(self.counter))
self.counter = 0;
self.lastPush = time()