What permission is needed for udp in a chrome app? - sockets

What permission is needed for udp in a chrome app?
I get the error:
Unchecked runtime.lastError while running sockets.udp.bind: App does not have permission
but I can't find the permission needed.
My manifest.json file looks like this:
{
"name": "XX",
"description": "XX",
"version": "0.0.1",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["main.js"]
}
},
"icons": {
"16": "icon-16.png",
"128": "icon-128.png"
},
"sockets": {
"udp": {
"send": "*"
}
},
"permissions": [
"fullscreen", "alwaysOnTopWindows", "videoCapture", "storage", "browser"
]
}

you need to ask for the bind permission
"udp": {
"send": ["*"],
"bind": ["*"]
}

Using UDP
Chrome Apps can make connections to any service that supports UDP.
Sending data
Here's a sample showing how to send data (sockets.udp.send) over the network using UDP:
// Create the Socket
chrome.sockets.udp.create({}, function(socketInfo) {
// The socket is created, now we can send some data
var socketId = socketInfo.socketId;
chrome.sockets.udp.send(socketId, arrayBuffer,
'127.0.0.1', 1337, function(sendInfo) {
console.log("sent " + sendInfo.bytesSent);
});
});
Receiving data
This example is very similar to the 'Sending data' example, except we setup an event handler for receiving data.
var socketId;
// Handle the "onReceive" event.
var onReceive = function(info) {
if (info.socketId !== socketId)
return;
console.log(info.data);
};
// Create the Socket
chrome.sockets.udp.create({}, function(socketInfo) {
socketId = socketInfo.socketId;
// Setup event handler and bind socket.
chrome.sockets.udp.onReceive.addListener(onReceive);
chrome.sockets.udp.bind(socketId,
"0.0.0.0", 0, function(result) {
if (result < 0) {
console.log("Error binding socket.");
return;
}
chrome.sockets.udp.send(socketId, arrayBuffer,
'127.0.0.1', 1337, function(sendInfo) {
console.log("sent " + sendInfo.bytesSent);
});
});
});
for more info: look here

Related

Failed to submit transaction: Error: no suitable peers available to initialize from

