前端代码

This commit is contained in:
ChloeChen0423
2025-05-12 16:42:36 +09:00
commit 7c63f2f07b
4531 changed files with 656010 additions and 0 deletions

View File

@ -0,0 +1,201 @@
(function (angular) {
const SECTION_NAME = "network-throttle";
angular
.module("BrowserSync")
.controller("NetworkThrottleController", [
"options",
"pagesConfig",
"Socket",
"$scope",
NetworkThrottleController
]);
/**
* @param options
* @param pagesConfig
* @param Socket
* @param $scope
*/
function NetworkThrottleController (options, pagesConfig, Socket, $scope) {
var ctrl = this;
ctrl.section = pagesConfig[SECTION_NAME];
ctrl.options = options.bs;
ctrl.uiOptions = options.ui;
ctrl.clientFiles = options.ui.clientFiles || {};
ctrl.section = pagesConfig[SECTION_NAME];
ctrl.throttle = ctrl.uiOptions[SECTION_NAME];
ctrl.selected = ctrl.throttle.targets[0].id;
ctrl.servers = ctrl.throttle.servers;
ctrl.port = "";
ctrl.portEntry = "auto";
ctrl.serverCount = Object.keys(ctrl.servers).length;
ctrl.blurs = [];
ctrl.state = {
success: false,
waiting: false,
classname: "ready"
};
ctrl.createServer = function (selected, event) {
if (ctrl.blurs.indexOf(event.target) === -1) {
ctrl.blurs.push(event.target);
}
var item = getByProp(ctrl.throttle.targets, "id", ctrl.selected);
if (ctrl.portEntry === "auto") {
return send("");
}
if (!ctrl.port || !ctrl.port.length) {
setError();
return;
}
if (!ctrl.port.match(/\d{4,5}/)) {
setError();
return;
}
var port = parseInt(ctrl.port, 10);
if (port < 1024 || port > 65535) {
setError();
return;
}
send(ctrl.port);
function setError() {
ctrl.state.waiting = false;
ctrl.state.portError = true;
}
function send (port) {
ctrl.state.classname = "waiting";
ctrl.state.waiting = true;
Socket.uiEvent({
namespace: SECTION_NAME,
event: "server:create",
data: {
speed: item,
port: port
}
});
}
};
ctrl.destroyServer = function (item, port) {
Socket.uiEvent({
namespace: SECTION_NAME,
event: "server:destroy",
data: {
speed: item,
port: port
}
});
};
ctrl.toggleSpeed = function (item) {
if (!item.active) {
item.urls = [];
}
};
ctrl.update = function (data) {
ctrl.servers = data.servers;
ctrl.serverCount = Object.keys(ctrl.servers).length;
if (data.event === "server:create") {
updateButtonState();
}
$scope.$digest();
};
function updateButtonState() {
ctrl.state.success = true;
ctrl.state.classname = "success";
setTimeout(function () {
ctrl.blurs.forEach(function (elem) {
elem.blur();
});
setTimeout(function () {
ctrl.state.success = false;
ctrl.state.waiting = false;
ctrl.state.classname = "ready";
$scope.$digest();
}, 500);
}, 300);
}
/**
* @param collection
* @param prop
* @returns {*}
*/
function getByProp (collection, prop, name) {
var match = collection.filter(function (item) {
return item[prop] === name;
});
if (match.length) {
return match[0];
}
return false;
}
Socket.on("ui:network-throttle:update", ctrl.update);
$scope.$on("$destroy", function () {
Socket.off("ui:network-throttle:update", ctrl.update);
});
}
/**
* Display the snippet when in snippet mode
*/
angular
.module("BrowserSync")
.directive("throttle", function () {
return {
restrict: "E",
replace: true,
scope: {
"target": "=",
"options": "="
},
templateUrl: "network-throttle.directive.html",
controller: ["$scope", "Socket", throttleDirectiveControlller],
controllerAs: "ctrl"
};
});
/**
* @param $scope
*/
function throttleDirectiveControlller ($scope) {
var ctrl = this;
ctrl.throttle = $scope.options[SECTION_NAME];
}
})(angular);

View File

@ -0,0 +1,12 @@
<section bs-panel-content>
<div ng-if="target.active">
<p ng-if="!target.urls.length">
Creating a throttled server, please wait...
</p>
<div ng-if="target.urls.length">
<ul bs-list>
<li ng-repeat="url in target.urls"><a href="{{url}}">{{url}}</a></li>
</ul>
</div>
</div>
</section>

View File

