1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-04 10:19:30 +02:00

Reverse port forwarding UI actually works now.

This commit is contained in:
Simo Kinnunen 2014-10-14 22:57:44 +09:00
parent 99864fb223
commit cecf08a244
10 changed files with 158 additions and 134 deletions

View file

@ -130,6 +130,7 @@ dbapi.saveDevice = function(serial, device) {
, statusChangedAt: r.now() , statusChangedAt: r.now()
, createdAt: r.now() , createdAt: r.now()
, lastHeartbeatAt: r.now() , lastHeartbeatAt: r.now()
, reverseForwards: []
} }
return db.run(r.table('devices').get(serial).update(data)) return db.run(r.table('devices').get(serial).update(data))
.then(function(stats) { .then(function(stats) {
@ -230,6 +231,12 @@ dbapi.setDeviceRotation = function(serial, rotation) {
})) }))
} }
dbapi.setDeviceReverseForwards = function(serial, forwards) {
return db.run(r.table('devices').get(serial).update({
reverseForwards: forwards
}))
}
dbapi.setDeviceChannel = function(serial, channel) { dbapi.setDeviceChannel = function(serial, channel) {
return db.run(r.table('devices').get(serial).update({ return db.run(r.table('devices').get(serial).update({
channel: channel channel: channel

View file

@ -2,6 +2,7 @@ var net = require('net')
var Promise = require('bluebird') var Promise = require('bluebird')
var syrup = require('syrup') var syrup = require('syrup')
var _ = require('lodash')
var wire = require('../../../../wire') var wire = require('../../../../wire')
var logger = require('../../../../util/logger') var logger = require('../../../../util/logger')
@ -61,33 +62,37 @@ module.exports = syrup.serial()
}) })
} }
plugin.createForward = function(port, to) { plugin.createForward = function(id, forward) {
log.info( log.info(
'Creating reverse port forward from ":%d" to "%s:%d"' 'Creating reverse port forward "%s" from ":%d" to "%s:%d"'
, port , id
, to.host , forward.devicePort
, to.port , forward.targetHost
, forward.targetPort
) )
return connectService(1) return connectService(1)
.then(function(out) { .then(function(out) {
var header = new Buffer(4) var header = new Buffer(4)
header.writeUInt16LE(0, 0) header.writeUInt16LE(0, 0)
header.writeUInt16LE(port, 2) header.writeUInt16LE(forward.devicePort, 2)
out.write(header) out.write(header)
return manager.add(port, out, to) return manager.add(id, out, forward)
}) })
} }
plugin.removeForward = function(port) { plugin.removeForward = function(id) {
log.info('Removing reverse port forward ":%d"', port) log.info('Removing reverse port forward "%s"', id)
manager.remove(port) manager.remove(id)
return Promise.resolve() return Promise.resolve()
} }
plugin.connect = function(options) { plugin.connect = function(options) {
var resolver = Promise.defer() var resolver = Promise.defer()
var conn = net.connect(options) var conn = net.connect({
host: options.targetHost
, port: options.targetPort
})
function connectListener() { function connectListener() {
resolver.resolve(conn) resolver.resolve(conn)
@ -112,44 +117,29 @@ module.exports = syrup.serial()
group.on('leave', plugin.reset) group.on('leave', plugin.reset)
manager.on('add', function(port, to) { var pushForwards = _.debounce(
push.send([ function() {
wireutil.global push.send([
, wireutil.envelope(new wire.DeviceForwardAddEvent( wireutil.global
options.serial , wireutil.envelope(new wire.ReverseForwardsEvent(
, port options.serial
, to.host , manager.listAll()
, to.port ))
)) ])
]) }
}) , 200
)
manager.on('remove', function(port) { manager.on('add', pushForwards)
push.send([ manager.on('remove', pushForwards)
wireutil.global
, wireutil.envelope(new wire.DeviceForwardRemoveEvent(
options.serial
, port
))
])
})
return startService() return startService()
.then(awaitServer) .then(awaitServer)
.then(function() { .then(function() {
plugin.createForward(3000, {
host: '127.0.0.1'
, port: 3000
})
router router
.on(wire.ForwardTestMessage, function(channel, message) { .on(wire.ForwardTestMessage, function(channel, message) {
var reply = wireutil.reply(options.serial) var reply = wireutil.reply(options.serial)
plugin.connect({ plugin.connect(message)
host: message.targetHost
, port: message.targetPort
})
.then(function(conn) { .then(function(conn) {
conn.end() conn.end()
push.send([ push.send([
@ -166,10 +156,7 @@ module.exports = syrup.serial()
}) })
.on(wire.ForwardCreateMessage, function(channel, message) { .on(wire.ForwardCreateMessage, function(channel, message) {
var reply = wireutil.reply(options.serial) var reply = wireutil.reply(options.serial)
plugin.createForward(message.devicePort, { plugin.createForward(message.id, message)
host: message.targetHost
, port: message.targetPort
})
.then(function() { .then(function() {
push.send([ push.send([
channel channel
@ -186,7 +173,7 @@ module.exports = syrup.serial()
}) })
.on(wire.ForwardRemoveMessage, function(channel, message) { .on(wire.ForwardRemoveMessage, function(channel, message) {
var reply = wireutil.reply(options.serial) var reply = wireutil.reply(options.serial)
plugin.removeForward(message.devicePort) plugin.removeForward(message.id)
.then(function() { .then(function() {
push.send([ push.send([
channel channel

View file

@ -7,45 +7,51 @@ var ForwardWriter = require('./writer')
// Handles multiple ports // Handles multiple ports
function ForwardManager() { function ForwardManager() {
var handlersByPort = Object.create(null) var handlersById = Object.create(null)
this.has = function(port) { this.has = function(id) {
return !!handlersByPort[port] return !!handlersById[id]
} }
this.add = function(port, conn, to) { this.add = function(id, conn, options) {
function endListener() { function endListener() {
delete handlersByPort[port] delete handlersById[id]
this.emit('remove', port, to) this.emit('remove', id, options)
} }
var handler = new ForwardHandler(conn, to) if (this.has(id)) {
this.remove(id)
}
var handler = new ForwardHandler(conn, options)
handler.on('end', endListener.bind(this)) handler.on('end', endListener.bind(this))
handlersByPort[port] = handler handlersById[id] = handler
this.emit('add', port, to) this.emit('add', id, options)
} }
this.remove = function(port) { this.remove = function(id) {
var handler = handlersByPort[port] var handler = handlersById[id]
if (handler) { if (handler) {
handler.end() handler.end()
} }
} }
this.removeAll = function() { this.removeAll = function() {
Object.keys(handlersByPort).forEach(function(port) { Object.keys(handlersById).forEach(function(id) {
handlersByPort[port].end() handlersById[id].end()
}) })
} }
this.listAll = function() { this.listAll = function() {
return Object.keys(handlersByPort).map(function(port) { return Object.keys(handlersById).map(function(id) {
var handler = handlersByPort[port] var handler = handlersById[id]
return { return {
port: port id: id
, to: handler.to , devicePort: handler.options.devicePort
, targetHost: handler.options.targetHost
, targetPort: handler.options.targetPort
} }
}) })
} }
@ -56,7 +62,7 @@ function ForwardManager() {
util.inherits(ForwardManager, events.EventEmitter) util.inherits(ForwardManager, events.EventEmitter)
// Handles a single port // Handles a single port
function ForwardHandler(conn, to) { function ForwardHandler(conn, options) {
var destHandlersById = Object.create(null) var destHandlersById = Object.create(null)
function endListener() { function endListener() {
@ -73,7 +79,7 @@ function ForwardHandler(conn, to) {
if (packet) { if (packet) {
if (!dest) { if (!dest) {
// Let's create a new connection // Let's create a new connection
dest = destHandlersById[id] = new DestHandler(id, conn, to) dest = destHandlersById[id] = new DestHandler(id, conn, options)
dest.on('end', packetEndListener.bind(null, id)) dest.on('end', packetEndListener.bind(null, id))
} }
@ -87,11 +93,16 @@ function ForwardHandler(conn, to) {
} }
} }
function readableListener() {
// No-op but must exist so that we get the 'end' event.
}
conn.pipe(new ForwardReader()) conn.pipe(new ForwardReader())
.on('end', endListener.bind(this)) .on('end', endListener.bind(this))
.on('packet', packetListener) .on('packet', packetListener)
.on('readable', readableListener)
this.to = to this.options = options
this.end = function() { this.end = function() {
conn.end() conn.end()
@ -103,7 +114,7 @@ function ForwardHandler(conn, to) {
util.inherits(ForwardHandler, events.EventEmitter) util.inherits(ForwardHandler, events.EventEmitter)
// Handles a single connection // Handles a single connection
function DestHandler(id, conn, to) { function DestHandler(id, conn, options) {
function endListener() { function endListener() {
conn.removeListener('drain', drainListener) conn.removeListener('drain', drainListener)
this.emit('end') this.emit('end')
@ -133,7 +144,10 @@ function DestHandler(id, conn, to) {
} }
} }
var dest = net.connect(to) var dest = net.connect({
host: options.targetHost
, port: options.targetPort
})
.on('error', errorListener) .on('error', errorListener)
var writer = dest.pipe(new ForwardWriter(id)) var writer = dest.pipe(new ForwardWriter(id))

View file

@ -154,6 +154,10 @@ module.exports = function(options) {
dbapi.setDeviceRotation(message.serial, message.rotation) dbapi.setDeviceRotation(message.serial, message.rotation)
appDealer.send([channel, data]) appDealer.send([channel, data])
}) })
.on(wire.ReverseForwardsEvent, function(channel, message, data) {
dbapi.setDeviceReverseForwards(message.serial, message.forwards)
appDealer.send([channel, data])
})
.handler()) .handler())
lifecycle.observe(function() { lifecycle.observe(function() {

View file

@ -106,6 +106,7 @@ module.exports = function(options) {
, provider: message.provider , provider: message.provider
, present: true , present: true
, owner: null , owner: null
, reverseForwards: []
} }
}) })
}) })
@ -240,6 +241,15 @@ module.exports = function(options) {
} }
}) })
}) })
.on(wire.ReverseForwardsEvent, function(channel, message) {
socket.emit('device.change', {
important: false
, data: {
serial: message.serial
, reverseForwards: message.forwards
}
})
})
.handler() .handler()
// Global messages // Global messages
@ -676,7 +686,6 @@ module.exports = function(options) {
if (!data.targetHost || data.targetHost === 'localhost') { if (!data.targetHost || data.targetHost === 'localhost') {
data.targetHost = socket.request.ip data.targetHost = socket.request.ip
} }
socket.emit('forward.create', data)
joinChannel(responseChannel) joinChannel(responseChannel)
push.send([ push.send([
channel channel
@ -687,7 +696,6 @@ module.exports = function(options) {
]) ])
}) })
.on('forward.remove', function(channel, responseChannel, data) { .on('forward.remove', function(channel, responseChannel, data) {
socket.emit('forward.remove', data)
joinChannel(responseChannel) joinChannel(responseChannel)
push.send([ push.send([
channel channel

View file

@ -70,8 +70,7 @@ enum MessageType {
AccountGetMessage = 62; AccountGetMessage = 62;
AccountRemoveMessage = 55; AccountRemoveMessage = 55;
SdStatusMessage = 61; SdStatusMessage = 61;
DeviceForwardAddEvent = 72; ReverseForwardsEvent = 72;
DeviceForwardRemoveEvent = 73;
} }
message Envelope { message Envelope {
@ -399,25 +398,26 @@ message ForwardTestMessage {
} }
message ForwardCreateMessage { message ForwardCreateMessage {
required uint32 devicePort = 1; required string id = 1;
required string targetHost = 2;
required uint32 targetPort = 3;
}
message ForwardRemoveMessage {
required uint32 devicePort = 1;
}
message DeviceForwardAddEvent {
required string serial = 1;
required uint32 devicePort = 2; required uint32 devicePort = 2;
required string targetHost = 3; required string targetHost = 3;
required uint32 targetPort = 4; required uint32 targetPort = 4;
} }
message DeviceForwardRemoveEvent { message ForwardRemoveMessage {
required string serial = 1; required string id = 1;
}
message ReverseForward {
required string id = 1;
required uint32 devicePort = 2; required uint32 devicePort = 2;
required string targetHost = 3;
required uint32 targetPort = 4;
}
message ReverseForwardsEvent {
required string serial = 1;
repeated ReverseForward forwards = 2;
} }
message BrowserOpenMessage { message BrowserOpenMessage {

View file

@ -172,7 +172,8 @@ module.exports = function ControlServiceFactory(
this.createForward = function(forward) { this.createForward = function(forward) {
return sendTwoWay('forward.create', { return sendTwoWay('forward.create', {
devicePort: forward.devicePort id: forward.id
, devicePort: forward.devicePort
, targetHost: forward.targetHost , targetHost: forward.targetHost
, targetPort: forward.targetPort , targetPort: forward.targetPort
}) })
@ -180,7 +181,7 @@ module.exports = function ControlServiceFactory(
this.removeForward = function(forward) { this.removeForward = function(forward) {
return sendTwoWay('forward.remove', { return sendTwoWay('forward.remove', {
devicePort: forward.devicePort id: forward.id
}) })
} }

View file

@ -3,13 +3,8 @@ require('./port-forwarding.css')
module.exports = angular.module('stf.port-forwarding', [ module.exports = angular.module('stf.port-forwarding', [
require('stf/common-ui/table').name, require('stf/common-ui/table').name,
require('stf/settings').name, require('stf/settings').name,
require('gettext').name, require('gettext').name
require('angular-xeditable').name
]) ])
.run(function (editableOptions) {
editableOptions.theme = 'bs3'
})
.run(["$templateCache", function ($templateCache) { .run(["$templateCache", function ($templateCache) {
$templateCache.put( $templateCache.put(
'control-panes/advanced/port-forwarding/port-forwarding.jade', 'control-panes/advanced/port-forwarding/port-forwarding.jade',

View file

@ -1,42 +1,67 @@
var _ = require('lodash') var uuid = require('node-uuid')
var Promise = require('bluebird')
module.exports = function PortForwardingCtrl($scope module.exports = function PortForwardingCtrl(
, SettingsService) { $scope
, SettingsService
var defaultPortForwards = { ) {
targetHost: 'localhost' function defaults(id) {
return {
id: id
, targetHost: 'localhost'
, targetPort: 8080 , targetPort: 8080
, devicePort: 8080 , devicePort: 8080
, enabled: false , enabled: false
}
} }
$scope.reversePortForwards = [ $scope.reversePortForwards = [defaults('_default')]
defaultPortForwards
]
SettingsService.bind($scope, { SettingsService.bind($scope, {
target: 'reversePortForwards' target: 'reversePortForwards'
, source: 'reversePortForwards' , source: 'reversePortForwards'
}) })
$scope.enableForward = function (forward) { $scope.$watch('device.reverseForwards', function(newValue) {
forward.processing = true var map = Object.create(null)
return $scope.control.createForward(forward)
.finally(function () { if (newValue) {
forward.processing = false newValue.forEach(function(forward) {
map[forward.id] = forward
}) })
}
$scope.reversePortForwards.forEach(function(forward) {
var deviceForward = map[forward.id]
forward.enabled = !!(deviceForward && deviceForward.id === forward.id &&
deviceForward.devicePort == forward.devicePort)
})
})
$scope.applyForward = function (forward) {
return forward.enabled
? $scope.control.createForward(forward)
: $scope.control.removeForward(forward)
}
$scope.enableForward = function (forward) {
if (forward.enabled) {
return Promise.resolve()
}
return $scope.control.createForward(forward)
} }
$scope.disableForward = function (forward) { $scope.disableForward = function (forward) {
forward.processing = true if (!forward.enabled) {
return Promise.resolve()
}
return $scope.control.removeForward(forward) return $scope.control.removeForward(forward)
.finally(function () {
forward.processing = false
})
} }
$scope.addRow = function () { $scope.addRow = function () {
$scope.reversePortForwards.push(defaultPortForwards) $scope.reversePortForwards.push(defaults(uuid.v4()))
} }
$scope.removeRow = function (forward) { $scope.removeRow = function (forward) {
@ -44,13 +69,4 @@ module.exports = function PortForwardingCtrl($scope
$scope.reversePortForwards.splice( $scope.reversePortForwards.splice(
$scope.reversePortForwards.indexOf(forward), 1) $scope.reversePortForwards.indexOf(forward), 1)
} }
$scope.showApply = function () {
$scope.isShowApply = true
}
$scope.applyTable = function () {
console.log('TODO: Sync back the changes')
$scope.isShowApply = false
}
} }

View file

@ -9,7 +9,6 @@
i.fa.fa-plus.fa-fw i.fa.fa-plus.fa-fw
.widget-content.padded(collapse='isCollapsed') .widget-content.padded(collapse='isCollapsed')
//form(editable-form, name='table') //form(editable-form, name='table')
table.table.table-bordered.table-hover.table-condensed table.table.table-bordered.table-hover.table-condensed
tr tr
@ -38,24 +37,17 @@
td(width='35%') td(width='35%')
div.input-group div.input-group
span.input-group-addon span.input-group-addon
input(type='checkbox', ng-model='forward.enabled') input(type='checkbox', ng-model='forward.enabled', ng-change='applyForward(forward)')
input.form-control(type='number', min='0', ng-model='forward.devicePort', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Port"|translate}}', ng-change='showApply()') input.form-control(type='number', min='0', ng-model='forward.devicePort', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Port"|translate}}', ng-change='disableForward(forward)')
td td
i.fa.fa-arrow-right.fa-fw i.fa.fa-arrow-right.fa-fw
td(width='40%') td(width='40%')
input.form-control(type='text', ng-model='forward.targetHost', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Hostname"|translate}}', ng-change='showApply()') input.form-control(type='text', ng-model='forward.targetHost', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Hostname"|translate}}', ng-change='disableForward(forward)')
td td
span : span :
td(width='25%') td(width='25%')
input.form-control(type='number', min='0', ng-model='forward.targetPort', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Port"|translate}}', ng-change='showApply()') input.form-control(type='number', min='0', ng-model='forward.targetPort', ng-model-options="{ updateOn: 'default blur' }", placeholder='{{"Port"|translate}}', ng-change='disableForward(forward)')
td td
button.btn.btn-sm.btn-danger-outline(ng-click='removeRow(forward)') button.btn.btn-sm.btn-danger-outline(ng-click='removeRow(forward)')
i.fa.fa-trash-o i.fa.fa-trash-o
//span(translate) Remove //span(translate) Remove
div(ng-show='isShowApply')
button.btn.btn-sm.btn-primary-outline.pull-right(ng-click='applyTable()')
//i.fa.fa-trash-o
span(translate) Apply
br
br