Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): allow specifying the default protocol in config files #1713

Merged
merged 2 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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: 8083,
wss: 8084,
}

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
Loading