Webhooks from Zapier in F# not working - f#

I am trying to make WebHooks from Zapier work in F#
Very simply
let wc = new System.Net.WebClient()
System.Net.ServicePointManager.SecurityProtocol <- System.Net.SecurityProtocolType.Ssl3
let result = wc.DownloadString("WEB HOOK URL GOES HERE")
printfn "%s" result
It just times out.
All webhooks are "https"
Some docs:
https://zapier.com/blog/how-use-zapier-webhooks/
Has anyone got this to work and/or can see what I am doing wrong?

Zapier co-founder here, we are using the ELBSecurityPolicy-2014-01 which you can read about here http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-security-policy-table.html. It isn't uncommon to have a box/libs that default to unsupported SSL protocols/ciphers.

Related

How does Kong detect connection timeout?

Currently, whenever an upstream service is down, kong will throw
"{"message":"failure to get a peer from the ring-balancer"}"
I am trying to create a custom plugin that detects the connection time out and return a customized message to the client, the blocker I am facing right now is writing lua codes in my custom plugin to detect the timeout. I have tried using
if(kong.response.get_source() == "error")
but that does not seem to detect timeout either.
Does anyone have any idea what I should do to detect connection timeout in when writing a custom kong plugin?
Sorry, I didn't catch you. Because I don't know what your function will return
If kong.response.get_source() returns a string {"message":"failure to get a peer from the ring-balancer"}
You need to use the JSON library to parse it.
local json = require("json")
local res = json.deceode(kong.response.get_source())
if res.message == "xxx" then
end
But your message is a little long. You can add a new key-value to the JSON string to represent the state.
For example:"{"status":"error","message":"failure to get a peer from the ring-balancer"}"
Then you can write code like this.
local json = require("json")
local res = json.deceode(kong.response.get_source())
if res.status == "error" then
end
I just looked at the Kong API Docs.
I find that the return value of kong.response.get_source() is HTTP status code, such as 200/500.
You can try print(kong.response.get_source()) and see the results.

The type provider 'ProviderImplementation.HtmlProvider' reported an error: The 'Value'='XXXX' part of the cookie is invalid

