Skip to content

Commit

Permalink
Update help text and configuration handling; replace static values wi…
Browse files Browse the repository at this point in the history
…th dynamic placeholders for gong, vote, and flush limits
  • Loading branch information
htilly committed Jan 7, 2025
1 parent 36476a5 commit ad7d682
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 167 deletions.
8 changes: 4 additions & 4 deletions helpText.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Current commands!
=== === === === === === ===
`add` *text* : add song to the queue and start playing if idle. Will start with a fresh queue.
`addalbum` *text* : add an album to the queue and start playing if idle. Will start with a fresh queue.
`bestof` : *text* : add topp 10 tracks by the artist
`bestof` : *text* : add top 10 tracks by the artist
`status` : show current status of Sonos
`current` : list current track
`search` *text* : search for a track, does NOT add it to the queue
Expand All @@ -12,10 +12,10 @@ Current commands!
`append` *text* : append a song to the previous playlist and start playing the same list again.
`vote` *number* : vote for a track to be played next!!! :rocket:
`votecheck` : how many votes there are currently, as well as who has voted.
`gong` : current track is bad! *5* gongs will skip the track
`gong` : current track is bad! *{{gongLimit}}* gongs will skip the track
`gongcheck` : how many gong votes there are currently, as well as who has gonged.
`voteimmune` *number* : vote to make the current track immune to gong. *3* votes will make it immune
`flushvote` : vote to flush the queue. *4* votes will flush the queue :toilet:
`voteimmune` *number* : vote to make the current track immune to gong. *{{voteLimit}}* votes will make it immune
`flushvote` : vote to flush the queue. *{{flushVoteLimit}}* votes will flush the queue :toilet:
`upnext` : show the next track to be played
`volume` : view current volume
`list` : list current queue
243 changes: 80 additions & 163 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1057,10 +1057,22 @@ function _help(input, channel) {
const adminMessage = fs.readFileSync(helpTextPathAdmin, 'utf8');
let message = fs.readFileSync(helpTextPath, 'utf8');

// Read configuration values
const gongLimit = config.get('gongLimit');
const voteLimit = config.get('voteLimit');
const flushVoteLimit = config.get('flushVoteLimit');
const maxVolume = config.get('maxVolume');

// Replace placeholders in help text
message = message.replace(/{{gongLimit}}/g, gongLimit);
message = message.replace(/{{voteLimit}}/g, voteLimit);
message = message.replace(/{{flushVoteLimit}}/g, flushVoteLimit);
message = message.replace(/{{maxVolume}}/g, maxVolume);

if (channel === global.adminChannel) {
message += '\n' + adminMessage;
}
_slackMessage(message, channel)
_slackMessage(message, channel);
}

function _play(input, channel, userName, state) {
Expand Down Expand Up @@ -1788,49 +1800,19 @@ function _status(channel, state) {
})
}

// Ensure the _debug function is defined


