I am using Spark AR to create a simple effect that grabs text from an api and displays it.
Here is my code
const Scene = require('Scene');
const Diagnostics = require('Diagnostics');
const Patches = require('Patches');
const Textures = require('Textures');
const Materials = require('Materials');
const Networking = require('Networking');
const URL = 'https://gabby-airbus.glitch.me/random';
Networking.fetch(URL).then(function(result){
if( (result.status >=200) && (result.status < 300)){ return result.json(); }
else { throw new Error('HTTP Status Code: ' + result.status); }
}).then(function(json){
// show json data in console
Diagnostics.log(json.item);
// Asign json data to text object
itemText.text = json.item;
}).catch(function(error){
itemText = 'Failed to start';
Diagnostics.log(result.status + error);
});
I get the following error
Error:Cannot read property 'fetch' of undefined
{
"line": 12,
"column": 17,
"sourceURL": "script.js"
}
I am not sure why i am getting undefined when https://gabby-airbus.glitch.me/random is clearly not undefined. it has a random json object.
I am following the solution suggested in this SO post
Currently it is not possible, the Networking capability is disabled for security reasons. There is a plan to have it back soon though.
https://sparkar.facebook.com/ar-studio/learn/reference/classes/networkingmodule
Related
I've never received an error like this before,
I have a file that defines functions for making API calls, currently I'm reading the endpoint base URLs from the environment variables:
/**
* Prepended to request URL indicating base URL for API and the API version
*/
const VERSION_URL = `${process.env.NEXT_PUBLIC_API_BASE_URL}/${process.env.NEXT_PUBLIC_API_VERSION}`
I tried to make a quick workaround because environment variables weren't being loaded correctly, by hardcoding the URLS incase the variable wasn't defined.
/**
* Prepended to request URL indicating base URL for API and the API version
*/
const VERSION_URL = `${process.env.NEXT_PUBLIC_API_BASE_URL || 'https://hardcodedURL.com'}/${process.env.NEXT_PUBLIC_API_VERSION || 'v1'}`
In development and production mode when running on my local machine it works fine (docker container). However, as soon as it's pushed to production, I then get the following screen:
This is the console output:
framework-bb5c596eafb42b22.js:1 TypeError: Path must be a string. Received undefined
at t (137-10e3db828dbede8a.js:46:750)
at join (137-10e3db828dbede8a.js:46:2042)
at J (898-576b101442c0ef86.js:1:8158)
at G (898-576b101442c0ef86.js:1:10741)
at oo (framework-bb5c596eafb42b22.js:1:59416)
at Wo (framework-bb5c596eafb42b22.js:1:68983)
at Ku (framework-bb5c596eafb42b22.js:1:112707)
at Li (framework-bb5c596eafb42b22.js:1:98957)
at Ni (framework-bb5c596eafb42b22.js:1:98885)
at Pi (framework-bb5c596eafb42b22.js:1:98748)
cu # framework-bb5c596eafb42b22.js:1
main-f51d4d0442564de3.js:1 TypeError: Path must be a string. Received undefined
at t (137-10e3db828dbede8a.js:46:750)
at join (137-10e3db828dbede8a.js:46:2042)
at J (898-576b101442c0ef86.js:1:8158)
at G (898-576b101442c0ef86.js:1:10741)
at oo (framework-bb5c596eafb42b22.js:1:59416)
at Wo (framework-bb5c596eafb42b22.js:1:68983)
at Ku (framework-bb5c596eafb42b22.js:1:112707)
at Li (framework-bb5c596eafb42b22.js:1:98957)
at Ni (framework-bb5c596eafb42b22.js:1:98885)
at Pi (framework-bb5c596eafb42b22.js:1:98748)
re # main-f51d4d0442564de3.js:1
main-f51d4d0442564de3.js:1 A client-side exception has occurred, see here for more info: https://nextjs.org/docs/messages/client-side-exception-occurred
re # main-f51d4d0442564de3.js:1
Viewing the source at t (137-10e3db828dbede8a.js:46:750)
I'm completely at a lost at what this means or what is happening. Why would hardcoding in a string for the path result in this client error? The lack of a readable source code is making this impossible for me to understand what's happening.
Quick googling suggests that I should upgrade some package, but the error is so vague, I'm not even sure what package is giving the issue.
This is the roughly the how the version URL path is being used
/**
* Send a get request to a given endpoint
*
* **Returns a Promise**
*/
function GET(token, data, parent, api) {
return new Promise((resolve, reject) => {
try {
let req = new XMLHttpRequest()
let endpoint = `${VERSION_URL}/${parent}/${api}` // base url with the params not included
let params = new URLSearchParams() // URLSearchParams used for adding params to url
// put data in GET request params
for (const [key, value] of Object.entries(data)) {
params.set(key, value)
}
let query_url = endpoint + "?" + params.toString() // final query url
req.open("GET", query_url, true)
req.setRequestHeader("token", token) // put token into header
req.onloadend = () => {
if (req.status === 200) {
// success, return response
resolve([req.response, req.status])
} else {
reject([req.responseText, req.status])
}
}
req.onerror = () => {
reject([req.responseText, req.status])
}
req.send()
} catch (err) {
reject(["Exception", 0])
}
})
}
From my experience, this problem can happen for multiple reasons. The most common one is because you didn't put the data accessing checker properly when data comes from an API. Sometimes this things we don't see in browser but it gives such error when you deploy.
For example:
const response = fetch("some_url");
const companyId = response.data.companyId; ❌
const companyId = response?.data?.companyId; ✔️
I am facing one issue. In my application my page is requesting to server which is run by Node.js to fetch 2000 record at a time. Here the records are coming from Node but in dev tool console its not expanding and also I have some loader implementation that is not stopping even after receiving the response. I am explaining whole code below.
demo.component.ts:
onFileSelect($event) {
const file = $event.target.files[0];
const fileName = file.name;
const fileExtension = fileName.replace(/^.*\./, '');
if (fileExtension === 'ubot') {
this.loginService.startSpinner(true);
const formData = new FormData();
formData.append('cec', this.cec);
formData.append('screenName', this.intFlow);
formData.append('fileCategory', 'payload');
formData.append('file', file);
this.intentService.reverseFile(formData).subscribe(async (res: any) => {
console.log('response', res);
console.log('succ', res.status);
if (res && res.status === 'success') {
this.loginService.startSpinner(false);
this.intentService.intentData = '';
this.resettoOriginalState();
this.cdref.detach();
await this.repopulateDataFromFile(res.body);
(<HTMLInputElement>document.getElementById('fileuploader')).value = "";
}
else {
this.loginService.startSpinner(false);
this._notifications.create(res.msg, '', this.errorNotificationType);
(<HTMLInputElement>document.getElementById('fileuploader')).value = "";
}
});
} else {
this.loginService.startSpinner(false);
this._notifications.create('Please choose a file', '', this.errorNotificationType);
}
}
Here I am requesting to server through one service which is given below.
reverseFile(value) {
// const token = localStorage.getItem('token')
// let headers = new HttpHeaders({
// Authorization: 'Bearer ' + token
// })
return this.http.post(this.nodeAppUrl + 'reverseFile', value,{ observe: 'response'})
.pipe(
tap((res:any) => this.loginService.validateToken(res)),
map((res:any) => {
return res.body
})
)
}
Here the angular is requesting the spinner is starting and after some sec the response also coming from Node.js but as we have the line this.loginService.startSpinner(false); after success message but the spinner is still running.
Here in the response we have more than 2000 records which is in nested array of object format and we are populating the record using this.repopulateDataFromFile(res.body); method. I am attaching below the screen shot of console tool.
Even the status is success I am not able to stop the spinner and also I am not able to expand the record the console which is showing the value was evaluated upon first expanding.......
Can anybody please give any help why it is happening and how to resolve this.
i try to activate Revit Levels and 2D Minimap extension in autodesk forge viewer, but can not get AEC Model Data. I got this worning`
i tried to get AEC data with this code
const url = window.location.search;
console.log(url);
const svf_path = `${url.replace("?", "/storage/").replace(/%20/g, " ")}`;
Autodesk.Viewing.endpoint.getItemApi = (endpoint, derivativeUrn, api) => {
return svf_path;
};
Autodesk.Viewing.Initializer(options, async () => {
const paths = svf_path.split("/");
const [dest, svf_dir] = [paths[2], paths[3]];
const url = `/api/viewer/dest/${dest}/svf/${svf_dir}/manifest`;
const response = await fetch(url);
const manifest = await response.json();
const init_div = document.getElementById("init_div");
viewer = new Autodesk.Viewing.GuiViewer3D(init_div, config3d);
const viewerDocument = new Autodesk.Viewing.Document(manifest);
const viewable = viewerDocument.getRoot().getDefaultGeometry();
viewer.start();
await viewerDocument.downloadAecModelData();
viewer.loadDocumentNode(viewerDocument, viewable)
.then(function (result) {
Autodesk.Viewing.Document.getAecModelData(viewable);
})
});
wats wrong in my code?
The warning comes from the BubbleNode.prototype.getAecModelData method. You are not calling it in your code but it's possible that it's being called by the LevelsExtension itself. Try configuring the extension so that it doesn't detect the AEC data automatically by passing in { autoDetectAecModelData: false } as the extension options.
Btw. to debug the issue on your side, you can also try getting the non-minified version of viewer3D.js, put a breakpoint to where the warning is being logged, and see the call stack when the breakpoint is hit.
So I had been stuck on this exercise in Treehouse some time ago and just moved on. I came back to it now that I understand things better and I'm still fighting with the wunderground api. I've read through the json data and documentation, updated a few things from when the class was first recorded (and the API updated since then), and still am getting errors I can't field. I've got three js files- app.js, weather.js, and api.json (which is just my api key so not shared here.)
After my corrections, I'm still getting the error "TypeError: Cannot read property 'temp_f' of undefined" which doesn't make sense as I keep reading over the JSON to check that it's pointing to the right place.
Can anyone put an end to my misery trying to fix this?
App.js:
const weather = require('./weather');
//Join multiple values passed as arguments and replace all spaces with underscores
const query = process.argv.slice(2).join("_").replace(' ', '_');
//query: 90201
//query: Cleveland_OH
//query: London_England
weather.get(query);
Weather.js
const https = require('https');
const http = require('http');
const api = require('./api.json');
// Print out temp details
function printWeather(weather) {
const message = `Current temp in ${weather.location} is ${weather.current_observation.temp_f}F`;
console.log(message);
}
// Print out error message
function get(query) {
const request = http.get(`http://api.wunderground.com/api/${api.key}/conditions/q/${query}.json`, response => {
let body = "";
// Read the data
response.on('data', chunk => {
body += chunk;
});
response.on('end', () => {
//Parse data
const weather = JSON.parse(body);
//Print the data
printWeather(weather);
});
});
}
module.exports.get = get;
//TODO: Handle any errors
My ultimate goal is the following: my gardener has several devices that can send data to my Node.js server via TCP. This data is in JSON format, and looks something like the following:
Device A:
{"pagename": "spacekittens", "count": 11};
Device B:
{"pagename": "norwegiansultans", "count": 22};
As each of these are streamed to my server via TCP, I have added a ; to separate each stream. In addition, the count in each device stream is randomly generated.
Now, I want to add dynamic routes for each TCP packet that comes my way, and display content from that stream to that route.
So my route myserver:4000/spacekittens should show the following:
{"pagename": "spacekittens", "count": [random number every second]};
And my route myserver:4000/norwegiansultans should show:
{"pagename": "norwegiansultans", "count": [random number every second]};
In order to accomplish this I have set up the following code:
server.on("connection", function(socket) {
let chunk = "";
socket.on('data', function(data) {
chunk += data.toString(); // Add string on the end of the variable 'chunk'
let d_index = chunk.indexOf(';'); // Find the delimiter
// While loop to keep going until no delimiter can be found
while (d_index > -1) {
try {
let string = chunk.substring(0, d_index); // Create string up until the delimiter
// define local variables that can be used in a closure
let json = JSON.parse(string); // Parse the current string
let localData = data;
console.log(json.pagename); // Function that does something with the current chunk of valid json.
app.get("/" + json.pagename, function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.write(JSON.stringify(json));
res.end();
});
} catch (e) {
console.log(e);
}
chunk = chunk.substring(d_index + 1); // Cuts off the processed chunk
d_index = chunk.indexOf(';'); // Find the new delimiter
}
});
socket.on("close", function() {
console.log("connection closed");
});
});
I appreciate any thoughts and comments on methodology with regards to what I am trying to accomplish. However, I did not post only for this reason. I have a problem.
Currently, my res.write() line only populates the data in my routes one time. Adding new data via sockets does not replace the content on my route.
So under the myserver:4000/spacekittens route my count shows 11, and even though I stream an updated number ("count": 12) my route myserver:4000/spacekittens still only shows 11. Console logging gives me the correct response each time data is sent. So I am not using the res.write() correctly since it does not override old data.
Unsure how to rectify.
I would seperate the pages data and route setup from the connection handling. You can't set the same route up every time you receive a JSON blob so this modifies the app route to return the data to the user. The data will change with each blob of JSON.
class Pages {
constructor(app){
this._store = {}
this.app = app
}
get( name ){
return this._store[name]
}
set( name, data ){
if ( !this.exists(name) ) this.setupRoute(name)
return this._store[name] = data
}
exists( name ){
return this._store.hasOwnProperty(name)
}
addJSON( json_string ){
let data = JSON.parse(json_string)
if ( !data.pagename ) throw new Error('No pagename in data: "%s"', json_string)
if ( !data.count ) throw new Error('No count in data "%s"', json_string)
return this.set(data.pagename, data)
}
setupRoute( name ){
let route = `/${name}`
this.app.get(route, (req, res)=>{
res.json(this.get(name))
})
console.log('setup route: %s', route)
return this.app
}
}
Then the connection handling just deals with pulling out the JSON strings for Pages.
const pages = new Pages(app)
server.on("connection", function(socket) {
let chunk = "";
socket.on('data', function(data) {
chunk += data.toString(); // Add string on the end of the variable 'chunk'
let d_index = chunk.indexOf(';'); // Find the delimiter
// While loop to keep going until no delimiter can be found
while (d_index > -1) {
try {
let string = chunk.substring(0, d_index); // Create string up until the delimiter
pages.addJSON(string)
} catch (e) {
console.error(e);
}
chunk = chunk.substring(d_index + 1); // Cuts off the processed chunk
d_index = chunk.indexOf(';'); // Find the new delimiter
}
});
socket.on("close", function() {
console.log("connection closed");
});
});
You could also use one of the line delimited JSON parsing libraries which will take a binary stream and emit the JSON out as plain objects:
ndjson or ld-jsonstream