How do I get the balance of an account on ThunderCore? - web3js

I want to programmatically query the balance of an address or a list of addresses. What's the best way to do it?

To get the balance of 0xc466c8ff5dAce08A09cFC63760f7Cc63734501C1 at the latest block, do:
curl -X POST -H 'Content-Type: application/json' -s --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xad23b02673214973e354d41e19999d9e01f3be58", "latest"], "id":1}' https://mainnet-rpc.thundercore.com/
Output: {"jsonrpc":"2.0","id":1,"result":"0xde0b6b3a7640000"}
Fetching the balance of a single account with web3.js:
const Eth = require('web3-eth');
const Web3 = require('web3');
const web3Provider = () => {
return Eth.giveProvider || 'https://mainnet-rpc.thundercore.com';
}
const balance = async (address) => {
const eth = new Eth(web3Provider());
return Web3.utils.fromWei(await eth.getBalance(address));
}
Sample Session
const address = '0xc466c8ff5dAce08A09cFC63760f7Cc63734501C1';
await balance(address) // -> '1'
Units
0xde0b6b3a7640000 equals 10**18
Using Ethereum terminology, fromWei converts 10^18 Wei to 1 Ether, or using Thunder terminology
Using ThunderCore terminology, fromWei converts 10^18 Ella to 1 TT
fromWei(0xde0b6b3a7640000) equals fromWei(10**18) equals 1
Batch Request to Query Balance
For an array of addresses, you can use JSON-RPC 2.0's Batch Requests to save network round trips
When querying https://mainnet-rpc.thundercore.com, limit the batch size to around 30
The following class wraps web3.js-1.2.6's BatchRequest and make it return a Javascript Promise:
class BatchRequest {
constructor(web3) {
this.b = new web3.BatchRequest();
this.results = [];
this.resolve = null;
this.reject = null;
this.resultsFilled = 0;
}
web3BatchRequestCallBack(index, err, result) {
/* if any request in our batch fails, reject the promise we return from `execute` */
if (err) {
this.reject(new Error(`request ${index} failed: ${err}`))
return;
}
this.results[index] = result;
this.resultsFilled++;
if (this.resultsFilled === this.results.length) {
this.resolve(this.results);
}
}
resultPromiseExecutor(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}
add(method /* web3-core-method.Method */) {
const index = this.results.length;
method.callback = (err, result) => {
this.web3BatchRequestCallBack(index, err, result)
};
this.b.add(method);
this.results.push(undefined);
}
execute() /*: Promise */ {
const p = new Promise((resolve, reject) => { this.resultPromiseExecutor(resolve, reject) });
/* must arrange for resultPromiseExecutor to be called before b.execute */
this.b.execute();
return p;
}
}
const balanceBatch = async (addresses) => {
const eth = new Eth(web3Provider());
const b = new BatchRequest(eth);
for (a of addresses) {
b.add(eth.getBalance.request(a));
}
const ellaS = await b.execute();
const ttS = [];
for (e of ellaS) {
ttS.push(Web3.utils.fromWei(e));
}
return ttS;
}
batch-balance-test.js
const Web3 = require('web3');
(async() => {
const web3 = new Web3('https://mainnet-rpc.thundercore.com');
const results = await balanceBatch([
'0xc466c8ff5dAce08A09cFC63760f7Cc63734501C1',
'0x4f3c8e20942461e2c3bdd8311ac57b0c222f2b82',
]);
console.log('results:', results);
})();
Sample Session
$ node batch-balance-test.js
results: [ '1', '84.309961496' ]
See the complete project setup here in the balance branch of the field-support repo.

Related

Memory heap keeps increasing using ag-grid, angular and websocket