I am running my blockchain project which is election system using blockchain using hyperledger fabric and IBM blockchain Platform VSCode Extension (runnning my network locally). I am successfull to run connect to local fabric and my gateway is running successfully(image attached). Also all docker containers of peer,orderer,certificate authority are running (image attached).
connected to local fabric and gateway
all docker containers running successfuly
The problem which I am facing is that when (after connecting to local fabric and gateway) I am running invoke.js file using the command "node invoke.js" I am encountering above error. following picture link shows how I am running invoke.js
trying to run invoke.js but facing error
following is my config.json file code
{
"connection_file": "fabric_connection.json",
"appAdmin": "admin",
"appAdminSecret": "adminpw",
"orgMSPID": "org1MSP",
"caName": "ca",
"userName": "V1",
"gatewayDiscovery": { "enabled": true, "asLocalhost": true }
}
and following is my fabric-connection.json file code
{
"certificateAuthorities": {
"ca.org1.example.com": {
"caName": "ca",
"url": "http://localhost:17090"
}
},
"client": {
"connection": {
"timeout": {
"orderer": "300",
"peer": {
"endorser": "300"
}
}
},
"organization": "Org1MSP"
},
"name": "ca.org1.example.com",
"organizations": {
"Org1MSP": {
"certificateAuthorities": [
"ca.org1.example.com"
],
"mspid": "Org1MSP",
"peers": [
"Org1Peer1"
]
}
},
"peers": {
"Org1Peer1": {
"url": "grpc://localhost:17091"
}
},
"version": "1.0.0"
}
and following is my invoke.js file complete code
//Import Hyperledger Fabric 1.4 programming model - fabric-network
'use strict';
const { FileSystemWallet, Gateway } = require('fabric-network');
const path = require('path');
const fs = require('fs');
//connect to the config file
const configPath = path.join(process.cwd(), './config.json');
const configJSON = fs.readFileSync(configPath, 'utf8');
const config = JSON.parse(configJSON);
// connect to the connection file
const ccpPath = path.join(process.cwd(), './ibpConnection.json');
const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
const connectionProfile = JSON.parse(ccpJSON);
// A wallet stores a collection of identities for use
const walletPath = path.join(process.cwd(), './wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
const peerIdentity = 'admin';
async function queryAll() {
try {
let response;
// Check to see if we've already enrolled the user.
const userExists = await wallet.exists(peerIdentity);
if (!userExists) {
console.log('An identity for the user ' + peerIdentity + ' does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
response.error = 'An identity for the user ' + peerIdentity + ' does not exist in the wallet. Register ' + peerIdentity + ' first';
return response;
}
//connect to Fabric Network, but starting a new gateway
const gateway = new Gateway();
//use our config file, our peerIdentity, and our discovery options to connect to Fabric network.
await gateway.connect(connectionProfile, { wallet, identity: peerIdentity, discovery: config.gatewayDiscovery });
//connect to our channel that has been created on IBM Blockchain Platform
const network = await gateway.getNetwork('mychannel');
//connect to our insurance contract that has been installed / instantiated on IBM Blockchain Platform
const contract = await network.getContract('voteChainDemo');
//submit transaction to the smart contract that is installed / instnatiated on the peers
console.log('calling contract.evaluateTransaction, with args');
response = await contract.submitTransaction('queryAll');
response = JSON.parse(response.toString());
console.log(`response from evaluateTransaction: ${(response)}`)
console.log('Transaction has been submitted');
// Disconnect from the gateway.
await gateway.disconnect();
} catch (error) {
console.error(`Failed to submit transaction: ${error}`);
}
}
// let args = ["V1"]
// args = args.toString();
queryAll();
and I see following logs when I view docker container logs of peer0.org1.example.com
enter image description here
following is the code of ibpconnection.json file
{
"name": "mychannel",
"description": "Network on IBP v2",
"version": "1.0.0",
"client": {
"organization": "org1MSP"
},
"organizations": {
"org1MSP": {
"mspid": "org1MSP",
"peers": [
"173.193.112.109:17091"
],
"certificateAuthorities": [
"173.193.112.109:7054"
]
}
},
"orderers": {
"173.193.112.109:7050": {
"url": "grpcs://173.193.112.109:17097",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICJzCCAc6gAwIBAgIUCZxOyrvnwM/IG/3zQ9opnOE/gBEwCgYIKoZIzj0EAwIw\nZTELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRYwFAYDVQQDEw1PcmRlcmVy\nQ0EtdGxzMB4XDTE5MDYxNDIwNDcwMFoXDTM0MDYxMDIwNDcwMFowZTELMAkGA1UE\nBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQKEwtIeXBlcmxl\nZGdlcjEPMA0GA1UECxMGRmFicmljMRYwFAYDVQQDEw1PcmRlcmVyQ0EtdGxzMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOXI7XkoPBn7a9Q1x2S8SpmilQBalhorq\nCo96GChxQU0HJX/1qRPNN72CKx2YS/ksl+eOaHe/+pH32S5VWZLxaKNcMFowDgYD\nVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFIdV28CJ\nPozrl6hpxVkKpNdmAO7vMBUGA1UdEQQOMAyHBK3BcG2HBApM2GAwCgYIKoZIzj0E\nAwIDRwAwRAIgTOPmbGXzIL8SriNT/x8XdBLoTbpEVd/HIpv9nf0bWysCIBvOppOp\nvINgCydCwV1FTbP5tuqYxuShVTAba1h9ZZmm\n-----END CERTIFICATE-----\n"
}
}
},
"peers": {
"173.193.112.109:17091": {
"url": "grpcs://173.193.112.109:17093",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\nMIICIzCCAcqgAwIBAgIUbY5U1xnvvSqJ61CgeMp9/qu448owCgYIKoZIzj0EAwIw\nYzELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMRQwEgYDVQQK\nEwtIeXBlcmxlZGdlcjEPMA0GA1UECxMGRmFicmljMRQwEgYDVQQDEwtWb3RlckNB\nLXRsczAeFw0xOTA2MTQyMDQwMDBaFw0zNDA2MTAyMDQwMDBaMGMxCzAJBgNVBAYT\nAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTEUMBIGA1UEChMLSHlwZXJsZWRn\nZXIxDzANBgNVBAsTBkZhYnJpYzEUMBIGA1UEAxMLVm90ZXJDQS10bHMwWTATBgcq\nhkjOPQIBBggqhkjOPQMBBwNCAASFv8sUAUfTvn8AJ/fiqrk0wdoMaKlG38nU6HZB\nkdUgFWZH9vnlTTBT77+GYRXuv78lg7ttus6DEAJE0X1xDd27o1wwWjAOBgNVHQ8B\nAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUHuwEDf9d4vrv\nZM+qveoS9PV8/5cwFQYDVR0RBA4wDIcErcFwbYcECkzYYDAKBggqhkjOPQQDAgNH\nADBEAiBjynyKK+Bo4WX3wQII1nk2BU8OaYAuBvpTS/pPROdX+QIgSsLzKWuR7dFN\n50KrbM4ayRuaFBOFL88FflKxaRjQels=\n-----END CERTIFICATE-----\n"
},
"grpcOptions": {
"ssl-target-name-override": "173.193.112.109"
}
}
},
"certificateAuthorities": {
"173.193.112.109:7054": {
"url": "https://173.193.112.109:17090",
"caName": "ca",
"tlsCACerts": {
"pem": "-----BEGIN CERTIFICATE-----\r\nMIICezCCAeSgAwIBAgIJNQli68LG70HNMA0GCSqGSIb3DQEBBQUAMHUxGDAWBgNV\r\nBAMTDzE3My4xOTMuMTEyLjEwOTELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRo\r\nIENhcm9saW5hMRAwDgYDVQQHEwdSYWxlaWdoMQwwCgYDVQQKEwNJQk0xEzARBgNV\r\nBAsTCkJsb2NrY2hhaW4wHhcNMTkwNjE0MjA0NDM2WhcNMjAwNjEzMjA0NDM2WjB1\r\nMRgwFgYDVQQDEw8xNzMuMTkzLjExMi4xMDkxCzAJBgNVBAYTAlVTMRcwFQYDVQQI\r\nEw5Ob3J0aCBDYXJvbGluYTEQMA4GA1UEBxMHUmFsZWlnaDEMMAoGA1UEChMDSUJN\r\nMRMwEQYDVQQLEwpCbG9ja2NoYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\r\ngQCXKBfHLyQfavboQU0y/3S4jlqh6vQgXZKeAMliXfigf6aLG/3Oc4pxuQxBccB6\r\nAiYTFZdShTy2Usx5GsDf5PWxfD4vJ8FWzAGlIYmVqseKXXjsQvwMlCMyS9K2NaDo\r\n9tXwvHz8Sgncq7KccseVYwX4FFpSQWZsIV27Y2xkMZ9bVQIDAQABoxMwETAPBgNV\r\nHREECDAGhwStwXBtMA0GCSqGSIb3DQEBBQUAA4GBAG1+VZNSQdm0DX9CbZzx9zbx\r\nnTEHyrhVTgZs5YuUvZX8BErYfJFxuPBsXhOpQan/L9y+a7C/Caac4WJ/l/l34e5M\r\nG1Hn603wkHpR0UFuGCikdctm+6iHUVro5CMfQlEPIqaJSTFb7Ju5aeeerHnkvQx8\r\nBShP1pNsvsyOctmFhQCQ\r\n-----END CERTIFICATE-----\r\n"
}
}
}
}
In my project which is pretty much having the same things as you, I did not specified the orderers in my connection config file. I am not sure if it is required in your scenario.
Besides, I think the issue is caused by incorrect urls specified in your ibpconnection.jsonfile.
orderers should have "url": "grpcs://173.193.112.109:7050"
AND
peers should have "url": "grpcs://173.193.112.109:17091"
Hope this will fix the error. Good luck!!!!

Include Loopback relation in POST response

I have a working chat-room loopback project, which also utilises Socket.IO.
Once I create a Message (POST to Loopback REST API), I need the response the include the 'creator' relation.
This works fine when using GET, but I cannot include the relation to the POST response.
I'm sure it's a simple remote hook, but I'm stuck...
Any help is greatly appreciated!
"relations": {
"creator": {
"type": "belongsTo",
"model": "Person",
"foreignKey": "",
"options": {
"nestRemoting": true
}
},
"event": {
"type": "belongsTo",
"model": "Event",
"foreignKey": "",
"options": {
"nestRemoting": true
}
}
},
There are two options how you can do it with Loopback 2.x or 3.x (not sure about the Loopback 4.x).
Let's assume we have the following "Note" model:
{
"name": "Note",
"properties": {
"title": {
"type": "string",
"required": true
},
"content": {
"type": "string"
},
"userId": {
"type": "number"
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "User",
"foreignKey": "userId"
}
}
}
Now, to include "user" property (which is a belongsTo relation of Note) in the response when you create (POST) a Note you have two options.
Option #1 (Recommended): Create a custom remote method and hide the default method in your model's script file. In this case your note.js file should look something like:
module.exports = function (Note) {
// Hide the default 'create' remote method
Note.disableRemoteMethod('create', true);
// Add a custom 'customCreate' remote method
Note.remoteMethod('customCreate', {
description: 'Create a new instance of the model and persist it into the data source.',
accessType: 'WRITE',
accepts: [
{
arg: 'data',
type: 'object',
model: 'Note',
allowArray: true,
description: 'Model instance data',
http: { source: 'body' },
},
{ arg: 'options', type: 'object', http: 'optionsFromRequest' },
],
returns: { arg: 'data', type: 'Note', root: true },
http: { verb: 'post', path: '/' },
isStatic: true,
});
Note.customCreate = function (data, options, cb) {
Note.create(data, options, function(err, newObj) {
if (err) {
cb(err);
}
else {
// here we try to load the user value
newObj.user(function (err, user) {
if (user) {
// if we found a user we add it to __data, so it appears in the output (a bit hacky way)
newObj.__data.user = user;
}
cb(err, newObj);
});
}
});
};
};
I would recommend using this option because you achieve what you need with minimal changes in the default logic of the loopback model, i.e. all the default methods like create, upsert, etc. continue to have default behavior.
Option 2: Use 'after save' operation hook (be careful with this approach as it changes the way how create, upsert, upsertWithWhere and other default methods work)
In this case your note.js file should look something like:
module.exports = function (Note) {
Note.observe('after save', function (ctx, next) {
ctx.instance.user(function (err, user) {
ctx.instance.__data.user = user;
next();
});
});
};
The second option has less code, but as I mentioned before you should be very careful using it because it will change the behavior of default "create" method of the model. I.e. 'after save' action will be executed each time you call Model.create, Model.upsert, etc. It will also slow down these operation as you add additional select query in the 'after save' hook.

