Add access log widget
This commit is contained in:
parent
bc9a8283c6
commit
0a994e5b98
|
@ -390,6 +390,9 @@ desktop:
|
||||||
post: "Post"
|
post: "Post"
|
||||||
placeholder: "What's happening?"
|
placeholder: "What's happening?"
|
||||||
|
|
||||||
|
mk-access-log-home-widget:
|
||||||
|
title: "Access log"
|
||||||
|
|
||||||
mk-repost-form:
|
mk-repost-form:
|
||||||
quote: "Quote..."
|
quote: "Quote..."
|
||||||
cancel: "Cancel"
|
cancel: "Cancel"
|
||||||
|
|
|
@ -390,6 +390,9 @@ desktop:
|
||||||
post: "投稿"
|
post: "投稿"
|
||||||
placeholder: "いまどうしてる?"
|
placeholder: "いまどうしてる?"
|
||||||
|
|
||||||
|
mk-access-log-home-widget:
|
||||||
|
title: "アクセスログ"
|
||||||
|
|
||||||
mk-repost-form:
|
mk-repost-form:
|
||||||
quote: "引用する..."
|
quote: "引用する..."
|
||||||
cancel: "キャンセル"
|
cancel: "キャンセル"
|
||||||
|
|
19
src/api/stream/requests.ts
Normal file
19
src/api/stream/requests.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import * as websocket from 'websocket';
|
||||||
|
import Xev from 'xev';
|
||||||
|
|
||||||
|
const ev = new Xev();
|
||||||
|
|
||||||
|
export default function homeStream(request: websocket.request, connection: websocket.connection): void {
|
||||||
|
const onRequest = request => {
|
||||||
|
connection.send(JSON.stringify({
|
||||||
|
type: 'request',
|
||||||
|
body: request
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
ev.addListener('request', onRequest);
|
||||||
|
|
||||||
|
connection.on('close', () => {
|
||||||
|
ev.removeListener('request', onRequest);
|
||||||
|
});
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import isNativeToken from './common/is-native-token';
|
||||||
import homeStream from './stream/home';
|
import homeStream from './stream/home';
|
||||||
import messagingStream from './stream/messaging';
|
import messagingStream from './stream/messaging';
|
||||||
import serverStream from './stream/server';
|
import serverStream from './stream/server';
|
||||||
|
import requestsStream from './stream/requests';
|
||||||
import channelStream from './stream/channel';
|
import channelStream from './stream/channel';
|
||||||
|
|
||||||
module.exports = (server: http.Server) => {
|
module.exports = (server: http.Server) => {
|
||||||
|
@ -27,6 +28,11 @@ module.exports = (server: http.Server) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.resourceURL.pathname === '/requests') {
|
||||||
|
requestsStream(request, connection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Connect to Redis
|
// Connect to Redis
|
||||||
const subscriber = redis.createClient(
|
const subscriber = redis.createClient(
|
||||||
config.redis.port, config.redis.host);
|
config.redis.port, config.redis.host);
|
||||||
|
|
21
src/log-request.ts
Normal file
21
src/log-request.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
import * as express from 'express';
|
||||||
|
import * as proxyAddr from 'proxy-addr';
|
||||||
|
import Xev from 'xev';
|
||||||
|
|
||||||
|
const ev = new Xev();
|
||||||
|
|
||||||
|
export default function(req: express.Request) {
|
||||||
|
const ip = proxyAddr(req, () => true);
|
||||||
|
|
||||||
|
const md5 = crypto.createHash('md5');
|
||||||
|
md5.update(ip);
|
||||||
|
const hashedIp = md5.digest('hex').substr(0, 3);
|
||||||
|
|
||||||
|
ev.emit('request', {
|
||||||
|
ip: hashedIp,
|
||||||
|
method: req.method,
|
||||||
|
hostname: req.hostname,
|
||||||
|
path: req.originalUrl
|
||||||
|
});
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import * as morgan from 'morgan';
|
||||||
import Accesses from 'accesses';
|
import Accesses from 'accesses';
|
||||||
import vhost = require('vhost');
|
import vhost = require('vhost');
|
||||||
|
|
||||||
|
import log from './log-request';
|
||||||
import config from './conf';
|
import config from './conf';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +36,11 @@ app.use(morgan(process.env.NODE_ENV == 'production' ? 'combined' : 'dev', {
|
||||||
stream: config.accesslog ? fs.createWriteStream(config.accesslog) : null
|
stream: config.accesslog ? fs.createWriteStream(config.accesslog) : null
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
log(req);
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
// Drop request when without 'Host' header
|
// Drop request when without 'Host' header
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
if (!req.headers['host']) {
|
if (!req.headers['host']) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import * as riot from 'riot';
|
||||||
import activateMe from './i';
|
import activateMe from './i';
|
||||||
import activateApi from './api';
|
import activateApi from './api';
|
||||||
import ServerStreamManager from '../scripts/server-stream-manager';
|
import ServerStreamManager from '../scripts/server-stream-manager';
|
||||||
|
import RequestsStreamManager from '../scripts/requests-stream-manager';
|
||||||
|
|
||||||
export default (me, stream) => {
|
export default (me, stream) => {
|
||||||
activateMe(me);
|
activateMe(me);
|
||||||
|
@ -11,4 +12,5 @@ export default (me, stream) => {
|
||||||
(riot as any).mixin('stream', { stream });
|
(riot as any).mixin('stream', { stream });
|
||||||
|
|
||||||
(riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() });
|
(riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() });
|
||||||
|
(riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() });
|
||||||
};
|
};
|
||||||
|
|
12
src/web/app/common/scripts/requests-stream-manager.ts
Normal file
12
src/web/app/common/scripts/requests-stream-manager.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import StreamManager from './stream-manager';
|
||||||
|
import Connection from './requests-stream';
|
||||||
|
|
||||||
|
export default class RequestsStreamManager extends StreamManager<Connection> {
|
||||||
|
public getConnection() {
|
||||||
|
if (this.connection == null) {
|
||||||
|
this.connection = new Connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.connection;
|
||||||
|
}
|
||||||
|
}
|
14
src/web/app/common/scripts/requests-stream.ts
Normal file
14
src/web/app/common/scripts/requests-stream.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import Stream from './stream';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests stream connection
|
||||||
|
*/
|
||||||
|
class Connection extends Stream {
|
||||||
|
constructor() {
|
||||||
|
super('requests');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Connection;
|
93
src/web/app/desktop/tags/home-widgets/access-log.tag
Normal file
93
src/web/app/desktop/tags/home-widgets/access-log.tag
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<mk-access-log-home-widget>
|
||||||
|
<virtual if={ data.design == 0 }>
|
||||||
|
<p class="title"><i class="fa fa-server"></i>%i18n:desktop.tags.mk-access-log-home-widget.title%</p>
|
||||||
|
</virtual>
|
||||||
|
<div ref="log">
|
||||||
|
<p each={ requests }>
|
||||||
|
<span class="ip" style="color:{ fg }; background:{ bg }">{ ip }</span>
|
||||||
|
<span>{ method }</span>
|
||||||
|
<span>{ path }</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<style>
|
||||||
|
:scope
|
||||||
|
display block
|
||||||
|
overflow hidden
|
||||||
|
background #fff
|
||||||
|
|
||||||
|
> .title
|
||||||
|
z-index 1
|
||||||
|
margin 0
|
||||||
|
padding 0 16px
|
||||||
|
line-height 42px
|
||||||
|
font-size 0.9em
|
||||||
|
font-weight bold
|
||||||
|
color #888
|
||||||
|
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
||||||
|
|
||||||
|
> i
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
> div
|
||||||
|
max-height 250px
|
||||||
|
overflow auto
|
||||||
|
|
||||||
|
> p
|
||||||
|
margin 0
|
||||||
|
padding 8px
|
||||||
|
font-size 0.8em
|
||||||
|
color #555
|
||||||
|
|
||||||
|
&:nth-child(odd)
|
||||||
|
background rgba(0, 0, 0, 0.025)
|
||||||
|
|
||||||
|
> .ip
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
import seedrandom from 'seedrandom';
|
||||||
|
|
||||||
|
this.data = {
|
||||||
|
design: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.mixin('widget');
|
||||||
|
|
||||||
|
this.mixin('requests-stream');
|
||||||
|
this.connection = this.requestsStream.getConnection();
|
||||||
|
this.connectionId = this.requestsStream.use();
|
||||||
|
|
||||||
|
this.requests = [];
|
||||||
|
|
||||||
|
this.on('mount', () => {
|
||||||
|
this.connection.on('request', this.onRequest);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('unmount', () => {
|
||||||
|
this.connection.off('request', this.onRequest);
|
||||||
|
this.requestsStream.dispose(this.connectionId);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onRequest = request => {
|
||||||
|
const random = seedrandom(request.ip);
|
||||||
|
const r = Math.floor(random() * 255);
|
||||||
|
const g = Math.floor(random() * 255);
|
||||||
|
const b = Math.floor(random() * 255);
|
||||||
|
const luma = (0.2126 * r) + (0.7152 * g) + (0.0722 * b); // SMPTE C, Rec. 709 weightings
|
||||||
|
request.bg = `rgb(${r}, ${g}, ${b})`;
|
||||||
|
request.fg = luma >= 165 ? '#000' : '#fff';
|
||||||
|
|
||||||
|
this.requests.push(request);
|
||||||
|
if (this.requests.length > 30) this.requests.shift();
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
this.refs.log.scrollTop = this.refs.log.scrollHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.func = () => {
|
||||||
|
if (++this.data.design == 2) this.data.design = 0;
|
||||||
|
this.save();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</mk-access-log-home-widget>
|
|
@ -20,6 +20,7 @@
|
||||||
<option value="recommended-polls">投票</option>
|
<option value="recommended-polls">投票</option>
|
||||||
<option value="post-form">投稿フォーム</option>
|
<option value="post-form">投稿フォーム</option>
|
||||||
<option value="channel">チャンネル</option>
|
<option value="channel">チャンネル</option>
|
||||||
|
<option value="access-log">アクセスログ</option>
|
||||||
<option value="server">サーバー情報</option>
|
<option value="server">サーバー情報</option>
|
||||||
<option value="donation">寄付のお願い</option>
|
<option value="donation">寄付のお願い</option>
|
||||||
<option value="nav">ナビゲーション</option>
|
<option value="nav">ナビゲーション</option>
|
||||||
|
|
|
@ -43,6 +43,7 @@ require('./home-widgets/slideshow.tag');
|
||||||
require('./home-widgets/channel.tag');
|
require('./home-widgets/channel.tag');
|
||||||
require('./home-widgets/timemachine.tag');
|
require('./home-widgets/timemachine.tag');
|
||||||
require('./home-widgets/post-form.tag');
|
require('./home-widgets/post-form.tag');
|
||||||
|
require('./home-widgets/access-log.tag');
|
||||||
require('./timeline.tag');
|
require('./timeline.tag');
|
||||||
require('./messaging/window.tag');
|
require('./messaging/window.tag');
|
||||||
require('./messaging/room-window.tag');
|
require('./messaging/room-window.tag');
|
||||||
|
|
Loading…
Reference in a new issue