mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-05 20:58:28 +02:00

- Moved stream proxy config from database to file based conf - Optimized implementation for detecting proxy rule running - Fixed #320 (hopefully)
393 lines
16 KiB
HTML
393 lines
16 KiB
HTML
<div class="standardContainer">
|
|
<div class="ui basic segment">
|
|
<h2>Stream Proxy</h2>
|
|
<p>Proxy traffic flow on layer 3 via TCP or UDP</p>
|
|
</div>
|
|
<div class="ui divider"></div>
|
|
<div class="ui basic segment" style="margin-top: 0;">
|
|
<h3>TCP / UDP Proxy Rules</h3>
|
|
<p>A list of TCP / UDP proxy rules created on this host.</p>
|
|
<div style="overflow-x: auto; ">
|
|
<table id="proxyTable" class="ui celled basic unstackable table">
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Listening Address</th>
|
|
<th>Target Address</th>
|
|
<th>Mode</th>
|
|
<th>Timeout (s)</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<br>
|
|
<button class="ui basic right floated button" onclick="initProxyConfigList();" title="Refresh List"><i class="ui green refresh icon"></i>Refresh</button>
|
|
<br><br>
|
|
</div>
|
|
<div class="ui divider"></div>
|
|
<div class="ui basic segment" id="addproxyConfig">
|
|
<h3>Add or Edit Stream Proxy</h3>
|
|
<p>Create or edit a new stream proxy instance</p>
|
|
<form id="streamProxyForm" class="ui form">
|
|
<div class="field" style="display:none;">
|
|
<label>UUID</label>
|
|
<input type="text" name="uuid">
|
|
</div>
|
|
<div class="field">
|
|
<label>Name</label>
|
|
<input type="text" name="name" placeholder="Config Name">
|
|
</div>
|
|
<div class="field">
|
|
<label>Listening Address with Port</label>
|
|
<input type="text" name="listenAddr" placeholder="">
|
|
<small>Address to listen on this host. e.g. :25565 or 127.0.0.1:25565. <br>
|
|
If you are using Docker, you will also need to expose this port to host network.</small>
|
|
</div>
|
|
<div class="field">
|
|
<label>Proxy Target Address with Port</label>
|
|
<input type="text" name="proxyAddr" placeholder="">
|
|
<small>Server address to forward TCP / UDP package. e.g. 192.168.1.100:25565</small>
|
|
</div>
|
|
<div class="field">
|
|
<label>Timeout (s)</label>
|
|
<input type="text" name="timeout" placeholder="" value="10">
|
|
<small>Connection timeout in seconds</small>
|
|
</div>
|
|
<Br>
|
|
<div class="field">
|
|
<div class="ui toggle checkbox">
|
|
<input type="checkbox" tabindex="0" name="useTCP" class="hidden">
|
|
<label>Enable TCP<br>
|
|
<small>Forward TCP request on this listening socket</small>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="field">
|
|
<div class="ui toggle checkbox">
|
|
<input type="checkbox" tabindex="0" name="useUDP" class="hidden">
|
|
<label>Enable UDP<br>
|
|
<small>Forward UDP request on this listening socket</small></label>
|
|
</div>
|
|
</div>
|
|
<button id="addStreamProxyButton" class="ui basic button" type="submit"><i class="ui green add icon"></i> Create</button>
|
|
<button id="editStreamProxyButton" class="ui basic button" onclick="confirmEditTCPProxyConfig(event, this);" style="display:none;"><i class="ui green check icon"></i> Update</button>
|
|
<button class="ui basic red button" onclick="event.preventDefault(); cancelStreamProxyEdit(event);"><i class="ui red remove icon"></i> Cancel</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
let editingStreamProxyConfigUUID = ""; //The current editing TCP Proxy config UUID
|
|
|
|
$("#streamProxyForm .dropdown").dropdown();
|
|
$('#streamProxyForm').on('submit', function(event) {
|
|
event.preventDefault();
|
|
|
|
//Check if update mode
|
|
if ($("#editStreamProxyButton").is(":visible")){
|
|
confirmEditTCPProxyConfig(event,$("#editStreamProxyButton")[0]);
|
|
return;
|
|
}
|
|
|
|
var form = $(this);
|
|
|
|
var formValid = validateTCPProxyConfig(form);
|
|
if (!formValid){
|
|
return;
|
|
}
|
|
|
|
// Send the AJAX POST request
|
|
$.cjax({
|
|
type: 'POST',
|
|
url: '/api/streamprox/config/add',
|
|
data: form.serialize(),
|
|
success: function(response) {
|
|
if (response.error) {
|
|
msgbox(response.error, false, 6000);
|
|
}else{
|
|
msgbox("Config Added");
|
|
}
|
|
clearStreamProxyAddEditForm();
|
|
initProxyConfigList();
|
|
},
|
|
error: function() {
|
|
msgbox('An error occurred while processing the request', false);
|
|
}
|
|
});
|
|
});
|
|
|
|
function clearStreamProxyAddEditForm(){
|
|
$('#streamProxyForm input, #streamProxyForm select').val('');
|
|
$('#streamProxyForm select').dropdown('clear');
|
|
$("#streamProxyForm input[name=timeout]").val(10);
|
|
$("#streamProxyForm .toggle.checkbox").checkbox("set unchecked");
|
|
}
|
|
|
|
function cancelStreamProxyEdit(event=undefined) {
|
|
clearStreamProxyAddEditForm();
|
|
$("#addStreamProxyButton").show();
|
|
$("#editStreamProxyButton").hide();
|
|
}
|
|
|
|
function validateTCPProxyConfig(form){
|
|
//Check if name is filled. If not, generate a random name for it
|
|
var name = form.find('input[name="name"]').val()
|
|
if (name == ""){
|
|
let randomName = "Proxy Rule (#" + Math.round(Date.now()/1000) + ")";
|
|
form.find('input[name="name"]').val(randomName);
|
|
}
|
|
|
|
// Validate timeout is an integer
|
|
var timeout = parseInt(form.find('input[name="timeout"]').val());
|
|
if (form.find('input[name="timeout"]').val() == ""){
|
|
//Not set. Assign a random one to it
|
|
form.find('input[name="timeout"]').val("10");
|
|
timeout = 10;
|
|
}
|
|
|
|
if (isNaN(timeout)) {
|
|
form.find('input[name="timeout"]').parent().addClass("error");
|
|
msgbox('Timeout must be a valid integer', false, 5000);
|
|
return false;
|
|
}else{
|
|
form.find('input[name="timeout"]').parent().removeClass("error");
|
|
}
|
|
|
|
// Validate mode is selected
|
|
var mode = form.find('select[name="mode"]').val();
|
|
if (mode === '') {
|
|
form.find('select[name="mode"]').parent().addClass("error");
|
|
msgbox('Please select a mode', false, 5000);
|
|
return false;
|
|
}else{
|
|
form.find('select[name="mode"]').parent().removeClass("error");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function renderProxyConfigs(proxyConfigs) {
|
|
var tableBody = $('#proxyTable tbody');
|
|
tableBody.empty();
|
|
if (proxyConfigs.length === 0) {
|
|
var noResultsRow = $('<tr><td colspan="7"><i class="green check circle icon"></i>No Proxy Configs</td></tr>');
|
|
tableBody.append(noResultsRow);
|
|
} else {
|
|
|
|
proxyConfigs.forEach(function(config) {
|
|
var runningLogo = 'Stopped';
|
|
var runningClass = "stopped";
|
|
var startButton = `<button onclick="startStreamProx('${config.UUID}');" class="ui basic mini circular icon button" title="Start Proxy"><i class="green play icon"></i></button>`;
|
|
if (config.Running){
|
|
runningLogo = 'Running';
|
|
startButton = `<button onclick="stopStreamProx('${config.UUID}');" class="ui basic mini circular icon button" title="Stop Proxy"><i class="red stop icon"></i></button>`;
|
|
runningClass = "running"
|
|
}
|
|
|
|
var modeText = [];
|
|
if (config.UseTCP){
|
|
modeText.push("TCP")
|
|
}
|
|
|
|
if (config.UseUDP){
|
|
modeText.push("UDP")
|
|
}
|
|
|
|
modeText = modeText.join(" & ")
|
|
|
|
var thisConfig = encodeURIComponent(JSON.stringify(config));
|
|
|
|
var row = $(`<tr class="streamproxConfig ${runningClass}" uuid="${config.UUID}" config="${thisConfig}">`);
|
|
row.append($('<td>').html(`
|
|
${config.Name}
|
|
<div class="statusText">${runningLogo}</div>`));
|
|
row.append($('<td>').text(config.ListeningAddress));
|
|
row.append($('<td>').text(config.ProxyTargetAddr));
|
|
row.append($('<td>').text(modeText));
|
|
row.append($('<td>').text(config.Timeout));
|
|
row.append($('<td>').html(`
|
|
${startButton}
|
|
<button onclick="editTCPProxyConfig('${config.UUID}');" class="ui circular basic mini icon button" title="Edit Config"><i class="edit icon"></i></button>
|
|
<button onclick="deleteTCPProxyConfig('${config.UUID}');" class="ui circular red basic mini icon button" title="Delete Config"><i class="trash icon"></i></button>
|
|
`));
|
|
tableBody.append(row);
|
|
});
|
|
}
|
|
}
|
|
|
|
function getConfigDetailsFromDOM(configUUID){
|
|
let thisConfig = null;
|
|
$(".streamproxConfig").each(function(){
|
|
let uuid = $(this).attr("uuid");
|
|
if (configUUID == uuid){
|
|
//This is the one we are looking for
|
|
thisConfig = JSON.parse(decodeURIComponent($(this).attr("config")));
|
|
}
|
|
});
|
|
return thisConfig;
|
|
}
|
|
|
|
function editTCPProxyConfig(configUUID){
|
|
let targetConfig = getConfigDetailsFromDOM(configUUID);
|
|
if (targetConfig != null){
|
|
$("#addStreamProxyButton").hide();
|
|
$("#editStreamProxyButton").show();
|
|
$.each(targetConfig, function(key, value) {
|
|
var field;
|
|
if (key == "UseTCP"){
|
|
let checkboxEle = $("#streamProxyForm input[name=useTCP]").parent();
|
|
if (value === true){
|
|
$(checkboxEle).checkbox("set checked");
|
|
}else{
|
|
$(checkboxEle).checkbox("set unchecked");
|
|
}
|
|
return;
|
|
}else if (key == "UseUDP"){
|
|
let checkboxEle = $("#streamProxyForm input[name=useUDP]").parent();
|
|
if (value === true){
|
|
$(checkboxEle).checkbox("set checked");
|
|
}else{
|
|
$(checkboxEle).checkbox("set unchecked");
|
|
}
|
|
return;
|
|
}else if (key == "ListeningAddress"){
|
|
field = $("#streamProxyForm input[name=listenAddr]");
|
|
}else if (key == "ProxyTargetAddr"){
|
|
field = $("#streamProxyForm input[name=proxyAddr]");
|
|
}else if (key == "UUID"){
|
|
field = $("#streamProxyForm input[name=uuid]");
|
|
}else if (key == "Name"){
|
|
field = $("#streamProxyForm input[name=name]");
|
|
}else if (key == "Timeout"){
|
|
field = $("#streamProxyForm input[name=timeout]");
|
|
}
|
|
|
|
if (field != undefined && field.length > 0) {
|
|
field.val(value);
|
|
}
|
|
});
|
|
editingStreamProxyConfigUUID = configUUID;
|
|
}else{
|
|
msgbox("Unable to load target config", false);
|
|
}
|
|
}
|
|
|
|
function confirmEditTCPProxyConfig(event, btn){
|
|
event.preventDefault();
|
|
event.stopImmediatePropagation();
|
|
var form = $("#streamProxyForm");
|
|
let originalButtonHTML = $(btn).html();
|
|
$(btn).html(`<i class="ui loading spinner icon"></i> Updating`);
|
|
$(btn).addClass("disabled");
|
|
|
|
var formValid = validateTCPProxyConfig(form);
|
|
if (!formValid){
|
|
$(btn).html(originalButtonHTML);
|
|
$(btn).removeClass("disabled");
|
|
return;
|
|
}
|
|
|
|
// Send the AJAX POST request
|
|
$.cjax({
|
|
type: 'POST',
|
|
url: '/api/streamprox/config/edit',
|
|
method: "POST",
|
|
data: {
|
|
uuid: $("#streamProxyForm input[name=uuid]").val().trim(),
|
|
name: $("#streamProxyForm input[name=name]").val().trim(),
|
|
listenAddr: $("#streamProxyForm input[name=listenAddr]").val().trim(),
|
|
proxyAddr: $("#streamProxyForm input[name=proxyAddr]").val().trim(),
|
|
useTCP: $("#streamProxyForm input[name=useTCP]")[0].checked ,
|
|
useUDP: $("#streamProxyForm input[name=useUDP]")[0].checked ,
|
|
timeout: parseInt($("#streamProxyForm input[name=timeout]").val().trim()),
|
|
},
|
|
success: function(response) {
|
|
$(btn).html(originalButtonHTML);
|
|
$(btn).removeClass("disabled");
|
|
if (response.error) {
|
|
msgbox(response.error, false, 6000);
|
|
}else{
|
|
msgbox("Config Updated");
|
|
}
|
|
initProxyConfigList();
|
|
cancelStreamProxyEdit();
|
|
clearStreamProxyAddEditForm();
|
|
|
|
},
|
|
error: function() {
|
|
$(btn).html(originalButtonHTML);
|
|
$(btn).removeClass("disabled");
|
|
msgbox('An error occurred while processing the request', false);
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteTCPProxyConfig(configUUID){
|
|
$.cjax({
|
|
url: "/api/streamprox/config/delete",
|
|
method: "POST",
|
|
data: {uuid: configUUID},
|
|
success: function(data){
|
|
if (data.error != undefined){
|
|
msgbox(data.error, false, 6000);
|
|
}else{
|
|
msgbox("Proxy Config Removed");
|
|
initProxyConfigList();
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
//Start a TCP proxy by their config UUID
|
|
function startStreamProx(configUUID){
|
|
$.cjax({
|
|
url: "/api/streamprox/config/start",
|
|
method: "POST",
|
|
data: {uuid: configUUID},
|
|
success: function(data){
|
|
if (data.error != undefined){
|
|
msgbox(data.error, false, 6000);
|
|
}else{
|
|
msgbox("Service Started");
|
|
initProxyConfigList();
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
//Stop a TCP proxy by their config UUID
|
|
function stopStreamProx(configUUID){
|
|
$.cjax({
|
|
url: "/api/streamprox/config/stop",
|
|
method: "POST",
|
|
data: {uuid: configUUID},
|
|
success: function(data){
|
|
if (data.error != undefined){
|
|
msgbox(data.error, false, 6000);
|
|
}else{
|
|
msgbox("Service Stopped");
|
|
initProxyConfigList();
|
|
}
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
function initProxyConfigList(){
|
|
$.ajax({
|
|
type: 'GET',
|
|
url: '/api/streamprox/config/list',
|
|
success: function(response) {
|
|
renderProxyConfigs(response);
|
|
},
|
|
error: function() {
|
|
msgbox('Unable to load proxy configs', false);
|
|
}
|
|
});
|
|
}
|
|
initProxyConfigList();
|
|
</script>
|
|
</div> |