google actions: conversation exit using actions sdk does not invoke actions.intent.CANCEL

I am using the actions SDK to build fulfilments. I am using Google Functions for the same. I have the following in the action.json
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "App"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
. . .
]
}
}
}
],
"conversations": {
"App": {
"name": " ... ",
"url": " ...",
"fulfillmentApiVersion": 2
}
},
"locale": "en"
}
In the function code I notice that the custom intent code of actions.intent.CANCEL is not getting called when the user says/ types exit or Goodbye. In the emulator only the <earcon> appears. The JS code is as below:
app.intent('actions.intent.MAIN', (conv) => {
conv.ask('Welcome to ...');
});
app.intent('actions.intent.TEXT', (conv, input) => {
// the main logic of the application is here
});
app.intent('actions.intent.CANCEL', (conv) => {
conv.close(`Okay, let's try this again later.`);
// this code does not get called
});
Is something to be set in action.json for the cancel intent to work
Yes, you need to add something to your action.json for it to send you the CANCEL Intent. In your existing conversations object, add an inDialogIntents attribute with an array of objects giving the name of the CANCEL Intent. Something like this:
"conversations": {
"App": {
"name": "...",
"url": "...",
"fulfillmentApiVersion": 2
"inDialogIntents": [
{
"name": "actions.intent.CANCEL"
}
]
}
}