@ -0,0 +1,93 @@
<article>
<div bs-panel="controls outline">
<h1 bs-heading>
<icon icon="{{ctrl.section.icon}}"></icon>
{{ctrl.section.title}}
</h1>
</div>
<div bs-panel="no-border" ng-if="ctrl.options.mode === 'snippet'">
<div bs-panel-content="basic">
<p class="lede">Sorry, Network Throttling is only available in Server or Proxy mode.</p>
</div>
</div>
<div bs-panel="no-border" ng-if="ctrl.options.mode !== 'snippet'">
<div bs-panel-content="basic">
<div bs-inputs bs-grid="wide-3 desk-2">
<div bs-grid-item>
<p bs-label-heading>Speed</p>
<div bs-input="inline" ng-repeat="(key, item) in ctrl.throttle.targets | orderObjectBy:'order'">
<input
type="radio"
id="speed-{{item.id}}"
checked name="speed"
ng-model="ctrl.selected"
value="{{item.id}}">
<label for="speed-{{item.id}}" bs-input-label="light">{{item.title}}</label>
</div>
</div>
<div bs-grid-item>
<p bs-label-heading>Port</p>
<div bs-input="text">
<div bs-input="inline">
<input type="radio" name="port-select" id="port-auto" checked value="auto"
ng-model="ctrl.portEntry">
<label for="port-auto" bs-input-label="light">Auto Detection</label>
</div>
<div bs-input="inline">
<input type="radio" id="port-manual" name="port-select" value="manual" ng-model="ctrl.portEntry">
<label for="port-manual" bs-input-label="light">User specified <span ng-if="ctrl.state.portError">(between
1024 & 65535)</span></label>
</div>
<input id="server-port"
type="text"
value=""
placeholder="Eg: 1024"
ng-model="ctrl.port"
ng-focus="ctrl.portEntry = 'manual'"
custom-validation>
</div>
<br/>
<div ng-class="[ctrl.state.classname]" bs-state-wrapper>
<button
id="create-server"
bs-button="size-small subtle-alt icon-left"
ng-click="ctrl.createServer(ctrl.selected, $event)"
ng-disabled="ctrl.state.waiting"
>
<icon icon="circle-plus"></icon>
Create Server
</button>
<div bs-state-icons>
<icon icon="circle-ok" bs-state="success inline"></icon>
<icon icon="circle-minus" bs-state="waiting inline" bs-anim="spin"></icon>
</div>
</div>
</div>
<div bs-grid-item>
</div>
</div>
</div>
<br/>
<div bs-panel-content="basic">
<h3 ng-if="ctrl.serverCount">Your Servers:</h3>
<h3 ng-if="!ctrl.serverCount">Your Servers will appear here...</h3>
</div>
<ul bs-list="bordered inline-controls" bs-offset="basic" id="throttle-server-list">
<li ng-repeat="(key, item) in ctrl.servers track by key">
<p bs-width="5">{{$index + 1}}.</p>
<p bs-width="10"><b>{{item.speed.id | uppercase}}</b></p>
<p><a href="{{item.urls[0]}}">{{item.urls[0]}}</a></p>
<p><a href="{{item.urls[1]}}">{{item.urls[1]}}</a></p>
<div bs-button-group>
<button href="#" bs-button="subtle-alt icon" ng-click="ctrl.destroyServer(item, key)">
<svg bs-svg-icon><use xlink:href="#svg-bin"></use></svg>
</button>
</div>
</li>
</ul>
</div>
</article>

View File

@ -0,0 +1,160 @@
var Immutable = require("immutable");
module.exports.init = function (ui) {
var optPath = ["network-throttle"];
var serverOptPath = optPath.concat(["servers"]);
var listenHost = ui.options.get("listen");
ui.servers = {};
ui.setOptionIn(optPath, Immutable.fromJS({
name: "network-throttle",
title: "Network Throttle",
active: false,
targets: require("./targets")
}));
ui.setOptionIn(serverOptPath, Immutable.Map({}));
/**
* @param input
* @returns {number}
*/
function getPortArg(input) {
input = input.trim();
if (input.length && input.match(/\d{3,5}/)) {
input = parseInt(input, 10);
} else {
input = ui.bs.options.get("port") + 1;
}
return input;
}
/**
* @returns {string}
*/
function getTargetUrl() {
return require("url").parse(ui.bs.options.getIn(["urls", "local"]));
}
var methods = {
/**
* @param data
*/
"server:create": function (data) {
data.port = getPortArg(data.port);
data.cb = data.cb || function () { /* noop */};
/**
* @param opts
*/
function saveThrottleInfo (opts) {
var urls = getUrls(ui.bs.options.set("port", opts.port).toJS());
ui.setOptionIn(serverOptPath.concat([opts.port]), Immutable.fromJS({
urls: urls,
speed: opts.speed
}));
setTimeout(function () {
ui.socket.emit("ui:network-throttle:update", {
servers: ui.getOptionIn(serverOptPath).toJS(),
event: "server:create"
});
ui.servers[opts.port] = opts.server;
data.cb(null, opts);
}, 300);
}
/**
* @param err
* @param port
*/
function createThrottle (err, port) {
var target = getTargetUrl();
var args = {
port: port,
target: target,
speed: data.speed
};
if (ui.bs.getOption("scheme") === "https") {
var httpsOpts = require("browser-sync/lib/server/utils").getHttpsOptions(ui.bs.options);
args.key = httpsOpts.key;
args.cert = httpsOpts.cert;
}
args.server = require("./throttle-server")(args, listenHost);
require('server-destroy')(args.server);
args.server.listen(port, listenHost);
saveThrottleInfo(args);
}
/**
* Try for a free port
*/
ui.bs.utils.portscanner.findAPortNotInUse(data.port, data.port + 100, (listenHost || "127.0.0.1"), function (err, port) {
if (err) {
return createThrottle(err);
} else {
createThrottle(null, port);
}
});
},
/**
* @param data
*/
"server:destroy": function (data) {
if (ui.servers[data.port]) {
ui.servers[data.port].destroy();
ui.setMany(function (item) {
item.deleteIn(serverOptPath.concat([parseInt(data.port, 10)]));
});
delete ui.servers[data.port];
}
ui.socket.emit("ui:network-throttle:update", {
servers: ui.getOptionIn(serverOptPath).toJS(),
event: "server:destroy"
});
},
/**
* @param event
*/
event: function (event) {
methods[event.event](event.data);
}
};
return methods;
};
/**
* Get local + external urls with a different port
* @param opts
* @returns {List<T>|List<any>}
*/
function getUrls (opts) {
var list = [];
var bsLocal = require("url").parse(opts.urls.local);
list.push([bsLocal.protocol + "//", bsLocal.hostname, ":", opts.port].join(""));
if (opts.urls.external) {
var external = require("url").parse(opts.urls.external);
list.push([bsLocal.protocol + "//", external.hostname, ":", opts.port].join(""));
}
return Immutable.List(list);
}

