Skip to content

Commit

Permalink
feat: basePath
Browse files Browse the repository at this point in the history
  • Loading branch information
surunzi committed Aug 12, 2022
1 parent 3b72a63 commit d997c61
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 160 deletions.
1 change: 1 addition & 0 deletions bin/chii.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ program
.option('-p, --port <port>', 'set the port to start on. defaults to 3000', parseInt)
.option('-h, --host <host>', 'set the host. defaults to 0.0.0.0')
.option('-d, --domain <domain>', 'set the domain. defaults to localhost:port')
.option('--base-path <basePath>', 'set base path. defaults to /')
.option('--cdn <cdn>', 'use cdn like jsdelivr')
.option('--https', 'serve chii over https')
.option('--ssl-cert <cert>', 'provide an ssl certificate')
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"koa-router": "^8.0.8",
"koa-send": "^5.0.0",
"licia": "^1.37.0",
"request": "^2.88.2",
"ws": "^7.2.3"
}
}
20 changes: 17 additions & 3 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,35 @@ const router = require('./middle/router');
const compress = require('./middle/compress');
const util = require('./lib/util');
const fs = require('licia/fs');
const endWith = require('licia/endWith');
const WebSocketServer = require('./lib/WebSocketServer');

async function start({ port = 8080, host, domain, server, cdn, https: useHttps, sslCert, sslKey } = {}) {
async function start({
port = 8080,
host,
domain,
server,
cdn,
https: useHttps,
sslCert,
sslKey,
basePath = '/',
} = {}) {
domain = domain || 'localhost:' + port;
if (!endWith(basePath, '/')) {
basePath += '/';
}

const app = new Koa();
const wss = new WebSocketServer();

app.use(compress()).use(router(wss.channelManager, domain, cdn));
app.use(compress()).use(router(wss.channelManager, domain, cdn, basePath));

if (server) {
server.on('request', app.callback());
wss.start(server);
} else {
util.log(`starting server at ${domain}`);
util.log(`starting server at ${domain}${basePath}`);
if (useHttps) {
const cert = await fs.readFile(sslCert, 'utf8');
const key = await fs.readFile(sslKey, 'utf8');
Expand Down
5 changes: 3 additions & 2 deletions server/lib/WebSocketServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ module.exports = class WebSocketServer {
const urlObj = url.parse(request.url);
const pathname = urlObj.pathname.split('/');

const type = pathname[1];
const id = pathname[2];
const len = pathname.length;
const type = pathname[len - 2];
const id = pathname[len - 1];

if (type === 'target' || type === 'client') {
wss.handleUpgrade(request, socket, head, ws => {
Expand Down
39 changes: 39 additions & 0 deletions server/lib/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const request = require('request');

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

module.exports = async function (ctx, url) {
const headers = Object.assign({}, ctx.header);
delete headers.host;
delete headers.cookie;

const options = {
uri: url,
method: ctx.method,
timeout: 5000,
headers,
};

await pipeRequest(ctx, options);
};

function pipeRequest(ctx, options) {
return new Promise((resolve, reject) => {
const req = request(options);
ctx.req.pipe(req);
req
.on('response', res => {
const { headers } = res;

delete headers['set-cookie'];
})
.pipe(ctx.res);
req.on('error', err => {
reject(err);
});
req.on('end', () => {
ctx.res.end();
resolve();
});
});
}
24 changes: 15 additions & 9 deletions server/middle/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ const map = require('licia/map');
const ms = require('licia/ms');

const pkg = require('../../package.json');
const proxy = require('../lib/proxy');

const maxAge = ms('2h');

module.exports = function (channelManager, domain, cdn) {
module.exports = function (channelManager, domain, cdn, basePath) {
const router = new Router();

router.get('/', async ctx => {
router.get(basePath, async ctx => {
const targets = reverse(
map(pairs(channelManager.getTargets()), item => ({
id: item[0],
Expand All @@ -27,12 +28,17 @@ module.exports = function (channelManager, domain, cdn) {
ctx.body = tpl({
targets,
domain,
basePath,
version: pkg.version,
});
});

router.all(`${basePath}proxy`, async ctx => {
await proxy(ctx, ctx.query.url);
});

if (cdn) {
router.get('/front_end/chii_app.html', async ctx => {
router.get(`${basePath}front_end/chii_app.html`, async ctx => {
const tpl = await readTpl('chii_app');
ctx.body = tpl({
cdn,
Expand All @@ -41,31 +47,31 @@ module.exports = function (channelManager, domain, cdn) {
}

let timestamp = now();
router.get('/timestamp', ctx => {
router.get(`${basePath}timestamp`, ctx => {
ctx.body = timestamp;
});
channelManager.on('target_changed', () => (timestamp = now()));

function createStatic(prefix, folder) {
router.get(`${prefix}/*`, async ctx => {
await send(ctx, ctx.path.slice(prefix.length), {
router.get(`${basePath}${prefix}/*`, async ctx => {
await send(ctx, ctx.path.slice(basePath.length + prefix.length), {
root: path.resolve(__dirname, `../..${folder}`),
maxAge,
});
});
}

function createStaticFile(file) {
router.get(`/${file}`, async ctx => {
router.get(`${basePath}${file}`, async ctx => {
await send(ctx, file, {
root: path.resolve(__dirname, '../../public'),
maxAge,
});
});
}

createStatic('/front_end', '/public/front_end');
createStatic('/test', '/test');
createStatic('front_end', '/public/front_end');
createStatic('test', '/test');
createStaticFile('target.js');
createStaticFile('index.js');

Expand Down
11 changes: 7 additions & 4 deletions server/tpl/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,15 @@
{{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}}/target.js">{{domain}}/target.js</a> <br/>
Or just open the demo page <a target="_blank" href="//{{domain}}/test/demo.html">{{domain}}/test/demo.html</a> to play around with.<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}}
<script>window.domain = '{{domain}}';</script>
<script src="//{{domain}}/index.js"></script>
<script>
window.domain = '{{domain}}';
window.basePath = '{{basePath}}';
</script>
<script src="//{{domain}}{{basePath}}index.js"></script>
</body>
</html>
7 changes: 4 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@ switch (os) {
}

window.inspect = function (id: string) {
const domain = window.domain;
const { domain, basePath } = window;
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
const url =
location.protocol + `//${domain}/front_end/chii_app.html?${protocol}=${domain}/client/${randomId(6)}?target=${id}`;
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();
setInterval(() => {
fetch('/timestamp')
fetch(`${window.basePath}timestamp`)
.then(res => res.text())
.then(
timestamp => {
Expand Down
136 changes: 5 additions & 131 deletions src/target.ts
Original file line number Diff line number Diff line change
@@ -1,135 +1,9 @@
import query from 'licia/query';
import randomId from 'licia/randomId';
import safeStorage from 'licia/safeStorage';
import $ from 'licia/$';
import contain from 'licia/contain';
import Socket from 'licia/Socket';
import ready from 'licia/ready';
import chobitsu from 'chobitsu';
import DevtoolsFrame from './DevtoolsFrame';
import createUrl from 'licia/createUrl';

const sessionStore = safeStorage('session');

let ChiiServerUrl = location.host;

function getTargetScriptEl() {
const elements = document.getElementsByTagName('script');
let i = 0;
while (i < elements.length) {
const element = elements[i];
if (-1 !== element.src.indexOf('/target.js')) {
return element;
}
i++;
}
}

if ((window as any).ChiiServerUrl) {
ChiiServerUrl = (window as any).ChiiServerUrl;
} else {
const element = getTargetScriptEl();
if (element) {
const pattern = /((https?:)?\/\/(.*?)\/)/;
const match = pattern.exec(element.src);
if (match) {
ChiiServerUrl = match[3];
}
}
}

let embedded = false;
let cdn = '';
const element = getTargetScriptEl();
if (element) {
if (element.getAttribute('embedded') === 'true') {
embedded = true;
}
cdn = element.getAttribute('cdn') || '';
}

function getFavicon() {
let favicon = location.origin + '/favicon.ico';

const $link = $('link');
$link.each(function (this: HTMLElement) {
if (contain(this.getAttribute('rel') || '', 'icon')) {
const href = this.getAttribute('href');
if (href) favicon = fullUrl(href);
}
});

return favicon;
}

const link = document.createElement('a');

function fullUrl(href: string) {
link.href = href;

return link.protocol + '//' + link.host + link.pathname + link.search + link.hash;
}

let isInit = false;

let id = sessionStore.getItem('chii-id');
if (!id) {
id = randomId(6);
sessionStore.setItem('chii-id', id);
}
import { embedded } from './target/config';
import connectServer from './target/connectServer';
import connectIframe from './target/connectIframe';

if (!embedded) {
const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';

const ws = new Socket(
`${protocol}//${ChiiServerUrl}/target/${id}?${query.stringify({
url: location.href,
title: (window as any).ChiiTitle || document.title,
favicon: getFavicon(),
})}`
);

ws.on('open', () => {
isInit = true;
ws.on('message', event => {
chobitsu.sendRawMessage(event.data);
});
});

chobitsu.setOnMessage((message: string) => {
if (!isInit) return;
ws.send(message);
});
connectServer();
} else {
const protocol = location.protocol === 'https:' ? 'https:' : 'http:';
let serverUrl = `${protocol}//${ChiiServerUrl}`;
if (cdn) {
serverUrl = createUrl(
`
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>DevTools</title>
<style>
@media (prefers-color-scheme: dark) {
body {
background-color: rgb(41 42 45);
}
}
</style>
<meta name="referrer" content="no-referrer">
<script type="module" src="${cdn}/front_end/entrypoints/chii_app/chii_app.js"></script>
<body class="undocked" id="-blink-dev-tools">
`,
{
type: 'text/html',
}
);
}
const devtoolsFrame = new DevtoolsFrame();
if (document.body) {
devtoolsFrame.attach(serverUrl);
} else {
ready(() => devtoolsFrame.attach(serverUrl));
}
connectIframe();
}
12 changes: 7 additions & 5 deletions src/DevtoolsFrame.ts → src/target/DevtoolsFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import toNum from 'licia/toNum';
import startWith from 'licia/startWith';
import isStr from 'licia/isStr';
import isJson from 'licia/isJson';
import { getOrigin } from './util';

const $document = $(document as any);

Expand Down Expand Up @@ -64,7 +65,7 @@ export default class DevtoolsFrame {
this.height = height;
localStorage.setItem('chii-embedded-height', toStr(height));
}
attach(serverUrl: string) {
attach(devtoolsUrl: string) {
let protocol = location.protocol;
let host = location.host;
if (protocol === 'about:' || protocol === 'blob:') {
Expand All @@ -79,12 +80,13 @@ export default class DevtoolsFrame {
width: '100%',
height: '100%',
});
let targetOrigin = serverUrl;
if (startWith(serverUrl, 'blob:')) {
let targetOrigin = '';
if (startWith(devtoolsUrl, 'blob:')) {
targetOrigin = hostOrigin;
frame.src = `${serverUrl}#?embedded=${encodeURIComponent(hostOrigin)}`;
frame.src = `${devtoolsUrl}#?embedded=${encodeURIComponent(hostOrigin)}`;
} else {
frame.src = `${serverUrl}/front_end/chii_app.html?embedded=${encodeURIComponent(hostOrigin)}`;
targetOrigin = getOrigin(devtoolsUrl);
frame.src = `${devtoolsUrl}?embedded=${encodeURIComponent(hostOrigin)}`;
}

chobitsu.setOnMessage((message: string) => {
Expand Down
Loading

0 comments on commit d997c61

Please sign in to comment.