Storing data "across conversations" in Google Action

I'm a bit confused by the Google Actions documentation about storing data and hoped someone can help clarify...
The docs state that data in the conv.user.storage object will be saved "across conversations". I took this to mean that if the user exited the conversation these values would be persisted and available the next time they interact with my action. Is that understanding correct?
The reason I ask is that I can't get this behaviour to work in my action.
I have built a simple action fulfilment service (using Actions on Google NodeJS library v2.4.0 and Koa v2.5.3). The fulfilment is triggered from an intent defined in Dialogflow (after an account has been linked with Google Sign In) and stores a value in conversation storage. The code is as follows:
server.js (base server - loads actions dynamically from the local ./actions/ dir)
/* Load the environment */
const dotenv = require('dotenv');
const path = require('path');
const packageJson = require('./package.json');
dotenv.config({
silent: true,
path: process.env.ENV_FILE!=undefined && process.env.ENV_FILE.trim()!='' ? path.normalize(process.env.ENV_FILE) : path.join(__dirname, './.env')
});
const SERVER_NAME = process.env.NAME || packageJson.name;
const SERVER_PORT = process.env.PORT||'8080';
const SERVER_HOST = process.env.HOST||'0.0.0.0';
const HANDLERS_PATH = './actions/';
/* Load the dependencies */
const logger = require('utils-general').logger('google-server');
const Koa = require('koa');
const KoaBody = require('koa-body');
const KoaActionsOnGoogle = require('koa-aog');
const fs = require('fs');
const { dialogflow } = require('actions-on-google');
/* Load and initialise the Google Assistant actions */
//Initialise DialogFlow
const action = dialogflow({ debug: process.env.ACTIONS_DEBUG==='true', clientId: process.env.GOOGLE_CLIENT_ID });
//Load the action intent handlers
const handlers = [];
let handlerFiles = fs.readdirSync(HANDLERS_PATH);
handlerFiles.forEach(function loadHandlers(file) {
let handlerImpl = require(HANDLERS_PATH+file);
let handler = {};
handler[handlerImpl.intent] = handlerImpl.action;
handlers.push(handler);
});
//Add the actions intent handlers to DialogFlow
handlers.forEach(item => {
let key = Object.keys(item)[0];
logger.info(`Adding handler for action intent ${key}`);
action.intent(key, item[key]);
});
/* Create the application server to handle fulfilment requests */
logger.info(`Initialising the ${SERVER_NAME} server (port: ${SERVER_PORT}, host: ${SERVER_HOST})`);
//Create the server
const app = new Koa();
//Add default error handler middleware
app.on('error', function handleAppError(err) {
logger.error(`Unhandled ${err.name||'Error'}: ${err.message || JSON.stringify(err)}`);
});
//Add body parsing middleware
app.use(KoaBody({ jsonLimit: '50kb' }));
//Log the request/ response
app.use(async (ctx, next) => {
logger.trace(`REQUEST ${ctx.method} ${ctx.path} ${JSON.stringify(ctx.request.body)}`);
await next();
logger.trace(`RESPONSE (${ctx.response.status}) ${ctx.response.body ? JSON.stringify(ctx.response.body) : ''}`);
});
//Make the action fulfilment endpoint available on the server
app.use(KoaActionsOnGoogle({ action: action }));
/* Start server on the specified port */
app.listen(SERVER_PORT, SERVER_HOST, function () {
logger.info(`${SERVER_NAME} server started at ${new Date().toISOString()} and listening for requests on port ${SERVER_PORT}`);
});
module.exports = app;
storage-read.js (fulfilment for the "STORAGE_READ" intent - reads stored uuid from conversation storage):
const logger = require('utils-general').logger('google-action-storage-read');
const { SimpleResponse } = require('actions-on-google');
const { getUserId } = require('../utils/assistant-util');
const _get = require('lodash.get');
module.exports = {
intent: 'STORAGE_READ',
action: async function (conv, input) {
logger.debug(`Processing STORAGE_READ intent request: ${JSON.stringify(conv)}`, { traceid: getUserId(conv) });
let storedId = _get(conv, 'user.storage.uuid', undefined);
logger.debug(`User storage UUID is ${storedId}`);
conv.close(new SimpleResponse((storedId!=undefined ? `This conversation contains stored data` : `There is no stored data for this conversation`)));
}
}
storage-write.js (fulfils the "STORAGE_WRITE" intent - writes a UUID to conversation storage):
const logger = require('utils-general').logger('google-action-storage-read');
const { SimpleResponse } = require('actions-on-google');
const { getUserId } = require('../utils/assistant-util');
const _set = require('lodash.set');
const uuid = require('uuid/v4');
module.exports = {
intent: 'STORAGE_WRITE',
action: async function (conv, input) {
logger.debug(`Processing STORAGE_WRITE intent request`, { traceid: getUserId(conv) });
let newId = uuid();
logger.debug(`Writing new UUID to conversation storage: ${newId}`);
_set(conv, 'user.storage.uuid', newId);
conv.close(new SimpleResponse(`OK, I've written a new UUID to conversation storage`));
}
}
This "STORAGE_WRITE" fulfilment stores the data and makes it available between turns in the same conversation (i.e. another intent triggered in the same conversation can read the stored data). However, when the conversation is closed, subsequent (new) conversations with the same user are unable to read the data (i.e. when the "STORAGE_READ" intent is fulfilled) - the conv.user.storage object is always empty.
I have voice match set up on the Google account/ Home Mini I'm using, but I can't see how I determine in the action if the voice is matched (although it seems to be as when I start a new conversation my linked account is used). I'm also getting the same behaviour on the simulator.
Sample request/ responses (when using the simulator) are as follows:
STORAGE_WRITE request:
{
"user": {
"userId": "AB_Hidden_EWVzx3q",
"locale": "en-US",
"lastSeen": "2018-10-18T12:52:01Z",
"idToken": "eyMyHiddenTokenId"
},
"conversation": {
"conversationId": "ABwppHFrP5DIKzykGIfK5mNS42yVzuunzOfFUhyPctG0h0xM8p6u0E9suX8OIvaaGdlYydTl60ih-WJ5kkqV4acS5Zd1OkRJ5pnE",
"type": "NEW"
},
"inputs": [
{
"intent": "actions.intent.MAIN",
"rawInputs": [
{
"inputType": "KEYBOARD",
"query": "ask my pathfinder to write something to conversation storage"
}
],
"arguments": [
{
"name": "trigger_query",
"rawText": "write something to conversation storage",
"textValue": "write something to conversation storage"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
}
]
},
"isInSandbox": true,
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
}
]
}
],
"requestType": "SIMULATOR"
}
STORAGE_WRITE response:
{
"conversationToken": "[]",
"finalResponse": {
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "OK, I've written a new UUID to conversation storage"
}
}
]
}
},
"responseMetadata": {
"status": {
"message": "Success (200)"
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "a7e54fcf-8ff1-4690-a311-e4c6a8d1bfd7"
}
},
"userStorage": "{\"data\":{\"uuid\":\"7dc835fa-0470-4028-b8ed-3374ed65ac7c\"}}"
}
Subsequent STORAGE_READ request:
{
"user": {
"userId": "AB_Hidden_EWVzx3q",
"locale": "en-US",
"lastSeen": "2018-10-18T12:52:47Z",
"idToken": "eyMyHiddenTokenId"
},
"conversation": {
"conversationId": "ABwppHHVvp810VEfa4BhBJPf1NIfKUGzyvw9JCw7kKq9YBd_F8w0VYjJiSuzGLrHcXHGc9pC6ukuMB62XVkzkZOaC24pEbXWLQX5",
"type": "NEW"
},
"inputs": [
{
"intent": "STORAGE_READ",
"rawInputs": [
{
"inputType": "KEYBOARD",
"query": "ask my pathfinder what is in conversation storage"
}
],
"arguments": [
{
"name": "trigger_query",
"rawText": "what is in conversation storage",
"textValue": "what is in conversation storage"
}
]
}
],
"surface": {
"capabilities": [
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
},
{
"name": "actions.capability.MEDIA_RESPONSE_AUDIO"
}
]
},
"isInSandbox": true,
"availableSurfaces": [
{
"capabilities": [
{
"name": "actions.capability.WEB_BROWSER"
},
{
"name": "actions.capability.AUDIO_OUTPUT"
},
{
"name": "actions.capability.SCREEN_OUTPUT"
}
]
}
],
"requestType": "SIMULATOR"
}
STORAGE_READ response:
{
"conversationToken": "[]",
"finalResponse": {
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "There is no stored data for this conversation"
}
}
]
}
},
"responseMetadata": {
"status": {
"message": "Success (200)"
},
"queryMatchInfo": {
"queryMatched": true,
"intent": "368d08d3-fe0c-4481-aa8e-b0bdfa659eeb"
}
}
}
Can someone set me straighten me out on whether I'm misinterpreting the docs or maybe I have a bug somewhere?
Thanks!
my suspicion is that personal results are turned off in your case.
You mentioned you're testing on Home Mini and Prisoner was able reproduce on device (in the comments).
Shared devices like Smart Speakers (Home, Mini) and Smart Displays have personal results disabled by default. Check this documentation to enable it.
Open Settings on your Android phone
Under "Assistant devices," select your device (e.g. Mini)
Turn Personal results on
Beware that this means personal results like Calendar entries can be accessed through the device.
To check if userStorage will persist, you can use the GUEST/VERIFIED flag, see documentation here.

Add event to calendar on SharePoint through REST API

I'm trying to add a calendar event to a SharePoint Calendar through REST API but i can't seems to find the relevant resources to achieve this.
If i understand correctly, the calendar in SharePoint is a List of events object, as such I should be able to add the event via ListItem object?
Sorry if this sounds wrong as I'm not familiar with SharePoint structure.
Thanks
This is the example for OAuth token Authentication but REST part is anyway like this.
var dataObj = {
"Subject": "Birthday Party"
"Body": {
"ContentType": "Text",
"Content": "Birthday Party for Cathy",
},
"Start": {
"dateTime": "2016-07-03T09:00:00Z",
"timeZone": "Asia/Tokyo"
},
"End": {
"dateTime": "2016-07-04T11:00:00Z",
"timeZone": "Asia/Tokyo"
},
"Location": {
"DisplayName": "Conference Room 1"
},
"ShowAs": "Busy",
"Attendees": [
{
"EmailAddress": { "Name": "Alex Darrow", "Address": "darrow.alex#company.com" },
"Type": "Required"
}
]
};
var url = "https://graph.microsoft.com/v1.0/me/events/";
var data = JSON.stringify(dataObj);
$.ajax({
url: url,
type: "POST",
data: data,
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader("Accept", "application/json;odata.metadata=full;odata.streaming=true");
XMLHttpRequest.setRequestHeader('Authorization', 'Bearer ' + accessToken);
XMLHttpRequest.setRequestHeader("content-type", "application/json;odata=verbose");
},
success: function (result, textStatus, jqXHR) {
//Success
},
error: function (data) {
//
}});