How to send a BytesIO like file object (sound) to API telegram bot using a python requests? - https

Can't send. Through the python-telegram-bot library, the data is sent ok. But I have to send it in a few places synchronously.
This is a working code for sending text messages:
def send_text_msg(_chat_id: int, text: str) -> None:
token = TELEGRAM_BOT_TOKEN
chat_id = str(_chat_id)
url = "https://api.telegram.org/bot" + token + "/sendMessage" + "?chat_id=" +
chat_id + "&text=" + text
try:
response = requests.get(url, timeout=5)
# print(response.json())
except requests.exceptions.HTTPError as err:
print('Error fetching response using requests')
And this code doesn't work, this is what I want:
def send_voice_msg(chat_id: int, voice_file: BytesIO) -> None:
token = TELEGRAM_BOT_TOKEN
url = "https://api.telegram.org/bot" + token + "/sendMessage"
data = {"chat_id": chat_id, "caption": 'voice.ogg'},
files = {'voice': voice_file}
headers = {'Content-Type': 'multipart/form-data'}
r = requests.post(url, headers=headers, data=data, files=files, timeout=3)

This is a working code.
def send_voice_msg(chat_id: int, voice_file: BytesIO) -> None:
token = TELEGRAM_BOT_TOKEN
url = "https://api.telegram.org/bot" + token + "/sendVoice" + "?chat_id=" + str(chat_id) + "&voice="
file = {'voice': ('voice.ogg', voice_file)}
try:
post = requests.post(url, files=file, timeout=3)
logger.info(f'voice message status code is {post.status_code}')
except requests.exceptions.HTTPError as err:
logger.warning('Error fetching response using requests')

Related

How to wait for request to finish in Jmeter

I am currently new to Jmeter, and trying to create a Jmeter script to test how long a request takes to process and complete.
a) Authenticate using Token - Complete
b) Post Request - Complete - Returns 200
c) Get Request - Partially Completed
C: I am Trying to get be able to monitor this request to find out when its either completed failed etc.
I have created the Http Request Sample with a Get Request
I am able to get the Request 200 but it doesn't wait for completion
So running this in a console app, it waits for a certain time checking for status....
Is there a way to possibly write a code similar to the C# code in bean shell or groovy to wait. I was reading about while controller as well...
var result = WaitForBuildToComplete(dest, requestData, token, timeout);
static string GetStatus(string path, Token token)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
AddToken(token, httpWebRequest);
WebResponse response = httpWebRequest.GetResponse();
string responseFromServer = "";
using (Stream dataStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(dataStream);
responseFromServer = reader.ReadToEnd();
}
// Close the response.
response.Close();
return responseFromServer;
}
static int WaitForBuildToComplete(string dest, RequestData requestData, Token token, int
timeout)
{
if (timeout <= 0) return 0;
var path = $"{ConfigurationManager.AppSettings[dest]}/policy?id={requestData.id}";
var startTime = DateTime.Now;
do
{
var status = GetStatus(path, token);
var msg = JsonConvert.DeserializeObject<string>(status);
var requestStatus = JsonConvert.DeserializeObject<RequestStatus>(msg);
if (!string.IsNullOrEmpty(requestStatus.DllUrl))
{
Console.WriteLine($"\nResult dll at: {requestStatus.DllUrl}");
return 0;
}
if (requestStatus.Status.ToUpper() == "FAILED")
{
Console.WriteLine($"\nFAILED");
Console.WriteLine(requestStatus.Message);
return -1;
}
if (requestStatus.Status.ToUpper() == "FAILED_DATA_ERROR")
{
Console.WriteLine($"\nFAILED_DATA_ERROR");
Console.WriteLine(requestStatus.Message);
return -1;
}
if (requestStatus.Status.ToUpper() == "NOT_NEEDED")
{
Console.WriteLine($"\nNOT_NEEDED");
Console.WriteLine(requestStatus.Message);
return -1;
}
Console.Write(".");
System.Threading.Thread.Sleep(1000);
} while ((DateTime.Now - startTime).TotalSeconds < timeout);
Console.WriteLine("Time out waiting for dll.");
return -1;
}
I started by looking at JSR223 Sampler but wanted to see if there is a better and easier way to accomplish this.
List<String> sendRequest(String url, String method, Map<String,Object> body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
StringEntity entity = new StringEntity(new Gson().toJson(body), "UTF-8");
HttpUriRequest request = RequestBuilder.create(method)
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.setEntity(entity)
.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n" + EntityUtils.toString(entity) + "\n";
HttpClientBuilder.create().build().withCloseable {httpClient ->
httpClient.execute(request).withCloseable {response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res );
return Arrays.asList(req, res);
}
}
}
List sendGet(String url, Map<String,String> body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
RequestBuilder requestBuilder = RequestBuilder.get()
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
body.forEach({key, value -> requestBuilder.addParameter(key, value)});
HttpUriRequest request = requestBuilder.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n";
HttpClientBuilder.create().build().withCloseable {httpClient ->
httpClient.execute(request).withCloseable {response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res );
return Arrays.asList(req, res);
}
}
}
The approach which is normally used in JMeter is placing your request under the While Controller which will be checking the Status value which in its turn can be fetched from the response using a suitable Post-Processor so the request will be retried unless the "Status" changes to some value which you expect (or times out)
If you place the whole construction under the Transaction Controller you will get the whole time for the status to change.
Example test plan outline:

