Skip to content

Commit

Permalink
feat: use luna data grid
Browse files Browse the repository at this point in the history
  • Loading branch information
surunzi committed Nov 24, 2022
1 parent 5525b3a commit 9ea1455
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 74 deletions.
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"babel-eslint": "^10.1.0",
"chobitsu": "^1.3.0",
"chobitsu": "^1.3.1",
"css-loader": "^6.7.2",
"es-check": "^6.2.1",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"gulp": "^4.0.2",
"gulp-clean": "^0.4.0",
"luna-data-grid": "^0.2.0",
"ncp": "^2.0.0",
"style-loader": "^3.3.1",
"terser": "^5.10.0",
"ts-loader": "^9.3.1",
"typescript": "^3.8.3",
Expand Down
3 changes: 2 additions & 1 deletion server/lib/ChannelManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module.exports = class ChannelManager extends Emitter {
this._targets = {};
this._clients = {};
}
createTarget(id, ws, url, title, favicon) {
createTarget(id, ws, url, title, favicon, ip) {
const channel = new Channel(ws);

util.log(`${ansiColor.yellow('target')} ${id}:${truncate(title, 10)} ${ansiColor.green('connected')}`);
Expand All @@ -21,6 +21,7 @@ module.exports = class ChannelManager extends Emitter {
url,
favicon,
channel,
ip,
};

channel.on('close', () => this.removeTarget(id, title));
Expand Down
8 changes: 6 additions & 2 deletions server/lib/WebSocketServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ module.exports = class WebSocketServer {

const wss = (this._wss = new WebSocket.Server({ noServer: true }));

wss.on('connection', ws => {
wss.on('connection', (ws, req) => {
const type = ws.type;
if (type === 'target') {
const { id, chiiUrl, title, favicon } = ws;
this.channelManager.createTarget(id, ws, chiiUrl, title, favicon);
let ip = req.socket.remoteAddress;
if (req.headers['x-forwarded-for']) {
ip = eq.headers['x-forwarded-for'].split(',')[0].trim();
}
this.channelManager.createTarget(id, ws, chiiUrl, title, favicon, ip);
} else {
const { id, target } = ws;
this.channelManager.createClient(id, ws, target);
Expand Down
25 changes: 17 additions & 8 deletions server/middle/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,8 @@ module.exports = function (channelManager, domain, cdn, basePath) {
const router = new Router();

router.get(basePath, async ctx => {
const targets = reverse(
map(pairs(channelManager.getTargets()), item => ({
id: item[0],
...item[1],
}))
);

const tpl = await readTpl('index');
ctx.body = tpl({
targets,
domain,
basePath,
version: pkg.version,
Expand All @@ -52,6 +44,23 @@ module.exports = function (channelManager, domain, cdn, basePath) {
});
channelManager.on('target_changed', () => (timestamp = now()));

router.get(`${basePath}targets`, ctx => {
const targets = reverse(
map(pairs(channelManager.getTargets()), item => {
const ret = {
id: item[0],
...item[1],
};
delete ret.channel;
return ret;
})
);

ctx.body = {
targets,
};
});

function createStatic(prefix, folder) {
router.get(`${basePath}${prefix}/*`, async ctx => {
await send(ctx, ctx.path.slice(basePath.length + prefix.length), {
Expand Down
81 changes: 23 additions & 58 deletions server/tpl/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,80 +23,45 @@
a {
color: #1966d2;
}
img {
flex-shrink: 0;
height: 16px;
padding-left: 2px;
padding-right: 5px;
vertical-align: top;
width: 23px;
}
.content-header {
background: linear-gradient(white, white 40%, rgba(255, 255, 255, 0.92));
border-bottom: 1px solid #eee;
font-size: 150%;
padding: 20px 0 10px 0;
z-index: 1;
margin-bottom: 8px;
}
.row {
padding: 6px 0;
position: relative;
}
.properties-box {
display: flex;
}
.subrow-box {
display: inline-block;
vertical-align: top;
}
.subrow {
display: flex;
flex-flow: row wrap;
}
.subrow > div {
margin-right: 0.5em;
}
.url {
color: #999;
}
.action {
color: rgb(17, 85, 204);
cursor: pointer;
margin-right: 15px;
}
.description {
margin: 1rem 0;
font-size: .875rem;
line-height: 2;
}
.targets, .description, .content-header {
max-width: 800px;
}
.hidden {
display: none;
}
.luna-data-grid img {
height: 14px;
width: 14px;
margin: 0;
padding: 0;
margin-right: 2px;
flex-shrink: 0;
vertical-align: top;
}
</style>
</head>
<body>
<div class="content-header">Pages</div>
{{#each targets}}
<div class="row">
<div class="properties-box">
<img src="{{favicon}}"/>
<div class="subrow-box">
<div class="subrow">
<div class="name">{{title}}</div>
<div class="url">{{url}}</div>
</div>
<div class="actions">
<a class="action" onclick="inspect('{{id}}')">inspect</a>
</div>
</div>
</div>
</div>
{{else}}
<div class="description">
You can use this script to inject the chii target code into your web page.<br/>
<a target="_blank" href="//{{domain}}{{basePath}}target.js">{{domain}}{{basePath}}target.js</a> <br/>
Or just open the demo page <a target="_blank" href="//{{domain}}{{basePath}}test/demo.html">{{domain}}{{basePath}}test/demo.html</a> to play around with.<br/>
<a target="_blank" href="https://github.com/liriliri/chii">Chii v{{version}}</a>
</div>
{{/each}}
<div class="description">
You can use this script to inject the chii target code into your web page.<br/>
<a target="_blank" href="//{{domain}}{{basePath}}target.js">{{domain}}{{basePath}}target.js</a> <br/>
Or just open the demo page <a target="_blank" href="//{{domain}}{{basePath}}test/demo.html">{{domain}}{{basePath}}test/demo.html</a> to play around with.<br/>
<a target="_blank" href="https://github.com/liriliri/chii">Chii v{{version}}</a>
</div>
<div class="targets hidden"></div>
<script>
window.domain = '{{domain}}';
window.basePath = '{{basePath}}';
Expand Down
107 changes: 103 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ import detectOs from 'licia/detectOs';
import $ from 'licia/$';
import randomId from 'licia/randomId';
import toInt from 'licia/toInt';
import isEmpty from 'licia/isEmpty';
import LunaDataGrid from 'luna-data-grid';
import each from 'licia/each';
import throttle from 'licia/throttle';
import escape from 'licia/escape';
import toEl from 'licia/toEl';
import h from 'licia/h';
import 'luna-data-grid/luna-data-grid.css';

declare const window: any;

Expand All @@ -16,20 +24,111 @@ switch (os) {
break;
}

window.inspect = function (id: string) {
function inspect(id: string) {
const { domain, basePath } = window;
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
const url =
location.protocol +
`//${domain}${basePath}front_end/chii_app.html?${protocol}=${domain}${basePath}client/${randomId(6)}?target=${id}`;
window.open(url, '_blank');
};
}

const start = Date.now();
let start = Date.now();
setInterval(() => {
fetch(`${window.basePath}timestamp`)
.then(res => res.text())
.then(timestamp => {
if (toInt(timestamp) > start) location.reload();
if (toInt(timestamp) > start) {
start = toInt(timestamp);
update();
}
});
}, 2000);

const $description = $('.description');
const $targets = $('.targets');
const $contentHeader = $('.content-header');

const dataGrid = new LunaDataGrid($targets.get(0) as HTMLElement, {
columns: [
{
id: 'title',
title: 'Title',
weight: 30,
sortable: true,
},
{
id: 'url',
title: 'URL',
weight: 40,
sortable: true,
},
{
id: 'ip',
title: 'IP',
sortable: true,
weight: 15,
},
{
id: 'action',
title: 'Action',
weight: 15,
},
],
minHeight: 100,
});

function update() {
fetch(`${window.basePath}targets`)
.then(res => res.json())
.then(data => {
const targets = data.targets;

if (isEmpty(targets)) {
$description.rmClass('hidden');
$targets.addClass('hidden');
} else {
$description.addClass('hidden');
$targets.rmClass('hidden');
render(targets);
}
});
}

function render(targets: any[]) {
dataGrid.clear();
each(targets, target => {
const title = toEl(`<span><img src="${escape(target.favicon)}"/>${escape(target.title)}</span>`) as HTMLElement;
const url = toEl(`<a href="${escape(target.url)}" target="_blank">${escape(target.url)}</a>`) as HTMLElement;
const action = h(
'a',
{
style: {
cursor: 'pointer',
},
onclick() {
inspect(target.id);
},
},
'inspect'
);

dataGrid.append({
title,
url,
ip: target.ip,
action,
});
});
}

update();

function updateDataGridHeight() {
const height = window.innerHeight - $contentHeader.offset().height - 8 * 3 - 2;
dataGrid.setOption('maxHeight', height);
}

updateDataGridHeight();

window.addEventListener('resize', throttle(updateDataGridHeight, 16));
4 changes: 4 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ module.exports = (env, argv) => {
test: /\.ts$/,
loader: 'ts-loader',
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
Expand Down

0 comments on commit 9ea1455

Please sign in to comment.