Add stats route (WIP) + add /web/ testing route (WIP)

This commit is contained in:
PJ 2020-01-27 13:06:18 +01:00
parent 34851a7078
commit b720b5f0d6
5 changed files with 228 additions and 16 deletions

View File

@ -1,10 +1,10 @@
/** @jsx jsx */
import { AppBar, Button, Card, CardContent, Container, Input, Tab, Tabs, Typography } from "@material-ui/core"
import * as R from "ramda"
import { useState } from "react"
import { Box, Flex, jsx } from "theme-ui"
import Dropzone from "../src/components/Dropzone"
import { TabPanel } from "../src/components/TabPanel"
import { AppBar, Button, Card, CardContent, Container, Input, Tab, Tabs, Typography } from "@material-ui/core";
import * as R from "ramda";
import { useState } from "react";
import { Box, Flex, jsx } from "theme-ui";
import Dropzone from "../src/components/Dropzone";
import { TabPanel } from "../src/components/TabPanel";
const Index = () => {
const [value, setValue] = useState(1)
@ -31,6 +31,9 @@ const Index = () => {
<Typography sx={{ fontWeight: 700 }}>Sia Skynet</Typography>
</Box>
<Box sx={{ ml: "auto" }}>
<Button href="/stats">
Statistics
</Button>
<Button href="https://sia.tech/" target="_blank">
About Sia
</Button>

View File

@ -0,0 +1,94 @@
/** @jsx jsx */
import { Button, CircularProgress, Container, Typography } from "@material-ui/core";
import axios from "axios";
import { useState } from "react";
import { Box, Flex, jsx } from "theme-ui";
const API_ENDPOINT = process.env.NODE_ENV === "development" ? "http://localhost:4000" : "/api"
type PSeries = {
'p80-1': number,
'p95-1': number,
'p99-1': number,
'p80-24': number,
'p95-24': number,
'p99-24': number,
'p80-168': number,
'p95-168': number,
'p99-168': number,
}
type TSeries = {
1: number,
24: number,
168: number,
720?: number,
2160?: number,
}
type Stats = {
'ttfb': PSeries,
'download_small': PSeries,
'download_throughput': PSeries,
'download_total': TSeries,
'upload_small': PSeries,
'upload_throughput': PSeries,
'upload_total': TSeries,
'money_spent': TSeries,
'total_files_pinned': number,
'total_files_served': TSeries,
}
const Stats = () => {
const [loading, setLoading] = useState(true)
const [stats, setStats] = useState<Stats>()
if (loading) {
axios.get(`${API_ENDPOINT}/stats`)
.then((response: any) => {
console.log(response)
setLoading(false)
setStats(response.data as Stats)
}).catch(e => {
console.log('ERROR:', e)
})
}
return (
<>
<Box color="white">
<Container>
<Flex sx={{ alignItems: "center", height: 120 }}>
<Box>
<Typography sx={{ fontWeight: 700 }}>Sia Skynet</Typography>
</Box>
<Box sx={{ ml: "auto" }}>
<Button href="/stats">
Statistics
</Button>
<Button href="https://sia.tech/" target="_blank">
About Sia
</Button>
</Box>
</Flex>
</Container>
</Box>
<Box>
<Container>
<h2>Portal Statistics</h2>
<Flex
sx={{ height: 400, justifyContent: "center", alignItems: "center" }}
>
{loading && <CircularProgress />}
{!loading &&
JSON.stringify(stats)
}
</Flex>
</Container>
</Box>
</>
)
}
export default Stats

View File

@ -9,8 +9,18 @@ const logger = createLogger({
),
transports: [
new transports.Console(),
new transports.File({ filename: './error.log', level: 'error' }),
new transports.File({ filename: './info.log', level: 'info' }),
new transports.File({
filename: './error.log',
level: 'error',
maxsize: 5242880,
maxFiles: 2
}),
new transports.File({
filename: './info.log',
level: 'info',
maxsize: 5242880,
maxFiles: 5
}),
],
exitOnError: false,
});

View File

@ -1,16 +1,33 @@
import axios from "axios"
import * as AxiosLogger from 'axios-logger'
import cors from "cors"
import express, { Request, Response } from "express"
import fileUpload, { UploadedFile } from "express-fileupload"
import proxy from "express-http-proxy"
import requestId from "express-request-id"
import morgan from 'morgan'
import path from "path"
import R from "ramda"
import shortid from "shortid"
import { Logger } from "winston"
import logger from "./logger"
// import * as AxiosLogger from 'axios-logger'
// AxiosLogger.setGlobalConfig({
// prefixText: 'your prefix',
// dateFormat: 'HH:MM:ss',
// status: true,
// headers: false,
// data: false
// });
// // add interceptors
// siad.interceptors.request.use(
// AxiosLogger.requestLogger,
// AxiosLogger.errorLogger
// );
// siad.interceptors.response.use(
// AxiosLogger.responseLogger,
// AxiosLogger.errorLogger
// );
const MAX_UPLOAD_FILESIZE = 1000 * 1024 * 1024
const SIAD_ENDPOINT = "http://localhost:9980"
@ -28,9 +45,6 @@ const siad = axios.create({
}
})
// add interceptors
siad.interceptors.request.use(AxiosLogger.requestLogger, AxiosLogger.errorLogger);
siad.interceptors.response.use(AxiosLogger.responseLogger, AxiosLogger.errorLogger);
// Ramda shared utility functions
const selectFile = R.path(["files", "file"])
@ -65,17 +79,19 @@ export class Server {
}
private configureMiddleware() {
// add request id middleware (add unique id to X-Request-Id header)
this.app.use(requestId())
// add morgan middleware (HTTP request logging)
const options = {
stream: {
write: (msg: string) => { this.logger.info(msg) }
write: (msg: string) => {
this.logger.info(msg)
}
}
}
this.app.use(morgan("combined", options));
// add request id middleware (add unique id to X-Request-Id header)
this.app.use(requestId())
// configure CORS (simply enable all CORS requests)
this.app.use(cors())
@ -100,6 +116,87 @@ export class Server {
}
})
)
this.app.get(
"/web/:hash", (req: Request, res: Response) => {
const { hash } = req.params
this.logger.info(`GET /web/:hash -> ${hash}`)
res.sendFile(path.join(__dirname + '/testing.html'));
}
)
this.app.get(
"/:hash", (req: Request, res: Response) => {
const { hash } = req.params
this.logger.info(`GET /:hash -> ${hash}`)
res.sendFile(path.join(__dirname + '/testing.html'));
}
)
this.app.get(
"/stats", this.handleStatsGET.bind(this)
// TODO: redirect to protalstats
// proxy("http://localhost:9980/renter/portalstats", {
// proxyReqOptDecorator: (opts, _) => {
// opts.headers["User-Agent"] = "Sia-Agent"
// return opts
// },
// })
)
}
private async handleStatsGET(req: Request, res: Response): Promise<Response> {
// + pSeries = p80-1, p95-1, p99-1, p80-24, p95-24, p99-24, p80-168, p95-168, p99-168
// + p80-1 means the p80 on all requests over the past 1 hour
// + pSeries on ttfb for downloads over 4 MiB in size
// + pSeries on total time to download a file under 256 KiB in size
// + p80, p95, p99 on total time to download a file under 1 MiB in size
// + p80, p95, p99 on download throughput
// + p80. p95, p99 on upload throughput
// + Total number of files pinned
// + Total number of sialink requests served in the past 1, 24, 168 hours
// + Total amount of data uploaded in past 1, 24, 168 hours
// + total amount of data downloaded in past 1, 24, 168 hours
// + total amount of money spent in the past 1, 24, 168, 720, 2160 hours (7,
// 30, 90 days for the last values)
const mockPSeries = {
'p80-1': 40,
'p95-1': 44,
'p99-1': 48,
'p80-24': 42,
'p95-24': 44,
'p99-24': 46,
'p80-168': 41,
'p95-168': 45,
'p99-168': 49,
}
const mockSeries = {
1: 22,
24: 438,
168: 2389,
}
const mockSeriesLarge = {
1: 22,
24: 438,
168: 2389,
720: 12045,
2160: 63900
}
const data = {
'ttfb': mockPSeries,
'download_small': mockPSeries,
'download_throughput': mockPSeries,
'download_total': mockSeries,
'upload_small': mockPSeries,
'upload_throughput': mockPSeries,
'upload_total': mockSeries,
'money_spent': mockSeriesLarge,
'total_files_pinned': 143,
'total_files_served': mockSeries,
}
return res.send(data)
}
private async verifyConnection(): Promise<string | null> {
@ -165,6 +262,7 @@ export class Server {
return res.status(500).send({ error: err.message })
}
}
}
module.exports = new Server(logger).app

View File

@ -0,0 +1,7 @@
<html>
<body>
<video width="320" height="240" controls autoplay loop muted>
<source src="http://siasky.net/direct/AAAtQI8_78U_ytrCBuhgBdF4lcO6-ehGt8m4f9MsrqlrHA" type="video/mp4">
</video>
</body>
</html>