We needed to create a Live Monitor sort of screen that gets the feed through a WebSocket. Angular 11 is used for the UI part. When the page is left on Chrome for a few minutes, the memory heap starts increasing and gradually it increases to a greater extent. After some time, the application will hang and we can't go to another page of the application.
I'm unable to understand the cause of the memory leak, if any.
HTML Code:
<ag-grid-angular #LiveHedgeGrid class="ag-theme-balham" [rowData]="hedgeRowData" [columnDefs]="hedgeColumn" (gridReady)="onLiveHedgeReady($event)" (columnRowGroupChanged)="oncolumnRowGroupChanged($event)" (gridSizeChanged)="onGridSizeChanged($event)"
[enableCellChangeFlash]="true" [rowBuffer]="10" [debounceVerticalScrollbar]="true" [suppressColumnVirtualisation]="true" [groupIncludeTotalFooter]="true" [gridOptions]="gridOptions" [suppressAggFuncInHeader]="true" [groupDefaultExpanded]="groupDefaultExpanded"
[domLayout]="domLayout">
</ag-grid-angular>
TypeScript Code:
websocketCall() {
let socket = new WebSocket(ApiService.webSocketUrl);
socket.onopen = e => {
};
socket.onmessage = e => {
let server_message;
try {
server_message = JSON.parse(e.data);
server_message = JSON.parse(server_message);
if (server_message instanceof Array) {
this.bindTableValues(server_message);
} else {
this.bindTableValues([server_message]);
}
} catch (e) {
this.bindTableValues(server_message);
}
// console.log('socket open');
};
socket.onclose = () => {
//console.log('Web Socket Connection Closed');
};}
async bindTableValues(server_message) {
await server_message.forEach(element => {
this.ricData = {};
let ricPeriod = '';
let itemsToUpdate = [];
let data = {};
let value = 0;
let ricData = this.ricList[element['RIC']];
if (ricData) {
if (ricData['type'] == 'swap') {
value = element['Fields']['NETCHNG_1'];
ricPeriod = ricData['disp_name'];
ricPeriod = ricPeriod.toString().trim().substring(0, ricPeriod.length - 1).toLowerCase();
if (value) {
//const itemsToUpdate: any[] = [];
this.gridApi.forEachNodeAfterFilterAndSort((rowNode) => {
if(!rowNode.group) {
data = rowNode.data;
if(data['Tenor'] == ricPeriod) {
data['LivePnL'] = parseFloat(data['DV01']) * value * 100;
itemsToUpdate.push(data);
}
}
});
// this.gridApi.applyTransaction({ update: itemsToUpdate })!;
// this.gridApi.applyTransactionAsync({ update: itemsToUpdate })!;
this.gridApi.batchUpdateRowData({ update: itemsToUpdate })!;
};
}
};
});}
ngOnDestroy(): void {
try {
//console.log('Destroy ' + this.socket.readyState);
// if (this.socket.readyState === WebSocket.OPEN) {
if (this.socket.readyState === 1) {
this.socket.close();
}
this.getRic.unsubscribe();
this.getTable.unsubscribe();
}
catch (e) {
console.log(e);
}}

how to encode buffer to sent it to server (icecast) using mediaDevices.getUserMedia

I am trying to stream my browser (chrome) microphone using Icecast.
I think my problem that i need to encode the output data
so how can i make an audio stream captured in browser using to streamed live via icecast ? i'm using liquidsoap
I want to send cooredt output to server via websocket.
start.addEventListener("click", () => {
socket = new WebSocket(localURL, "webcast");
socket.onopen = function () {
socket.send(
JSON.stringify({
type: "hello",
data: hello,
})
);
};
navigator.mediaDevices.getUserMedia(constraintObj).then((stream) => {
const context = new AudioContext();
stream.getTracks().forEach((track) => (track.enabled = true));
var source = context.createMediaStreamSource(stream);
var processor = source.context.createScriptProcessor(4096, 2, 2);
source.connect(processor);
processor.connect(context.destination);
processor.onaudioprocess = function (e) {
// get mic data
var left = e.inputBuffer.getChannelData(0);
sendData(left);
};
});
});
const sendData = function (data) {
if (!((data != null ? data.length : void 0) > 0)) {
return;
}
if (!(data instanceof ArrayBuffer)) {
data = data.buffer.slice(
data.byteOffset,
data.length * data.BYTES_PER_ELEMENT
);
}
return socket.send(data);
};

discordjs Embed won't show up

Ok, so i'm trying to make a push notification for my discord.
i found this script online.
but it will not post the embed....
This is my monitor code:
TwitchMonitor.onChannelLiveUpdate((streamData) => {
const isLive = streamData.type === "live";
// Refresh channel list
try {
syncServerList(false);
} catch (e) { }
// Update activity
StreamActivity.setChannelOnline(streamData);
// Generate message
const msgFormatted = `${streamData.user_name} is nu live op twitch <:bday:967848861613826108> kom je ook?`;
const msgEmbed = LiveEmbed.createForStream(streamData);
// Broadcast to all target channels
let anySent = false;
for (let i = 0; i < targetChannels.length; i++) {
const discordChannel = targetChannels[i];
const liveMsgDiscrim = `${discordChannel.guild.id}_${discordChannel.name}_${streamData.id}`;
if (discordChannel) {
try {
// Either send a new message, or update an old one
let existingMsgId = messageHistory[liveMsgDiscrim] || null;
if (existingMsgId) {
// Fetch existing message
discordChannel.messages.fetch(existingMsgId)
.then((existingMsg) => {
existingMsg.edit(msgFormatted, {
embed: msgEmbed
}).then((message) => {
// Clean up entry if no longer live
if (!isLive) {
delete messageHistory[liveMsgDiscrim];
liveMessageDb.put('history', messageHistory);
}
});
})
.catch((e) => {
// Unable to retrieve message object for editing
if (e.message === "Unknown Message") {
// Specific error: the message does not exist, most likely deleted.
delete messageHistory[liveMsgDiscrim];
liveMessageDb.put('history', messageHistory);
// This will cause the message to be posted as new in the next update if needed.
}
});
} else {
// Sending a new message
if (!isLive) {
// We do not post "new" notifications for channels going/being offline
continue;
}
// Expand the message with a #mention for "here" or "everyone"
// We don't do this in updates because it causes some people to get spammed
let mentionMode = (config.discord_mentions && config.discord_mentions[streamData.user_name.toLowerCase()]) || null;
if (mentionMode) {
mentionMode = mentionMode.toLowerCase();
if (mentionMode === "Nu-Live") {
// Reserved # keywords for discord that can be mentioned directly as text
mentionMode = `#${mentionMode}`;
} else {
// Most likely a role that needs to be translated to <#&id> format
let roleData = discordChannel.guild.roles.cache.find((role) => {
return (role.name.toLowerCase() === mentionMode);
});
if (roleData) {
mentionMode = `<#&${roleData.id}>`;
} else {
console.log('[Discord]', `Cannot mention role: ${mentionMode}`,
`(does not exist on server ${discordChannel.guild.name})`);
mentionMode = null;
}
}
}
let msgToSend = msgFormatted;
if (mentionMode) {
msgToSend = msgFormatted + ` ${mentionMode}`
}
let msgOptions = {
embed: msgEmbed
};
discordChannel.send(msgToSend, msgOptions)
.then((message) => {
console.log('[Discord]', `Sent announce msg to #${discordChannel.name} on ${discordChannel.guild.name}`)
messageHistory[liveMsgDiscrim] = message.id;
liveMessageDb.put('history', messageHistory);
})
.catch((err) => {
console.log('[Discord]', `Could not send announce msg to #${discordChannel.name} on ${discordChannel.guild.name}:`, err.message);
});
}
anySent = true;
} catch (e) {
console.warn('[Discord]', 'Message send problem:', e);
}
}
}
liveMessageDb.put('history', messageHistory);
return anySent;
});
This is the embed code:
const Discord = require('discord.js');
const moment = require('moment');
const humanizeDuration = require("humanize-duration");
const config = require('../data/config.json');
class LiveEmbed {
static createForStream(streamData) {
const isLive = streamData.type === "live";
const allowBoxArt = config.twitch_use_boxart;
let msgEmbed = new Discord.MessageEmbed();
msgEmbed.setColor(isLive ? "RED" : "BLACK");
msgEmbed.setURL(`https://twitch.tv/${(streamData.login || streamData.user_name).toLowerCase()}`);
// Thumbnail
let thumbUrl = streamData.profile_image_url;
if (allowBoxArt && streamData.game && streamData.game.box_art_url) {
thumbUrl = streamData.game.box_art_url;
thumbUrl = thumbUrl.replace("{width}", "288");
thumbUrl = thumbUrl.replace("{height}", "384");
}
msgEmbed.setThumbnail(thumbUrl);
if (isLive) {
// Title
msgEmbed.setTitle(`:red_circle: **${streamData.user_name} is live op Twitch!**`);
msgEmbed.addField("Title", streamData.title, false);
} else {
msgEmbed.setTitle(`:white_circle: ${streamData.user_name} was live op Twitch.`);
msgEmbed.setDescription('The stream has now ended.');
msgEmbed.addField("Title", streamData.title, true);
}
// Add game
if (streamData.game) {
msgEmbed.addField("Game", streamData.game.name, false);
}
if (isLive) {
// Add status
msgEmbed.addField("Status", isLive ? `Live with ${streamData.viewer_count} viewers` : 'Stream has ended', true);
// Set main image (stream preview)
let imageUrl = streamData.thumbnail_url;
imageUrl = imageUrl.replace("{width}", "1280");
imageUrl = imageUrl.replace("{height}", "720");
let thumbnailBuster = (Date.now() / 1000).toFixed(0);
imageUrl += `?t=${thumbnailBuster}`;
msgEmbed.setImage(imageUrl);
// Add uptime
let now = moment();
let startedAt = moment(streamData.started_at);
msgEmbed.addField("Uptime", humanizeDuration(now - startedAt, {
delimiter: ", ",
largest: 2,
round: true,
units: ["y", "mo", "w", "d", "h", "m"]
}), true);
}
return msgEmbed;
}
}
module.exports = LiveEmbed;
But it won't post the embed, only the msg. as you can see it updates teh msg aswell.
enter image description here
i'm stuck on this for four days now, can someone help?

Attach files to record in Netsuite

