diff --git a/luci-app-advancedplus/Makefile b/luci-app-advancedplus/Makefile
index 0b28c5c4e..1c1c6eb07 100644
--- a/luci-app-advancedplus/Makefile
+++ b/luci-app-advancedplus/Makefile
@@ -11,7 +11,7 @@ LUCI_DEPENDS:=+luci-compat +curl
LUCI_PKGARCH:=all
PKG_VERSION:=1.8.9
-PKG_RELEASE:=1
+PKG_RELEASE:=2
define Package/$(PKG_NAME)/conffiles
/etc/config/advancedplus
diff --git a/luci-app-advancedplus/root/etc/init.d/advancedplus b/luci-app-advancedplus/root/etc/init.d/advancedplus
index 82f6f3dd4..c24feb5a6 100755
--- a/luci-app-advancedplus/root/etc/init.d/advancedplus
+++ b/luci-app-advancedplus/root/etc/init.d/advancedplus
@@ -92,7 +92,6 @@ advancedset(){
start_service() {
[ -f $LOCK ] && exit
- [ "x$(uci -q get advancedplus.@basic[0].uhttpd)" = "x1" ] && uhttpd_service
touch $LOCK
rm -rf /tmp/luci-*
rm -f $LOCK 2>/dev/null
diff --git a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js
index d5ba630bc..ca2a0619f 100644
--- a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js
+++ b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx.js
@@ -48,12 +48,12 @@ function generateLocationId() {
var adminCode = '110101'; // Default to Beijing Dongcheng District (positions 1-6)
var serviceType = '100'; // Commercial internet service location (positions 7-9)
var sequenceNum = '';
-
+
// Generate 5-digit random sequence number (positions 10-14)
for (var i = 0; i < 5; i++) {
sequenceNum += Math.floor(Math.random() * 10);
}
-
+
return adminCode + serviceType + sequenceNum; // 6 + 3 + 5 = 14 digits
}
@@ -78,58 +78,58 @@ function updateMacStatus(macAddr, isSuccess, errorMsg, isFallback) {
var statusElement = document.getElementById('mac-status');
if (isSuccess) {
var prefix = isFallback ? _('✓ WAN MAC address obtained (fallback): ') : _('✓ WAN MAC address obtained: ');
- var suffix = isFallback ? '' : ' (interface: ' + arguments[4] + ')';
+ var suffix = isFallback ? '' : _(' (interface: ') + arguments[4] + _(')');
statusElement.innerHTML = prefix + macAddr + suffix;
} else {
- statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || 'Unknown error');
+ statusElement.innerHTML = _('✗ Failed to get WAN MAC address: ') + (errorMsg || _('Unknown error'));
}
}
function generateAndUpdateIds(macAddr) {
var deviceId = generateDeviceId(macAddr);
var locationId = generateLocationId();
-
+
document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + deviceId;
document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + locationId;
-
+
return { deviceId: deviceId, locationId: locationId };
}
function getMacAddressPromise(results) {
- return callGetWanMac().then(function(response) {
+ return callGetWanMac().then(function (response) {
if (response && response.status === 'success') {
var macAddr = response.mac.toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr;
updateMacStatus(macAddr, true, null, false, response.interface);
-
+
var ids = generateAndUpdateIds(macAddr);
results.deviceId = ids.deviceId;
results.locationId = ids.locationId;
} else {
return getMacAddressFallback(results);
}
- }).catch(function(error) {
+ }).catch(function (error) {
return getMacAddressFallback(results);
});
}
function getMacAddressFallback(results) {
document.getElementById('mac-status').innerHTML = _('RPC failed, trying fallback...');
-
- return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function(response) {
+
+ return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function (response) {
if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr;
updateMacStatus(macAddr, true, null, true);
-
+
var ids = generateAndUpdateIds(macAddr);
results.deviceId = ids.deviceId;
results.locationId = ids.locationId;
} else {
- updateMacStatus(null, false, 'Unknown error');
+ updateMacStatus(null, false, _('Unknown error'));
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address');
}
- }).catch(function(error) {
+ }).catch(function (error) {
updateMacStatus(null, false, error.message);
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error');
});
@@ -145,32 +145,32 @@ function formatCoordinate(coord) {
}
function getLocationPromise(results) {
- return callGetLocation().then(function(response) {
+ return callGetLocation().then(function (response) {
if (response && response.status === 'success') {
var lat = formatCoordinate(response.lat);
var lon = formatCoordinate(response.lon);
-
+
results.longitude = lon;
results.latitude = lat;
document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + lat + ', ' + lon;
} else {
- var errorMsg = (response && response.message) ? response.message : 'Unknown error';
+ var errorMsg = (response && response.message) ? response.message : _('Unknown error');
document.getElementById('location-status').innerHTML = _('✗ Failed to get location: ') + errorMsg;
}
- }).catch(function(error) {
+ }).catch(function (error) {
return getLocationFallback(results);
});
}
function getLocationFallback(results) {
document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...');
-
- return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function(response) {
+
+ return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function (response) {
if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
try {
var data = JSON.parse(response.stdout);
var lat, lon;
-
+
if (data.latitude && data.longitude) {
lat = formatCoordinate(data.latitude);
lon = formatCoordinate(data.longitude);
@@ -179,7 +179,7 @@ function getLocationFallback(results) {
lat = formatCoordinate(coords[0]);
lon = formatCoordinate(coords[1]);
}
-
+
if (lat && lon) {
results.longitude = lon;
results.latitude = lat;
@@ -193,7 +193,7 @@ function getLocationFallback(results) {
} else {
document.getElementById('location-status').innerHTML = _('✗ Failed to get location data');
}
- }).catch(function(fallbackError) {
+ }).catch(function (fallbackError) {
document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message;
});
}
@@ -209,14 +209,14 @@ function fillFormFields(results) {
{ result: 'longitude', selector: 'ap_longitude', label: _('Longitude: ') },
{ result: 'latitude', selector: 'ap_latitude', label: _('Latitude: ') }
];
-
- fieldMappings.forEach(function(mapping) {
+
+ fieldMappings.forEach(function (mapping) {
if (results[mapping.result]) {
var field = document.querySelector('input[data-name="' + mapping.selector + '"]') ||
- document.querySelector('input[name*="' + mapping.selector + '"]') ||
- document.querySelector('input[id*="' + mapping.selector + '"]') ||
- document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector);
-
+ document.querySelector('input[name*="' + mapping.selector + '"]') ||
+ document.querySelector('input[id*="' + mapping.selector + '"]') ||
+ document.querySelector('#cbid\\.wifidogx\\.default\\.' + mapping.selector);
+
if (field) {
field.value = results[mapping.result];
field.dispatchEvent(new Event('input', { bubbles: true }));
@@ -227,13 +227,13 @@ function fillFormFields(results) {
totalFields++;
}
});
-
+
return { successCount: successCount, totalFields: totalFields, messages: messages };
}
function showAutoFillResult(stats) {
ui.hideModal();
-
+
if (stats.successCount === stats.totalFields && stats.totalFields > 0) {
ui.addNotification(null, E('p', _('Auto fill completed successfully! All fields have been filled.') + '
' + stats.messages.join('
')), 'info');
} else if (stats.successCount > 0) {
@@ -267,20 +267,20 @@ function renderStatus(isRunning) {
}
return view.extend({
- render: function() {
+ render: function () {
var m, s, o, ss;
m = new form.Map('wifidogx', _('ApFree-WiFiDog'));
m.description = github.desc('apfree-wifidog offers a stable and secure captive portal solution.', 'liudf0716', 'apfree-wifidog');
-
- s = m.section(form.NamedSection, 'common', _('Configuration'));
+
+ s = m.section(form.NamedSection, 'common', _('Configuration'));
s.addremove = false;
s.anonymous = true;
-
+
s.tab('basic', _('Basic Settings'));
- s.tab('gateway', _('Gateway Settings'));
s.tab('auth', _('Auth Server Settings'));
+ s.tab('gateway', _('Gateway Settings'));
s.tab('advanced', _('Advanced Settings'));
s.tab('rule', _('Rule Settings'));
s.tab('qos', _('QoS Settings'));
@@ -291,7 +291,7 @@ return view.extend({
o.rmempty = false;
o = s.taboption('basic', form.ListValue, 'auth_server_mode', _('Auth Server Mode'),
- _('The mode of the authentication server.'));
+ _('The mode of the authentication server.'));
o.value('cloud', _('Cloud Auth'));
o.value('local', _('Local Auth'));
o.value('bypass', _('Bypass Auth'));
@@ -300,30 +300,30 @@ return view.extend({
// 添加一个下拉框,列出当前定义的认证服务列表,并选择当前选中的认证服务
o = s.taboption('basic', form.ListValue, 'selected_auth_server', _('Authentication Server'),
- _('Select the authentication server to use for cloud authentication.'));
+ _('Select the authentication server to use for cloud authentication.'));
o.rmempty = false;
o.optional = false;
o.depends('auth_server_mode', 'cloud');
- o.load = function(section_id) {
+ o.load = function (section_id) {
this.keylist = [];
this.vallist = [];
-
+
var sections = uci.sections('wifidogx', 'auth');
if (sections.length == 0) {
this.value('', _('Please create an authentication server first'));
} else {
- sections.forEach(L.bind(function(section) {
+ sections.forEach(L.bind(function (section) {
var name = section['.name'];
- var hostname = section.auth_server_hostname || 'Unknown';
+ var hostname = section.auth_server_hostname || _('Unknown');
this.value(name, '%s (%s)'.format(name, hostname));
}, this));
}
-
+
return this.super('load', [section_id]);
};
o = s.taboption('basic', widgets.NetworkSelect, 'external_interface', _('External Interface'),
- _('The external interface of the device, if bypass mode, do not choose.'));
+ _('The external interface of the device, if bypass mode, do not choose.'));
o.rmempty = true;
o.nocreate = true;
o.loopback = false;
@@ -337,7 +337,7 @@ return view.extend({
o.depends('auth_server_mode', 'bypass');
o = s.taboption('basic', form.Value, 'local_portal', _('Local Portal'),
- _('The local portal url.'));
+ _('The local portal url.'));
o.rmempty = false;
o.datatype = 'string';
o.optional = true;
@@ -345,12 +345,12 @@ return view.extend({
o.depends('auth_server_mode', 'local');
o = s.taboption('basic', form.Flag, 'disable_portal_auth', _('Disable Portal Authentication'),
- _('When enabled, users can access the internet without portal authentication. Firewall redirect rules will not be created. Use this mode for pure traffic statistics without captive portal.'));
+ _('When enabled, users can access the internet without portal authentication. Firewall redirect rules will not be created. Use this mode for pure traffic statistics without captive portal.'));
o.rmempty = false;
o.default = '1';
o = s.taboption('basic', form.ListValue, 'log_level', _('Log Level'),
- _('The log level of the apfree-wifidog.'));
+ _('The log level of the apfree-wifidog.'));
o.value(7, _('Debug'));
o.value(6, _('Info'));
o.value(5, _('Notice'));
@@ -367,9 +367,9 @@ return view.extend({
ss = o.subsection;
ss.addremove = true;
ss.nodescriptions = true;
-
+
o = ss.option(form.Flag, 'gateway_auth_enabled', _('Auth Enabled'),
- _('Enable the authentication of the gateway.'));
+ _('Enable the authentication of the gateway.'));
o.rmempty = false;
o.defaulValue = true;
@@ -380,19 +380,19 @@ return view.extend({
o.default = 'lan';
o = ss.option(form.Value, 'gateway_channel', _('Gateway Channel'),
- _('The channel of the gateway.'));
+ _('The channel of the gateway.'));
o.datatype = 'string';
o.rmempty = false;
o.optional = false;
o = ss.option(form.Value, 'gateway_id', _('Gateway ID'),
- _('The ID of the gateway.'));
+ _('The ID of the gateway.'));
o.datatype = 'string';
o.rmempty = false;
o.optional = true;
-
+
o = ss.option(form.Value, 'gateway_subnetv4', _('Gateway Subnetv4'),
- _('The ipv4 subnet of the gateway.'));
+ _('The ipv4 subnet of the gateway.'));
o.datatype = 'cidr4';
o.rmempty = false;
o.optional = false;
@@ -400,53 +400,53 @@ return view.extend({
// advanced settings
o = s.taboption('advanced', form.Value, 'check_interval', _('Check Interval'),
- _('The interval of the check(s).'));
+ _('The interval of the check(s).'));
o.datatype = 'uinteger';
o.rmempty = false;
o.optional = false;
o.defaulValue = 60;
o = s.taboption('advanced', form.Value, 'client_timeout', _('Client Timeout'),
- _('The timeout of the client.'));
+ _('The timeout of the client.'));
o.datatype = 'uinteger';
o.rmempty = false;
o.optional = false;
o.defaulValue = 5;
o = s.taboption('advanced', form.Flag, 'wired_passed', _('Wired Passed'),
- _('Wired users do not need to authenticate to access the internet.'));
+ _('Wired users do not need to authenticate to access the internet.'));
o.rmempty = false;
o = s.taboption('advanced', form.Flag, 'apple_cna', _('Apple CNA'),
- _('Enable Apple Captive Network Assistant.'));
+ _('Enable Apple Captive Network Assistant.'));
o.rmempty = false;
o.defaulValue = false;
o = s.taboption('advanced', form.Flag, 'js_filter', _('JS Filter'),
- _('Enable JS redirect.'));
+ _('Enable JS redirect.'));
o.rmempty = false;
o.defaulValue = true;
o = s.taboption('advanced', form.Flag, 'enable_anti_nat', _('Enable Anti NAT'),
- _('Enable Anti NAT devices.'));
+ _('Enable Anti NAT devices.'));
o.rmempty = false;
o.defaulValue = false;
o = s.taboption('advanced', form.Value, 'ttl_value', _('TTL Value'),
- _('The TTL value of the gateway support.'));
+ _('The TTL value of the gateway support.'));
o.datatype = 'string';
o.rmempty = false;
o.defaulValue = '64,128';
o.depends('enable_anti_nat', '1');
o = s.taboption('advanced', form.Value, 'anti_nat_permit_macs', _('Anti NAT Permit MAC'),
- _('The MAC address of the Anti NAT permit.'));
+ _('The MAC address of the Anti NAT permit.'));
o.datatype = 'macaddr';
o.rmempty = true;
o.depends('enable_anti_nat', '1');
o = s.taboption('advanced', form.Flag, 'enable_event_log', _('Enable Internet Access Log'),
- _('Enable logging of internet access events and user activities.'));
+ _('Enable logging of internet access events and user activities.'));
o.rmempty = false;
o.defaulValue = false;
@@ -456,100 +456,115 @@ return view.extend({
ss.addremove = true;
ss.nodescriptions = true;
- o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'),
- _('The domain or IP address of the authentication server.'));
+ o = ss.option(form.Value, 'auth_server_hostname', _('Auth Server Hostname'),
+ _('The domain or IP address of the authentication server.'));
o.rmempty = false;
o.datatype = 'or(host,ip4addr)';
o.optional = false;
-
+
o = ss.option(form.Value, 'auth_server_port', _('Auth Server Port'),
- _('The port of the authentication server.'));
+ _('The port of the authentication server.'));
o.rmempty = false;
o.datatype = 'port';
o.optional = false;
o.default = '443';
-
+
o = ss.option(form.Value, 'auth_server_path', _('Auth Server URI path'),
- _('The URI path of the authentication server.'));
+ _('The URI path of the authentication server.'));
o.rmempty = false;
o.datatype = 'string';
o.optional = false;
o.default = '/wifidog/';
-
+
o = ss.option(form.ListValue, 'long_conn_mode', _('Persistent Connection Mode'),
- _('The persistent connection mode of the device to auth server.'));
+ _('The persistent connection mode of the device to auth server.'));
o.value('ws', _('WebSocket Connection Mode'));
o.value('wss', _('WebSocket Secure Connection Mode'));
o.value('mqtt', _('MQTT Connection Mode'));
+ o.value('mqtts', _('MQTT Secure Connection Mode'))
o.rmempty = false;
o.defaulValue = 'wss';
o.optional = false;
+ o.modalonly = true;
+
o = ss.option(form.Value, 'ws_server_hostname', _('WebSocket Hostname'),
- _('The hostname of the websocket, if the field is left empty, automatically use the same hostname as the auth server.'));
+ _('The hostname of the websocket, if the field is left empty, automatically use the same hostname as the auth server.'));
o.datatype = 'or(host,ip4addr)';
o.rmempty = true;
o.optional = true;
o.depends('long_conn_mode', 'ws');
o.depends('long_conn_mode', 'wss');
+ o.modalonly = true;
o = ss.option(form.Value, 'ws_server_port', _('WebSocket Port'),
- _('The port of the websocket, if the field is left empty, automatically use the same port as the auth server.'));
+ _('The port of the websocket, if the field is left empty, automatically use the same port as the auth server.'));
o.datatype = 'port';
o.rmempty = true;
o.optional = true;
o.default = '443';
o.depends('long_conn_mode', 'wss');
-
+ o.depends('long_conn_mode', 'ws');
+ o.modalonly = true;
+
o = ss.option(form.Value, 'ws_server_path', _('WebSocket URI path'),
- _('The URI path of the websocket.'));
+ _('The URI path of the websocket.'));
o.datatype = 'string';
o.rmempty = true;
o.optional = true;
o.default = '/ws/wifidogx';
o.depends('long_conn_mode', 'ws');
o.depends('long_conn_mode', 'wss');
+ o.modalonly = true;
o = ss.option(form.Value, 'mqtt_server_hostname', _('MQTT Hostname'),
- _('The hostname of the mqtt.'));
+ _('The hostname of the mqtt.'));
o.datatype = 'or(host,ip4addr)';
o.rmempty = true;
o.optional = true;
o.depends('long_conn_mode', 'mqtt');
+ o.depends('long_conn_mode', 'mqtts');
+ o.modalonly = true;
o = ss.option(form.Value, 'mqtt_server_port', _('MQTT Port'),
- _('The port of the mqtt.'));
+ _('The port of the mqtt.'));
o.datatype = 'port';
o.rmempty = false;
o.optional = false;
o.depends('long_conn_mode', 'mqtt');
+ o.depends('long_conn_mode', 'mqtts');
o.default = 1883;
+ o.modalonly = true;
o = ss.option(form.Value, 'mqtt_username', _('MQTT Username'),
- _('The username of the mqtt.'));
+ _('The username of the mqtt.'));
o.datatype = 'string';
o.rmempty = true;
o.optional = true;
o.depends('long_conn_mode', 'mqtt');
+ o.depends('long_conn_mode', 'mqtts');
+ o.modalonly = true;
o = ss.option(form.Value, 'mqtt_password', _('MQTT Password'),
- _('The password of the mqtt.'));
+ _('The password of the mqtt.'));
o.datatype = 'string';
o.rmempty = true;
o.optional = true;
o.depends('long_conn_mode', 'mqtt');
+ o.depends('long_conn_mode', 'mqtts');
+ o.modalonly = true;
// QoS settings
o = s.taboption('qos', form.Flag, 'enable_qos', _('Enable Global QoS'),
- _('Enable Global QoS.'));
+ _('Enable Global QoS.'));
o.rmempty = false;
o.defaulValue = false;
o = s.taboption('qos', form.Value, 'qos_up', _('Global QoS Up'),
- _('The global QoS up value(Mbps).'));
+ _('The global QoS up value(Mbps).'));
o.datatype = 'uinteger';
o.rmempty = true;
o.optional = true;
@@ -557,7 +572,7 @@ return view.extend({
o.depends('enable_qos', '1');
o = s.taboption('qos', form.Value, 'qos_down', _('Global QoS Down'),
- _('The global QoS down value(Mbps).'));
+ _('The global QoS down value(Mbps).'));
o.datatype = 'uinteger';
o.rmempty = true;
o.optional = true;
@@ -567,12 +582,12 @@ return view.extend({
// Authentication Location Settings
// Add auto-fill button
o = s.taboption('location', form.Button, '_auto_fill', _('Auto Fill All Fields'),
- _('Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude'));
+ _('Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude'));
o.inputtitle = _('Auto Fill All Fields');
o.inputstyle = 'apply';
- o.onclick = function() {
+ o.onclick = function () {
showAutoFillModal();
-
+
var results = {
macAddress: null,
deviceId: null,
@@ -580,20 +595,20 @@ return view.extend({
longitude: null,
latitude: null
};
-
+
var promises = [
getMacAddressPromise(results),
getLocationPromise(results)
];
-
+
// Wait for all promises to complete and fill form fields
- Promise.all(promises).then(function() {
- setTimeout(function() {
+ Promise.all(promises).then(function () {
+ setTimeout(function () {
fillFormFields(results);
}, 2000);
});
};
-
+
// Helper function to show the auto-fill modal
function showAutoFillModal() {
ui.showModal(_('Auto Fill'), [
@@ -610,40 +625,40 @@ return view.extend({
])
]);
}
-
+
// Helper function to get MAC address with fallback
function getMacAddressPromise(results) {
- return callGetWanMac().then(function(response) {
+ return callGetWanMac().then(function (response) {
if (response && response.status === 'success') {
var macAddr = response.mac.toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr;
document.getElementById('mac-status').innerHTML = _('✓ WAN MAC address obtained: ') + macAddr + ' (interface: ' + response.interface + ')';
-
+
results.deviceId = generateDeviceId(macAddr);
document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + results.deviceId;
-
+
results.locationId = generateLocationId();
document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + results.locationId;
} else {
return getMacAddressFallback(results);
}
- }).catch(function(error) {
+ }).catch(function (error) {
document.getElementById('mac-status').innerHTML = _('✗ RPC call failed, trying fallback...');
return getMacAddressFallback(results);
});
}
-
+
// Helper function for MAC address fallback
function getMacAddressFallback(results) {
- return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function(response) {
+ return fs.exec('/bin/sh', ['-c', 'ip route | grep default | awk \'{print $5}\' | head -n1 | xargs -I {} cat /sys/class/net/{}/address 2>/dev/null || echo "failed"']).then(function (response) {
if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
var macAddr = response.stdout.trim().toUpperCase().replace(/:/g, '-');
results.macAddress = macAddr;
document.getElementById('mac-status').innerHTML = _('✓ WAN MAC address obtained (fallback): ') + macAddr;
-
+
results.deviceId = generateDeviceId(macAddr);
document.getElementById('device-id-status').innerHTML = _('✓ Device ID generated: ') + results.deviceId;
-
+
results.locationId = generateLocationId();
document.getElementById('location-id-status').innerHTML = _('✓ Location ID generated: ') + results.locationId;
} else {
@@ -651,39 +666,39 @@ return view.extend({
document.getElementById('mac-status').innerHTML = _('✗ Failed to get WAN MAC address: ') + errorMsg;
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID without MAC address');
}
- }).catch(function(error) {
+ }).catch(function (error) {
document.getElementById('mac-status').innerHTML = _('✗ Error getting WAN MAC address: ') + error.message;
document.getElementById('device-id-status').innerHTML = _('✗ Cannot generate Device ID due to MAC error');
});
}
-
+
// Helper function to get location with fallback
function getLocationPromise(results) {
- return callGetLocation().then(function(response) {
+ return callGetLocation().then(function (response) {
if (response && response.status === 'success') {
var lat = parseFloat(response.lat).toFixed(6);
var lon = parseFloat(response.lon).toFixed(6);
-
+
formatAndSetCoordinates(results, lat, lon);
document.getElementById('location-status').innerHTML = _('✓ Location obtained: ') + results.latitude + ', ' + results.longitude;
} else {
var errorMsg = (response && response.message) ? response.message : 'Unknown error';
document.getElementById('location-status').innerHTML = _('✗ Failed to get location: ') + errorMsg;
}
- }).catch(function(error) {
+ }).catch(function (error) {
document.getElementById('location-status').innerHTML = _('RPC failed, trying direct method...');
return getLocationFallback(results);
});
}
-
+
// Helper function for location fallback
function getLocationFallback(results) {
- return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function(response) {
+ return fs.exec('/bin/sh', ['-c', 'curl -s --connect-timeout 10 --max-time 30 "https://ipapi.co/json" 2>/dev/null || curl -s --connect-timeout 10 --max-time 30 "http://ipinfo.io/json" 2>/dev/null || echo "failed"']).then(function (response) {
if (response.code === 0 && response.stdout && response.stdout.trim() !== 'failed') {
try {
var data = JSON.parse(response.stdout);
var lat, lon;
-
+
if (data.latitude && data.longitude) {
lat = parseFloat(data.latitude).toFixed(6);
lon = parseFloat(data.longitude).toFixed(6);
@@ -692,7 +707,7 @@ return view.extend({
lat = parseFloat(coords[0]).toFixed(6);
lon = parseFloat(coords[1]).toFixed(6);
}
-
+
if (lat && lon) {
formatAndSetCoordinates(results, lat, lon);
document.getElementById('location-status').innerHTML = _('✓ Location obtained (fallback): ') + results.latitude + ', ' + results.longitude;
@@ -705,11 +720,11 @@ return view.extend({
} else {
document.getElementById('location-status').innerHTML = _('✗ Failed to get location data');
}
- }).catch(function(fallbackError) {
+ }).catch(function (fallbackError) {
document.getElementById('location-status').innerHTML = _('✗ Error getting location: ') + fallbackError.message;
});
}
-
+
// Helper function to format coordinates
function formatAndSetCoordinates(results, lat, lon) {
// Pad coordinates to required format
@@ -718,23 +733,23 @@ return view.extend({
} else {
lat = '-' + Math.abs(lat).toFixed(6).padStart(9, '0');
}
-
+
if (lon >= 0) {
lon = lon.padStart(10, '0');
} else {
lon = '-' + Math.abs(lon).toFixed(6).padStart(9, '0');
}
-
+
results.longitude = lon;
results.latitude = lat;
}
-
+
// Helper function to fill form fields
function fillFormFields(results) {
var successCount = 0;
var totalFields = 0;
var messages = [];
-
+
var fieldMappings = [
{ key: 'macAddress', selectors: ['input[data-name="ap_mac_address"]', 'input[name*="ap_mac_address"]', 'input[id*="ap_mac_address"]', '#cbid\\.wifidogx\\.default\\.ap_mac_address'], label: _('MAC Address: ') },
{ key: 'deviceId', selectors: ['input[data-name="ap_device_id"]', 'input[name*="ap_device_id"]', 'input[id*="ap_device_id"]', '#cbid\\.wifidogx\\.default\\.ap_device_id'], label: _('Device ID: ') },
@@ -742,15 +757,15 @@ return view.extend({
{ key: 'longitude', selectors: ['input[data-name="ap_longitude"]', 'input[name*="ap_longitude"]', 'input[id*="ap_longitude"]', '#cbid\\.wifidogx\\.default\\.ap_longitude'], label: _('Longitude: ') },
{ key: 'latitude', selectors: ['input[data-name="ap_latitude"]', 'input[name*="ap_latitude"]', 'input[id*="ap_latitude"]', '#cbid\\.wifidogx\\.default\\.ap_latitude'], label: _('Latitude: ') }
];
-
- fieldMappings.forEach(function(mapping) {
+
+ fieldMappings.forEach(function (mapping) {
if (results[mapping.key]) {
var field = null;
for (var i = 0; i < mapping.selectors.length; i++) {
field = document.querySelector(mapping.selectors[i]);
if (field) break;
}
-
+
if (field) {
field.value = results[mapping.key];
field.dispatchEvent(new Event('input', { bubbles: true }));
@@ -761,14 +776,14 @@ return view.extend({
totalFields++;
}
});
-
+
showAutoFillResult(successCount, totalFields, messages);
}
-
+
// Helper function to show auto-fill results
function showAutoFillResult(successCount, totalFields, messages) {
ui.hideModal();
-
+
if (successCount === totalFields && totalFields > 0) {
ui.addNotification(null, E('p', _('Auto fill completed successfully! All fields have been filled.') + '
' + messages.join('
')), 'info');
} else if (successCount > 0) {
@@ -786,123 +801,123 @@ return view.extend({
o.depends('auth_server_mode', 'cloud');
o.depends('auth_server_mode', 'bypass');
o.placeholder = '110101100123456';
- o.validate = function(section_id, value) {
+ o.validate = function (section_id, value) {
if (!value || value === '')
return _('Location ID is required');
-
+
// Check total length
if (value.length !== 14) {
return _('Location ID must be exactly 14 digits long');
}
-
+
// Check if all characters are digits
if (!/^\d{14}$/.test(value)) {
return _('Location ID must contain only digits (0-9)');
}
-
+
// Validate administrative division code (first 6 digits)
var adminCode = value.substring(0, 6);
if (!/^\d{6}$/.test(adminCode)) {
return _('First 6 digits must be valid administrative division code (GB/T 2260)');
}
-
+
// Validate service type code (7-9 digits)
var serviceType = value.substring(6, 9);
if (serviceType !== '100' && serviceType !== '2' + value.charAt(7) + value.charAt(8) && serviceType !== '3' + value.charAt(7) + value.charAt(8)) {
return _('Service type code (7-9 digits) must be "100" for commercial internet service locations, "2XX" for non-commercial locations, or "3XX" for WiFi wireless collection terminals');
}
-
+
// Validate sequence number (10-14 digits)
var sequenceNum = value.substring(9);
if (!/^\d{5}$/.test(sequenceNum)) {
return _('Last 5 digits must be sequence number (00000-99999)');
}
-
+
return true;
};
o = s.taboption('location', form.Value, 'ap_device_id', _('AP Device ID'),
- _('The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase).'));
+ _('The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase).'));
o.rmempty = true;
o.optional = true;
- o.validate = function(section_id, value) {
+ o.validate = function (section_id, value) {
if (!value || value === '')
return true; // Optional field, empty is allowed
-
+
// Check total length
if (value.length !== 21) {
return _('AP Device ID must be exactly 21 characters long');
}
-
+
// Check if all characters are alphanumeric (letters and digits)
if (!/^[A-Z0-9]+$/.test(value)) {
return _('AP Device ID must contain only uppercase letters and digits');
}
-
+
// Extract MAC address part (last 12 characters)
var macPart = value.substring(9);
-
+
// Validate MAC address format (12 hexadecimal characters)
if (!/^[A-F0-9]{12}$/.test(macPart)) {
return _('Last 12 characters must be a valid MAC address in uppercase hexadecimal format (e.g., 00E04C3B7D2F)');
}
-
+
return true;
};
o.placeholder = 'AW123456700E04C3B7D2F';
o = s.taboption('location', form.Value, 'ap_mac_address', _('AP MAC Address'),
- _('The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens).'));
+ _('The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens).'));
o.rmempty = true;
o.optional = true;
o.placeholder = '00-E0-4C-3B-7D-2F';
- o.validate = function(section_id, value) {
+ o.validate = function (section_id, value) {
if (!value || value === '')
return true; // Optional field, empty is allowed
-
+
// Check total length
if (value.length !== 17) {
return _('MAC address must be exactly 17 characters long');
}
-
+
// Check format: XX-XX-XX-XX-XX-XX where X is uppercase hex digit
if (!/^[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}-[A-F0-9]{2}$/.test(value)) {
return _('MAC address must be in format XX-XX-XX-XX-XX-XX (uppercase hexadecimal separated by hyphens)');
}
-
+
// Get the AP Device ID to check consistency
var deviceId = uci.get('wifidogx', section_id, 'ap_device_id');
if (deviceId && deviceId.length === 21) {
var deviceMacPart = deviceId.substring(9);
var normalizedMac = value.replace(/-/g, '');
-
+
if (normalizedMac !== deviceMacPart) {
return _('MAC address should match the MAC address part (last 12 characters) in AP Device ID');
}
}
-
+
return true;
};
o = s.taboption('location', form.Value, 'ap_longitude', _('Mobile AP Longitude'),
- _('The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West.'));
+ _('The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West.'));
o.rmempty = true;
o.optional = true;
o.placeholder = '123.230000';
- o.validate = function(section_id, value) {
+ o.validate = function (section_id, value) {
if (!value || value === '')
return true; // Optional field, empty is allowed
-
+
// Allow more flexible input, then validate and suggest correct format
var numValue = parseFloat(value);
if (isNaN(numValue)) {
return _('Longitude must be a valid number');
}
-
+
if (numValue < -180 || numValue > 180) {
return _('Longitude must be between -180.000000 and 180.000000');
}
-
+
// Check if the input matches the strict format requirement
if (!/^[+-]?\d{3}\.\d{6}$/.test(value)) {
// Format the number to the required format and suggest it
@@ -911,41 +926,41 @@ return view.extend({
var parts = formatted.split('.');
var intPart = parts[0];
var decPart = parts[1];
-
+
// Pad integer part to 3 digits
if (intPart.startsWith('-')) {
intPart = '-' + intPart.substring(1).padStart(3, '0');
} else {
intPart = intPart.padStart(3, '0');
}
-
+
formatted = intPart + '.' + decPart;
}
return _('Longitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 123.230000 or -133.000000). Suggested format: ') + formatted;
}
-
+
return true;
};
o = s.taboption('location', form.Value, 'ap_latitude', _('Mobile AP Latitude'),
- _('The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South.'));
+ _('The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South.'));
o.rmempty = true;
o.optional = true;
o.placeholder = '39.900000';
- o.validate = function(section_id, value) {
+ o.validate = function (section_id, value) {
if (!value || value === '')
return true; // Optional field, empty is allowed
-
+
// Allow more flexible input, then validate and suggest correct format
var numValue = parseFloat(value);
if (isNaN(numValue)) {
return _('Latitude must be a valid number');
}
-
+
if (numValue < -90 || numValue > 90) {
return _('Latitude must be between -90.000000 and 90.000000');
}
-
+
// Check if the input matches the strict format requirement
if (!/^[+-]?\d{3}\.\d{6}$/.test(value)) {
// Format the number to the required format and suggest it
@@ -954,70 +969,70 @@ return view.extend({
var parts = formatted.split('.');
var intPart = parts[0];
var decPart = parts[1];
-
+
// Pad integer part to 3 digits
if (intPart.startsWith('-')) {
intPart = '-' + intPart.substring(1).padStart(3, '0');
} else {
intPart = intPart.padStart(3, '0');
}
-
+
formatted = intPart + '.' + decPart;
}
return _('Latitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 39.900000 or -33.000000). Suggested format: ') + formatted;
}
-
+
return true;
};
// rule settings
o = s.taboption('rule', form.DynamicList, 'trusted_wildcard_domains', _('Trusted Wildcard Domains'),
- _('The trusted wildcard domains of the gateway'));
+ _('The trusted wildcard domains of the gateway'));
o.rmempty = true;
o.optional = true;
o.datatype = 'wildcard';
o.placeholder = '.example.com';
-
+
o = s.taboption('rule', form.DynamicList, 'trusted_domains', _('Trusted Domains'),
- _('The trusted domains of the gateway'));
+ _('The trusted domains of the gateway'));
o.rmempty = true;
o.optional = true;
o.datatype = 'hostname';
o.placeholder = 'www.example.com';
o = s.taboption('rule', form.DynamicList, 'trusted_macs', _('Trusted MACs'),
- _('The trusted wildcard domains of the gateway.'));
+ _('The trusted wildcard domains of the gateway.'));
o.rmempty = true;
o.optional = true;
o.datatype = 'macaddr';
o.placeholder = 'A0:B1:C2:D3:44:55';
-
+
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'app_white_list', _('App White List'),
- _('The app white list of the gateway.'));
+ _('The app white list of the gateway.'));
o.rmempty = true;
o.multiple = true;
o.nocreate = true;
-
+
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'mac_white_list', _('MAC White List'),
- _('The MAC white list of the gateway.'));
+ _('The MAC white list of the gateway.'));
o.rmempty = true;
o.multiple = true;
o.nocreate = true;
o.setGroupType('mac');
o = s.taboption('rule', widgets.WifidogxGroupSelect, 'wildcard_white_list', _('Wildcard White List'),
- _('The wildcard domain white list of the gateway.'));
+ _('The wildcard domain white list of the gateway.'));
o.rmempty = true;
o.multiple = true;
o.nocreate = true;
o.setGroupType('wildcard');
-
- s = m.section(form.GridSection, 'group', _('Group Define'));
+
+ s = m.section(form.GridSection, 'group', _('Group Define'));
s.addremove = true;
s.anonymous = false;
s.nodescriptions = true;
- s.handleRemove = function(section_id, ev) {
+ s.handleRemove = function (section_id, ev) {
// according section_id to check whether it is used by app_white_list or mac_white_list
var group = uci.get('wifidogx', section_id, 'g_type') === '1' ? 'app_white_list' : 'mac_white_list';
var groupList = uci.get('wifidogx', 'common', group);
diff --git a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js
index 9e69ab869..8cf833629 100644
--- a/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js
+++ b/luci-app-apfree-wifidog/htdocs/luci-static/resources/view/wifidogx/status.js
@@ -99,6 +99,8 @@ return view.extend({
[_('Uptime'), uptime],
[_('Internet Connected'), data.is_internet_connected ? _('Yes') : _('No')],
[_('Auth Server Connected'), data.is_auth_server_connected ? _('Yes') : _('No')],
+ [_('MQTT Connected'), data.is_mqtt_connected ? _('Yes') : _('No')],
+ [_('WebSocket Connected'), data.is_websocket_connected ? _('Yes') : _('No')],
[_('Auth Server Mode'), authModeText]
];
diff --git a/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po b/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po
index 968ee9dde..961e83a40 100644
--- a/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po
+++ b/luci-app-apfree-wifidog/po/zh_Hans/apfree-wifidog.po
@@ -654,6 +654,12 @@ msgstr "互联网连接"
msgid "Auth Server Connected"
msgstr "认证服务器连接"
+msgid "MQTT Connected"
+msgstr "MQTT 连接"
+
+msgid "WebSocket Connected"
+msgstr "WebSocket 连接"
+
msgid "Auth Server Mode"
msgstr "认证服务器模式"
@@ -791,3 +797,234 @@ msgstr "实时下载速度"
msgid "Real-time Upload Speed"
msgstr "实时上传速度"
+
+msgid "AP Device ID"
+msgstr "AP设备ID"
+
+msgid "AP Device ID must be exactly 21 characters long"
+msgstr "AP设备ID必须是21个字符长"
+
+msgid "AP Device ID must contain only uppercase letters and digits"
+msgstr "AP设备ID只能包含大写字母和数字"
+
+msgid "AP MAC Address"
+msgstr "AP MAC地址"
+
+msgid "Auto Fill"
+msgstr "自动填充"
+
+msgid "Auto Fill All Fields"
+msgstr "自动填充所有字段"
+
+msgid "Auto fill completed successfully! All fields have been filled."
+msgstr "自动填充成功!所有字段已填写。"
+
+msgid "Auto fill failed. No fields could be filled. Please check your network connection and try again."
+msgstr "自动填充失败。无法填写任何字段。请检查您的网络连接并重试。"
+
+msgid "Auto fill partially completed."
+msgstr "自动填充部分完成。"
+
+msgid "Automatically fill AP MAC address, Device ID, Location ID, Longitude, and Latitude"
+msgstr "自动填充 AP MAC地址、设备ID、位置ID、经度和纬度"
+
+msgid "Device ID: "
+msgstr "设备ID: "
+
+msgid "First 6 digits must be valid administrative division code (GB/T 2260)"
+msgstr "前6位必须是有效的行政区划代码 (GB/T 2260)"
+
+msgid "Generating Device ID..."
+msgstr "生成设备ID..."
+
+msgid "Generating Location ID..."
+msgstr "生成位置ID..."
+
+msgid "Getting WAN MAC address..."
+msgstr "正在获取 WAN MAC 地址..."
+
+msgid "Getting device information and location data, please wait..."
+msgstr "正在获取设备信息和位置数据,请稍候..."
+
+msgid "Getting location coordinates..."
+msgstr "正在获取位置坐标..."
+
+msgid "Last 12 characters must be a valid MAC address in uppercase hexadecimal format (e.g., 00E04C3B7D2F)"
+msgstr "最后12个字符必须是大写十六进制格式的有效MAC地址(例如:00E04C3B7D2F)"
+
+msgid "Last 5 digits must be sequence number (00000-99999)"
+msgstr "最后5位必须是序列号 (00000-99999)"
+
+msgid "Latitude must be a valid number"
+msgstr "纬度必须是一个有效的数字"
+
+msgid "Latitude must be between -90.000000 and 90.000000"
+msgstr "纬度必须在 -90.000000 到 90.000000 之间"
+
+msgid "Latitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 39.900000 or -33.000000). Suggested format: "
+msgstr "纬度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:39.900000 或 -33.000000)。建议格式:"
+
+msgid "Latitude: "
+msgstr "纬度: "
+
+msgid "Location ID"
+msgstr "位置ID"
+
+msgid "Location ID is required"
+msgstr "必须填写位置ID"
+
+msgid "Location ID must be exactly 14 digits long"
+msgstr "位置ID必须是14位数字"
+
+msgid "Location ID must contain only digits (0-9)"
+msgstr "位置ID只能包含数字 (0-9)"
+
+msgid "Location ID: "
+msgstr "位置ID: "
+
+msgid "Longitude must be a valid number"
+msgstr "经度必须是一个有效的数字"
+
+msgid "Longitude must be between -180.000000 and 180.000000"
+msgstr "经度必须在 -180.000000 到 180.000000 之间"
+
+msgid "Longitude must be in format ±XXX.XXXXXX (3 integer digits + 6 decimal digits, e.g., 123.230000 or -133.000000). Suggested format: "
+msgstr "经度格式必须为 ±XXX.XXXXXX(3位整数 + 6位小数,例如:123.230000 或 -133.000000)。建议格式:"
+
+msgid "Longitude: "
+msgstr "经度: "
+
+msgid "MAC Address: "
+msgstr "MAC地址: "
+
+msgid "MAC address must be exactly 17 characters long"
+msgstr "MAC地址必须是17个字符长"
+
+msgid "MAC address must be in format XX-XX-XX-XX-XX-XX (uppercase hexadecimal separated by hyphens)"
+msgstr "MAC地址格式必须为 XX-XX-XX-XX-XX-XX(大写十六进制,由连字符分隔)"
+
+msgid "MAC address should match the MAC address part (last 12 characters) in AP Device ID"
+msgstr "MAC地址应与 AP设备ID 中的 MAC地址部分(最后12个字符)匹配"
+
+msgid "MQTT Connection Mode"
+msgstr "MQTT连接模式"
+
+msgid "MQTT Secure Connection Mode"
+msgstr "MQTT安全连接模式"
+
+msgid "MQTT Hostname"
+msgstr "MQTT主机名"
+
+msgid "Mobile AP Latitude"
+msgstr "移动AP纬度"
+
+msgid "Mobile AP Longitude"
+msgstr "移动AP经度"
+
+msgid "Persistent Connection Mode"
+msgstr "持久连接模式"
+
+msgid "RPC failed, trying direct method..."
+msgstr "RPC失败,正在尝试直接方法..."
+
+msgid "RPC failed, trying fallback..."
+msgstr "RPC失败,正在尝试备用方法..."
+
+msgid "Service type code (7-9 digits) must be \"100\" for commercial internet service locations, \"2XX\" for non-commercial locations, or \"3XX\" for WiFi wireless collection terminals"
+msgstr "服务类型代码(第7-9位)必须是:商业上网场所为\"100\",非商业场所为\"2XX\",或WiFi无线采集终端为\"3XX\""
+
+msgid "The MAC address of the AP device. Must be 17 characters in format XX-XX-XX-XX-XX-XX (uppercase, separated by hyphens)."
+msgstr "AP设备的MAC地址。必须为17个字符,格式为 XX-XX-XX-XX-XX-XX(大写,由连字符分隔)。"
+
+msgid "The hostname of the mqtt."
+msgstr "MQTT的主机名。"
+
+msgid "The latitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for North, negative for South."
+msgstr "纬度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。北纬为正,南纬为负。"
+
+msgid "The longitude coordinate using format: ±XXX.XXXXXX (3 integer digits + 6 decimal digits). Positive for East, negative for West."
+msgstr "经度坐标,使用格式:±XXX.XXXXXX(3位整数 + 6位小数)。东经为正,西经为负。"
+
+msgid "The mode of the authentication server."
+msgstr "认证服务器的模式。"
+
+msgid "The persistent connection mode of the device to auth server."
+msgstr "设备到认证服务器的持久连接模式。"
+
+msgid "The trusted wildcard domains of the gateway"
+msgstr "网关信任的通配符域名"
+
+msgid "The unique identifier of the AP device. Must be 21 characters: 9-character vendor code + 12-character MAC address (uppercase)."
+msgstr "AP设备的唯一标识符。必须是21个字符:9位厂商代码 + 12位MAC地址(大写)。"
+
+msgid "The unique identifier of the internet service location."
+msgstr "上网服务场所的唯一标识符。"
+
+msgid "WebSocket Connection Mode"
+msgstr "WebSocket连接模式"
+
+msgid "WebSocket Secure Connection Mode"
+msgstr "WebSocket加密连接模式"
+
+msgid "fields filled successfully."
+msgstr "个字段已填充。"
+
+msgid "✓ Device ID generated: "
+msgstr "✓ 设备ID已生成: "
+
+msgid "✓ Location ID generated: "
+msgstr "✓ 位置ID已生成: "
+
+msgid "✓ Location obtained (fallback): "
+msgstr "✓ 已获取位置(备用方法): "
+
+msgid "✓ Location obtained: "
+msgstr "✓ 已获取位置: "
+
+msgid "✓ WAN MAC address obtained (fallback): "
+msgstr "✓ 已获取 WAN MAC 地址(备用方法): "
+
+msgid "✓ WAN MAC address obtained: "
+msgstr "✓ 已获取 WAN MAC 地址: "
+
+msgid "✗ Cannot generate Device ID due to MAC error"
+msgstr "✗ 由于 MAC 错误,无法生成设备 ID"
+
+msgid "✗ Cannot generate Device ID without MAC address"
+msgstr "✗ 没有 MAC 地址,无法生成设备 ID"
+
+msgid "✗ Error getting WAN MAC address: "
+msgstr "✗ 获取 WAN MAC 地址错误: "
+
+msgid "✗ Error getting location: "
+msgstr "✗ 获取位置错误: "
+
+msgid "✗ Failed to get WAN MAC address: "
+msgstr "✗ 获取 WAN MAC 地址失败: "
+
+msgid "✗ Failed to get location data"
+msgstr "✗ 获取位置数据失败"
+
+msgid "✗ Failed to get location: "
+msgstr "✗ 获取位置失败: "
+
+msgid "✗ Failed to parse location data"
+msgstr "✗ 解析位置数据失败"
+
+msgid "✗ No valid coordinates found"
+msgstr "✗ 未找到有效的坐标"
+
+msgid "✗ RPC call failed, trying fallback..."
+msgstr "✗ RPC 调用失败,正在尝试备用方法..."
+
+msgid " (interface: "
+msgstr " (接口: "
+
+msgid ")"
+msgstr ")"
+
+msgid "Unknown error"
+msgstr "未知错误"
+
+msgid "Unknown"
+msgstr "未知"
diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua
index 69ff385b9..49b054640 100644
--- a/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -749,7 +749,6 @@ function gen_config(var)
local fakedns = nil
local routing = nil
local observatory = nil
- local burstObservatory = nil
local strategy = nil
local inbounds = {}
local outbounds = {}
@@ -975,29 +974,19 @@ function gen_config(var)
fallbackTag = fallback_node_tag,
strategy = strategy
})
- if _node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag then
- if _node.balancingStrategy == "leastLoad" then
- if not burstObservatory then
- burstObservatory = {
- subjectSelector = { "blc-" },
- pingConfig = {
- destination = _node.useCustomProbeUrl and _node.probeUrl or nil,
- interval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m",
- sampling = 3,
- timeout = "5s"
- }
- }
- end
- else
- if not observatory then
- observatory = {
- subjectSelector = { "blc-" },
- probeUrl = _node.useCustomProbeUrl and _node.probeUrl or nil,
- probeInterval = (api.format_go_time(_node.probeInterval) ~= "0s") and api.format_go_time(_node.probeInterval) or "1m",
- enableConcurrency = true
- }
- end
+ if not observatory and (_node.balancingStrategy == "leastPing" or _node.balancingStrategy == "leastLoad" or fallback_node_tag) then
+ local t = api.format_go_time(_node.probeInterval)
+ if t == "0s" then
+ t = "60s"
+ elseif not t:find("[hm]") and tonumber(t:match("%d+")) < 10 then
+ t = "10s"
end
+ observatory = {
+ subjectSelector = { "blc-" },
+ probeUrl = _node.useCustomProbeUrl and _node.probeUrl or "https://www.google.com/generate_204",
+ probeInterval = t,
+ enableConcurrency = true
+ }
end
local loopback_outbound = gen_loopback(loopback_tag, loopback_dst)
local inbound_tag = loopback_outbound.settings.inboundTag
@@ -1652,8 +1641,7 @@ function gen_config(var)
-- 传出连接
outbounds = outbounds,
-- 连接观测
- observatory = (not burstObservatory) and observatory or nil,
- burstObservatory = burstObservatory,
+ observatory = observatory,
-- 路由
routing = routing,
-- 本地策略
diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile
index 88904b2b9..783a25f37 100644
--- a/luci-app-passwall2/Makefile
+++ b/luci-app-passwall2/Makefile
@@ -34,21 +34,21 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
+ip-full +libuci-lua +lua +luci-compat +luci-lib-jsonc +resolveip +tcping \
+xray-core +geoview +v2ray-geoip +v2ray-geosite \
+unzip \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
- +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \
- +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \
- +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
- +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
- +PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \
- +PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \
- +PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \
- +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs-client \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \
++ +PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin \
+PACKAGE_$(PKG_NAME)_INCLUDE_IPv6_Nat:ip6tables-mod-nat
define Package/$(PKG_NAME)/config
@@ -90,6 +90,7 @@ config PACKAGE_$(PKG_NAME)_Nftables_Transparent_Proxy
config PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy
bool "Include Haproxy"
+ select PACKAGE_haproxy
default y if aarch64||arm||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria
@@ -105,6 +106,8 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
bool "Include Shadowsocks Libev Client"
+ select PACKAGE_shadowsocks-libev-ss-local
+ select PACKAGE_shadowsocks-libev-ss-redir
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server
@@ -115,6 +118,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
bool "Include Shadowsocks Rust Client"
depends on !i386
+ select PACKAGE_shadowsocks-rust-sslocal
default y if aarch64||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server
@@ -125,6 +129,8 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client
bool "Include ShadowsocksR Libev Client"
+ select PACKAGE_shadowsocksr-libev-ssr-local
+ select PACKAGE_shadowsocksr-libev-ssr-redir
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server
@@ -134,11 +140,12 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server
config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
bool "Include Simple-Obfs (Shadowsocks Plugin)"
+ select PACKAGE_simple-obfs-client
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox
bool "Include Sing-Box"
- default y if aarch64||arm||i386||x86_64
+ default y
config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
bool "Include tuic-client"
@@ -148,6 +155,7 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
bool "Include V2ray-Plugin (Shadowsocks Plugin)"
+ select PACKAGE_v2ray-plugin
default y if aarch64||arm||i386||x86_64
endif
diff --git a/openwrt-fastfetch/Makefile b/openwrt-fastfetch/Makefile
index 7b7b55425..27b20c037 100644
--- a/openwrt-fastfetch/Makefile
+++ b/openwrt-fastfetch/Makefile
@@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fastfetch
-PKG_VERSION:=2.59.0
-PKG_RELEASE:=1
+PKG_VERSION:=2.60.0
+PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)?