async function _debug(channel, userName) {
_logUserAction(userName, 'debug');
var url = 'http://' + sonosIp + ':1400/xml/device_description.xml';

// Function to get the IP address of the machine (Docker container if inside Docker)
function getIPAddress() {
const interfaces = os.networkInterfaces();
for (const name of Object.keys(interfaces)) {
for (const iface of interfaces[name]) {
if (iface.family === 'IPv4' && !iface.internal) {
return iface.address;
}
}
}
return 'IP address not found';
}

// Improved function to check if running inside Docker
function isRunningInDocker() {
try {
// Check if running in Docker by inspecting /proc/1/cgroup and the presence of .dockerenv
const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
if (cgroup.includes('docker')) {
return true;
}
} catch (err) {
// Ignore errors, continue to next check
}

try {
// Check if .dockerenv file exists (another indication of being inside Docker)
if (fs.existsSync('/.dockerenv')) {
return true;
}
} catch (err) {
// Ignore errors
function maskSensitiveInfo(value) {
if (typeof value === 'string' && value.length > 6) {
return value.slice(0, 3) + '--xxx-MASKED-xxx--' + value.slice(-3);
}

return false; // Default to not inside Docker if all checks fail
return value;
}

// Function to get the host's IP address if running inside Docker
function getHostIPAddress() {
try {
const result = fs.readFileSync('/proc/net/route', 'utf8');
Expand All @@ -1853,7 +1835,6 @@ async function _debug(channel, userName) {
}
}

// Helper function to convert hex IP from /proc/net/route to a readable IP address
function hexToIp(hex) {
return [
parseInt(hex.slice(6, 8), 16),
Expand All @@ -1863,25 +1844,36 @@ async function _debug(channel, userName) {
].join('.');
}

const isDocker = isRunningInDocker(); // Improved check for Docker environment
const isRunningInDocker = () => {
try {
const cgroup = fs.readFileSync('/proc/1/cgroup', 'utf8');
if (cgroup.includes('docker')) {
return true;
}
} catch (err) {}

try {
if (fs.existsSync('/.dockerenv')) {
return true;
}
} catch (err) {}

return false;
};

const isDocker = isRunningInDocker();

if (isDocker) {
// Check if IP is defined in the environment
// Get the IP address from the configuration
console.log('IP Address from config:', ipAddress);
if (!ipAddress) {
// Log error and set a default value for IP
const warningMessage = 'Make sure you have configured IP in the config.json';
logger.error(warningMessage);
ipAddress = warningMessage; // Set the value of IP to the warning message
ipAddress = warningMessage;
}
} else {
ipAddress = getIPAddress(); // IP of the machine if not in Docker
ipAddress = getIPAddress();
}

const dockerIPAddress = isDocker ? getHostIPAddress() : null; // Host IP if running inside Docker

// Define nodeVersion outside the if block
const dockerIPAddress = isDocker ? getHostIPAddress() : null;
const nodeVersion = JSON.stringify(process.versions);

xmlToJson(url, async function (err, data) {
Expand All @@ -1890,86 +1882,35 @@ async function _debug(channel, userName) {
logger.error('Error occurred ' + err);
sonosInfo = 'SONOS device is offline or not responding.';
} else {
logger.info('BuildNumber of SlackONOS: ', buildNumber);
logger.info('Platform: ', process.platform);
logger.info('Node version: ', process.version);
logger.info('Node dependencies: ', process.versions);

// Log Sonos information
logger.info(data.root.device[0].modelDescription);
logger.info(data.root.device[0].softwareVersion);
logger.info(data.root.device[0].displayName);
logger.info(data.root.device[0].hardwareVersion);
logger.info(data.root.device[0].apiVersion);
logger.info(data.root.device[0].roomName);
logger.info(data.root.device[0].friendlyName);
logger.info(data.root.device[0].modelNumber);
logger.info(data.root.device[0].serialNum);
logger.info(data.root.device[0].MACAddress);

sonosInfo =
'\n*Sonos Info*' +
'\nFriendly Name: ' + (data.root.device[0].friendlyName) +
'\nRoom Name: ' + (data.root.device[0].roomName) +
'\nDisplay Name: ' + (data.root.device[0].displayName) +
'\nModel Description: ' + (data.root.device[0].modelDescription) +
'\nModelNumber: ' + (data.root.device[0].modelNumber) +
'\nSerial Number: ' + (data.root.device[0].serialNum) +
'\nMAC Address: ' + (data.root.device[0].MACAddress) +
'\nSW Version: ' + (data.root.device[0].softwareVersion) +
'\nHW Version: ' + (data.root.device[0].hardwareVersion) +
'\nAPI Version: ' + (data.root.device[0].apiVersion);
'\nFriendly Name: ' + data.root.device[0].friendlyName;
}

// Get memory usage
const memoryUsage = process.memoryUsage();
const formattedMemoryUsage = `
*Memory Usage*:
RSS: ${Math.round(memoryUsage.rss / 1024 / 1024)} MB
Heap Total: ${Math.round(memoryUsage.heapTotal / 1024 / 1024)} MB
Heap Used: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)} MB
External: ${Math.round(memoryUsage.external / 1024 / 1024)} MB
Array Buffers: ${Math.round(memoryUsage.arrayBuffers / 1024 / 1024)} MB
`;

// Get uptime
const uptime = process.uptime();
const formattedUptime = `
*Uptime*: ${Math.floor(uptime / 60)} minutes ${Math.floor(uptime % 60)} seconds
`;

// Get network interfaces
const networkInterfaces = os.networkInterfaces();
const formattedNetworkInterfaces = Object.entries(networkInterfaces).map(([name, addresses]) => {
return addresses.map(addr => `${name}: ${addr.address}`).join('\n');
}).join('\n');

// Get disk usage (example for Unix-like systems)
const diskUsage = execSync('df -h /').toString();
const formattedDiskUsage = `
*Disk Usage*:
${diskUsage}
`;



// Read configuration values only from config.json
const configKeys = Object.keys(config.stores.file.store); // Access only the file-based store
const configValues = configKeys.map(key => `${key}: ${config.get(key)}`).join('\n');

// Debug log for verification
logger.info('DEBUG -- Config values from config.json: ' + configValues);

// Ensure environment variables are handled separately
const envVars = `
*Environment Variables*:
NODE_VERSION: ${process.env.NODE_VERSION || 'not set'}
HOSTNAME: ${process.env.HOSTNAME || 'not set'}
YARN_VERSION: ${process.env.YARN_VERSION || 'not set'}
HOME: ${process.env.HOME || 'not set'}
PATH: ${process.env.PATH}
PWD: ${process.env.PWD}
`;
const formattedMemoryUsage = `\n*Memory Usage*:\n RSS: ${Math.round(memoryUsage.rss / 1024 / 1024)} MB`;

const envVars = `\n*Environment Variables*:\n NODE_VERSION: ${process.env.NODE_VERSION || 'not set'}\n HOSTNAME: ${process.env.HOSTNAME || 'not set'}\n YARN_VERSION: ${process.env.YARN_VERSION || 'not set'}`;

const sensitiveKeys = ['token', 'spotifyClientId', 'spotifyClientSecret', 'openaiApiKey'];
const configKeys = Object.keys(config.stores.file.store);
const configValues = configKeys
.map(key => {
const value = config.get(key);
return sensitiveKeys.includes(key) ? `${key}: ${maskSensitiveInfo(value)}` : `${key}: ${value}`;
})
.join('\n');

// Identify missing configuration values
const defaultConfig = config.stores.defaults.store;
const missingConfigValues = Object.keys(defaultConfig)
.filter(key => !configKeys.includes(key))
.map(key => {
const value = defaultConfig[key].value || defaultConfig[key];
return value === 'literal' ? null : `${key}: ${value}`;
})
.filter(line => line !== null) // Remove excluded entries
.join('\n');

const blocks = [
{
Expand Down Expand Up @@ -2012,16 +1953,6 @@ ${diskUsage}
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: formattedUptime
}
},
{
type: 'divider'
},
{
type: 'section',
text: {
Expand All @@ -2032,45 +1963,30 @@ ${diskUsage}
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: '*Network Interfaces*\n' + formattedNetworkInterfaces
}
},
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: formattedDiskUsage
}
},
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: '*Configuration Values*\n' + configValues
}
},
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: envVars
}
}
];

if (missingConfigValues) {
blocks.push(
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: '*Missing Configuration Values*\n' + missingConfigValues
}
}
);
}

const message = {
channel: channel,
blocks: blocks
Expand All @@ -2089,6 +2005,7 @@ ${diskUsage}




async function _blacklist(input, channel, userName) {
_logUserAction(userName, 'blacklist');
if (channel !== global.adminChannel) {
Expand Down

0 comments on commit ad7d682

Please sign in to comment.