View File

@ -0,0 +1,53 @@
var networkThrottle = require("./network-throttle");
const PLUGIN_NAME = "Network Throttle";
/**
* @type {{plugin: Function, plugin:name: string, markup: string}}
*/
module.exports = {
/**
* Plugin init
*/
"plugin": function (ui, bs) {
ui.throttle = networkThrottle.init(ui, bs);
ui.listen("network-throttle", ui.throttle);
},
/**
* Hooks
*/
"hooks": {
"markup": fileContent("/network-throttle.html"),
"client:js": [fileContent("/network-throttle.client.js")],
"templates": [],
"page": {
path: "/network-throttle",
title: PLUGIN_NAME,
template: "network-throttle.html",
controller: "NetworkThrottleController",
order: 5,
icon: "time"
}
},
/**
* Plugin name
*/
"plugin:name": PLUGIN_NAME
};
/**
* @param filepath
* @returns {*}
*/
function getPath (filepath) {
return require("path").join(__dirname, filepath);
}
/**
* @param filepath
* @returns {*}
*/
function fileContent (filepath) {
return require("fs").readFileSync(getPath(filepath));
}

View File

@ -0,0 +1,57 @@
module.exports = [
{
active: false,
title: "DSL (2Mbs, 5ms RTT)",
id: "dsl",
speed: 200,
latency: 5,
urls: [],
order: 1
},
{
active: false,
title: "4G (4Mbs, 20ms RTT)",
id: "4g",
speed: 400,
latency: 10,
urls: [],
order: 2
},
{
active: false,
title: "3G (750kbs, 100ms RTT)",
id: "3g",
speed: 75,
latency: 50,
urls: [],
order: 3
},
{
active: false,
id: "good-2g",
title: "Good 2G (450kbs, 150ms RTT)",
speed: 45,
latency: 75,
urls: [],
order: 4
},
{
active: false,
id: "2g",
title: "Regular 2G (250kbs, 300ms RTT)",
speed: 25,
latency: 150,
urls: [],
order: 5
},
{
active: false,
id: "gprs",
title: "GPRS (50kbs, 500ms RTT)",
speed: 5,
latency: 250,
urls: [],
order: 6
}
];

View File

@ -0,0 +1,70 @@
var ThrottleGroup = require("stream-throttle").ThrottleGroup;
module.exports = throttle;
/**
*
*/
function throttle (opts, listenHost) {
var options = {
local_host: listenHost,
remote_host: listenHost,
upstream: 10*1024,
downstream: opts.speed.speed * 1024,
keepalive: false
};
var serverOpts = {
allowHalfOpen: true,
rejectUnauthorized: false
};
var module = "net";
var method = "createConnection";
if (opts.key) {
module = "tls";
method = "connect";
serverOpts.key = opts.key;
serverOpts.cert = opts.cert;
}
return require(module).createServer(serverOpts, function (local) {
var remote = require(module)[method]({
host: opts.target.hostname,
port: opts.target.port,
allowHalfOpen: true,
rejectUnauthorized: false
});
var upThrottle = new ThrottleGroup({ rate: options.upstream });
var downThrottle = new ThrottleGroup({ rate: options.downstream });
var localThrottle = upThrottle.throttle();
var remoteThrottle = downThrottle.throttle();
setTimeout(function () {
local
.pipe(localThrottle)
.pipe(remote);
}, opts.speed.latency);
setTimeout(function () {
remote
.pipe(remoteThrottle)
.pipe(local);
}, opts.speed.latency);
local.on("error", function() {
remote.destroy();
local.destroy();
});
remote.on("error", function() {
local.destroy();
remote.destroy();
});
});
}