mirror of
https://github.com/OutlineFoundation/outline-server.git
synced 2026-08-04 14:37:34 +00:00
Merge pull request #133 from Jigsaw-Code/trevj-patch-1
less extreme message for auto-update migration
This commit is contained in:
commit
fad667fd71
10 changed files with 41 additions and 37 deletions
|
|
@ -1,24 +1,24 @@
|
|||
{
|
||||
"__COMMENTS__": [
|
||||
"There is no version 100; this file exists now only to prompt users of versions 1.0.5 and ",
|
||||
"This file exists now only to prompt users of versions 1.0.5 and ",
|
||||
"earlier to update to the latest, auto-updates-by-electron-builder, version."
|
||||
],
|
||||
"latestVersions": {
|
||||
"outline-manager-darwin-x64": {
|
||||
"location": "https://raw.githubusercontent.com/Jigsaw-Code/outline-releases/master/manager/Outline-Manager.dmg",
|
||||
"version": "100.0.0"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"outline-manager-linux-ia32": {
|
||||
"location": "https://raw.githubusercontent.com/Jigsaw-Code/outline-releases/master/manager/Outline-Manager.AppImage",
|
||||
"version": "100.0.0"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"outline-manager-linux-x64": {
|
||||
"location": "https://raw.githubusercontent.com/Jigsaw-Code/outline-releases/master/manager/Outline-Manager.AppImage",
|
||||
"version": "100.0.0"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"outline-manager-win32-ia32": {
|
||||
"location": "https://raw.githubusercontent.com/Jigsaw-Code/outline-releases/master/manager/Outline-Manager.exe",
|
||||
"version": "100.0.0"
|
||||
"version": "1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ export interface ManagedServer extends Server {
|
|||
|
||||
// The managed machine where the Outline Server is running.
|
||||
export interface ManagedServerHost {
|
||||
// Returns the monthly transfer limit.
|
||||
getMonthlyTransferLimit(): DataAmount;
|
||||
// Returns the monthly outbound transfer limit.
|
||||
getMonthlyOutboundTransferLimit(): DataAmount;
|
||||
// Returns the monthly cost.
|
||||
getMonthlyCost(): MonetaryCost;
|
||||
// Returns the server region.
|
||||
|
|
|
|||
|
|
@ -282,8 +282,8 @@
|
|||
<div id='titleWrapper'>
|
||||
<h3>{{serverName}}</h3>
|
||||
<p>
|
||||
<span class='totalBytes measurement'>[[_formatBytesTransferred(totalBytesTransferred, '0')]]</span>
|
||||
<span hidden$='{{!monthlyTransferBytes}}'>of [[_formatBytesTransferred(monthlyTransferBytes)]] Transfer</span>
|
||||
<span class='totalBytes measurement'>[[_formatBytesTransferred(totalInboundBytes, '0')]]</span>
|
||||
<span hidden$='{{!monthlyOutboundTransferBytes}}'>of [[_formatBytesTransferred(monthlyOutboundTransferBytes)]] Transfer</span>
|
||||
<span hidden$='{{!monthlyCost}}'>, ${{monthlyCost}} US/Mo</span>
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -371,20 +371,20 @@
|
|||
// be unset in some old versions of Outline that allowed deleting this
|
||||
// row.
|
||||
myConnection: Object,
|
||||
totalBytesTransferred: Number,
|
||||
totalInboundBytes: Number,
|
||||
accessKeyRows: {type: Array, value: []},
|
||||
hasNonAdminAccessKeys: Boolean,
|
||||
deleteEnabled: Boolean,
|
||||
forgetEnabled: Boolean,
|
||||
metricsEnabled: Boolean,
|
||||
serverId: String,
|
||||
// Initialize monthlyTransferBytes and monthlyCost to 0, so they can
|
||||
// Initialize monthlyOutboundTransferBytes and monthlyCost to 0, so they can
|
||||
// be bound to hidden attributes. Initializing to undefined does not
|
||||
// cause hidden$=... expressions to be evaluated and so elements may be
|
||||
// shown incorrectly. See:
|
||||
// https://stackoverflow.com/questions/33700125/polymer-1-0-hidden-attribute-negate-operator
|
||||
// https://www.polymer-project.org/1.0/docs/devguide/data-binding.html
|
||||
monthlyTransferBytes: {type: Number, value: 0},
|
||||
monthlyOutboundTransferBytes: {type: Number, value: 0},
|
||||
monthlyCost: {type: Number, value: 0}
|
||||
},
|
||||
observers: [
|
||||
|
|
@ -470,7 +470,7 @@
|
|||
},
|
||||
_encodeURIComponent: encodeURIComponent,
|
||||
setServerTransferredData(total_bytes) {
|
||||
this.totalBytesTransferred = total_bytes
|
||||
this.totalInboundBytes = total_bytes
|
||||
},
|
||||
updateAccessKeyRow(accessKeyId, fields) {
|
||||
if (accessKeyId === MY_CONNECTION_USER_ID) {
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ class FakeManagedServer extends FakeServer implements server.ManagedServer {
|
|||
}
|
||||
getHost() {
|
||||
return {
|
||||
getMonthlyTransferLimit: () => ({terabytes: 1}),
|
||||
getMonthlyOutboundTransferLimit: () => ({terabytes: 1}),
|
||||
getMonthlyCost: () => ({usd: 5}),
|
||||
getRegionId: () => 'fake-region',
|
||||
delete: () => Promise.resolve(),
|
||||
|
|
|
|||
|
|
@ -486,15 +486,8 @@ export class App {
|
|||
view.monthlyCost = host.getMonthlyCost().usd;
|
||||
view.deleteEnabled = true;
|
||||
view.forgetEnabled = false;
|
||||
// Set monthly transfer byte limit for UI. For UI simplicity we are:
|
||||
// 1. Showing 1 TB as 1000 GB (not 1024)
|
||||
// 2. Dividing the total transfer limit by 2 to account for inbound and
|
||||
// outbound connections, i.e. if I download a 10 GB file, it has to
|
||||
// first be download from destination to the Outline server, then from
|
||||
// the Outline server to my client, and costs me 20 GB against my quota,
|
||||
// in this case it's simpler to say I used 10/500GB instead of 20/1000GB.
|
||||
const monthlyTransferGb = host.getMonthlyTransferLimit().terabytes * 1000 / 2;
|
||||
view.monthlyTransferBytes = monthlyTransferGb * (2 ** 30);
|
||||
const monthlyOutboundTransferGb = host.getMonthlyOutboundTransferLimit().terabytes * 1000;
|
||||
view.monthlyOutboundTransferBytes = monthlyOutboundTransferGb * (2 ** 30);
|
||||
} else {
|
||||
// TODO(dborkan): consider using dom-if with restamp property
|
||||
// https://www.polymer-project.org/1.0/docs/api/elements/dom-if
|
||||
|
|
@ -502,7 +495,7 @@ export class App {
|
|||
// the server-view when we display a new server. This should be fixed
|
||||
// once we support multiple servers.
|
||||
view.monthlyCost = undefined;
|
||||
view.monthlyTransferBytes = undefined;
|
||||
view.monthlyOutboundTransferBytes = undefined;
|
||||
view.deleteEnabled = false;
|
||||
view.forgetEnabled = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -324,7 +324,9 @@ class DigitalOceanHost implements server.ManagedServerHost {
|
|||
private digitalOcean: DigitalOceanSession, private dropletInfo: DropletInfo,
|
||||
private deleteCallback: Function) {}
|
||||
|
||||
getMonthlyTransferLimit(): server.DataAmount {
|
||||
getMonthlyOutboundTransferLimit(): server.DataAmount {
|
||||
// Details on the bandwidth limits can be found at
|
||||
// https://www.digitalocean.com/community/tutorials/digitalocean-bandwidth-billing-faq
|
||||
return {terabytes: this.dropletInfo.size.transfer};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,6 @@ export interface ShadowsocksInstance {
|
|||
// Registers a callback to be invoked when the ShadowsocksInstance has
|
||||
// transferred data (inbound and outbond). bytes is the number of
|
||||
// bytes transferred since the last callback.
|
||||
onBytesTransferred(callback: (bytes: number, ipAddresses: string[]) => void);
|
||||
onInboundBytes(callback: (bytes: number, ipAddresses: string[]) => void);
|
||||
stop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,16 @@ class LibevShadowsocksServerInstance implements ShadowsocksInstance {
|
|||
this.childProcess.kill();
|
||||
}
|
||||
|
||||
public onBytesTransferred(callback: (bytes: number, ipAddresses: string[]) => void) {
|
||||
// onBytesTransferred only reports inbound bytes, received from the client or from the target.
|
||||
//
|
||||
// This measure under-estimates outbound traffic because:
|
||||
// 1) The traffic to and from the client has overhead from Shadowsocks
|
||||
// 2) The overhead on the traffic to the client is larger than on the traffic from the client
|
||||
// because, from the client perspective, download traffic is usually larger than upload.
|
||||
//
|
||||
// The measure is calculated here:
|
||||
// https://github.com/shadowsocks/shadowsocks-libev/blob/a16826b83e73af386806d1b51149f8321820835e/src/server.c#L172
|
||||
public onInboundBytes(callback: (bytes: number, ipAddresses: string[]) => void) {
|
||||
if (this.eventEmitter.listenerCount(this.BYTES_TRANSFERRED_EVENT) === 0) {
|
||||
this.createStatsListener();
|
||||
}
|
||||
|
|
@ -104,7 +113,7 @@ class LibevShadowsocksServerInstance implements ShadowsocksInstance {
|
|||
}
|
||||
|
||||
private createStatsListener() {
|
||||
let lastBytesTransferred = 0;
|
||||
let lastInboundBytes = 0;
|
||||
this.statsSocket.on('message', (buf: Buffer) => {
|
||||
let statsMessage;
|
||||
try {
|
||||
|
|
@ -117,11 +126,11 @@ class LibevShadowsocksServerInstance implements ShadowsocksInstance {
|
|||
// Ignore stats for other ss-servers, which post to the same statsSocket.
|
||||
return;
|
||||
}
|
||||
const delta = statsMessage.totalBytesTransferred - lastBytesTransferred;
|
||||
const delta = statsMessage.totalInboundBytes - lastInboundBytes;
|
||||
if (delta > 0) {
|
||||
this.getConnectedClientIPAddresses()
|
||||
.then((ipAddresses: string[]) => {
|
||||
lastBytesTransferred = statsMessage.totalBytesTransferred;
|
||||
lastInboundBytes = statsMessage.totalInboundBytes;
|
||||
this.eventEmitter.emit(this.BYTES_TRANSFERRED_EVENT, delta, ipAddresses);
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
@ -159,20 +168,20 @@ class LibevShadowsocksServerInstance implements ShadowsocksInstance {
|
|||
|
||||
interface StatsMessage {
|
||||
portNumber: number;
|
||||
totalBytesTransferred: number;
|
||||
totalInboundBytes: number;
|
||||
}
|
||||
|
||||
function parseStatsMessage(buf): StatsMessage {
|
||||
const jsonString = buf.toString()
|
||||
.substr('stat: '.length) // remove leading "stat: "
|
||||
.replace(/\0/g, ''); // remove trailing null terminator
|
||||
// statObj is in the form {"port#": totalBytesTransferred}, where
|
||||
// statObj is in the form {"port#": totalInboundBytes}, where
|
||||
// there is always only 1 port# per JSON object. If there are multiple
|
||||
// ss-servers communicating to the same manager, we will get multiple
|
||||
// message events.
|
||||
const statObj = JSON.parse(jsonString);
|
||||
// Object.keys is used here because node doesn't support Object.values.
|
||||
const portNumber = parseInt(Object.keys(statObj)[0], 10);
|
||||
const totalBytesTransferred = statObj[portNumber];
|
||||
return {portNumber, totalBytesTransferred};
|
||||
const totalInboundBytes = statObj[portNumber];
|
||||
return {portNumber, totalInboundBytes};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class ManagedAccessKeyRepository implements AccessKeyRepository {
|
|||
accessKeyJson.port, accessKeyJson.password, statsSocket,
|
||||
accessKeyJson.encryptionMethod)
|
||||
.then((ssInstance) => {
|
||||
ssInstance.onBytesTransferred(this.handleBytesTransferred.bind(
|
||||
ssInstance.onInboundBytes(this.handleBytesTransferred.bind(
|
||||
this, accessKeyJson.id, accessKeyJson.metricsId));
|
||||
const accessKey = new ManagedAccessKey(
|
||||
accessKeyJson.id, accessKeyJson.metricsId, accessKeyJson.name, ssInstance);
|
||||
|
|
@ -148,7 +148,7 @@ class ManagedAccessKeyRepository implements AccessKeyRepository {
|
|||
this.reservedPorts.add(port);
|
||||
const id = this.allocateId();
|
||||
const metricsId = uuidv4();
|
||||
ssInstance.onBytesTransferred(this.handleBytesTransferred.bind(this, id, metricsId));
|
||||
ssInstance.onInboundBytes(this.handleBytesTransferred.bind(this, id, metricsId));
|
||||
const accessKey = new ManagedAccessKey(id, metricsId, '', ssInstance);
|
||||
this.accessKeys.set(accessKey.id, accessKey);
|
||||
this.persistState();
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ class MockShadowsocksInstance implements ShadowsocksInstance {
|
|||
public password = 'password',
|
||||
public encryptionMethod = 'encryption',
|
||||
public accessUrl = 'ss://somethingsomething') {}
|
||||
onBytesTransferred(callback: (bytes: number, ipAddresses: string[]) => void) {}
|
||||
onInboundBytes(callback: (bytes: number, ipAddresses: string[]) => void) {}
|
||||
stop() {}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue