Open marcperrinp opened 4 years ago
Suppose the HTTP vs HTTPS issue was out of the way, unless I'm mistaken I don't see a Access-Control-Allow-Origin: *
in the API response, so how can I make API requests from the frontend? I'm afraid the answer is "I can't", no? 😛
@marcperrinp it is possible. But you just need to set up a http proxy and direct it at the environment you want to interact with.
@jankjr I tried in production, which runs on HTTPS of course, and I'm getting the same error..
Are you saying there is a way to bypass the fact that Nash API's response doesn't contain a Access-Control-Allow-Origin: *
header?
@marcperrinp
I think our CORS headers are restrictive for security reasons. So the browser probably won't let you call our service directly.
But what you can do is run an a small express server to act as a proxy for your browser app, which will remove the CORS restriction as you are calling your own service. It is essentially how our development setup works. Below is an example of now it can be configured for our production environment.
const app = express();
const proxy = require('http-proxy-middleware')
const PROXY_BACKEND = 'https://app.nash.io'
const proxyTimeout = 3600000
const cookieDomainRewrite = { '*': '' }
const onProxyRes = (proxyRes, req, res) => {
const sc = proxyRes.headers['set-cookie']
if (Array.isArray(sc)) {
proxyRes.headers['set-cookie'] = sc.map(sc => {
return sc
.split(';')
.filter(v => v.trim().toLowerCase() !== 'secure')
.join('; ')
})
}
}
app.use(
proxy('/api/socket', {
target: PROXY_BACKEND,
changeOrigin: true,
ws: true,
proxyTimeout,
cookieDomainRewrite,
onProxyRes,
})
)
app.use(
proxy('/api', {
target: PROXY_BACKEND,
changeOrigin: true,
cookieDomainRewrite,
onProxyRes,
})
)
app.listen(3000);
If your proxy is hosted at localhost:3000
then you will need to initialize the SDK like so:
const nash = new Client({
...EnvironmentConfiguration.production,
host: 'localhost:3000',
isLocal: true
})
Once you deploy the service somewhere, say nashcasino.com/proxy
, the SDK needs to be configured as follows:
const nash = new Client({
...EnvironmentConfiguration.production,
host: 'nashcasino.com/proxy'
})
Thanks a lot @jankjr.
Unfortunately I cannot set up a custom express app, as I'm using Vercel which only provides serverless functions. I did however successfully set up a rewrite rule specifically for API calls directed towards Nash (thanks to your explanation).
It works since I don't have the CORS issue anymore, but somehow it looks like I'm not getting a response. After some time, it appears I'm getting an "Invalid timestamp" error, but it may be due to some sort of timeout?
Anyway I just tried now (in production) at around 7:23:50 UTC if you have logs and time to check it out.
I'll continue to investigate, thanks again.
@marcperrinp I think you can run a proxy in a serverless setup as well. But of course my snippet can't be used without some modifications then :)
Have you updated to the very latest SDK? It is the only thing I can think of that is causing the issue.
@jankjr Upgrading to 5.0.35 (from 5.0.31) solved it!... for a minute only 🙀 It was working on my staging (which is connected to Nash's Production), but when I released to Production shortly after it wasn't anymore. Now back on my staging , it's not working anymore.
Those were the successful trades, so it was at around 11:30PM (UTC+2 time):
Did anything change on Nash side?
Not sure @marcperrinp
Can you double check that the time is set correctly on your computer? I've seen that sometime the browser is reporting incorrect time.
@jankjr Your answer helped me identify the issue. It is two-fold:
using my Mac which is connected on wifi, it's likely that my clock was slightly off, even though I thoroughly followed this tutorial. I actually sometimes have the "Sync your clock" warning on this Mac when trading on the exchange. Restarting my Mac usually solves the problem. Also, this explains why it was working on my staging, then not in production.
now to the real issue: when I trigger the very first spin, Webpack fetches a few simple chunks of code. The operation takes around 50ms, but apparently it's enough to trigger the "Invalid timestamp" error from the API..
On the next spins, the chunks don't need to be fetched again so passing the order via the API goes smooth. When I was executing the order from the server, this didn't happen obviously, which is why I'm only having the issue now.
To solve this, I guess I'll have to dig into Webpack to understand how to have it pre-download those chunks.
Thanks for reading, I'm explaining in details hoping it could help others in the future 😄
Hi @jankjr, I'm writing to you again after having tried many things, but I couldn't get it to work.
I narrowed it down to the fact that those 3 chunks are downloaded precisely when calling placeLimitOrder
(other authenticated method of the API have the same behavior).
Do you have any idea what they could be?
@marcperrinp
I know I suggested this before in a different context, I am wondering if you could retry the call if it fails?
try {
// try placing the call first time
return client.placeLimitOrder(...)
} catch(e){
// if it fails because of timing issues because it is loading modules. Then calling it again should succeed?
return client.placeLimitOrder(...)
/// if it fails here again then maybe there is something else that is wrong
}
I am not sure I know how to coerce Webpack into behaving.
@jankjr Thanks for the reply!
I tried it but it does not work.
What's happening actually is that the placeLimitOrder
method calls the following mutation:
query: "mutation dhFillRPool($blockchain: Blockchain!, $dhPublics: [Base16]!) {↵ dhFillPool(dhPublics: $dhPublics, blockchain: $blockchain)↵}↵"
after 30+ seconds a response is returned (30s feels like it might have timed out, but weirdly I do get a response..):
then only is the actual placeLimitOrder mutation called:
and unsurprisingly, the return is an "Invalid timestamp" error:
As a result the try // catch
you suggested doesn't actually catch an error until 30 seconds after the spin started. Not only is this not acceptable in terms of playing experience, but the fallback placeLimitOrder
method in the catch statement doesn't seem to trigger anyway.
My questions are the following:
dhFillRPool
mutation takes so much time to respond?Thanks again for your time, Jan!
This is partly solved thanks to one of @jankjr's PRs.
Adding this snippet to your code will prevent the delay/timeout:
import {
configurePoolSettings
} from '@neon-exchange/nash-protocol'
// Do not go lower than 4. The lower, the more work is done during the trade. (Default is 100)
configurePoolSettings(4)
I'm keeping this thread open because I'm still having a freeze issue. It's due to the browser doing some calculations which throttles the RAM, apparently. I'll be this thread updated with any additional info.
Trying to make an API request from the browser, but I'm getting a CORS error:
I guess I need to fix this on my side*, but could you just confirm this is the right way to include a header at client login:
* : Not sure if there's any way to make this work locally since I'm in HTTP. Probably will just need to add local certificates to be in HTTPS, but will it be enough?
Any tips would be appreciated :)