ilp-core
Version:
ILP core module managing ledger abstraction
171 lines (143 loc) • 5.12 kB
JavaScript
import Express from 'express'
import React from 'react'
import ReactDOM from 'react-dom/server'
import config from './config'
import favicon from 'serve-favicon'
import compression from 'compression'
import httpProxy from 'http-proxy'
import path from 'path'
import createStore from './redux/store'
import ApiClient from './helpers/ApiClient'
import Html from './helpers/Html'
import PrettyError from 'pretty-error'
import http from 'http'
import forceSSL from 'express-force-ssl'
import url from 'url'
import { match } from 'react-router'
import { ReduxAsyncConnect, loadOnServer } from 'redux-async-connect'
import createHistory from 'react-router/lib/createMemoryHistory'
import {Provider} from 'react-redux'
import getRoutes from './routes'
const targetUrl = 'http://' + config.apiHost + ':' + config.apiPort
const pretty = new PrettyError()
const app = new Express()
const server = new http.Server(app)
const proxyApi = httpProxy.createProxyServer({
target: targetUrl,
ws: true
})
const proxyLedger = httpProxy.createProxyServer({
target: config.ledgerUri,
ws: true
})
if (['true', '1'].indexOf(process.env.WALLET_FORCE_HTTPS) !== -1) {
console.info('forcing HTTPS enabled')
app.set('forceSSLOptions', {
enable301Redirects: true,
trustXFPHeader: ['true', '1'].indexOf(process.env.WALLET_TRUST_XFP_HEADER) !== -1
})
app.use(forceSSL)
}
app.use(compression())
app.use(favicon(path.join(__dirname, '..', 'static', 'favicon.png')))
app.use(Express.static(path.join(__dirname, '..', 'static')))
// Proxy to API server
app.use('/api', (req, res) => {
proxyApi.web(req, res, {target: targetUrl})
})
app.use('/.well-known/webfinger', (req, res) => {
proxyApi.web(req, res, {target: targetUrl + '/webfinger'})
})
server.on('upgrade', (req, socket, head) => {
let u = url.parse(req.url).pathname.split('/')[1]
if (u === 'api') {
proxyApi.ws(req, socket, head, {target: targetUrl + '/socket.io'})
}
if (u === 'ledger') {
const parsedUrl = url.parse(req.url)
// TODO /ledger shouldn't be hardcoded here
parsedUrl.pathname = parsedUrl.pathname.replace('/ledger', '')
req.url = url.format(parsedUrl)
proxyLedger.ws(req, socket, head)
}
})
// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxyApi.on('error', (error, req, res) => {
let json
if (error.code !== 'ECONNRESET' && error.code !== 'ECONNREFUSED') {
console.error('proxy error', error)
}
// if (!res.headersSent) {
// res.writeHead(500, {'content-type': 'application/json'})
// }
json = {error: 'server_error', reason: 'API is unavailable'}
res.end(JSON.stringify(json))
})
// Proxy to ledger
app.use('/ledger', (req, res) => {
proxyLedger.web(req, res)
})
// added the error handling to avoid https://github.com/nodejitsu/node-http-proxy/issues/527
proxyLedger.on('error', (error, req, res) => {
let json
if (error.code !== 'ECONNRESET') {
console.error('proxy error', error)
}
// if (!res.headersSent) {
// res.writeHead(500, {'content-type': 'application/json'})
// }
json = {error: 'server_error', reason: 'Ledger is unavailable'}
res.end(JSON.stringify(json))
})
app.use((req, res) => {
if (__DEVELOPMENT__) {
// Do not cache webpack stats: the script file would change since
// hot module replacement is enabled in the development env
webpackIsomorphicTools.refresh()
}
const client = new ApiClient(req)
const history = createHistory(req.originalUrl)
const store = createStore(history, client)
function hydrateOnClient() {
res.send('<!doctype html>\n' +
ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} store={store}/>))
}
if (__DISABLE_SSR__) {
hydrateOnClient()
return
}
match({ history, routes: getRoutes(store), location: req.originalUrl }, (error, redirectLocation, renderProps) => {
if (redirectLocation) {
res.redirect(redirectLocation.pathname + redirectLocation.search)
} else if (error) {
console.error('ROUTER ERROR:', pretty.render(error))
res.status(500)
hydrateOnClient()
} else if (renderProps) {
loadOnServer({...renderProps, store, helpers: {client}}).then(() => {
const component = (
<Provider store={store} key="provider">
<ReduxAsyncConnect {...renderProps} />
</Provider>
)
res.status(200)
global.navigator = {userAgent: req.headers['user-agent']}
res.send('<!doctype html>\n' +
ReactDOM.renderToString(<Html assets={webpackIsomorphicTools.assets()} component={component} store={store}/>))
})
} else {
res.status(404).send('Not found')
}
})
})
if (config.port) {
server.listen(config.port, (err) => {
if (err) {
console.error(err)
}
console.info('----\n==> %s is running, talking to API server on %s.', 'ILP Kit', config.apiPort)
console.info('==> Open http://%s:%s in a browser to view the app.', config.host, config.port)
})
} else {
console.error('==> ERROR: No PORT environment variable has been specified')
}