Error publishing python dict to Solace using AMQP/qpid-proton - solace

Trying to run producer.py from solace-samples-amqp-qpid-proton-python with payload of python dict
Message(id=(self.sent+1), body={'sequence':(self.sent+1)})
Get following error
Reject message: 1 Remote disposition:
Condition('amqp:not-implemented', 'unsupported AMQP value type:
TOK_MAP_START')
Get similar error when trying to send integer value in body - TOK_TYPE_INT
Does solace support only Strings over AMQP?

Solace message brokers support amqp-value message sections containing values of types null, string, binary, symbol, or uuid. (https://docs.solace.com/Open-APIs-Protocols/AMQP/AMQP-Protocol-Conformance.htm#Sec3-2-8)
This is done in order to preserve maximum message inter-operability.
Any published message using a language specific semantic can only be consumed using the same semantic. I.e. if you publish with Python dict, you can only decode using Python dict, so if you are using a MQTT or REST consumer, it will not be able to decode the message.
The best option is to use a cross-language serialization library, which will make it easier for future expansions. For example, you might decide to add an REST consumer to in future, which can decode the data using the cross-language serialization library.

Related

Posting byte message in solace queue through jmeter

Need to post a byte message to solace queue using Jmeter. I have tried in following manner might be am incorrect but tried with following:
Use JMSPublisher sampler
create jndi.properties file and put in jmeter/lib
jndi.properties
java.naming.factory.initial = com.solacesystems.jndi.SolJNDIInitialContextFactory
java.naming.provider.url = smf://<remote IP and port>
java.naming.security.principal=<username>
java.naming.security.credentials=<password>
Solace_JMS_VPN=<VPN Name>
in JMSPublisher sampler (in GUI)
Connection Factory = connectionFactory
Destination = (Queue Name )
Message Type (radio button---Byte message)
Content encoding -- RAW
in text area ---> (Byte message)
Note : I have used actual values of IP/port/username/port/queuename/bytemessage, cannot share those. Soljms jar is available in lib folder too.
getting error :
Response message: javax.naming.NamingException: JNDI lookup failed - 503: Service Unavailable [Root exception is (null) com.solacesystems.jcsmp.JCSMPErrorResponseException: 503: Service Unavailable]
Though it is working perfectly fine when did with java spring boot. There used properties files in place of JNDI.
It would be great if anyone can guide me , please do not give activeMQ JNDI am actively looking for posting on solace queue or create connection to solace appliances through Jmeter.
I don't think you should be putting your Byte message into the textarea as it accepts either plain text or an XStream object, consider providing your payload via binary file(s) instead
If you're capable of sending the message using Java code you should be able to replicate the same using:
JMeter's JSR223 Sampler with Groovy language (Java syntax will work)
Or JUnit Request sampler if you need "strict" java

Spring Cloud Dataflow Splitter with JSON Array

I'm trying to use the Splitter app to split a JSON array e.g. [{...},{...}] into multiple messages {...} {...}. With input contentType=application/json (per the docs) Spring Cloud is surfacing an exception from Jackson:
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: [B#163b1945; line: 1, column: 1]
Unit tests showed I have the correct pattern for the split to work:
splitter.expression=#jsonPath(payload,'$.[*]')
This worked for me in Spring XD 1.3. How should Spring Cloud (or Splitter) be configured to handle this case? Input and output are both Kafka strings (no headers).
If the messages to the splitter come from non Spring Cloud Stream applications, then you would need to set --spring.cloud.stream.bindings.<inputChannelName>.consumer.headerMode=raw. While the application/json contentType messages have jackson exception, this would at least get the text/plain contentType messages evaluated against the expression appropriately.

Is there a default media type for GET and other methods

Is there any default media type when the query is not specified with any supported media types in RESTCONF ?
No. There is no standard default. This is server implementation dependent, so do not rely on it.
From draft-ietf-netconf-restconf-17, Section 5.3, Message Encoding:
The server MUST support the "Accept" header field and "406 Not
Acceptable" status-line, as defined in [RFC7231]. The response
output content encoding formats that the client will accept are
identified with the Accept header field in the request. If it is not
specified, the request input encoding format SHOULD be used, or the
server MAY choose any supported content encoding format.
If there was no request input, then the default output encoding is
XML or JSON, depending on server preference. File extensions encoded
in the request are not used to identify format encoding.
And from draft-ietf-netconf-restconf-17, Section 7.1, Error Response Message:
The client SHOULD specify the desired encoding(s) for response
messages by specifying the appropriate media-type(s) in the Accept
header. If the client did not specify an Accept header, then the
same structured syntax name suffix used in the request message SHOULD
be used, or the server MAY choose any supported message encoding
format. If there is no request message the server MUST select
"application/yang-data+xml" or "application/yang-data+json",
depending on server preference.
The final RFC stood by the draft, just as #predi said:
On Message Encoding, Section 5.2:
If there was no request input, then the default output encoding is
XML or JSON, depending on server preference. File extensions encoded
in the request are not used to identify format encoding.
And Error Message Response, Section 7.1
If the client did not specify an "Accept" header, then the same
structured syntax name suffix used in the request message SHOULD be
used, or the server MAY choose any supported message-encoding
format. If there is no request message, the server MUST select
"application/yang-data+xml" or "application/yang-data+json",
depending on server preference.

Content-Type alternative in MQTT

I am Working on MQTT communication using Paho and Mosqitto. We have to support both model of serialization - xml and json. So I am looking How to identify the content type or payload type in MQTT. Is there something similar HTTP Content-Type in MQTT to identify it quickly ?
Content-Type : application/json
Content-Type : application/xml
Thanks
No, MQTT payloads are just byte arrays and there is no space in the headers (because MQTT is designed to be as light weight as possible on the network). Anything else is down to the application to implement with in the payload.
You could use multiple topics to show the difference.
e.g. foo/bar/xml or foo/bar/json and subscribe to foo/bar/+ which will match both and then switch based on the topic.
or just test the first char of the payload, '{' = json '<' = xml
2021 answer
MQTT 5.0 introduced the concept of Properties. Basically, properties are UTF-8 string key-value pairs that you can add to an MQTT packet. The new specification also defines payload-format and content-type to convey information about the MIME type contained in the payload. So in principle, you can use this property in your application much like in HTTP you use Content-Type header.

Twitter stream API - Erlang client

I'm very new in Erlang world and I'm trying to write a client for the Twitter Stream API. I'm using httpc:request to make a POST request and I constantly get 401 error, I'm obviously doing something wrong with how I'm sending the request... What I have looks like this:
fetch_data() ->
Method = post,
URL = "https://stream.twitter.com/1.1/statuses/filter.json",
Headers = "Authorization: OAuth oauth_consumer_key=\"XXX\", oauth_nonce=\"XXX\", oauth_signature=\"XXX%3D\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"XXX\", oauth_token=\"XXX-XXXXX\", oauth_version=\"1.0\"",
ContentType = "application/json",
Body = "{\"track\":\"keyword\"}",
HTTPOptions = [],
Options = [],
R = httpc:request(Method, {URL, Headers, ContentType, Body}, HTTPOptions, Options),
R.
At this point I'm confident there's no issue with the signature as the same signature works just fine when trying to access the API with curl. I'm guessing there's some issue with how I'm making the request.
The response I'm getting with the request made the way demonstrated above is:
{ok,{{"HTTP/1.1",401,"Unauthorized"},
[{"cache-control","must-revalidate,no-cache,no-store"},
{"connection","close"},
{"www-authenticate","Basic realm=\"Firehose\""},
{"content-length","1243"},
{"content-type","text/html"}],
"<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n<title>Error 401 Unauthorized</title>\n</head>\n<body>\n<h2>HTTP ERROR: 401</h2>\n<p>Problem accessing '/1.1/statuses/filter.json'. Reason:\n<pre> Unauthorized</pre>\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n</body>\n</html>\n"}}
When trying with curl I'm using this:
curl --request 'POST' 'https://stream.twitter.com/1.1/statuses/filter.json' --data 'track=keyword' --header 'Authorization: OAuth oauth_consumer_key="XXX", oauth_nonce="XXX", oauth_signature="XXX%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="XXX", oauth_token="XXX-XXXX", oauth_version="1.0"' --verbose
and I'm getting the events just fine.
Any help on this would be greatly appreciated, new with Erlang and I've been pulling my hair out on this one for quite a while.
There are several issues with your code:
In Erlang you are encoding parameters as a JSON body while with curl, you are encoding them as form data (application/x-www-form-urlencoded). Twitter API expects the latter. In fact, you get a 401 because the OAuth signature does not match, as you included the track=keyword parameter in the computation while Twitter's server computes it without the JSON body, as it should per OAuth RFC.
You are using httpc with default options. This will not work with the streaming API as the stream never ends. You need to process results as they arrive. For this, you need to pass {sync, false} option to httpc. See also stream and receiver options.
Eventually, while httpc can work initially to access Twitter streaming API, it brings little value to the code you need to develop around it to stream from Twitter API. Depending on your needs you might want to replace it a simple client directly built on ssl, especially considering it can decode HTTP packets (what is left for you is the HTTP chunk encoding).
For example, if your keywords are rare, you might get a timeout from httpc. Besides, it might be easier to update the list of keywords or your code with no downtime without httpc.
A streaming client directly based on ssl could be implemented as a gen_server (or a simple process, if you do not follow OTP principles) or even better a gen_fsm to implement reconnection strategies. You could proceed as follows:
Connect using ssl:connect/3,4 specifying that you want the socket to decode the HTTP packets with {packet, http_bin} and you want the socket to be configured in passive mode {active, false}.
Send the HTTP request packet (preferably as an iolist, with binaries) with ssl:send/2,3. It shall spread on several lines separated with CRLF (\r\n), with first the query line (GET /1.1/statuses/filter.json?... HTTP/1.1) and then the headers including the OAuth headers. Make sure you include Host: stream.twitter.com as well. End with an empty line.
Receive the HTTP response. You can implement this with a loop (since the socket is in passive mode), calling ssl:recv/2,3 until you get http_eoh (end of headers). Note down whether the server will send you data chunked or not by looking at the Transfer-Encoding response header.
Configure the socket in active mode with ssl:setopts/2 and specify you want packets as raw and data in binary format. In fact, if data is chunked, you could continue to use the socket in passive mode. You could also get data line by line or get data as strings. This is a matter of taste: raw is the safest bet, line by line requires that you check the buffer size to prevent truncation of a long JSON-encoded tweet.
Receive data from Twitter as messages sent to your process, either with receive (simple process) or in handle_info handler (if you implemented this with a gen_server). If data is chunked, you shall first receive the chunk size, then the tweets and the end of the chunk eventually (cf RFC 2616). Be prepared to have tweets that spread on several chunks (i.e. maintain some kind of buffer). The best here is to do the minimum decoding in this process and send tweets to another process, possibly in binary format.
You should also handle errors and socket being closed by Twitter. Make sure you follow Twitter's guidelines for reconnection.

Resources