How to add metadata to nodejs grpc call - node.js

I'd like to know how to add metadata to a nodejs grpc function call. I can use channel credentials when making the client with
var client = new proto.Document('some.address:8000',
grpc.credentials.createInsecure()
)
Which are send when using client.Send(doc, callback), but the go grpc server looks in the call metadata for identification information which I have to set. I tried using grpc.credentials.combineChannelCredentials with the insecure connection and a grpc.Metadata instance but I can't find the right way to do it.
The error I run into is TypeError: compose's first argument must be a CallCredentials object. I tried to follow it down but it goes into c code which loses me, I can't see what javascript type I have to give to comebineChannelCredentials to achieve what I'm looking for and the docs are a little sparse on how to achieve this.

You can pass metadata directly as an optional argument to a method call. So, for example, you could do this:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);

For sake of completeness I'm going to extend on #murgatroid99 answer.
In order to attach metadata to a message on the client you can use:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);
On the server side int your RPC method being called, when you want to grab your data you can use:
function(call, callback){
var myVals = call.metadata.get("key");
//My vals will be an array, so if you want to grab a single value:
var myVal = myVals[0];
}

I eventually worked it out through introspecting the grpc credentials code and modifying the implementation to expose an inner function. In the grpc module in the node_modules, file grpc/src/node/src/credentials.js add the line
exports.CallCredentials = CallCredentials;
after CallCredentials is imported. Then, in your code, you can write something like
var meta = grpc.Metadata();
meta.add('key', 'value');
var extra_creds = grpc.credentials.CallCredentials.createFromPlugin(
function (url, callback) {
callback(null, meta);
}
)
Then use extra_creds in the client builder
var creds = grpc.credentials.combineChannelCredentials(
grpc.credentials.createSsl(),
extra_creds,
)
Now you can make your client
var client = new proto.Document(
'some.address:8000',
creds,
)

Related

how do i use bot.on features inside a module.exports file

I developed an algorithm that when u type in discord server's text channel : "-nuke #tag" that member will get a "Muted" role and his id will be added to an array. If he leaves the server and joins back, the bot will compare the new member's id with all the ids in the array and if they are matching it will automatically give that person the "Muted" role. The problem is, the bot.on doesn't seem to work inside something else than index.js. I dont really want to go inside all the event handlers and stuff, just to get this one working nuke.js
This answer is in reference to a comment I made. This will show you how to create and access a global map.
To start you need to extend the client class by the map you want to use. You do that like this.
const { Client } = require('discord.js');
module.exports = class extends Client {
constructor(config) {
super({});
this.muteIDs = new Map(); // you can name it whatever you like
this.config = config;
}
};
You should do that in a separate file. Lets call that file clientextend.js. Now you can create your bot client like you usually would, however you need to require the file that you just created. This example has both the file in which you extend the client and the file you create the client in, in the same directory. Note: In your example you have bot instead of client.
const Client = require('./clientextend.js')
const client = new Client();
You now have access to the map you created anywhere you have your client available to you. You can access it like this.
muteIDs = client.muteIDs;

display a herocard using luis action binding