I'm using HtmlProvider to web scrape stock company news e.g. https://www.nasdaq.com/symbol/{STOCK_SYMBOL_HERE}/news-headlines but I'm getting an error in this line of code
let [<Literal>] stockNewsUrl = "https://www.nasdaq.com/symbol/AAPL/news-headlines"
let news = new HtmlProvider<stockNewsUrl>()
There is squiggle on the second line and the error was Error FS3033 The type provider 'ProviderImplementation.HtmlProvider' reported an error: Cannot read sample HTML from 'https://www.nasdaq.com/symbol/AAPL/news-headlines': The 'Value'='AAPL,technology' part of the cookie is invalid.
To make an HTTP request to https://www.nasdaq.com/symbol/AAPL/news-headlines, we are required to provide a CookieContainer. Since you are using the FSharp.Data library, I suggest to use its HTTP Utilities:
type Nasdaq = HtmlProvider<"/tmp.html">
let cc = CookieContainer ()
let data =
Http.RequestString ("https://www.nasdaq.com/symbol/AAPL/news-headlines", cookieContainer = cc)
|> Nasdaq.Parse
data.Tables.``Today's Market Activity``.Html
|> printfn "%A"
Of course you have to pre-download the page and save to /tmp.html first.
Small note: if we already have the HTML string (as in our case), we use Nasdaq.Parse; if we have a url, we use Nasdaq.Load.
It looks like this fails because F# Data sends cookies in a format that the Nasdaq service does not like. An easy workaround is to download the page once to have a sample available at compile-time and then download the page at runtime using some other means.
type Nasdaq = HtmlProvider<"c:/temp/nasdaq.html">
let wc = new WebClient()
let downloaded = wc.DownloadString("https://www.nasdaq.com/symbol/AAPL/news-headlines")
let ns = Nasdaq.Load(downloaded)
This works, but there are two issues:
The page dos not contain any tables/lists, so the ns value is not giving you nice static access to anything useful
I get timeout exception when I try to download the data using WebClient, so perhaps that also does not work (but it might just be that I'm behind a proxy or something..)

How to send a speech to text request using google_speech1 in Rust?

I am trying to use google_speech1 for Rust, but the documentation provides incomplete examples, which makes it very hard for me, being both new at Rust and at using Google Speech Api, to figure out how to do send a speech to text request.
More specifically, I would like to be able to send a local audio file, indicate the source language and retrieve the transcription.
Here is the closest I could find in the official documentation(https://docs.rs/google-speech1/1.0.8+20181005/google_speech1/struct.SpeechRecognizeCall.html):
use speech1::RecognizeRequest;
// As the method needs a request, you would usually fill it with the desired information
// into the respective structure. Some of the parts shown here might not be applicable !
// Values shown here are possibly random and not representative !
let mut req = RecognizeRequest::default();
// You can configure optional parameters by calling the respective setters at will, and
// execute the final call using `doit()`.
// Values shown here are possibly random and not representative !
let result = hub.speech().recognize(req)
.doit();
UPDATE
Taking a step back, even simple examples provided on the website don't seem to run properly. Here is some sample very basic code:
pub mod speech_api_demo {
extern crate google_speech1 as speech1;
extern crate hyper;
extern crate hyper_rustls;
extern crate yup_oauth2 as oauth2;
use oauth2::{ApplicationSecret, Authenticator, DefaultAuthenticatorDelegate, MemoryStorage};
use speech1::Speech;
use speech1::{Error, Result};
use std::fs::File;
use std::io::Read;
#[derive(Deserialize, Serialize, Default)]
pub struct ConsoleApplicationSecret {
pub web: Option<ApplicationSecret>,
pub installed: Option<ApplicationSecret>,
}
pub fn speech_sample_demo() {
/*
Custom code to generate application secret
*/
let mut file =
File::open("C:\\Users\\YOURNAME\\.google-service-cli\\speech1-secret.json").unwrap();
let mut data = String::new();
file.read_to_string(&mut data).unwrap();
use serde_json as json;
let my_console_secret = json::from_str::<ConsoleApplicationSecret>(&data);
assert!(my_console_secret.is_ok());
let unwrappedConsoleSecret = my_console_secret.unwrap();
assert!(unwrappedConsoleSecret.installed.is_some() && unwrappedConsoleSecret.web.is_none());
let secret: ApplicationSecret = unwrappedConsoleSecret.installed.unwrap();
/*
Custom code to generate application secret - END
*/
// Instantiate the authenticator. It will choose a suitable authentication flow for you,
// unless you replace `None` with the desired Flow.
// Provide your own `AuthenticatorDelegate` to adjust the way it operates and get feedback about
// what's going on. You probably want to bring in your own `TokenStorage` to persist tokens and
// retrieve them from storage.
let auth = Authenticator::new(
&secret,
DefaultAuthenticatorDelegate,
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
<MemoryStorage as Default>::default(),
None,
);
let mut hub = Speech::new(
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
auth,
);
let result = hub.operations().get("name").doit();
match result {
Err(e) => match e {
// The Error enum provides details about what exactly happened.
// You can also just use its `Debug`, `Display` or `Error` traits
Error::HttpError(_)
| Error::MissingAPIKey
| Error::MissingToken(_)
| Error::Cancelled
| Error::UploadSizeLimitExceeded(_, _)
| Error::Failure(_)
| Error::BadRequest(_)
| Error::FieldClash(_)
| Error::JsonDecodeError(_, _) => (println!("{}", e)),
},
Ok(res) => println!("Success: {:?}", res),
}
}
}
Running this code (calling speech_sample_demo) gives the following error:
Token retrieval failed with error: Invalid Scope: 'no description
provided'
I also tried some very ugly code to force the scope into the request, but it did not make any difference. I am having a hard time understanding what this error means. Am I missing something in my request or is it something else getting in the way at the other end? Or maybe that api code library is just broken?
Please also note that client id and client secret provided by default don't work anymore, when I was using those it would say that account is deleted.
I then set up an OAuth 2.0 client and generated the json file which I copied over to default location and then started getting the error above. Maybe it is just me not setting Google Api account properly, but in any case would be great if someone else could try it out to see if I am the only one having those issues.
Once I get over running such a simple request, I have some more code ready to be tested that sends over an audio file, but for now it fails very early on in the process.
The error you get originates from here and means that the OAuth scope you used when generating your credentials file doesn't allow you to access the Google speech API. So the problem is not in your Rust code, but instead in the script you used to generate your OAuth access tokens.
Basically, this means that when you generated your OAuth json file, you requested access to the Google API in a general way, but you didn't say which specific APIs you meant to use. According to this document, you need to request access to the https://www.googleapis.com/auth/cloud-platform scope.
You are missing the flow param to Authenticator. This is how you get the access token. You create an Enum using FlowType.
example:
use oauth2::{ApplicationSecret, Authenticator, DefaultAuthenticatorDelegate, MemoryStorage,FlowType};
let Flo = FlowType::InstalledInteractive;
let auth = Authenticator::new(
&secret,
DefaultAuthenticatorDelegate,
hyper::Client::with_connector(hyper::net::HttpsConnector::new(
hyper_rustls::TlsClient::new(),
)),
<MemoryStorage as Default>::default(),
None,)
See here: https://docs.rs/yup-oauth2/1.0.3/yup_oauth2/enum.FlowType.html
Not exactly easy to figure out.
I made this work via service accounts by doing this
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.build();
let service_account_key: oauth2::ServiceAccountKey = oauth2::read_service_account_key(
&"PATH_TO_SERVICE_ACCOUNT.json".to_string(),
)
.await
.unwrap();
let auth = oauth2::ServiceAccountAuthenticator::builder(service_account_key)
.build()
.await
.unwrap();
let hub = Speech::new(hyper::Client::builder().build(https), auth);

Publish a message from Vernemq plugin

I want to convert an HTTP request to MQTT request. So for that I received the HTTP request which consist of the information like topic and message to publish. I have to publish the provided message to provided topic.
I am able to publish the message but the problem is that I can only provide the Topic and Payload to the function I used. Here is the piece of code I write to publish:
Data = mochiweb_request:parse_post(Req),
{RegisterFun, PublishFun, SubscribeFun} = vmq_reg:direct_plugin_exports(http_to_mqtt),
Topic = get_value("topic", Data),
List_of_topics = string:tokens(Topic, "/"),
Lot = lists:map(fun(X) -> list_to_binary(X) end, List_of_topics),
Payload = list_to_binary(get_value("message", Data)),
error_logger:info_msg("Topics: ~p~nPayload: ~p",[Lot, Payload]),
PublishFun(Lot,Payload),
Req:ok({"text/html", [], "<p>Thank you. <p>"})
Here the PublishFun I get from the vmq_reg can only allow to give topic and message. Is there any other way I can publish a message giving the value to Qos, Retain and Dup also.
I am creating a server using mochiweb and use it as a plugin in vernemq.
It is now possible in the new release of VerneMQ as stated by Andre.
Here is how it works :
Data = mochiweb_request:parse_post(Req),
{RegisterFun,PublishFun,SubscribeFun} = vmq_reg:direct_plugin_exports(http_to_mqtt),
Topic = get_value("topic", Data),
List_of_topics = string:tokens(Topic, "/"),
Lot = lists:map(fun(X) -> list_to_binary(X) end, List_of_topics),
Payload = list_to_binary(get_value("message", Data)),
Qos = erlang:list_to_integer(get_value("qos",Data)),
Retain = erlang:list_to_integer(get_value("retain",Data)),
error_logger:info_msg("Topics: ~p~nPayload: ~p~nQOS: ~p~nRetain: ~p",[Lot, Payload,Qos,Retain]),
PublishFun(Lot,Payload,#{qos => Qos, retain => Retain}),
Req:ok({"text/html", [], "<p>Thank you. <p>"})
It is not possible in the current version, but a planned feature for the future.

How can I get AttributeExchange and/or SimpleRegistration working with MVC?

I'm banging my head against a wall trying to get either AttributeExchange or SimpleRegistration working with the 3.2.0.9257 version of DotNetOpenAuth.
Here is what I've done:
Downloaded the 3.2.0.9257 tag from GitHub
Opened the DotNetOpenAuth visual studio solution
Made changes to the OpenIdRelyingPartyMvc sample
The changes are all in the Authenticate method of UserController.
I replaced line 44,
return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
with the following:
var request = openid.CreateRequest(Request.Form["openid_identifier"]);
// Add SimpleRegistration requests for Email and FullName
var sr = new ClaimsRequest();
sr.Email = DemandLevel.Request;
sr.FullName = DemandLevel.Request;
request.AddExtension(sr);
// Add AttributeExchange requests for Email and FullName
var ax = new FetchRequest();
ax.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email));
ax.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName));
request.AddExtension(ax);
return request.RedirectingResponse.AsActionResult();
(I also added the DotNetOpenAuth.OpenId.Extensions.AttributeExchange and DotNetOpenAuth.OpenId.Extensions.SimpleRegistration namespaces.)
Then, further down in the same method, after the "Stage 3 Authenticated", I try to get the responses:
var sr = response.GetExtension<ClaimsResponse>();
var ax = response.GetExtension<FetchResponse>();
However, those responses are always null. I've tried Google, Yahoo, and MyOpenID. In all cases, the authentication works correctly, but no SimpleRegistration or AttributeExchange data is returned.
What am I doing wrong?
Google doesn't support sreg, and its AX support is email-address-only, and only if you mark the email address as "required" (your code uses the default "optional").
Yahoo doesn't support AX, and its sreg support is a whitelisted RP only.
MyOpenID supports sreg, and a different variety of AX than DotNetOpenAuth uses by default. Are you sure the ClaimsResponse is null when used against MyOpenID? Because in my tests it works fine.
You can get around having to send sreg and AX requests, and the 3 different flavors of AX by just using the AXFetchAsSregTransform behavior described under Getting User Attributes of the DotNetOpenAuth documentation.

Resources