ok, so now I'm really puzzled. Executing the following code
const created = Rx.Observable.create(observer => {
observer.next(42)
})
const ofd = Rx.Observable.of(42)
const createSub = name => [
val => console.log(`${name} received ${val}`),
error => console.log(`${name} threw ${error.constructor.name}`)
]
created
.timeout(100)
.subscribe(
...createSub('created')
)
ofd
.timeout(100)
.subscribe(
...createSub('ofd')
)
Prints
"created received 42"
"ofd received 42"
"created threw TimeoutError"
I don't understand this at all, why does the created Observable error even though it emits a value but the ofd Observable does not??
Using RxJS 5, problem occurs with 5.0.3 in jsbin.com and 5.4.3 in my app.
(Note: This happens with subjects too, which led me to create this example)
Observable.of is completing the stream right after the value has been emitted.
Observable.create keeps the observable opened. And that's why the timeout is throwing an error.
Replace
const created = Rx.Observable.create(observer => {
observer.next(42)
})
By
const created = Rx.Observable.create(observer => {
observer.next(42);
observer.complete();
})
and there's no error anymore.
Related
The project is at this Github Repository. The file with the code is at components/Soundboard.js
This code was working previously, but now it looks like the promise is running forever. It looks like neither the resolve function, nor the reject function are executing because if I uncomment all the commented lines below and call the function askForPurchase() the only things printed to the console are
an object that looks like "_40": 0, "_55": {"_40": 0, "_55": null, "_65": 0, "_72": null}, "_65": 3, "_72": null} for the line console.log(RNIap.getPurchaseHistory())
and then the word end.
The buyProduct() function also is no longer initializing an IAP.
const buyProduct = function(){
RNIap.requestPurchase("1985162691", false).then(purchase => {
store.dispatch(setPurchases(purchase))
await RNIap.finishTransaction(purchase, false) //developerPayloadAndroid?: string Should I use this argument? I don't get how to use it
}).catch((error) => {
console.log(error.message);
})
}
const askForPurchase = function(){
if (!store.getState().purchase){
//console.log(RNIap.getPurchaseHistory())
RNIap.getPurchaseHistory().then(purchase => {
//console.log(`test1`)
store.dispatch(setPurchases(purchase))
if (purchase.length == 0){
//console.log(`test if`)
buyProduct()
}else{
//console.log(`test else`)
RNIap.getAvailablePurchases()
}
}, reason => {
console.log(reason)
})
//console.log(`end`)
}
}
EXTRA
This code was working a few months ago and I even pulled a commit(1b9cb81f229680e173ce910892dddedc632c1651, comment: "Made the seal pic more cartoony") from that time to test out. After pulling this commit, I deleted my node_modules and pods, and cleaned my build folder, but the askForPurchase() and buyProduct() functions no longer work in that commit either.
I am testing this on a real iPhone SE running ios 13.6.1
I created a sandbox tester if you need to test it out, but I don't think you'll need it
email: rniapsandbox#gmail.com
pw: Somepassword1
hello #Sam problem is async await problem they are not able to get value because they are not waiting to get data before getting data its firing without data and it was returning promise so you have to use async function
so your code be like
const buyProduct = async()=>{
await RNIap.requestPurchase("1985162691", false).then(purchase => {
store.dispatch(setPurchases(purchase))
await RNIap.finishTransaction(purchase, false) //developerPayloadAndroid?: string Should I use this argument? I don't get how to use it
}).catch((error) => {
console.log(error.message);
})}
const askForPurchase = async()=>{
if (!store.getState().purchase){
//console.log(await RNIap.getPurchaseHistory())
await RNIap.getPurchaseHistory().then(purchase => {
//console.log(`test1`)
store.dispatch(setPurchases(purchase))
if (purchase.length == 0){
//console.log(`test if`)
buyProduct()
}else{
//console.log(`test else`)
RNIap.getAvailablePurchases()
}
}, reason => {
console.log(reason)
})
//console.log(`end`)
}}
You will need to change from
console.log(RNIap.getPurchaseHistory())
to
console.log(await RNIap.getPurchaseHistory())
I've been playing around with stripe and would like to learn how to get ephemeral keys in the following way:
Back-end:
//Stripe API requirement for payment
exports.stripeEphemeralKey = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
//Get values
admin.database().ref().child("users").child(uid)
.on("value", (snapshot) =>{
//Get user data
let user = snapshot.val()
//Log data
console.log("Create ephemeral key for:")
console.log(user)
//Create ephemeral key
stripe.ephemeralKeys.create(
{customer: user.customerid },
{stripe_version: '2018-11-08'}
)
.then((key) => {
console.log(key)
console.log("Succesful path. Ephemeral created.")
return "Testing"
})
.catch((err) => {
console.log("Unsuccesful path. Ephemeral not created.")
console.log(err)
return {
valid: false,
data: "Error creating Stripe key"
}
})
})
})
Client-side:
functions.httpsCallable("stripeEphemeralKey").call(["text": "Testing"]) { (result, error) in
print(result?.data)
}
I have tested this code by replacing the body of the stripeEphemeralKey with a simple "Testing" string and that returns just fine. But with the code above I just get Optional() back.
For testing I added lots of console logs. Firebase logs show the execution path gets to the "Succesful path. Ephemeral created." log, and furthermore I can actually see the ephemeral key I get back from stripe.
So, what is the proper correct way to get the ephemeral key in Swift for iOS using the onCall Firebase function?
The backend does what it should, but I can't seem to get the answer back.
Thank you.
The backend does not actually do what it should do. You're doing at least two things wrong here.
First, your callable function needs to return a promise that resolves with the value that you want to send to the client. Right now, your function callback isn't returning anything at all, which means the client won't receive anything. You have return values inside promise handlers, but you need a top-level return statement.
Second, you're using on() to read data from Realtime Database, which attaches a listener that persists until it's removed. This is almost certainly never what you want to do in a Cloud Function. Instead, use once() to get a single snapshot of the data you want to read, and act on that.
For my own reference, and those who might find this helpful:
//Stripe API requirement for payment
exports.stripeEphemeralKey = functions.https.onCall((data, context) => {
const uid = context.auth.uid;
return admin.database().ref().child("users").child(uid)
.once("value", (snapshot) =>{
console.log(snapshot.val() )
})
.then( (snap) => {
const customer = snap.val()
//Log data
console.log("Create ephemeral key for:")
console.log(customer)
//Create ephemeral key
return stripe.ephemeralKeys.create(
{customer: customer.customerid },
{stripe_version: '2018-11-08'}
)
.then((key) => {
console.log(key)
console.log("Succesful path. Ephemeral created.")
return {
valid: true,
data: key
}
})
.catch((err) => {
console.log("Unsuccesful path. Ephemeral not created.")
console.log(err)
return {
valid: false,
data: "Error creating Stripe key"
}
})
})
.catch( err => {
console.log("Unsuccesful path. Ephemeral not created.")
console.log(err)
return {
valid: false,
data: "Error gettting customerid"
}
})
})
The key seems to be to chain the initial database request with .then(), and do our our work chaining the returns uninterrupted as we use functions that return promises. In particular, placing my work-code inside the callback on the original admin.database().ref().once() function did not work for me.
I am new to this kind of programming, so someone who knows about this might the why better.
I am running an NodeJS server with the following code to connect to the Hyperledger Runtime:
const BusinessNetworkConnection = require("composer-client")
.BusinessNetworkConnection;
this.businessNetworkConnection = new BusinessNetworkConnection();
this.CONNECTION_PROFILE_NAME = "hlfv1";
this.businessNetworkIdentifier = "testNetwork";
this.businessNetworkConnection
.connect(
this.CONNECTION_PROFILE_NAME,
this.businessNetworkIdentifier,
"admin",
"adminpwd"
)
.then(result => {
this.businessNetworkDefinition = result;
console.log("BusinessNetworkConnection: ", result);
})
.then(() => {
// Subscribe to events.
this.businessNetworkConnection.on("events", events => {
console.log("**********business event received**********", events);
});
})
// and catch any exceptions that are triggered
.catch(function(error) {
throw error;
});
I see data returned after the connection has been made in the result object and it is the correct network data that has been deployed.
However, when I submit transactions and made request VIA my generated REST APIs no events are seen by my server. In the Historian, I can see that events are emitted. Is there something else that I should be doing to see those events emitted by my transactions?
I tried same kind of test and I could receive events. I compared my test code and yours, and I found following difference:
this.bizNetworkConnection.on('events'
this.bizNetworkConnection.on('event'
I hope it helps.
I was watching Steve Sanderson's NDC presentation on up-and-coming web features, and saw his caching example as a prime candidate for an application I am developing. I couldn't find the code, so I have typed it up off the Youtube video as well as I could.
Unfortunately it doesn't work in Chrome (which is also what he is using in the demo) It fails with Uncaught TypeError: fetch(...).then(...).timeout is not a function
at self.addEventListener.event.
I trawled through Steve's Github, and found no trace of this, nor could I find anything on the NDC Conference page
//inspiration:
// https://www.youtube.com/watch?v=MiLAE6HMr10
//self.importScripts('scripts/util.js');
console.log('Service Worker script running');
self.addEventListener('install', event => {
console.log('WORKER: installing');
const urlsToCache = ['/ServiceWorkerExperiment/', '/ServiceWorkerExperiment/scripts/page.js'];
caches.delete('mycache');
event.waitUntil(
caches.open('mycache')
.then(cache => cache.addAll(urlsToCache))
.then(_ => self.skipWaiting())
);
});
self.addEventListener('fetch', event => {
console.log(`WORKER: Intercepted request for ${event.request.url}`);
if (event.request.method !== 'GET') {
return;
}
event.respondWith(
fetch(event.request)
.then(networkResponse => {
console.log(`WORKER: Updating cached data for ${event.request.url}`);
var responseClone = networkResponse.clone();
caches.open('mycache').then(cache => cache.put(event.request, responseClone));
return networkResponse;
})
//if network fails or is too slow, return cached data
//reference for this code: https://youtu.be/MiLAE6HMr10?t=1003
.timeout(200)
.catch(_ => {
console.log(`WORKER: Serving ${event.request.url} from CACHE`);
return caches.match(event.request);
})
);
});
As far as I read the fetch() documentation, there is no timeout function, so my assumption is that the timeout function is added in the util.js which is never shown in the presentation... can anyone confirm this? and does anyone have an Idea about how this is implemented?
Future:
It's coming.
According to Jake Archibald's comment on whatwg/fetch the future syntax will be:
Using the abort syntax, you'll be able to do:
const controller = new AbortController();
const signal = controller.signal;
const fetchPromise = fetch(url, {signal});
// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetchPromise;
// …
If you only wanted to timeout the request, not the response, add:
clearTimeout(timeoutId);
// …
And from another comment:
Edge & Firefox are already implementing. Chrome will start shortly.
Now:
If you want to try the solution that works now, the most sensible way is to use this module.
It allows you to use syntax like:
return fetch('/path', {timeout: 500}).then(function() {
// successful fetch
}).catch(function(error) {
// network request failed / timeout
})
// didn't add node definitions because this problem occurs on initial data fetch
// user type
const userType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: globalIdField('User'),
email: { type: GraphQLString },
posts: {
type: postConnection,
args: connectionArgs,
// getUserPosts() function is below
resolve: (user, args) => connectionFromArray(getUserPosts(user.id), args),
},
}),
interfaces: [nodeInterface],
})
// post type
const postType = new GraphQLObjectType({
name: 'Post',
fields: () => ({
id: globalIdField('Post'),
title: { type: GraphQLString },
content: { type: GraphQLString },
}),
interfaces: [nodeInterface],
})
// connection type
const {connectionType: postConnection} =
connectionDefinitions({name: 'Post', nodeType: postType})
// Mongoose query on other file
exports.getUserPosts = (userid) => {
return new Promise((resolve, reject) => {
Post.find({'author': userid}).exec((err, res) => {
err ? reject(err) : resolve(res)
})
})
}
I get the following warning in browser console:
Server request for query App failed for the following reasons:
Cannot read property 'length' of undefined
_posts40BFVD:posts(first:10) {
^^^
That's the only information I got, there's no more errors or references. What could be the reason?
This code is from relay-starter-kit, I only replaced all the Widget code with Post. Everything is almost the same as in starter, therefore I think the cause is somewhere around the database code.
But I can't see the problem because getUserPosts() returns same structure: array of objects..
What was the problem?
resolve: (user, args) => connectionFromArray(getUserPosts(user.id), args)
getUserPosts() returned a promise (blocking code would probably be a bad idea) but there was no callback. What happened in my opinion was that connectionFromArray() continued executing the code but it didn't have the data from getUserPosts() yet, which caused the whole system to fail.
One possible solution
I use Babel and JavaScript "future features" anyway, therefore I decided to use async and await. But there still was a problem and getUserPosts() returned an empty array.
Then I discovered that if another function is called with await in a async function, that another function has to be async as well, otherwise all await-s fail. Here's my final solution that works:
// async function that makes db query
exports.getUserPosts = async (userId) => {
try {
// db query
const posts = await Post.find({author: args}).exec()
return posts
} catch (err) {
return err
}
}
// and resolve method in Schema, also async
resolve: async (user, args) => {
const posts = await getUserPosts(user._id)
return connectionFromArray(posts, args)
}
Im not still sure though if it's the best way. My logic tells me that I should use async as much as possible in Node but Im far from Node expert. I'll update the question when I know more about it.
I would be glad to know if there's a better or even a recommended way to deal with this database query situation using Relay.
The problem is with the resolve function of posts field.
resolve: (user, args) => connectionFromArray(getUserPosts(user.id), args),
First, getUserPosts is an asynchronous function which returns a promise. You have to take that into account while writing resolve function. Second, user.id is a global ID field generated for you by graphql-relay module's globalIdField helper function. That ID should be converted to local ID.
With relay-starter-kit, you can use async and await. The code will look like:
resolve: async (user, args) => {
let userId = fromGlobalId(user.id).id;
// convert this userId string to Mongo ID if needed
// userId = mongoose.Types.ObjectId(userId).
const posts = await getUserPosts(userId);
return connectionFromArray(posts, args),
},
In your async version of getUserPosts, the err object is returned in case of error.
exports.getUserPosts = async (userId) => {
try {
// db query
const posts = await Post.find({author: args}).exec()
return posts
} catch (err) {
return err
}
}
A good practice is to either re-throw the error or return an empty array.
graphql-relay provides a connectionFromPromisedArray function which waits until the promise resolves. resolve: (user, args) => connectionFromPromisedArray(getUserPosts(user.id), args), which probably is the most recommended/easiest way when dealing with promised connections.
If your user.id is a global ID field then you have to extract the real DB ID from the base64 string const { type, id } = fromGlobalId(user.id);.
or
resolve: (user, args) => connectionFromPromisedArray(getUserPosts(fromGlobalId(user.id).id), args),
In a app I work on which is using Relay and Mongoose I found it better to write my own connection implementation to handle pagination and filtering on the DB level rather than on the app level. I took a lot of inspiration from graffiti-mongoose when I wrote it.