Skip to content
Draft
Show file tree
Hide file tree
Changes from 9 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
23 changes: 22 additions & 1 deletion app/src/actions/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import { globalActions } from './'
import { showError } from './Global'
import { showTree } from './Tree'
import { TopicViewModel } from '../model/TopicViewModel'
import {
backendEvents,
setMaxMessageSize as setMaxMessageSizeEvent,
MAX_MESSAGE_SIZE_UNLIMITED,
MAX_MESSAGE_SIZE_DEFAULT,
} from '../../../events'

const settingsIdentifier: StorageIdentifier<Partial<SettingsStateModel>> = {
id: 'Settings',
Expand All @@ -22,18 +28,24 @@ export const loadSettings = () => async (dispatch: Dispatch<any>, getState: () =
settings: getState().settings.merge(settings),
type: ActionTypes.SETTINGS_DID_LOAD_SETTINGS,
})
// Emit the maxMessageSize to backend after loading settings
const maxMessageSize = getState().settings.get('maxMessageSize')
backendEvents.emit(setMaxMessageSizeEvent, maxMessageSize)
} catch (error) {
dispatch(showError(error))
}
dispatch(globalActions.didLaunch())
}

export const storeSettings = () => async (dispatch: Dispatch<any>, getState: () => AppState) => {
const currentSettings = getState().settings.toJS()
const settings = {
...getState().settings.toJS(),
...currentSettings,
autoExpandLimit: undefined,
topicFilter: undefined,
visible: undefined,
// Don't persist unlimited - reset to default
maxMessageSize: currentSettings.maxMessageSize === MAX_MESSAGE_SIZE_UNLIMITED ? MAX_MESSAGE_SIZE_DEFAULT : currentSettings.maxMessageSize,
}

try {
Expand Down Expand Up @@ -169,3 +181,12 @@ export const toggleTheme = () => (dispatch: Dispatch<any>, getState: () => AppSt
})
dispatch(storeSettings())
}

export const setMaxMessageSize = (maxMessageSize: number) => (dispatch: Dispatch<any>) => {
dispatch({
maxMessageSize,
type: ActionTypes.SETTINGS_SET_MAX_MESSAGE_SIZE,
})
dispatch(storeSettings())
backendEvents.emit(setMaxMessageSizeEvent, maxMessageSize)
}
51 changes: 51 additions & 0 deletions app/src/components/SettingsDrawer/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import { globalActions, settingsActions } from '../../actions'
import { shell } from 'electron'
import { Theme, withStyles } from '@material-ui/core/styles'
import { TopicOrder } from '../../reducers/Settings'
import {
MAX_MESSAGE_SIZE_20KB,
MAX_MESSAGE_SIZE_100KB,
MAX_MESSAGE_SIZE_1MB,
MAX_MESSAGE_SIZE_5MB,
MAX_MESSAGE_SIZE_UNLIMITED,
} from '../../../../events'