How to include and send image in whats app message using chat api

My requirement is to send image as a whats app message, how can i achieve it, below is my code and i'm using chat api.
message = message.Replace("#", "\n");
message = "https://upload.wikimedia.org/wikipedia/ru/3/33/NatureCover2001.jpg";
string param = "phone=91" + phonenumber + "&body=" + message + "&filename=cover.jpg";
byte[] buffer = System.Text.Encoding.ASCII.GetBytes(param);
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create("https://eu9.chat-api.com/instance7102/message?token=i8ra4a0zlfxwh90b");
WebReq.Method = "POST";
WebReq.ContentType = "application/x-www-form-urlencoded";
WebReq.ContentLength = buffer.Length;
Stream PostData = WebReq.GetRequestStream();
PostData.Write(buffer, 0, buffer.Length);
PostData.Close();
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
Stream Answer = WebResp.GetResponseStream();
StreamReader _Answer = new StreamReader(Answer);
string response = _Answer.ReadToEnd();
return response;

How to upload a catalog file to azure cognitive service with ruby?

I want upload a catalog file to recommendation api (Azure Cognitive Service with ruby language.
With C# I will have the next code (extracted from https://github.com/Microsoft/Cognitive-Recommendations-Windows/blob/master/Sample/RecommendationsApiWrapper.cs):
public CatalogImportStats UploadCatalog(string modelId, string catalogFilePath, string catalogDisplayName)
{
Console.WriteLine("Uploading " + catalogDisplayName + " ...");
string uri = BaseUri + "/models/" + modelId + "/catalog?catalogDisplayName=" + catalogDisplayName;
using (var filestream = new FileStream(catalogFilePath, FileMode.Open, FileAccess.Read))
{
var response = _httpClient.PostAsync(uri, new StreamContent(filestream)).Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception(
String.Format("Error {0}: Failed to import catalog items {1}, for model {2} \n reason {3}",
response.StatusCode, catalogFilePath, modelId, ExtractErrorInfo(response)));
}
var jsonString = ExtractReponse(response);
var catalogImportStats = JsonConvert.DeserializeObject<CatalogImportStats>(jsonString);
return catalogImportStats;
}
How to upload a catalog file to cognitive service using ruby and http client?. I need a basic sample code.
Thanks
I've uploaded a sample here: https://github.com/miparnisari/ruby-cognitive-services
But the gist of it:
require 'net/http'
require 'IO/console'
class RecommendationsClient
def initialize(subscription_key, region)
#base_url="https://#{region}.api.cognitive.microsoft.com/recommendations/v4.0"
#subscription_key=subscription_key
end
def upload_catalog(model_id, catalog_display_name, catalog_path)
uri = URI("#{#base_url}/models/#{model_id}/catalog?catalogDisplayName=#{catalog_display_name}")
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'application/octet-stream'
request['Ocp-Apim-Subscription-Key'] = "#{#subscription_key}"
request.body = IO.binread(catalog_path)
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
return response.body
end
end
And then:
r = RecommendationsClient.new("your_key_here", "westus")
response = r.upload_catalog('1', 'catalog', 'books_catalog.txt')
puts response

Vertical response api in grails

I'm trying to use Vertical response api in my grails project. But it giving following error
CODE:
def http = new HTTPBuilder()
http.request('https://vrapi.verticalresponse.com/',GET, TEXT) { req ->
uri.path = 'api/v1/contacts?type=basic'
headers.'Authorization' = 'Bearer api_token'
headers.'Content-Type'='application/json'
print('====================================')
response.success = { resp, reader ->
assert resp.status == 200
println "My response handler got response: ${resp.statusLine}"
println "Response length: ${resp.headers.'Content-Length'}"
reader // print response reader
}
// called only for a 404 (not found) status code:
response.'404' = { resp ->
println 'Not found'
}
}
ERROR:
Unauthorized. Stacktrace follows:
groovyx.net.http.HttpResponseException: Unauthorized
at groovyx.net.http.HTTPBuilder.defaultFailureHandler(HTTPBuilder.java:652)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:508)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:441)
at groovyx.net.http.HTTPBuilder.request(HTTPBuilder.java:417)
...
After using HttpClient instead of HTTPBuilder it working without any problem. So I think the problem is with HTTPBuilder
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet('http://vrapi.verticalresponse.com/api/v1/contacts?type=basic');
// add request header
request.addHeader("Authorization","Bearer token")
HttpResponse response = client.execute(request);
print("Response Code : "
+ response.getStatusLine().getStatusCode())
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
render rd.readLines()

