Merge pull request #133 from Jigsaw-Code/trevj-patch-1

less extreme message for auto-update migration
This commit is contained in:
trevj 2018-05-14 10:04:37 -04:00 committed by fortuna
commit fad667fd71
10 changed files with 41 additions and 37 deletions

View file

@ -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"
}
}
}

View file

@ -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.

View file

@ -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) {

View file

@ -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(),

View file

@ -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;
}

View file

@ -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};
}

View file

@ -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();
}

View file

@ -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};
}

View file

@ -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();

View file

@ -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() {}
}