import {
Divider,
Expand Down Expand Up @@ -88,6 +95,7 @@ interface Props {
topicOrder: TopicOrder
visible: boolean
theme: 'light' | 'dark'
maxMessageSize: number
}

class Settings extends React.PureComponent<Props, {}> {
Expand Down Expand Up @@ -203,6 +211,47 @@ class Settings extends React.PureComponent<Props, {}> {
this.props.actions.settings.setTopicOrder(e.target.value as TopicOrder)
}

private renderMaxMessageSize() {
const { classes, maxMessageSize } = this.props

const formatSize = (size: number) => {
if (size === MAX_MESSAGE_SIZE_UNLIMITED) {
return 'Unlimited'
} else if (size >= 1000000) {
return `${size / 1000000} MB`
} else if (size >= 1000) {
return `${size / 1000} KB`
}
return `${size} bytes`
}

return (
<div style={{ padding: '8px', display: 'flex' }}>
<InputLabel htmlFor="max-message-size" style={{ flex: '1', marginTop: '8px' }}>
Max Message Size
</InputLabel>
<Select
value={maxMessageSize}
onChange={this.onChangeMaxMessageSize}
input={<Input name="max-message-size" id="max-message-size-label-placeholder" />}
name="max-message-size"
className={classes.input}
style={{ flex: '1' }}
>
<MenuItem value={MAX_MESSAGE_SIZE_20KB}>{formatSize(MAX_MESSAGE_SIZE_20KB)}</MenuItem>
<MenuItem value={MAX_MESSAGE_SIZE_100KB}>{formatSize(MAX_MESSAGE_SIZE_100KB)}</MenuItem>
<MenuItem value={MAX_MESSAGE_SIZE_1MB}>{formatSize(MAX_MESSAGE_SIZE_1MB)}</MenuItem>
<MenuItem value={MAX_MESSAGE_SIZE_5MB}>{formatSize(MAX_MESSAGE_SIZE_5MB)}</MenuItem>
<MenuItem value={MAX_MESSAGE_SIZE_UNLIMITED}>{formatSize(MAX_MESSAGE_SIZE_UNLIMITED)}</MenuItem>
</Select>
</div>
)
}

private onChangeMaxMessageSize = (e: React.ChangeEvent<{ value: unknown }>) => {
this.props.actions.settings.setMaxMessageSize(parseInt(String(e.target.value), 10))
}

public render() {
const { classes, actions, visible } = this.props
return (
Expand All @@ -220,6 +269,7 @@ class Settings extends React.PureComponent<Props, {}> {
{this.renderAutoExpand()}
{this.renderNodeOrder()}
<TimeLocale />
{this.renderMaxMessageSize()}
{this.renderHighlightTopicUpdates()}
{this.selectTopicsOnMouseOver()}
{this.toggleTheme()}
Expand All @@ -243,6 +293,7 @@ const mapStateToProps = (state: AppState) => {
highlightTopicUpdates: state.settings.get('highlightTopicUpdates'),
selectTopicWithMouseOver: state.settings.get('selectTopicWithMouseOver'),
theme: state.settings.get('theme'),
maxMessageSize: state.settings.get('maxMessageSize'),
}
}

Expand Down
17 changes: 16 additions & 1 deletion app/src/reducers/Settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createReducer } from './lib'
import { Record } from 'immutable'
import { MAX_MESSAGE_SIZE_DEFAULT } from '../../../events'

export enum TopicOrder {
none = 'none',
Expand All @@ -18,6 +19,7 @@ export interface SettingsStateModel {
valueRendererDisplayMode: ValueRendererDisplayMode
selectTopicWithMouseOver: boolean
theme: 'light' | 'dark'
maxMessageSize: number
}

export type SettingsState = Record<SettingsStateModel>
Expand All @@ -30,7 +32,8 @@ export type Actions = SetAutoExpandLimitAction &
SetValueRendererDisplayModeAction &
SetTheme &
SetSelectTopicWithMouseOverAction &
SetTimeLocale
SetTimeLocale &
SetMaxMessageSizeAction

export enum ActionTypes {
SETTINGS_SET_AUTO_EXPAND_LIMIT = 'SETTINGS_SET_AUTO_EXPAND_LIMIT',
Expand All @@ -43,6 +46,7 @@ export enum ActionTypes {
SETTINGS_SET_THEME_LIGHT = 'SETTINGS_SET_THEME_LIGHT',
SETTINGS_SET_THEME_DARK = 'SETTINGS_SET_THEME_DARK',
SETTINGS_SET_TIME_LOCALE = 'SETTINGS_SET_TIME_LOCALE',
SETTINGS_SET_MAX_MESSAGE_SIZE = 'SETTINGS_SET_MAX_MESSAGE_SIZE',
}

const initialState = Record<SettingsStateModel>({
Expand All @@ -54,6 +58,7 @@ const initialState = Record<SettingsStateModel>({
selectTopicWithMouseOver: false,
theme: 'light',
topicFilter: undefined,
maxMessageSize: MAX_MESSAGE_SIZE_DEFAULT,
})

const setTheme = (theme: 'light' | 'dark') => (state: SettingsState) => {
Expand All @@ -73,6 +78,7 @@ const reducerActions: {
SETTINGS_SET_THEME_LIGHT: setTheme('light'),
SETTINGS_SET_THEME_DARK: setTheme('dark'),
SETTINGS_SET_TIME_LOCALE: setTimeLocale,
SETTINGS_SET_MAX_MESSAGE_SIZE: setMaxMessageSize,
}

export const settingsReducer = createReducer(initialState(), reducerActions)
Expand Down Expand Up @@ -153,3 +159,12 @@ export interface FilterTopicsAction {
function filterTopics(state: SettingsState, action: FilterTopicsAction) {
return state.set('topicFilter', action.topicFilter)
}

export interface SetMaxMessageSizeAction {
type: ActionTypes.SETTINGS_SET_MAX_MESSAGE_SIZE
maxMessageSize: number
}

function setMaxMessageSize(state: SettingsState, action: SetMaxMessageSizeAction) {
return state.set('maxMessageSize', action.maxMessageSize)
}
26 changes: 24 additions & 2 deletions backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,18 @@ import {
makeConnectionStateEvent,
makePublishEvent,
removeConnection,
setMaxMessageSize as setMaxMessageSizeEvent,
MAX_MESSAGE_SIZE_DEFAULT,
MAX_MESSAGE_SIZE_20KB,
MAX_MESSAGE_SIZE_100KB,
MAX_MESSAGE_SIZE_1MB,
MAX_MESSAGE_SIZE_5MB,
MAX_MESSAGE_SIZE_UNLIMITED,
} from '../../events'

export class ConnectionManager {
private connections: { [s: string]: DataSource<any> } = {}
private maxMessageSize: number = MAX_MESSAGE_SIZE_DEFAULT

private handleConnectionRequest = (event: AddMqttConnection) => {
const connectionId = event.id
Expand Down Expand Up @@ -42,8 +50,9 @@ export class ConnectionManager {
const messageEvent = makeConnectionMessageEvent(connectionId)
connection.onMessage((topic: string, payload: Buffer, packet: any) => {
let buffer = payload
if (buffer.length > 20000) {
buffer = buffer.slice(0, 20000)
// Only apply limit if not unlimited
if (this.maxMessageSize !== MAX_MESSAGE_SIZE_UNLIMITED && buffer.length > this.maxMessageSize) {
buffer = buffer.slice(0, this.maxMessageSize)
}

let decoded_payload = null
Expand All @@ -64,6 +73,19 @@ export class ConnectionManager {
backendEvents.subscribe(removeConnection, (connectionId: string) => {
this.removeConnection(connectionId)
})
backendEvents.subscribe(setMaxMessageSizeEvent, (maxMessageSize: number) => {
// Validate the value is one of the allowed sizes
const validSizes = [
MAX_MESSAGE_SIZE_20KB,
MAX_MESSAGE_SIZE_100KB,
MAX_MESSAGE_SIZE_1MB,
MAX_MESSAGE_SIZE_5MB,
MAX_MESSAGE_SIZE_UNLIMITED,
]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot validation can be simplified, no exact values need to match, should be gte 20k and an integer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in de53571. Simplified validation to accept any integer >= 20KB or unlimited (-1), no exact value matching required.

if (typeof maxMessageSize === 'number' && validSizes.includes(maxMessageSize)) {
this.maxMessageSize = maxMessageSize
}
})
}

public removeConnection(connectionId: string) {
Expand Down
11 changes: 11 additions & 0 deletions events/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@ export const writeToFile: RpcEvent<{ filePath: string, data: string, encoding?:

export const readFromFile: RpcEvent<{ filePath: string, encoding?: string }, Buffer> = {
topic: 'readFromFile',
}

export const MAX_MESSAGE_SIZE_20KB = 20000
export const MAX_MESSAGE_SIZE_100KB = 100000
export const MAX_MESSAGE_SIZE_1MB = 1000000
export const MAX_MESSAGE_SIZE_5MB = 5000000
export const MAX_MESSAGE_SIZE_UNLIMITED = -1
export const MAX_MESSAGE_SIZE_DEFAULT = MAX_MESSAGE_SIZE_20KB

export const setMaxMessageSize: Event<number> = {
topic: 'settings/maxMessageSize',
}