I am currently working on a monitoring tool for webrtc sessions investigating into the transferred SDP from caller to callee and vice versa. Unfortunately I cannot figure out which ip flow is really used since there are >10 candidate lines per session establishment and somehow the session is established after some candidates are pushed inside the PC.
Is there any way to figure out which flow is being used of the set of candidate flows?
I solved the issue by myself! :)
There is a function called peerConnection.getStats(callback);
This will give a lot of information of the ongoing peerconnection.
Example: http://webrtc.googlecode.com/svn/trunk/samples/js/demos/html/constraints-and-stats.html
W3C Standard Description: http://dev.w3.org/2011/webrtc/editor/webrtc.html#statistics-model
Bye
I wanted to find out the same thing, so wrote a small funtion which returns a promise which resolves to candidate details:
function getConnectionDetails(peerConnection){
var connectionDetails = {}; // the final result object.
if(window.chrome){ // checking if chrome
var reqFields = [ 'googLocalAddress',
'googLocalCandidateType',
'googRemoteAddress',
'googRemoteCandidateType'
];
return new Promise(function(resolve, reject){
peerConnection.getStats(function(stats){
var filtered = stats.result().filter(function(e){return e.id.indexOf('Conn-audio')==0 && e.stat('googActiveConnection')=='true'})[0];
if(!filtered) return reject('Something is wrong...');
reqFields.forEach(function(e){connectionDetails[e.replace('goog', '')] = filtered.stat(e)});
resolve(connectionDetails);
});
});
}else{ // assuming it is firefox
var stream = peerConnection.getLocalStreams()[0];
if(!stream || !stream.getTracks()[0]) stream = peerConnection.getRemoteStreams()[0];
if(!stream) Promise.reject('no stream found')
var track = stream.getTracks()[0];
if(!track) Promise.reject('No Media Tracks Found');
return peerConnection.getStats(track).then(function(stats){
var selectedCandidatePair = stats[Object.keys(stats).filter(function(key){return stats[key].selected})[0]]
, localICE = stats[selectedCandidatePair.localCandidateId]
, remoteICE = stats[selectedCandidatePair.remoteCandidateId];
connectionDetails.LocalAddress = [localICE.ipAddress, localICE.portNumber].join(':');
connectionDetails.RemoteAddress = [remoteICE.ipAddress, remoteICE.portNumber].join(':');
connectionDetails.LocalCandidateType = localICE.candidateType;
connectionDetails.RemoteCandidateType = remoteICE.candidateType;
return connectionDetails;
});
}
}
Related
I'm a student in IT Big Data, I'm currently working on a school project where I want to create a graph of all recent transaction. But can't find a good way to get the data correctly from the API anybody has an idea to do it ?
My personal recommendation is to not use Etherscan, and instead to use ethers.js and an RPC provider like infura or alchemy - or if you're feeling ambitious, run your own node. Instantiate a provider and listen for the block event: https://docs.ethers.io/v5/api/providers/provider/#Provider--events. If you want to listen for EIP-20 token transfers only, you can use the answer in this question: https://ethereum.stackexchange.com/questions/87643/how-to-listen-to-contract-events-using-ethers-js
Getting the data manually might seem more complicated, but it's actually more simple (and quicker/more customizable!) than polling the Etherscan API.
So thanks for your answer, I chose to work with infura and JS here is the ways i made it work, with that you ll get all the transaction from 150 blocks on mainnet :
async function data() {
var Web3 = require('web3');
var provider = 'https://mainnet.infura.io/v3/apikey';
var web3Provider = new Web3.providers.HttpProvider(provider);
var web3 = new Web3(web3Provider);
console.log("transaction per block");
var k= 15623650;
for(var j= 15623650;k-j<150;j--){
var a;
var onumber_of_transaction_by_block = await web3.eth.getBlockTransactionCount(j).then(a = this);
var Number_by_block =await Number(onumber_of_transaction_by_block);
for(var i=1;i<=Number_by_block-1;i++){
console.log("transaction");
var transaction = await web3.eth.getTransactionFromBlock(j , i);
console.log("block :" + j + ", transaction :" + i)
}
}
I'm using flutter to work on an bluetooth low energy app, via the flutterBlue library, in which we are potentially connecting to multiple peripherals at the same time.
I am able to connect to multiple peripherals if I connect to them individually and send commands to all of them simultaneously.
For state management, my BluetoothHelper is the Model for my ScopedModel.
class BluetoothHelper extends Model {
bool isProcessing = false;
int val = 0;
FlutterBlue flutterBlue = FlutterBlue.instance; //bluetooth library instance
StreamSubscription scanSubscription;
Map<DeviceIdentifier, ScanResult> scanResults = new Map();
/// State
StreamSubscription stateSubscription;
BluetoothState state = BluetoothState.unknown;
/// Device
List<BluetoothDevice> devicesList = new List(); //todo
bool get isConnected => (deviceList.size != 0);
StreamSubscription deviceConnection;
StreamSubscription deviceStateSubscription;
List<BluetoothService> services = new List();
Map<Guid, StreamSubscription> valueChangedSubscriptions = {};
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;
Future startScan(String uuid) async {
isProcessing = true;
if (val == 0) {
Future.delayed(Duration(milliseconds: 25), () => scanAndConnect(uuid));
val++;
} else {
Future.delayed(Duration(seconds: 4), () => scanAndConnect(uuid));
}
}
scanAndConnect(String uuid){
scanSubscription =
flutterBlue.scan(timeout: const Duration(seconds: 120), withServices: [
//new Guid('FB755D40-8DE5-481E-A369-21C0B3F39664')]
]).listen((scanResult) {
if (scanResult.device.id.toString() == uuid) {
scanResults[scanResult.device.id] = scanResult;
print("found! Attempting to connect" + scanResult.device.id.toString());
device = scanResult.device;
//connect(device);
connect(device);
}
}, onDone: stopScan);
}
Future connect(BluetoothDevice d) {
deviceConnection = flutterBlue.connect(d).listen(
null,
);
deviceStateSubscription = d.onStateChanged().listen((s) {
if (s == BluetoothDeviceState.connected) {
stopScan();
d.discoverServices().then((s) {
print("connected to ${device.id.toString()}");
services = s;
services.forEach((service) {
var characteristics = service.characteristics;
for (BluetoothCharacteristic c in characteristics) {
if (c.uuid.toString() == '') {//we look for the uuid we want to write to
String handshakeValue ; //value is initiliazed here in code
List<int> bytes = utf8.encode(handshakeValue);
d.writeCharacteristic(c, bytes,
type: CharacteristicWriteType.withResponse);
devicesList.add(d);
}
}
});
});
}
});
}
}
I am trying to loop throw all peripheral Unique Identifier (UID) and then have them connect one after the other programmatically.
This wasnt working out great. It would always end up connecting to the very last peripheral. Seems like the flutterblue instance can only scan for one uid at a time, and if it receives another request, it immediately drops the last request and moves to the new one.
I applied this same logic to the connection of an individual peripheral logic where I'd tap one peripheral and the second immediately and it'd connect to the second one. (I'm not currently blocking the UI or anything while the connection process takes place)
I need to wait till the first peripheral is connected before moving onto the next one.
The code above is the only way I've gotten my peripherals but there are huge problems with this code. It can currently only connect to 2 devices. It's using delays instead of callbacks to achieve connection by giving enough time for the scan and connect to happen before moving onto the second peripheral.
My first instinct was to make the convert the startScan and connect methods into async methods but this isnt working out well as I'd hope.
{await connect(device); } => gives "The built in Identifier "await" cant be used as a type. I could just be setting up the asyncs incorrectly.
I have looked around for alternatives and I've come upon Completers and Isolates. I'm not sure how relevant that might be.
UI SIDE :
I have the following method set for the ontap of a button wrapped within a scoped model descendant. This is going to reliably load peripheralUIDs list with a few uids and then connect to them one after the other.
connectAllPeripherals(BluetoothHelper model, List<String> peripheralUIDs) {
for(var uuid in peripheralUIDs) { //list of strings containing the uuids for the peripherals I want to connect to
model.startScan(uuid);
}
}
Don't know if this point is still an issue.
Assuming your issue hasn't since been fixed. I think the issue you have is trying to maintain the connections within Flutter (rather than just connecting multiple devices and letting Flutter_Blue/the hardware manage the connections).
I've got it happily connecting to multiple devices; after you've setup the instance maintaining a list of multiple device attributes.
i.e. I made a ble-device class which contained each of the following:
StreamSubscription deviceConnection;
StreamSubscription deviceStateSubscription;
List<BluetoothService> services = new List();
Map<Guid, StreamSubscription> valueChangedSubscriptions = {};
BluetoothDeviceState deviceState = BluetoothDeviceState.disconnected;
Maintaining a LinkedHashMap with a new object initialised from the class above for each device connected works nicely.
Other than that - Flutter_Blue will only allow 1 concurrent request call at a time (like reading a characteristic), but you can stack them pretty easily with
await
with the above, I'm able to poll multiple devices within a few milliseconds of each other.
Don't know if that helps - but with any luck, someone also coming across my problem will hit this and save some time.
I'm using google apps script to code a distance finder for Google Maps. I've found examples of such, but they keep failing, so I thought I'd code my own. Sadly, this is failing with the same error:
TypeError: Cannot read property "legs" from undefined. (line 16).
It seems to be that it's sometimes working, and sometimes not. I have a few (3) places in my sheet that are calling the same functions, and at times one or more will return a valid response.
I saw elsewhere that people were suggesting using an API key to make sure that you get a good response, so that's what I've implemented below. (api keys redacted! is there a good way to tell if they've been recognised?)
Any ideas what might be going awry?!
Thanks in advance,
Mike
function mikeDistance(start, end){
start = "CV4 8DJ";
end = "cv4 9FE";
var maps = Maps;
maps.setAuthentication("#####", "#####");
var dirFind = maps.newDirectionFinder();
dirFind.setOrigin(start);
dirFind.setDestination(end);
var directions = dirFind.getDirections();
var rawDistance = directions["routes"][0]["legs"][0]["distance"]["value"];
var distance = rawDistance/1609.34;
return distance;
}
Here's my short term solution while the issue is being fixed.
Not ideal, but at least reduces using your API limit as much as possible.
function getDistance(start, end) {
return hackyHack(start, end, 0);
}
function hackyHack(start, end, level) {
if (level > 5) {
return "Error :(";
}
var directions = Maps.newDirectionFinder()
.setOrigin(start)
.setDestination(end)
.setMode(Maps.DirectionFinder.Mode.DRIVING)
.getDirections();
var route = directions.routes[0];
if (!route) return hackyHack(start, end, level+1); // Hacky McHackHack
var distance = route.legs[0].distance.text;
// var time = route.legs[0].duration.text;
return distance;
}
I'm building a control where there is visual feedback as progress is made for the server responding to the input from the client.
The control will be visible on multiple clients at once, and I want the client that made the change on the control to get slightly different feedback to all the others that will see less information about the state changes.
Is there a meteor inbuilt function to uniquely identify each client which I could use for this? If not, how could I go about making a non-repudiated identifier? It would need to identify two different tabs in the same browser as two different clients.
I couldn't find any easy way to do that built into Meteor, but you can try this depending on your exact use-case.
Here is a technique to track unique client connections per browser window or tab. Each connectionId below can be thought of as a chat room. Since the this.connection.id property inside a Meteor method is not unique per open window or tab, this will store the connection id along with a timestamp inside a collection. When the client closes the browser tab or window, you can use the callback inside the server method this.connection.onClose to lookup that particular connection by its id along with the timestamp and flag it as closed or offline.
Fiber = Npm.require('fibers');
Future = Npm.require('fibers/future');
Meteor.methods({
'client.disconnect': function(connectionId){
check(connectionId, String);
let query = {_id: connectionId};
let options = {$set: {isOnline: false}};
return Connections.update(query, options);
},
'client.connect': function(connectionId){
check(connectionId, String);
let lastSessionTime = Number(new Date().getTime());
let lastSessionId = this.connection.id;
let offlineQuery = {
_id: connectionId,
lastSessionTime: lastSessionTime,
lastSessionId: lastSessionId
}
let offlineOptions = {
$set: {isOnline: false}
}
// When the connection closes, turn this connection offline.
this.connection.onClose(function(){
// You could also remove the document.
Connections.update(offlineQuery, offlineOptions);
});
let onlineQuery = {
_id: connectionId
}
let onlineOptions = {
$set: {
lastSessionTime: lastSessionTime,
lastSessionId: lastSessionId,
isOnline: true}
}
var future = new Future();
Connections.upsert(onlineQuery, onlineOptions, function(err, res){
if (err){
future.throw('Connections.online error');
}else{
future.return(res);
}
});
}
});
I've been looking at the documentation for Synchronized Arrays https://www.firebase.com/docs/web/libraries/angular/api.html#angularfire-extending-the-services and https://www.firebase.com/docs/web/libraries/angular/guide/extending-services.html#section-firebasearray
I'm using Firebase version 2.2.7 and AngularFire version 1.1.2
Using the code below, I'm having trouble recognizing $$removed events.
.factory("ExtendedCourseList", ["$firebaseArray", function($firebaseArray) {
// create a new service based on $firebaseArray
var ExtendedCourseList= $firebaseArray.$extend({
$$added: function(dataSnapshot, prevChild){
var course = dataSnapshot.val();
var course_key = dataSnapshot.key();
console.log("new course");
return course;
},
$$removed: function(snap){
console.log("removed");
return true;
}
});
return function(listRef) {
return new ExtendedCourseList(listRef);
}
}])
.factory("CompanyRefObj", function(CompanyRef) {
//CompanyRef is a constant containing the url string
var ref = new Firebase(CompanyRef);
return ref;
})
.factory('CourseList', function (localstorage,$rootScope,ExtendedCourseList,CompanyRefObj) {
var companyID = localstorage.get("company");
$rootScope.courseList = ExtendedCourseList(CompanyRefObj.child(companyID).child("courses"));
)
If I run this code, only the $$added events will be triggered. To simulate the remove events I use the web-interface at Firebase to display data, where I press the remove button and accept the data being deleted permanently.
Additionally, if I delete the $$removed function, the extended service still won't synchronize when a record is deleted.
If I modify my code to use the $firebaseArray instead of extending the service (as seen above) both add and remove events will be recognized.
.factory('CourseList', function (localstorage,$rootScope,$firebaseArray,CompanyRefObj) {
var companyID = localstorage.get("company");
$rootScope.courseList = $firebaseArray(CompanyRefObj.child(companyID).child("courses"));
)
Finally, are there any bad practices I've missed that can cause some of the extended functions to not work?
Solved
$$added: function(dataSnapshot, prevChild){
var course = dataSnapshot.val();
var course_key = dataSnapshot.key();
//Modified below
course.$id = course_key;
//End of modification
console.log("new course");
return course;
}
After posting about the issue at firebase/angularfire github I received an answer that solved my issue. When $$added got overridden by the code provided, the $firebaseArray also lost its internal record $id.
Adding this line of code: course.$id = course_key; before returning the course, made AngularFire recognize when the record was removed from the server.