Unable to produce Proper Encryption Key in Ruby using HMAC

I am attempting to follow the documentation per Access Control and interrogating code like azure-documentdb-node SDK and I am unable to do so.
I get the following error: 401 Unauthorized: {"code":"Unauthorized","message":"The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndbs\n\n13 april 2015 18:21:05 gmt\n\n'\r\nActivityId: ...
My ruby code looks like the following:
require 'openssl'
require 'rest-client'
require 'base64'
require 'uri'
require 'json'
require 'time'
def get_databases url, master_key
time = Time.now.httpdate
authorization = get_master_auth_token "get", "", "dbs", time, master_key
header = { "authorization" => authorization, "x-ms-date" => time, "x-ms-version" => "2015-04-08" }
RestClient.get url, header
end
def get_master_auth_token verb, resource_id, resource_type, date, master_key
digest = OpenSSL::Digest::SHA256.new
key = Base64.decode64 master_key
text = verb + "\n" +
resource_type + "\n" +
resource_id + "\n" +
date + "\n" +
"\n"
hmac = OpenSSL::HMAC.digest digest, key, text.downcase
auth_string = "type=" + "master" + "&ver=" + "1.0" + "&sig=" + hmac
URI.escape auth_string
end
Thanks!
EDIT: After Ryan's advice and example I've simplified the code down to the following snippit that should be a match for the node code he has posted BUT it still fails in ruby:
def hard_coded_get_databases master_key, url
verb = "get"
resource_type = "dbs"
resource_id = ""
date = Time.now.httpdate
serv_version = '2014-08-21'
master_token = "master"
token_version = "1.0"
key = Base64.decode64 master_key
text = verb + "\n" + resource_type + "\n" + resource_id + "\n" + date + "\n\n"
body = text.downcase.force_encoding "utf-8"
signature = OpenSSL::HMAC.digest OpenSSL::Digest::SHA256.new, key, body
auth_token = URI.escape("type="+master_token + "&ver="+token_version + "&sig="+signature)
header = { "accept" => "application/json", "x-ms-version" => serv_version, "x-ms-date" => date, "authorization" => auth_token }
RestClient.get url, header
end
EDIT2: I believe I've isolated the problem to how I am doing the master key authentication.
Taking Ryan's example we can trim his node code down the following:
var crypto = require("crypto")
function encode_message(masterKey, message) {
var key = new Buffer(masterKey, "base64"); // encode/decode? base64 the masterKey
var body = new Buffer(message.toLowerCase(), "utf8"); // convert message to "utf8" and lower case
return crypto.createHmac("sha256", key).update(body).digest("base64"); // encrypt the message using key
}
If I call this node code I can produce the following key:
encode_message("blah", 'get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n')
'IYlLuyZtVLx5ANkGMAxviDHgC/DJJXSj1gUGLvN0oM8='
If I produce the equivalent ruby code to create the authentication my ruby code looks like the following:
require 'base64'
require 'openssl'
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message
Base64.urlsafe_encode64 hmac
end
If I call this code I get the following:
2.2.1 :021 > encode_message("blah", "get\ncolls\n\nTue, 14 Apr 2015 13:34:22 GMT\n\n")
=> "N6BL3n4eSvYA8dIL1KzlTIvR3TcYpdqW2UNPtKWrjP8="
Clearly the 2 encoded auth tokens are not the same. (Ryan again thanks so much for the help to get this far).
I have found the answer. Thanks to Magnus Stahre ... he is the man for helping me figure it out.
It was the encoding as I thought and the trick is this:
def encode_message master_key, message
key = Base64.urlsafe_decode64 master_key
hmac = OpenSSL::HMAC.digest 'sha256', key, message.downcase
Base64.encode64(hmac).strip
end
I was downcasing in my code too early AND my Base64.encode64 was failing to strip away a newline character that ruby was adding on the end.
i'll start off by apologizing for my limited Ruby knowledge but let me try assist here;
in your get_master_auth_token function it appears you are decoding the key before using it. is this correct? if so, why?
here is a node.js sample that uses the master key, builds up the auth header value and does a simple http call to list the collections in a database
var crypto = require("crypto");
var https = require("https");
https.globalAgent.options.secureProtocol = "TLSv1_client_method";
var verb = 'get';
var resourceType = 'dbs'; //the resource you are trying to get. dbs, colls, docs etc.
var resourceId = ''; //the parent resource id. note: not the id, but the _rid. but for you, because you are trying to lookup list of databases there is no parent
var masterKey = '...'; //your masterkey
var date = new Date().toUTCString();
var auth = getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey);
var options = {
hostname: '...', //your hostname (without https://)
port: 443,
path: '/dbs/',
method: 'GET',
headers: {
accept: 'application/json',
'x-ms-version': '2014-08-21',
'x-ms-date': date,
authorization: auth,
}
};
for (var i = 0; i < 1000; i++) {
var req = https.request(options, function (res) {
process.stdout.write(new Date().toUTCString() + " - statusCode: " + res.statusCode + "\n");
res.on('data', function (d) {
}).on('error', function (e) {
})
});
//console.log(req);
req.end();
}
function getAuthorizationTokenUsingMasterKey(verb, resourceId, resourceType, date, masterKey) {
var key = new Buffer(masterKey, "base64");
var text = (verb || "") + "\n" +
(resourceType || "") + "\n" +
(resourceId || "") + "\n" +
(date || "") + "\n" +
("") + "\n";
var body = new Buffer(text.toLowerCase(), "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);
}
In your example, the resourceId passed to the getAuthorizationTokenUsingMasterKey method should be "" and the resourceType should be "dbs" as you have it.
I did notice that in some cases you have to URI Encode the value, but I think you are doing that already as the very last line of the func.
the only difference I can spot in your code vs my code is that you appear to be decoding the master_key which I don't do.
what I would recommend you do is run this node sample and compare the values of the strings we have in body & signature to the your values. they need to match.

Resources