return users;
} catch (e) {
- // Fall back to text parsing for non-JSON output
- console.warn('JSON parsing failed, falling back to text parsing:', e.message);
- return this.parseUsersText(output);
+ console.error('Failed to parse JSON:', e.message);
+ return users;
}
},
device: entry?.device,
time: entry?.time || entry['connected-at'],
cipher: entry?.cipher,
- status: entry?.status
+ status: entry?.status,
+ tx: entry?._TX || entry?.TX || entry?.tx,
+ rx: entry?._RX || entry?.RX || entry?.rx
};
},
- parseUsersText: function(output) {
- const users = [];
- if (!output) return users;
-
- const lines = output.split('\n');
- for (let line of lines) {
- // Parse: id user group vpn_ip ip device time cipher status
- const match = line.match(/^\s*(\d+)\s+([-_\w]+)\s+([().*\-_\w]+)\s+([:.\-_\w]+)\s+([:.\-_\w]+)\s+([:.\-_\w]+)\s+([:.\-_\w]+)\s+([():.\-_\w]+)\s+([:.\-_\w]+)/);
- if (match) {
- users.push({
- id: match[1],
- user: match[2],
- group: match[3],
- vpn_ip: match[4],
- ip: match[5],
- device: match[6],
- time: match[7],
- cipher: match[8],
- status: match[9]
- });
- }
- }
- return users;
- },
-
handleDisconnect: function(id) {
return L.resolveDefault(
fs.exec('/usr/bin/occtl', ['disconnect', 'id', id]),
load: function() {
return L.resolveDefault(
- fs.exec('/usr/bin/occtl', ['show', 'users']).then(res => res.stdout),
+ fs.exec('/usr/bin/occtl', ['--json', 'show', 'users']).then(res => res.stdout),
''
);
},
E('div', { 'class': 'th' }, _('Time')),
E('div', { 'class': 'th' }, _('Cipher')),
E('div', { 'class': 'th' }, _('Status')),
+ E('div', { 'class': 'th' }, _('Tx')),
+ E('div', { 'class': 'th' }, _('Rx')),
E('div', { 'class': 'th' }, '\u00a0')
])
]);
E('div', { 'class': 'td' }, user.time),
E('div', { 'class': 'td' }, user.cipher),
E('div', { 'class': 'td' }, user.status),
- E('div', { 'class': 'td' },
+ E('div', { 'class': 'td' }, user.tx),
+ E('div', { 'class': 'td' }, user.rx),
+ E('div', { 'class': 'td' },
E('button', {
'class': 'cbi-button cbi-button-remove',
'click': L.bind(this.handleDisconnect, this, user.id)
}
}
- return E('div', { 'class': 'cbi-section' }, [
- E('legend', _('Active OpenConnect Users')),
- table
- ]);
+ return table;
}
});