How to create and display a "HeroCard" within the fulfill() function of LUIS action binding using node.js ? I am following the samples provided by the microsoft(https://github.com/Microsoft/BotBuilder-Samples/tree/master/Node/blog-LUISActionBinding)
Here is that how I tried to do this...
fulfill: function (parameters, callback) {
utilities.FilterFunction(parameters.x, parameters.y).then(function (matches){
utilities.CreateCard(session, matches).then(function(cards){
var reply = new builder.Message(session)
.attachmentLayout(builder.AttachmentLayout.carousel)
.attachments(cards);
callback(util.format(reply));
});
});
}
How can I use session value in the fulfill method?...without session "utilities.CreateCard" won't work...
Since session is not available in the action's fulfill method, we can make call to only to the utilities.FilterFunction and return the result via the callback. Now in our main js file, in the fulfillReplyHandler we get the actionModel which contains the result from utilities.FilterFunction.
Now we can create the "HeroCard" using the "session" that is accessible in the fulfillReplyHandler.

DocumentDB Stored Procs: what does the EnableScriptLogging option do?

The DocumentDB APIs for working with stored procedures take an optional RequestOptions argument that has, among others, the property EnableScriptLogging.
The help page for it is useless. The description for it is:
EnableScriptLogging is used to enable/disable logging in JavaScript stored procedures.
Mkay... so how do I log something? (assuming that's console.log(...))
And more importantly, how do I read the logs generated by stored procedures?
I was expecting the response of requests to stored procedures would somehow contain the logs, but can't find anything.
Yes, this is for console.log from script. Must be enabled by client (turned off by default, so that console.log in script is ignored), essentially this set http-header on request. In script you can do something like this:
function myScript() {
  console.log("This is trace log");
}
The log will be in response header (x-ms-documentdb-script-log-results), as well as can be accessible in SDK.
If you use C# SDK, you can use it like this:
var options = new RequestOptions { EnableScriptLogging = true };
var response = await client.ExecuteStoredProcedureAsync<string>(sprocUri, options);
Console.WriteLine(response.ScriptLog);
If you use node.js SDK:
var lib = require("documentdb");
var Client = lib.DocumentClient;
var client = new Client("https://xxxxxxx.documents.azure.com:443/", { masterKey: "xxxxxxxxxxxx" });
var sprocLink = ...;
client.executeStoredProcedure(sprocLink, "input params", { partitionKey: {}, enableScriptLogging: true }, function(err, res, responseHeaders) {
console.log(responseHeaders[lib.Constants.HttpHeaders.ScriptLogResults]);
}
Current limitations:
only enabled for stored procedures
\n is not supported (should be fixed soon)
not supported when script throws unhandled exception (should be fixed soon)

How to use Basic Auth with libsoup via Gjs

I'm trying to query github's api with a token. Github's api accepts generated tokens provided that they're sent as a basic auth header.
The API do not return HTTP 401 if the call is made without auth which means if one wants to query their api using Basic Auth, one must fill the header pre-emptively rather than doing a round trip.
I'm now trying to query the API using libsoup and Gjs.
I have noticed the SoupAuthManager has a function that seems to match perfectly what I need (soup_auth_manager_use_auth here) but can't find a way to invoke it.
This can be used to "preload" manager 's auth cache, to avoid an extra HTTP round trip in the case where you know ahead of time that a 401 response will be returned
This is what I currently use, but it does not work as the SoupAuthManager is a private object of the session; and has therefore no effect on the actual behaviour of the program
let httpSession = new Soup.Session();
let authUri = new Soup.URI(url);
authUri.set_user(this.handle);
authUri.set_password(this.token);
let message = new Soup.Message({method: 'GET', uri: authUri});
let authManager = new Soup.AuthManager();
let auth = new Soup.AuthBasic({host: 'api.github.com', realm: 'Github Api'});
authManager.use_auth(authUri, auth);
httpSession.queue_message(message, ...);
Are there other methods I could use to force Basic Auth on the first roud trip? or are there other library I could use from gjs to call github's API and force the basic auth?
I found the solution. To link the authorisation to the session, one can use the add_feature function. Now this is defined here but it turns out calling it directly doesn't work
this._httpSession.add_feature(authManager)
instead it seems to work if called like that:
Soup.Session.prototype.add_feature.call(httpSession, authManager);
finally, the github api rejects any call without a user agent, so I added the following:
httpSession.user_agent = 'blah'
the final code looks like:
let httpSession = new Soup.Session();
httpSession.user_agent = 'blah'
let authUri = new Soup.URI(url);
authUri.set_user(this.handle);
authUri.set_password(this.token);
let message = new Soup.Message({method: 'GET', uri: authUri});
let authManager = new Soup.AuthManager();
let auth = new Soup.AuthBasic({host: 'api.github.com', realm: 'Github Api'});
Soup.Session.prototype.add_feature.call(httpSession, authManager);
httpSession.queue_message(message, function() {...});

HttpClient response ReadAsAsync() doesn't fully deserialize object

I'm trying to consume a web service with the Web API client library. My problem is that the ReadAsAsync doesn't seem to want to fully deserailize the returned object when the submitting function uses a POST method.
If I get the response as a string and manually deserailize it works. (I get a apmsgMessage with all the fields populated)
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<apmsgMessage>(msg.Result);
I originally tried the code below which returns an apmsgMessage Object, but all the fields are null.
HttpClient client = GetClient();
var response = client.PostAsJsonAsync("api/robot/Preview", ad).Result;
var msg = response.Content.ReadAsAsync<apmsgMessage>().Result;
return msg;
My question is why dosn't my orginal (the PostAsJsonAsync) return a apmsgMessage fully populated. Am I doing somethign wrong with the ReadAsAsync?
I just had the same issue, and in my case I solved it by removing the [Serializable] attribute from the class.
I don't know why this attribute conflicts with the deserialization process, but as soon as I took that out, the ReadAsAsync method worked as expected.

Resources