Skip to content

Commit

Permalink
feat(cli): allow specifying the default protocol in config files
Browse files Browse the repository at this point in the history
  • Loading branch information
rpendleton committed Jul 7, 2024
1 parent 192e541 commit 5e54b11
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 12 deletions.
19 changes: 18 additions & 1 deletion cli/src/configs/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,27 @@ const DEFAULT_CONFIG: ConfigModel = {
mqtt: {
host: 'localhost',
port: 1883,
protocol: 'mqtt',
maxReconnectTimes: 10,
},
}

const VALID_OUTPUT_MODES: Array<ConfigModel['output']> = ['text', 'log']

export { USER_HOME_DIR, CONFIG_FILE_PATH, DEFAULT_CONFIG, VALID_OUTPUT_MODES }
const VALID_PROTOCOLS: Array<Protocol> = ['mqtt', 'mqtts', 'ws', 'wss']

const RECOMMENDED_PORTS_BY_PROTOCOL: Record<Protocol, number> = {
mqtt: 1883,
mqtts: 8883,
ws: 80,
wss: 443,
}

export {
USER_HOME_DIR,
CONFIG_FILE_PATH,
DEFAULT_CONFIG,
VALID_OUTPUT_MODES,
VALID_PROTOCOLS,
RECOMMENDED_PORTS_BY_PROTOCOL,
}
11 changes: 9 additions & 2 deletions cli/src/configs/load.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import { readFileSync, existsSync } from 'fs'
import ini from 'ini'
import { CONFIG_FILE_PATH, DEFAULT_CONFIG, VALID_OUTPUT_MODES } from './common'
import { CONFIG_FILE_PATH, DEFAULT_CONFIG, VALID_OUTPUT_MODES, VALID_PROTOCOLS } from './common'

/**
* Parses the content of a config file and returns a ConfigModel object.
* @param content - The content of the config file.
* @returns The parsed ConfigModel object.
* @throws Error if the output mode is invalid.
* @throws Error if the output mode or protocol is invalid.
*/
const parseConfigFile = (content: string): ConfigModel => {
const config = ini.parse(content)

const output = config.default?.output
if (output && !VALID_OUTPUT_MODES.includes(output)) {
throw new Error(`Invalid output mode: ${output}. Valid modes are: ${VALID_OUTPUT_MODES.join(', ')}`)
}

const protocol = config.mqtt?.protocol;
if (protocol && !VALID_PROTOCOLS.includes(protocol)) {
throw new Error(`Invalid protocol: ${protocol}. Valid protocols are: ${VALID_PROTOCOLS.join(', ')}`)
}

return {
output: config.default?.output || DEFAULT_CONFIG.output,
mqtt: {
host: config.mqtt?.host || DEFAULT_CONFIG.mqtt.host,
port: parseInt(config.mqtt?.port, 10) || DEFAULT_CONFIG.mqtt.port,
protocol: config.mqtt?.protocol || DEFAULT_CONFIG.mqtt.protocol,
maxReconnectTimes: parseInt(config.mqtt?.max_reconnect_times, 10) || DEFAULT_CONFIG.mqtt.maxReconnectTimes,
username: config.mqtt?.username || DEFAULT_CONFIG.mqtt.username,
password: config.mqtt?.password || DEFAULT_CONFIG.mqtt.password,
Expand Down
14 changes: 7 additions & 7 deletions cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class Commander {
.option('-k, --keepalive <SEC>', 'send a ping every SEC seconds', parseNumber, 30)
.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -168,7 +168,7 @@ export class Commander {
.option('-k, --keepalive <SEC>', 'send a ping every SEC seconds', parseNumber, 30)
.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -273,7 +273,7 @@ export class Commander {

.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -368,7 +368,7 @@ export class Commander {
.option('-k, --keepalive <SEC>', 'send a ping every SEC seconds', parseNumber, 30)
.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -478,7 +478,7 @@ export class Commander {
.option('-k, --keepalive <SEC>', 'send a ping every SEC seconds', parseNumber, 30)
.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -576,7 +576,7 @@ export class Commander {

.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down Expand Up @@ -688,7 +688,7 @@ export class Commander {
.option('-k, --keepalive <SEC>', 'send a ping every SEC seconds', parseNumber, 30)
.option('-u, --username <USER>', 'the username', state.getConfig('username'))
.option('-P, --password <PASS>', 'the password', state.getConfig('password'))
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, 'mqtt')
.option('-l, --protocol <PROTO>', 'the protocol to use, mqtt, mqtts, ws, or wss', parseProtocol, state.getConfig('protocol'))
.option('--path <PATH>', 'the path of websocket', '/mqtt')
.option('--key <PATH>', 'path to the key file')
.option('--cert <PATH>', 'path to the cert file')
Expand Down
17 changes: 15 additions & 2 deletions cli/src/lib/init.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { writeFileSync, mkdirSync } from 'fs'
import { join } from 'path'
import { select, input, password } from '@inquirer/prompts'
import { CONFIG_FILE_PATH, DEFAULT_CONFIG, USER_HOME_DIR } from '../configs/common'
import { CONFIG_FILE_PATH, DEFAULT_CONFIG, RECOMMENDED_PORTS_BY_PROTOCOL, USER_HOME_DIR } from '../configs/common'

/**
* Generates the content of a configuration INI file based on the provided config object.
Expand All @@ -11,6 +11,7 @@ import { CONFIG_FILE_PATH, DEFAULT_CONFIG, USER_HOME_DIR } from '../configs/comm
const generateConfigContent = (config: ConfigModel): string => {
let mqttConfig = `host = ${config.mqtt.host}
port = ${config.mqtt.port}
protocol = ${config.mqtt.protocol}
max_reconnect_times = ${config.mqtt.maxReconnectTimes}`

if (config.mqtt.username) {
Expand Down Expand Up @@ -42,14 +43,25 @@ async function initConfig(): Promise<void> {
default: DEFAULT_CONFIG.output,
})) as ConfigModel['output']

const protocol = (await select({
message: 'Select the default MQTT protocol',
choices: [
{ name: 'MQTT', value: 'mqtt' },
{ name: 'MQTTS', value: 'mqtts' },
{ name: 'WS', value: 'ws' },
{ name: 'WSS', value: 'wss' },
],
default: DEFAULT_CONFIG.mqtt.protocol,
})) as Protocol

const host = await input({
message: 'Enter the default MQTT broker host',
default: DEFAULT_CONFIG.mqtt.host,
})

const port = await input({
message: 'Enter the default MQTT port',
default: DEFAULT_CONFIG.mqtt.port.toString(),
default: RECOMMENDED_PORTS_BY_PROTOCOL[protocol].toString(),
validate: (input) => !isNaN(parseInt(input, 10)) || 'Port must be a number',
})

Expand All @@ -74,6 +86,7 @@ async function initConfig(): Promise<void> {
mqtt: {
host,
port: parseInt(port, 10),
protocol,
maxReconnectTimes: parseInt(maxReconnectTimes, 10),
username,
password: passwordAnswer,
Expand Down
1 change: 1 addition & 0 deletions cli/src/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ declare global {
mqtt: {
host: string
port: number
protocol?: Protocol
maxReconnectTimes: number
username?: string
password?: string
Expand Down

0 comments on commit 5e54b11

Please sign in to comment.