I am transferring attachments from Zoho to Netsuite. But facing problems while attaching it to opportunity or any other object. I have already uploaded the file to the file cabinet in netsuite and tried to bind it with the records notes. But that doesn't work. It only adds the note to the record but no sign of any file in the file option.
Thank you.
enter image description here
You would use the record.attach function. You would need the internal id of the file and of the transaction. In SS1 (using nlapiAttachRecord) it was important to list the file arguments first. The SS2 syntax makes that clearer:
record.attach({
record:{
type:'file',
id:fileid
},
to:{
type:'transaction',
id:transactionid
}
});
/**
* #NApiVersion 2.1
* #NScriptType MapReduceScript
* #NModuleScope SameAccount
*/
/**
* In this I am using Map Reduce script to process & attach multiple files from
* FileCabinet of NetSuite. So that it never goes out of governance.
/
define(['N/record','N/query'],
(record,query) => {
const getInputData = (getInputDataContext) => {
try
{
/**
* Query for getting transaction ID & other header detail of record.
*/
let transQuery = "SELECT custrecord_rf_tid as tid, custrecord_rf_fid as fid, id FROM customrecord_rflink where custrecord_rf_comp <> 'T' and custrecord_rf_type = 11";
let transQueryResult = runSuiteQuery(transQuery);
if(transQueryResult.length > 0){
log.debug("Count of record left to process--->", transQueryResult.length);
return transQueryResult;
}else{ //Incase where no transaction was left to transform.
log.debug({title: "No Remaining Transaction!"});
return 1;
}
}
catch (e)
{
log.error({title: "Error inside getinput data.", details: [e.message,e.stack]});
}
}
const map = (mapContext) => {
try{
let mapData = JSON.parse(mapContext.value);
log.debug({title: "mapData after parse", details: mapData});
let staginRecId = Number(mapData.id);
let fileId = Number(mapData.fid);
let billId = Number(mapData.tid);
let outputVal = attachfile('file',fileId, 'inventoryadjustment', billId);
let staginRec;
if(outputVal === true){
staginRec = record.submitFields({
type: 'customrecord_rflink',
id: staginRecId,
values: {
'custrecord_rf_comp': true
}
});
log.debug("record saved with id-->", staginRecId);
}else{
log.debug("record saving failed with id-->", staginRecId);
}
}
catch(e){
log.error({title: "Error in Map", details: [e.message,e.stack]});
}
}
const reduce = (reduceContext) => {
}
const summarize = (summarizeContext) => {
log.debug('Summarize completed');
}
function runSuiteQuery(queryString) {
log.debug("Query", queryString);
let resultSet = query.runSuiteQL({
query: queryString
});
log.debug("Query wise Data", resultSet.asMappedResults());
if(resultSet && resultSet.results && resultSet.results.length > 0) {
return resultSet.asMappedResults();
} else {
return [];
}
}
function attachfile(recType, recId, recTypeTo, recIdTo) {
record.attach({
record: {
type: recType,
id: recId
},
to: {
type: recTypeTo,
id: recIdTo
}
});
return true;
}
return {getInputData,map,reduce,summarize};
});

Pass an Array as a query String Parameter node.js

How can I pass an array as a query string parameter?
I've tried numerous ways including adding it to the path but i'm not able to pull the array on the back end.
If I hard code the array it works fine, but when I try to pass the array from my front end to the backend it does not work properly.
Can anyone point me in the right direction?
FrontEnd
function loadJob() {
return API.get("realtorPilot", "/myTable/ListJobs", {
'queryStringParameters': {
radius,
availableServices,
}
});
BackEnd
import * as dynamoDbLib from "./libs/dynamodb-lib";
import { success, failure } from "./libs/response-lib";
export async function main(event, context) {
const data = {
radius: event.queryStringParameters.radius,
availableServices: event.queryStringParameters.availableServices,
};
// These hold ExpressionAttributeValues
const zipcodes = {};
const services = {};
data.radius.forEach((zipcode, i) => {
zipcodes[`:zipcode${i}`] = zipcode;
});
data.availableServices.forEach((service, i) => {
services[`:services${i}`] = service;
});
// These hold FilterExpression attribute aliases
const zipcodex = Object.keys(zipcodes).toString();
const servicex = Object.keys(services).toString();
const params = {
TableName: "myTable",
IndexName: "zipCode-packageSelected-index",
FilterExpression: `zipCode IN (${zipcodex}) AND packageSelected IN (${servicex})`,
ExpressionAttributeValues : {...zipcodes, ...services},
};
try {
const result = await dynamoDbLib.call("scan", params);
// Return the matching list of items in response body
return success(result.Items);
} catch (e) {
return failure(e.message);
}
}
Pass a comma seperated string and split it in backend.
Example: https://example.com/apis/sample?radius=a,b,c,d&availableServices=x,y,z
And in the api defenition split the fields on comma.
const data = {
radius: event.queryStringParameters.radius.split(','),
availableServices: event.queryStringParameters.availableServices.split(',')
};

Resources