I would like to use the google iot core api from a firebase function.
It all works, but it is very slow. I think is due to the authentication process that needs to be carried out one very call. Is there a way to speed this up?
Right now I have this:
function getClient(cb) {
const API_VERSION = 'v1';
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
google.discoverAPI(discoveryUrl, {}).then( end_point => {
cb(end_point);
});
}
And this allows me to do:
export function sendCommandToDevice(deviceId, subfolder, mqtt_data) {
const cloudRegion = 'europe-west1';
const projectId = 'my-project-id;
const registryId = 'my-registry-id';
getClient(client => {
const parentName = `projects/${projectId}/locations/${cloudRegion}`;
const registryName = `${parentName}/registries/${registryId}`;
const binaryData = Buffer.from(mqtt_data).toString('base64');
const request = {
name: `${registryName}/devices/${deviceId}`,
binaryData: binaryData,
subfolder: subfolder
};
client.projects.locations.registries.devices.sendCommandToDevice(request,
(err, data) => {
if (err) {
console.log('Could not update config:', deviceId);
}
});
});
}
The way that I've found to speed it up is to avoid doing the authentication. I've solved it doing this:
const google = new GoogleApis();
const API_VERSION = 'v1';
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
var googleClient;
google.discoverAPI(discoveryUrl, {}).then( client => {
//cb(end_point);
googleClient = client;
});
// Returns an authorized API client by discovering the Cloud IoT Core API with
// the provided API key.
function getClient(cb) {
cb(googleClient);
}
But when happens then when the client expires? Is there any good solution from using google apis from firebase functions?
The problem may be the discovery pieces. There's a direct IoT Core admin REST API, so you don't have to use discovery...I think. I haven't worked with the Firebase Functions, but they're roughly equivalent to the Google Cloud Functions which may end up working here also. The code we (in a live demo we did) ran to do what you're doing is here if you wanted to tinker around and see if you can get this running in a Firebase Function.
Related
I want to get all new transactions from a specified wallet and Im using this code. It just dont work when I use the function tx["transaction"]["from"] and I filter the wallet or ca I want on "WALLET".
Im using Alchemy methods with ws and I have read the documentation about how to use it, I should be missing something.
const { Alchemy, Network, AlchemySubscription } = require("alchemy-sdk")
const {ethers, FixedNumber} = require("ethers")
const delay = require('delay')
require("dotenv").config()
const ARBI_WS_KEY = process.env.ARBI_WS_KEY
const settings = {
apiKey: ARBI_WS_KEY, // Replace with your Alchemy API Key
network: Network.ARB_MAINNET, // Replace with your network
}
const alchemy = new Alchemy(settings)
// Subscription for Alchemy's minedTransactions API
const add = async () => {
alchemy.ws.on(
{
method: AlchemySubscription.MINED_TRANSACTIONS,
},
(tx) => {
let add0 = String(tx["transaction"]["from"])
if( add0 == "WALLET"){
console.log(tx["transaction"]["hash"])
}
}
)
}
Its weird because everything works when I filter tx["transaction"]["to"] and I specify a wallet or a contract to filter but when trying to filter "from" I dont get anything.
I've following code snippet to get the "Controller" (The owner of the domain) but I need to get the "Registrant" of provided ENS name
const Web3 = require("web3")
const web3 = new Web3("https://cloudflare-eth.com");
var ens = web3.eth.ens;
var names = ['jtimberlake.eth', 'usman.eth'];
(async () => {
for (let domainName of names) {
// console.log('checking: ' + domainName);
const addr = await getDomain(domainName);
console.log(addr);
}
})();
async function getDomain(word) {
try {
const addr = await ens.getAddress(`${word}`)
// console.log(addr);
return addr;
} catch (err) {
console.error(err);
return;
}
}
Can you please guide how I can get the "Registrant" of provided ENS name e.g. jtimberlake.eth
Web3 is a steaming pile. It doesn't do it with its methods. The registrant used to be called the deed owner, and the controller the owner. Now it is registrant and controller. That's why the method name makes no sense at all now in Web3.js - it never got updated, and never was useful for this in the first place.
The good news is there is a simple way. You can derive the token ID of the ENS domain from its name with the getRegistrant function below. https://docs.ens.domains/dapp-developer-guide/ens-as-nft
The name variable in the docs is superfluous and does nothing. You will need to instantiate ethersjs (npm install ethers) to get the ethers methods to work. You have to use this crazy number of functions because the token ID of an ENS domain/NFT is a uint256. JavaScript hates those natively.
The web3 method to find the controller also still works well if you ever need that. I suggest putting it in another function.
const getRegistrant = (domainName) => {
const BigNumber = ethers.BigNumber
const utils = ethers.utils
const labelHash = utils.keccak256(utils.toUtf8Bytes(domainName))
const derivedTokenId = BigNumber.from(labelHash).toString()
//You need to instantiate the ENSRegistrarContract with its ABI and address. e.g. const ENSRegistrarContract = new web3.eth.Contract(ABI, ADDRESS)
ENSRegistrarContract.methods.ownerOf(derivedTokenId).call()
.then(function(registrant) {
console.log(domainName + "is owned by: " + registrant)
return registrant
})
}
const getController = (domainName) => {
//getOwner fetches the controller of a domain confusingly.
web3.eth.ens.getOwner(domainName).then(function(controller) {
console.log(domainName + "is controlled by: " + controller)
return controller
})
}
I am attempting to send a json file created from fields in a webpage to a node function in AWS Lambda to add it to a DynamoDB table. I have the JSON made but I don't know how to pass it from the js used for the page to the lambda function. As this is for a class project, my group and I have decided to forego amazon's gateway API, and are just raw calling lambda functions using amazon's js sdk. I've checked Amazon's documentation and other various examples, but I haven't been able to find a complete solution.
Node function in lambda
const AWS = require('aws-sdk');
const db = new AWS.DynamoDB.DocumentClient({region: 'us-east-1'});
exports.handler = async (event) => {
const params = {
TableName : 'characterTable',
Item: {
name : 'defaultName'
}
};
const userID = 'placeholder';
params.Item.userID = userID;
return await db.put(params).promise();
};
//}
Webpage js:
var lambda = new AWS.Lambda();
function makeJSON(){
var userID = "";
var name = document.forms["characterForm"]["characterName"].value;
var race = document.forms["characterForm"]["race"].value;
var playerClass = document.forms["characterForm"]["class"].value;
var strength = document.forms["characterForm"]["strength"].value;
var dexterity = document.forms["characterForm"]["dexterity"].value;
var constitution = document.forms["characterForm"]["constitution"].value;
var intelligence = document.forms["characterForm"]["intelligence"].value;
var wisdom = document.forms["characterForm"]["wisdom"].value;
var charisma = document.forms["characterForm"]["charisma"].value;
characterSheetObj = {userID: userID, name: name, race: race, class: playerClass, strength: strength, dexterity: dexterity, constitution: constitution, intelligence: intelligence, wisdom: wisdom, charisma: charisma}
characterSheetJSON = JSON.stringify(characterSheetObj);
alert(characterSheetJSON);
var myParams = {
FunctionName : 'addCharacterSheet',
InvocationType : 'RequestResponse',
LogType : 'None',
Payload : characterSheetJSON
}
lambda.invoke(myParams, function(err, data){
//if it errors, prompts an error message
if (err) {
prompt(err);
}
//otherwise puts up a message that it didnt error. the lambda function presently doesnt do anything
//in the future the lambda function should produce a json file for the JavaScript here to do something with
else {
alert("Did not error");
}
});
}
The html page for the raw javascript includes the proper setup for importing the sdk and configuring the region/user pool
I just don't know how to get the payload from the invocation in my node function, as this is my first time working with lambda and amazon's sdk, or doing any web development work at all, to be honest.
i would do it with async await. It's better to read.
lambda.invoke = util.promisify(lambda.invoke);
const result = await lambda.invoke(yourParams);
const payload = JSON.parse(result.Payload);
I am trying to understand the following code taken from a service created in a feathersjs app.
// Initializes the `users` service on path `/users`
const createService = require('feathers-knex');
const createModel = require('../../models/users.model');
const hooks = require('./users.hooks');
const filters = require('./users.filters');
module.exports = function () {
const app = this;
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'users',
Model,
paginate
};
// Initialize our service with any options it requires
app.use('/users', createService(options));
// Get our initialized service so that we can register hooks and filters
const service = app.service('users');
service.hooks(hooks);
if (service.filter) {
service.filter(filters);
}
};
This file is then imported as follows:
// many requires..
const feathers = require('feathers');
// more requires
const services = require('./services');
// other requires
const app = feathers();
Can someone explain as to what does the line
const app = this
do in the code that is creating the service?
It assigns the value of this to a variable (well, a constant) with a name that more clearly describes the value than this does. It is designed to make the code easier for maintainers to understand.
Working on a Chrome Extension, which needs to integrate with IndexedDB. Trying to figure out how to use Dexie.JS. Found a bunch of samples. Those don't look too complicated. There is one specific example particularly interesting for exploring IndexedDB with Dexie at https://github.com/dfahlander/Dexie.js/blob/master/samples/open-existing-db/dump-databases.html
However, when I run the one above - the "dump utility," it does not see IndexedDB databases, telling me: There are databases at the current origin.
From the developer tools Application tab, under Storage, I see my IndexedDB database.
Is this some sort of a permissions issue? Can any indexedDB database be accessed by any tab/user?
What should I be looking at?
Thank you
In chrome/opera, there is a non-standard API webkitGetDatabaseNames() that Dexie.js uses to retrieve the list of database names on current origin. For other browsers, Dexie emulates this API by keeping an up-to-date database of database-names for each origin, so:
For chromium browsers, Dexie.getDatabaseNames() will list all databases at current origin, but for non-chromium browsers, only databases created with Dexie will be shown.
If you need to dump the contents of each database, have a look at this issue, that basically gives:
interface TableDump {
table: string
rows: any[]
}
function export(db: Dexie): TableDump[] {
return db.transaction('r', db.tables, ()=>{
return Promise.all(
db.tables.map(table => table.toArray()
.then(rows => ({table: table.name, rows: rows})));
});
}
function import(data: TableDump[], db: Dexie) {
return db.transaction('rw', db.tables, () => {
return Promise.all(data.map (t =>
db.table(t.table).clear()
.then(()=>db.table(t.table).bulkAdd(t.rows)));
});
}
Combine the functions with JSON.stringify() and JSON.parse() to fully serialize the data.
const db = new Dexie('mydb');
db.version(1).stores({friends: '++id,name,age'});
(async ()=>{
// Export
const allData = await export (db);
const serialized = JSON.stringify(allData);
// Import
const jsonToImport = '[{"table": "friends", "rows": [{id:1,name:"foo",age:33}]}]';
const dataToImport = JSON.parse(jsonToImport);
await import(dataToImport, db);
})();
A working example for dumping data to a JSON file using the current indexedDB API as described at:
https://developers.google.com/web/ilt/pwa/working-with-indexeddb
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
The snippet below will dump recent messages from a gmail account with the Offline Mode enabled in the gmail settings.
var dbPromise = indexedDB.open("your_account#gmail.com_xdb", 109, function (db) {
console.log(db);
});
dbPromise.onerror = (event) => {
console.log("oh no!");
};
dbPromise.onsuccess = (event) => {
console.log(event);
var transaction = db.transaction(["item_messages"]);
var objectStore = transaction.objectStore("item_messages");
var allItemsRequest = objectStore.getAll();
allItemsRequest.onsuccess = function () {
var all_items = allItemsRequest.result;
console.log(all_items);
// save items as JSON file
var bb = new Blob([JSON.stringify(all_items)], { type: "text/plain" });
var a = document.createElement("a");
a.download = "gmail_messages.json";
a.href = window.URL.createObjectURL(bb);
a.click();
};
};
Running the code above from DevTools > Sources > Snippets will also let you set breakpoints and debug and inspect the objects.
Make sure you set the right version of the database as the second parameter to indexedDB.open(...). To peek at the value used by your browser the following code can be used:
indexedDB.databases().then(
function(r){
console.log(r);
}
);