From f368985a60663af9a93c0b7955f2231352e754ad Mon Sep 17 00:00:00 2001 From: Teagan glenn Date: Sat, 29 Jun 2024 21:03:19 +0000 Subject: [PATCH] feat(streams): Add multiple upstreams for basic load balancing --- backend/models/stream.js | 86 ++++++++++++---------- backend/schema/endpoints/streams.json | 34 ++++++--- backend/templates/stream.conf | 23 +++++- frontend/js/app/nginx/stream/form.ejs | 6 +- frontend/js/app/nginx/stream/form.js | 26 ++++++- frontend/js/app/nginx/stream/list/item.ejs | 13 +++- frontend/js/app/nginx/stream/list/main.ejs | 1 + frontend/js/i18n/messages.json | 4 +- frontend/js/models/stream.js | 2 +- 9 files changed, 135 insertions(+), 60 deletions(-) diff --git a/backend/models/stream.js b/backend/models/stream.js index 7d84d2c3..3ad4ea9f 100644 --- a/backend/models/stream.js +++ b/backend/models/stream.js @@ -1,55 +1,65 @@ // Objection Docs: // http://vincit.github.io/objection.js/ -const db = require('../db'); +const db = require('../db'); const Model = require('objection').Model; -const User = require('./user'); -const now = require('./now_helper'); +const User = require('./user'); +const now = require('./now_helper'); Model.knex(db); class Stream extends Model { - $beforeInsert () { - this.created_on = now(); - this.modified_on = now(); + $beforeInsert() { + this.created_on = now(); + this.modified_on = now(); - // Default for meta - if (typeof this.meta === 'undefined') { - this.meta = {}; - } - } + // Default for forwarding_hosts + if (typeof this.forwarding_hosts === 'undefined') { + this.forwarding_hosts = []; + } - $beforeUpdate () { - this.modified_on = now(); - } + // Default for meta + if (typeof this.meta === 'undefined') { + this.meta = {}; + } + } - static get name () { - return 'Stream'; - } + $beforeUpdate() { + this.modified_on = now(); - static get tableName () { - return 'stream'; - } + // Sort domain_names + if (typeof this.forwarding_hosts !== 'undefined') { + this.forwarding_hosts.sort(); + } + } - static get jsonAttributes () { - return ['meta']; - } + static get name() { + return 'Stream'; + } - static get relationMappings () { - return { - owner: { - relation: Model.HasOneRelation, - modelClass: User, - join: { - from: 'stream.owner_user_id', - to: 'user.id' - }, - modify: function (qb) { - qb.where('user.is_deleted', 0); - } - } - }; - } + static get tableName() { + return 'stream'; + } + + static get jsonAttributes() { + return ['forwarding_hosts', 'meta']; + } + + static get relationMappings() { + return { + owner: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'stream.owner_user_id', + to: 'user.id' + }, + modify: function (qb) { + qb.where('user.is_deleted', 0); + } + } + }; + } } module.exports = Stream; diff --git a/backend/schema/endpoints/streams.json b/backend/schema/endpoints/streams.json index 159c8036..da3de83e 100644 --- a/backend/schema/endpoints/streams.json +++ b/backend/schema/endpoints/streams.json @@ -20,7 +20,7 @@ "minimum": 1, "maximum": 65535 }, - "forwarding_host": { + "host": { "anyOf": [ { "$ref": "../definitions.json#/definitions/domain_name" @@ -35,6 +35,22 @@ } ] }, + "forwarding_hosts": { + "anyOf": [ + { + "$ref": "#/definitions/host" + }, + { + "type": "array", + "minItems": 1, + "maxItems": 15, + "uniqueItems": true, + "items": { + "$ref": "#/definitions/host" + } + } + ] + }, "forwarding_port": { "type": "integer", "minimum": 1, @@ -66,8 +82,8 @@ "incoming_port": { "$ref": "#/definitions/incoming_port" }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" + "forwarding_hosts": { + "$ref": "#/definitions/forwarding_hosts" }, "forwarding_port": { "$ref": "#/definitions/forwarding_port" @@ -118,15 +134,15 @@ "additionalProperties": false, "required": [ "incoming_port", - "forwarding_host", + "forwarding_hosts", "forwarding_port" ], "properties": { "incoming_port": { "$ref": "#/definitions/incoming_port" }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" + "forwarding_hosts": { + "$ref": "#/definitions/forwarding_hosts" }, "forwarding_port": { "$ref": "#/definitions/forwarding_port" @@ -165,8 +181,8 @@ "incoming_port": { "$ref": "#/definitions/incoming_port" }, - "forwarding_host": { - "$ref": "#/definitions/forwarding_host" + "forwarding_hosts": { + "$ref": "#/definitions/forwarding_hosts" }, "forwarding_port": { "$ref": "#/definitions/forwarding_port" @@ -231,4 +247,4 @@ } } ] -} +} \ No newline at end of file diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf index 76159a64..c7848223 100644 --- a/backend/templates/stream.conf +++ b/backend/templates/stream.conf @@ -3,6 +3,13 @@ # ------------------------------------------------------------ {% if enabled %} + +upstream stream_{{ incoming_port }}_tcp { + {% for forwarding_host in forwarding_hosts %} + server {{ forwarding_host }}:{{ forwarding_port }}; + {%- endfor %} +} + {% if tcp_forwarding == 1 or tcp_forwarding == true -%} server { listen {{ incoming_port }}; @@ -12,7 +19,7 @@ server { #listen [::]:{{ incoming_port }}; {% endif %} - proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; + proxy_pass stream_{{ incoming_port }}_tcp; # Custom include /data/nginx/custom/server_stream[.]conf; @@ -20,18 +27,26 @@ server { } {% endif %} {% if udp_forwarding == 1 or udp_forwarding == true %} + +upstream stream_{{ incoming_port }}_udp { + {% for forwarding_host in forwarding_hosts %} + server {{ forwarding_host }}:{{ forwarding_port }}; + {%- endfor %} +} + server { listen {{ incoming_port }} udp; {% if ipv6 -%} listen [::]:{{ incoming_port }} udp; {% else -%} - #listen [::]:{{ incoming_port }} udp; + #listen [::]:{{ incoming_port }} udp; {% endif %} - proxy_pass {{ forwarding_host }}:{{ forwarding_port }}; + + proxy_pass stream_{{ incoming_port }}_udp; # Custom include /data/nginx/custom/server_stream[.]conf; include /data/nginx/custom/server_stream_udp[.]conf; } {% endif %} -{% endif %} \ No newline at end of file +{% endif %} diff --git a/frontend/js/app/nginx/stream/form.ejs b/frontend/js/app/nginx/stream/form.ejs index 1fc4f134..7db7ac8d 100644 --- a/frontend/js/app/nginx/stream/form.ejs +++ b/frontend/js/app/nginx/stream/form.ejs @@ -2,7 +2,7 @@ + -<% } %> \ No newline at end of file +<% } %> diff --git a/frontend/js/app/nginx/stream/list/main.ejs b/frontend/js/app/nginx/stream/list/main.ejs index 5304f614..d778f5ca 100644 --- a/frontend/js/app/nginx/stream/list/main.ejs +++ b/frontend/js/app/nginx/stream/list/main.ejs @@ -3,6 +3,7 @@ <%- i18n('streams', 'incoming-port') %> <%- i18n('str', 'destination') %> <%- i18n('streams', 'protocol') %> + <%- i18n('streams', 'forwarding-port') %> <%- i18n('str', 'status') %> <% if (canManage) { %>   diff --git a/frontend/js/i18n/messages.json b/frontend/js/i18n/messages.json index 0bbde454..43eccf7a 100644 --- a/frontend/js/i18n/messages.json +++ b/frontend/js/i18n/messages.json @@ -167,7 +167,7 @@ "add": "Add Stream", "form-title": "{id, select, undefined{New} other{Edit}} Stream", "incoming-port": "Incoming Port", - "forwarding-host": "Forward Host", + "forwarding-hosts": "Forward Hoss", "forwarding-port": "Forward Port", "tcp-forwarding": "TCP Forwarding", "udp-forwarding": "UDP Forwarding", @@ -293,4 +293,4 @@ "default-site-redirect": "Redirect" } } -} +} \ No newline at end of file diff --git a/frontend/js/models/stream.js b/frontend/js/models/stream.js index ba035429..9c615969 100644 --- a/frontend/js/models/stream.js +++ b/frontend/js/models/stream.js @@ -9,7 +9,7 @@ const model = Backbone.Model.extend({ created_on: null, modified_on: null, incoming_port: null, - forwarding_host: null, + forwarding_hosts: [], forwarding_port: null, tcp_forwarding: true, udp_forwarding: false,