Configurable CPU Governor (fixed)
modified: .vscode/launch.json modified: react/CMakeLists.txt modified: react/public/var/config.json new file: react/src/GovernorSettings.tsx modified: react/src/JackHostStatus.tsx new file: react/src/ListSelectDialog.tsx modified: react/src/PiPedalModel.tsx modified: react/src/SettingsDialog.tsx modified: react/tmp.txt modified: src/BeastServer.cpp modified: src/BeastServer.hpp modified: src/CMakeLists.txt modified: src/ConfigMain.cpp new file: src/CpuGovernor.cpp new file: src/CpuGovernor.hpp new file: src/GovernorSettings.cpp new file: src/GovernorSettings.hpp new file: src/Ipv6Helpers.cpp new file: src/Ipv6Helpers.hpp modified: src/JackHost.cpp modified: src/PiPedalModel.cpp
This commit is contained in:
Vendored
+3
-1
@@ -47,7 +47,9 @@
|
||||
"/etc/pipedal/config",
|
||||
"/etc/pipedal/react",
|
||||
"-port",
|
||||
"0.0.0.0:8080"
|
||||
"0.0.0.0:8080",
|
||||
"-shutdownPort",
|
||||
"3147"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
|
||||
+75
-76
@@ -21,89 +21,88 @@ add_custom_command(
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/react
|
||||
|
||||
DEPENDS
|
||||
src/NumericInput.tsx
|
||||
src/RenameDialog.tsx
|
||||
src/ToobInputStageView.tsx
|
||||
src/ToobCabSimView.tsx
|
||||
src/SearchFilter.tsx
|
||||
src/Draggable.tsx
|
||||
src/SelectHoverBackground.tsx
|
||||
src/JackStatusView.tsx
|
||||
src/SplitControlView.tsx
|
||||
src/MidiBindingsDialog.tsx
|
||||
src/WifiChannel.tsx
|
||||
src/PluginControlView.tsx
|
||||
src/TemporaryDrawer.tsx
|
||||
src/logo.svg
|
||||
src/AlsaDeviceInfo.tsx
|
||||
src/JackServerSettingsDialog.tsx
|
||||
src/ZoomedUiControl.tsx
|
||||
src/PedalBoardView.tsx
|
||||
src/MainPage.tsx
|
||||
src/App.tsx
|
||||
src/AppThemed.tsx
|
||||
src/PresetDialog.tsx
|
||||
src/PluginPreset.tsx
|
||||
src/react-app-env.d.ts
|
||||
src/ToobSpectrumResponseView.tsx
|
||||
src/SettingsDialog.tsx
|
||||
src/SelectChannelsDialog.tsx
|
||||
src/StringBuilder.tsx
|
||||
src/ToobPowerStage2View.tsx
|
||||
src/SearchControl.tsx
|
||||
src/XxxSnippet.tsx
|
||||
src/Units.tsx
|
||||
src/Jack.tsx
|
||||
src/PluginControl.tsx
|
||||
src/ResizeResponsiveComponent.tsx
|
||||
src/Lv2Plugin.tsx
|
||||
src/index.tsx
|
||||
src/NoChangePassword.tsx
|
||||
src/VuMeter.tsx
|
||||
src/ControlViewFactory.tsx
|
||||
src/JackServerSettings.tsx
|
||||
src/MidiBinding.tsx
|
||||
src/UploadDialog.tsx
|
||||
src/PiPedalSocket.tsx
|
||||
src/PedalBoard.tsx
|
||||
src/JackHostStatus.tsx
|
||||
src/ZoomedDial.tsx
|
||||
src/Rect.tsx
|
||||
src/SvgPathBuilder.tsx
|
||||
src/IControlViewFactory.tsx
|
||||
src/PiPedalModel.tsx
|
||||
src/PluginInfoDialog.tsx
|
||||
src/reportWebVitals.ts
|
||||
src/PiPedalError.tsx
|
||||
src/BankDialog.tsx
|
||||
src/PluginIcon.tsx
|
||||
src/WifiConfigDialog.tsx
|
||||
src/PresetSelector.tsx
|
||||
src/LoadPluginDialog.tsx
|
||||
src/ToobFrequencyResponseView.tsx
|
||||
src/SplitControlView.tsx
|
||||
src/WifiConfigSettings.tsx
|
||||
src/setupTests.ts
|
||||
src/AboutDialog.tsx
|
||||
src/index.css
|
||||
src/Banks.tsx
|
||||
src/DialogEx.tsx
|
||||
src/ToobWaveShapeView.tsx
|
||||
src/FullScreenIME.tsx
|
||||
src/AppThemed.css
|
||||
src/JackHostStatus.tsx
|
||||
src/SearchFilter.tsx
|
||||
src/MainPage.tsx
|
||||
src/PiPedalModel.tsx
|
||||
src/PluginPresetSelector.tsx
|
||||
src/Utility.tsx
|
||||
src/SelectMidiChannelsDialog.tsx
|
||||
src/App.test.tsx
|
||||
src/MidiBindingView.tsx
|
||||
src/SplitUiControls.tsx
|
||||
src/PluginClass.tsx
|
||||
src/ObservableProperty.tsx
|
||||
src/Pedal.tsx
|
||||
src/GxTunerControl.tsx
|
||||
src/DraggableGrid.tsx
|
||||
src/ToobMLView.tsx
|
||||
src/SettingsDialog.tsx
|
||||
src/PiPedalSocket.tsx
|
||||
src/ToobFrequencyResponseView.tsx
|
||||
src/ControlViewFactory.tsx
|
||||
src/Utility.tsx
|
||||
src/ToobToneStackView.tsx
|
||||
src/SelectHoverBackground.tsx
|
||||
src/MidiBindingsDialog.tsx
|
||||
src/TemporaryDrawer.tsx
|
||||
src/GxTunerView.tsx
|
||||
src/ToobInputStageView.tsx
|
||||
src/DraggableGrid.tsx
|
||||
src/JackStatusView.tsx
|
||||
src/PluginControl.tsx
|
||||
src/XxxSnippet.tsx
|
||||
src/PluginPreset.tsx
|
||||
src/Jack.tsx
|
||||
src/AlsaDeviceInfo.tsx
|
||||
src/MidiBinding.tsx
|
||||
src/PiPedalError.tsx
|
||||
src/IControlViewFactory.tsx
|
||||
src/Lv2Plugin.tsx
|
||||
src/PedalBoard.tsx
|
||||
src/PedalBoardView.tsx
|
||||
src/PresetDialog.tsx
|
||||
src/AppThemed.tsx
|
||||
src/ZoomedDial.tsx
|
||||
src/RenameDialog.tsx
|
||||
src/SplitUiControls.tsx
|
||||
src/GovernorSettings.tsx
|
||||
src/AboutDialog.tsx
|
||||
src/ToobSpectrumResponseView.tsx
|
||||
src/PluginControlView.tsx
|
||||
src/NoChangePassword.tsx
|
||||
src/ToobSpectrumAnalyzerView.tsx
|
||||
|
||||
src/MidiBindingView.tsx
|
||||
src/GxTunerControl.tsx
|
||||
src/Banks.tsx
|
||||
src/PluginPresetsDialog.tsx
|
||||
src/BankDialog.tsx
|
||||
src/UploadDialog.tsx
|
||||
src/ToobPowerStage2View.tsx
|
||||
src/index.tsx
|
||||
src/Units.tsx
|
||||
src/VuMeter.tsx
|
||||
src/App.test.tsx
|
||||
src/DialogEx.tsx
|
||||
src/StringBuilder.tsx
|
||||
src/SelectChannelsDialog.tsx
|
||||
src/Draggable.tsx
|
||||
src/ZoomedUiControl.tsx
|
||||
src/Rect.tsx
|
||||
src/PluginClass.tsx
|
||||
src/PluginIcon.tsx
|
||||
src/App.tsx
|
||||
src/ResizeResponsiveComponent.tsx
|
||||
src/SvgPathBuilder.tsx
|
||||
src/NumericInput.tsx
|
||||
src/JackServerSettings.tsx
|
||||
src/ListSelectDialog.tsx
|
||||
src/JackServerSettingsDialog.tsx
|
||||
src/ObservableProperty.tsx
|
||||
src/SelectMidiChannelsDialog.tsx
|
||||
src/WifiChannel.tsx
|
||||
src/LoadPluginDialog.tsx
|
||||
src/WifiConfigDialog.tsx
|
||||
src/PluginInfoDialog.tsx
|
||||
src/ToobWaveShapeView.tsx
|
||||
src/ToobCabSimView.tsx
|
||||
src/PresetSelector.tsx
|
||||
|
||||
public/css/roboto.css
|
||||
public/fonts/Roboto-BlackItalic.woff2
|
||||
public/fonts/Roboto-Black.woff2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"socket_server_port": 8080,
|
||||
"socket_server_address": "*",
|
||||
"socket_server_address": "[fe80::df30:41b9:1ede:c23c]",
|
||||
|
||||
"max_upload_size": 1048576,
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
|
||||
export default class GovernorSettings {
|
||||
deserialize(input: any) : GovernorSettings{
|
||||
this.governors = input.governors;
|
||||
this.governor = input.governor;
|
||||
return this;
|
||||
}
|
||||
clone(): GovernorSettings
|
||||
{
|
||||
return new GovernorSettings().deserialize(this);
|
||||
}
|
||||
governors: string[] = ["ondemand","performance"];
|
||||
governor: string = "performance";
|
||||
|
||||
}
|
||||
@@ -93,10 +93,10 @@ export default class JackHostStatus {
|
||||
{
|
||||
(status.cpuFreqMax === status.cpuFreqMin)?
|
||||
(
|
||||
<span> {fmtCpuFreq(status.cpuFreqMax)} {status.governor} </span>
|
||||
<span> {status.governor} {fmtCpuFreq(status.cpuFreqMax)} </span>
|
||||
)
|
||||
:(
|
||||
<span> {fmtCpuFreq(status.cpuFreqMax)}-{fmtCpuFreq(status.cpuFreqMax)} {status.governor} </span>
|
||||
<span> {status.governor} {fmtCpuFreq(status.cpuFreqMax)}-{fmtCpuFreq(status.cpuFreqMax)} </span>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React from 'react';
|
||||
import Button from '@mui/material/Button';
|
||||
|
||||
|
||||
import Radio from '@mui/material/Radio';
|
||||
import List from '@mui/material/List';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListItemText from '@mui/material/ListItemText';
|
||||
|
||||
import Dialog from '@mui/material/Dialog';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||
|
||||
|
||||
export interface ListSelectDialogProps {
|
||||
open: boolean,
|
||||
title: string,
|
||||
width: number,
|
||||
selectedItem: string,
|
||||
items: string[],
|
||||
onOk: (selectedItem: string) => void,
|
||||
onClose: () => void
|
||||
};
|
||||
|
||||
export interface ListSelectDialogState {
|
||||
fullScreen: boolean;
|
||||
};
|
||||
|
||||
export default class ListSelectDialog extends ResizeResponsiveComponent<ListSelectDialogProps, ListSelectDialogState> {
|
||||
|
||||
refText: React.RefObject<HTMLInputElement>;
|
||||
|
||||
constructor(props: ListSelectDialogProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
fullScreen: false
|
||||
};
|
||||
this.refText = React.createRef<HTMLInputElement>();
|
||||
}
|
||||
mounted: boolean = false;
|
||||
|
||||
|
||||
|
||||
onWindowSizeChanged(width: number, height: number): void {
|
||||
this.setState({ fullScreen: height < 200 })
|
||||
}
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
super.componentDidMount();
|
||||
this.mounted = true;
|
||||
}
|
||||
componentWillUnmount() {
|
||||
super.componentWillUnmount();
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Dialog onClose={()=>this.props.onClose()} open={this.props.open}>
|
||||
<List sx={{pt: 0}}>
|
||||
{
|
||||
this.props.items.map(
|
||||
(value: string, index: number) => {
|
||||
return (
|
||||
<ListItem key={index} >
|
||||
<ListItemButton role={undefined} onClick={()=> this.props.onOk(value)} dense>
|
||||
<ListItemIcon>
|
||||
<Radio
|
||||
edge="start"
|
||||
checked={value === this.props.selectedItem}
|
||||
disableRipple
|
||||
/>
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={value} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
</List>
|
||||
<DialogActions>
|
||||
<Button onClick={()=> this.props.onClose()} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
+64
-29
@@ -31,8 +31,9 @@ import { BankIndex } from './Banks';
|
||||
import JackHostStatus from './JackHostStatus';
|
||||
import JackServerSettings from './JackServerSettings';
|
||||
import MidiBinding from './MidiBinding';
|
||||
import {PluginUiPresets} from './PluginPreset';
|
||||
import { PluginUiPresets } from './PluginPreset';
|
||||
import WifiConfigSettings from './WifiConfigSettings';
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
import WifiChannel from './WifiChannel';
|
||||
import AlsaDeviceInfo from './AlsaDeviceInfo';
|
||||
|
||||
@@ -316,6 +317,7 @@ export interface PiPedalModel {
|
||||
banks: ObservableProperty<BankIndex>;
|
||||
jackServerSettings: ObservableProperty<JackServerSettings>;
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings>;
|
||||
governorSettings: ObservableProperty<GovernorSettings>;
|
||||
|
||||
presets: ObservableProperty<PresetIndex>;
|
||||
|
||||
@@ -350,7 +352,7 @@ export interface PiPedalModel {
|
||||
saveCurrentPreset(): void;
|
||||
saveCurrentPresetAs(newName: string): void;
|
||||
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): void;
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number, newName: string): void;
|
||||
|
||||
loadPreset(instanceId: number): void;
|
||||
updatePresets(presets: PresetIndex): Promise<void>;
|
||||
@@ -397,7 +399,7 @@ export interface PiPedalModel {
|
||||
addControlValueChangeListener(instanceId: number, onValueChanged: ControlValueChangedHandler): ControlValueChangedHandle
|
||||
removeControlValueChangeListener(handle: ControlValueChangedHandle): void;
|
||||
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle;
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler): PluginPresetsChangedHandle;
|
||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void;
|
||||
|
||||
listenForAtomOutput(instanceId: number, onComplete: (instanceId: number, atomOutput: any) => void): ListenHandle;
|
||||
@@ -405,12 +407,13 @@ export interface PiPedalModel {
|
||||
|
||||
|
||||
|
||||
download(targetType: string, isntanceId: number|string): void;
|
||||
download(targetType: string, isntanceId: number | string): void;
|
||||
|
||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number>;
|
||||
uploadPreset(uploadPage: string, file: File, uploadAfter: number): Promise<number>;
|
||||
uploadBank(file: File, uploadAfter: number): Promise<number>;
|
||||
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>;
|
||||
setGovernorSettings(governor: string): Promise<void>;
|
||||
|
||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>;
|
||||
|
||||
@@ -447,6 +450,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
= new ObservableProperty<JackServerSettings>(new JackServerSettings());
|
||||
|
||||
wifiConfigSettings: ObservableProperty<WifiConfigSettings> = new ObservableProperty<WifiConfigSettings>(new WifiConfigSettings());
|
||||
governorSettings: ObservableProperty<GovernorSettings> = new ObservableProperty<GovernorSettings>(new GovernorSettings());
|
||||
|
||||
|
||||
presets: ObservableProperty<PresetIndex> = new ObservableProperty<PresetIndex>
|
||||
@@ -575,6 +579,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
} else if (message === "onWifiConfigSettingsChanged") {
|
||||
let wifiConfigSettings = new WifiConfigSettings().deserialize(body);
|
||||
this.wifiConfigSettings.set(wifiConfigSettings);
|
||||
}
|
||||
else if (message === "onGovernorSettingsChanged") {
|
||||
let governor = body as string;
|
||||
let newSettings = this.governorSettings.get().clone();
|
||||
newSettings.governor = governor;
|
||||
this.governorSettings.set(newSettings);
|
||||
} else if (message === "onBanksChanged") {
|
||||
let banks = new BankIndex().deserialize(body);
|
||||
this.banks.set(banks);
|
||||
@@ -660,6 +670,12 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
.then(data => {
|
||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
|
||||
|
||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||
})
|
||||
.then(data => {
|
||||
@@ -792,6 +808,11 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
.then(data => {
|
||||
this.wifiConfigSettings.set(new WifiConfigSettings().deserialize(data));
|
||||
|
||||
return this.getWebSocket().request<any>("getGovernorSettings");
|
||||
})
|
||||
.then(data => {
|
||||
this.governorSettings.set(new GovernorSettings().deserialize(data));
|
||||
|
||||
|
||||
return this.getWebSocket().request<any>("getJackServerSettings");
|
||||
})
|
||||
@@ -994,7 +1015,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
|
||||
_pluginPresetsChangedHandles: PluginPresetsChangedHandle[] = [];
|
||||
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler) : PluginPresetsChangedHandle {
|
||||
addPluginPresetsChangedListener(onPluginPresetsChanged: PluginPresetsChangedHandler): PluginPresetsChangedHandle {
|
||||
let handle = ++this.nextListenHandle;
|
||||
let t: PluginPresetsChangedHandle = {
|
||||
_id: handle,
|
||||
@@ -1003,28 +1024,23 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this._pluginPresetsChangedHandles.push(t);
|
||||
return t;
|
||||
}
|
||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void
|
||||
{
|
||||
removePluginPresetsChangedListener(handle: PluginPresetsChangedHandle): void {
|
||||
let pos = -1;
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
||||
{
|
||||
if (this._pluginPresetsChangedHandles[i]._id === handle._id)
|
||||
{
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i) {
|
||||
if (this._pluginPresetsChangedHandles[i]._id === handle._id) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos !== -1)
|
||||
{
|
||||
this._pluginPresetsChangedHandles.splice(pos,1);
|
||||
if (pos !== -1) {
|
||||
this._pluginPresetsChangedHandles.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
firePluginPresetsChanged(pluginUri: string): void {
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i)
|
||||
{
|
||||
for (let i = 0; i < this._pluginPresetsChangedHandles.length; ++i) {
|
||||
this._pluginPresetsChangedHandles[i]._handler(pluginUri);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1298,7 +1314,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
return data;
|
||||
});
|
||||
}
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number,newName: string): Promise<number> {
|
||||
saveCurrentPluginPresetAs(pluginInstanceId: number, newName: string): Promise<number> {
|
||||
// default behaviour is to save after the currently selected preset.
|
||||
let request: any = {
|
||||
instanceId: pluginInstanceId,
|
||||
@@ -1567,22 +1583,21 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
this.webSocket?.send("loadPluginPreset", { pluginInstanceId: pluginInstanceId, presetInstanceId: presetInstanceId });
|
||||
}
|
||||
|
||||
handlePluginPresetsChanged(pluginUri: string):void {
|
||||
handlePluginPresetsChanged(pluginUri: string): void {
|
||||
this.uncachePluginPreset(pluginUri);
|
||||
this.firePluginPresetsChanged(pluginUri);
|
||||
}
|
||||
|
||||
|
||||
updatePluginPresets(pluginUri: string, presets: PluginUiPresets): Promise<void>
|
||||
{
|
||||
updatePluginPresets(pluginUri: string, presets: PluginUiPresets): Promise<void> {
|
||||
this.presetCache[pluginUri] = presets;
|
||||
this.firePluginPresetsChanged(pluginUri);
|
||||
return nullCast(this.webSocket).request<void>("updatePluginPresets", presets);
|
||||
}
|
||||
duplicatePluginPreset(pluginUri: string, instanceId: number): Promise<number>
|
||||
{
|
||||
return nullCast(this.webSocket).request<number>("copyPluginPreset", {
|
||||
pluginUri: pluginUri, instanceId: instanceId });
|
||||
duplicatePluginPreset(pluginUri: string, instanceId: number): Promise<number> {
|
||||
return nullCast(this.webSocket).request<number>("copyPluginPreset", {
|
||||
pluginUri: pluginUri, instanceId: instanceId
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -1692,7 +1707,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
window.open(url, "_blank");
|
||||
}
|
||||
|
||||
uploadPreset(uploadPage: string,file: File, uploadAfter: number): Promise<number> {
|
||||
uploadPreset(uploadPage: string, file: File, uploadAfter: number): Promise<number> {
|
||||
let result = new Promise<number>((resolve, reject) => {
|
||||
try {
|
||||
if (file.size > this.maxUploadSize) {
|
||||
@@ -1775,6 +1790,27 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
setGovernorSettings(governor: string): Promise<void> {
|
||||
let newSettings = this.governorSettings.get().clone();
|
||||
newSettings.governor = governor;
|
||||
this.governorSettings.set(newSettings);
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
|
||||
let ws = this.webSocket;
|
||||
if (!ws) return;
|
||||
ws.request<void>(
|
||||
"setGovernorSettings",
|
||||
governor
|
||||
)
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void> {
|
||||
let result = new Promise<void>((resolve, reject) => {
|
||||
let oldSettings = this.wifiConfigSettings.get();
|
||||
@@ -1866,8 +1902,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
|
||||
preloadImages(imageList: string): void {
|
||||
let imageNames = imageList.split(';');
|
||||
for (let i = 0; i < imageNames.length; ++i)
|
||||
{
|
||||
for (let i = 0; i < imageNames.length; ++i) {
|
||||
let imageName = imageNames[i];
|
||||
let img = new Image();
|
||||
img.src = "/img/" + imageName;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import React, { SyntheticEvent, Component } from 'react';
|
||||
import ListSelectDialog from './ListSelectDialog';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
||||
@@ -36,6 +37,7 @@ import JackHostStatus from './JackHostStatus';
|
||||
import WifiConfigSettings from './WifiConfigSettings';
|
||||
import WifiConfigDialog from './WifiConfigDialog';
|
||||
import DialogEx from './DialogEx'
|
||||
import GovernorSettings from './GovernorSettings';
|
||||
|
||||
import Slide, {SlideProps} from '@mui/material/Slide';
|
||||
import { createStyles, Theme } from '@mui/material/styles';
|
||||
@@ -55,10 +57,12 @@ interface SettingsDialogState {
|
||||
jackSettings: JackChannelSelection;
|
||||
jackServerSettings: JackServerSettings;
|
||||
jackStatus?: JackHostStatus;
|
||||
governorSettings: GovernorSettings;
|
||||
|
||||
wifiConfigSettings: WifiConfigSettings;
|
||||
|
||||
showWifiConfigDialog: boolean;
|
||||
showGovernorSettingsDialog: boolean;
|
||||
showInputSelectDialog: boolean;
|
||||
showOutputSelectDialog: boolean;
|
||||
showMidiSelectDialog: boolean;
|
||||
@@ -146,7 +150,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
jackStatus: undefined,
|
||||
jackSettings: this.model.jackSettings.get(),
|
||||
wifiConfigSettings: this.model.wifiConfigSettings.get(),
|
||||
governorSettings: this.model.governorSettings.get(),
|
||||
showWifiConfigDialog: false,
|
||||
showGovernorSettingsDialog: false,
|
||||
showInputSelectDialog: false,
|
||||
showOutputSelectDialog: false,
|
||||
showMidiSelectDialog: false,
|
||||
@@ -160,6 +166,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.handleJackSettingsChanged = this.handleJackSettingsChanged.bind(this);
|
||||
this.handleJackServerSettingsChanged = this.handleJackServerSettingsChanged.bind(this);
|
||||
this.handleWifiConfigSettingsChanged = this.handleWifiConfigSettingsChanged.bind(this);
|
||||
this.handleGovernorSettingsChanged = this.handleGovernorSettingsChanged.bind(this);
|
||||
this.handleConnectionStateChanged = this.handleConnectionStateChanged.bind(this);
|
||||
|
||||
}
|
||||
@@ -182,6 +189,15 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.showAlert(err);
|
||||
});
|
||||
}
|
||||
handleApplyGovernorSettings(governor: string): void {
|
||||
this.model.setGovernorSettings(governor)
|
||||
.then(() => {
|
||||
|
||||
})
|
||||
.catch((err) => {
|
||||
this.model.showAlert(err);
|
||||
});
|
||||
}
|
||||
|
||||
handleWifiConfigSettingsChanged(): void {
|
||||
this.setState(
|
||||
@@ -190,6 +206,14 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
)
|
||||
}
|
||||
handleGovernorSettingsChanged(): void {
|
||||
this.setState(
|
||||
{
|
||||
governorSettings: this.model.governorSettings.get()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleJackSettingsChanged(): void {
|
||||
this.setState({
|
||||
jackSettings: this.model.jackSettings.get()
|
||||
@@ -233,6 +257,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.jackConfiguration.addOnChangedHandler(this.handleJackConfigurationChanged);
|
||||
this.model.jackServerSettings.addOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||
this.model.wifiConfigSettings.addOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||
this.model.governorSettings.addOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||
this.model.getJackStatus()
|
||||
.then((jackStatus) =>
|
||||
this.setState(
|
||||
@@ -261,6 +286,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
this.model.jackSettings.removeOnChangedHandler(this.handleJackSettingsChanged);
|
||||
this.model.jackServerSettings.removeOnChangedHandler(this.handleJackServerSettingsChanged);
|
||||
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleWifiConfigSettingsChanged);
|
||||
this.model.wifiConfigSettings.removeOnChangedHandler(this.handleGovernorSettingsChanged);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -314,6 +340,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
let newSelection = this.state.jackSettings.clone();
|
||||
newSelection.inputMidiPorts = channels;
|
||||
this.model.setJackSettings(newSelection);
|
||||
|
||||
}
|
||||
this.setState({
|
||||
showMidiSelectDialog: false,
|
||||
@@ -358,6 +385,11 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
showWifiConfigDialog: true
|
||||
});
|
||||
}
|
||||
handleShowGovernorSettingsDialogDialog() {
|
||||
this.setState({
|
||||
showGovernorSettingsDialog: true
|
||||
});
|
||||
}
|
||||
handleRestart() {
|
||||
this.setState({ restarting: true });
|
||||
this.model.restart()
|
||||
@@ -417,19 +449,19 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
>
|
||||
<div >
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||
AUDIO
|
||||
STATUS
|
||||
</Typography>
|
||||
{(!isConfigValid) ?
|
||||
(
|
||||
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||
<Typography display="block" variant="caption" color="textSecondary">Status: <span style={{ color: "#F00" }}>Not configured.</span></Typography>
|
||||
<Typography display="block" variant="caption" color="textSecondary">CPU: </Typography>
|
||||
<Typography display="block" variant="caption" color="textSecondary">Governor: </Typography>
|
||||
</div>
|
||||
) :
|
||||
(
|
||||
<div style={{ paddingLeft: 48, position: "relative", top: -12 }}>
|
||||
{JackHostStatus.getDisplayView("Status:\u00A0", this.state.jackStatus)}
|
||||
{JackHostStatus.getCpuInfo("CPU:\u00A0", this.state.jackStatus)}
|
||||
{JackHostStatus.getDisplayView("", this.state.jackStatus)}
|
||||
{ JackHostStatus.getCpuInfo("Governor:\u00A0", this.state.jackStatus)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -442,6 +474,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
)
|
||||
}
|
||||
<Typography className={classes.sectionHead} display="block" variant="caption" color="secondary">
|
||||
AUDIO
|
||||
</Typography>
|
||||
<ButtonBase className={classes.setting} onClick={() => this.handleJackServerSettings()}
|
||||
>
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
@@ -512,6 +547,18 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
<ButtonBase className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
|
||||
onClick={() => this.handleShowGovernorSettingsDialogDialog()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
<div style={{ width: "100%" }}>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
|
||||
CPU Governor</Typography>
|
||||
<Typography display="block" variant="caption" noWrap color="textSecondary">
|
||||
{this.state.governorSettings.governor }
|
||||
</Typography>
|
||||
|
||||
</div>
|
||||
</ButtonBase>
|
||||
<ButtonBase className={classes.setting} disabled={!isConfigValid || disableShutdown}
|
||||
onClick={() => this.handleRestart()} >
|
||||
<SelectHoverBackground selected={false} showHover={true} />
|
||||
@@ -556,6 +603,32 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
|
||||
)
|
||||
}
|
||||
{
|
||||
(this.state.showGovernorSettingsDialog) &&
|
||||
(
|
||||
<ListSelectDialog
|
||||
width={220}
|
||||
open={this.state.showGovernorSettingsDialog}
|
||||
items={this.state.governorSettings.governors}
|
||||
selectedItem={this.state.governorSettings.governor}
|
||||
title="Governor"
|
||||
onClose={()=> this.setState({showGovernorSettingsDialog: false})}
|
||||
onOk={(selectedValue) => {
|
||||
this.model.setGovernorSettings(selectedValue)
|
||||
.then(()=>{
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
this.model.showAlert(error);
|
||||
});
|
||||
|
||||
this.setState({showGovernorSettingsDialog: false})
|
||||
}}
|
||||
>
|
||||
</ListSelectDialog>
|
||||
)
|
||||
|
||||
}
|
||||
{
|
||||
(this.state.showMidiSelectDialog) &&
|
||||
(
|
||||
|
||||
+74
-76
@@ -1,83 +1,81 @@
|
||||
src
|
||||
src/NumericInput.tsx
|
||||
src/RenameDialog.tsx
|
||||
src/ToobInputStageView.tsx
|
||||
src/ToobCabSimView.tsx
|
||||
src/SearchFilter.tsx
|
||||
src/Draggable.tsx
|
||||
src/SelectHoverBackground.tsx
|
||||
src/JackStatusView.tsx
|
||||
src/SplitControlView.tsx
|
||||
src/MidiBindingsDialog.tsx
|
||||
src/WifiChannel.tsx
|
||||
src/PluginControlView.tsx
|
||||
src/TemporaryDrawer.tsx
|
||||
src/LoadPluginDialogBackup.tsx
|
||||
src/logo.svg
|
||||
src/AlsaDeviceInfo.tsx
|
||||
src/JackServerSettingsDialog.tsx
|
||||
src/ZoomedUiControl.tsx
|
||||
src/PedalBoardView.tsx
|
||||
src/MainPage.tsx
|
||||
src/App.tsx
|
||||
src/PresetDialog.tsx
|
||||
src/PluginPreset.tsx
|
||||
src/react-app-env.d.ts
|
||||
src/ToobSpectrumResponseView.tsx
|
||||
src/SettingsDialog.tsx
|
||||
src/SelectChannelsDialog.tsx
|
||||
src/StringBuilder.tsx
|
||||
src/ToobPowerStage2View.tsx
|
||||
src/SearchControl.tsx
|
||||
src/XxxSnippet.tsx
|
||||
src/Units.tsx
|
||||
src/Jack.tsx
|
||||
src/PluginControl.tsx
|
||||
src/ResizeResponsiveComponent.tsx
|
||||
src/Lv2Plugin.tsx
|
||||
src/index.tsx
|
||||
src/NoChangePassword.tsx
|
||||
src/VuMeter.tsx
|
||||
src/ControlViewFactory.tsx
|
||||
src/JackServerSettings.tsx
|
||||
src/MidiBinding.tsx
|
||||
src/UploadDialog.tsx
|
||||
src/PiPedalSocket.tsx
|
||||
src/PedalBoard.tsx
|
||||
src/JackHostStatus.tsx
|
||||
src/ZoomedDial.tsx
|
||||
src/Rect.tsx
|
||||
src/SvgPathBuilder.tsx
|
||||
src/IControlViewFactory.tsx
|
||||
src/PiPedalModel.tsx
|
||||
src/PluginInfoDialog.tsx
|
||||
src/reportWebVitals.ts
|
||||
src/PiPedalError.tsx
|
||||
src/BankDialog.tsx
|
||||
src/PluginIcon.tsx
|
||||
src/WifiConfigDialog.tsx
|
||||
src/PresetSelector.tsx
|
||||
src/LoadPluginDialog.tsx
|
||||
src/ToobFrequencyResponseView.tsx
|
||||
src/SplitControlView.tsx
|
||||
src/WifiConfigSettings.tsx
|
||||
src/setupTests.ts
|
||||
src/AboutDialog.tsx
|
||||
src/index.css
|
||||
src/Banks.tsx
|
||||
src/DialogEx.tsx
|
||||
src/ToobWaveShapeView.tsx
|
||||
src/FullScreenIME.tsx
|
||||
src/App.css
|
||||
src/JackHostStatus.tsx
|
||||
src/SearchFilter.tsx
|
||||
src/MainPage.tsx
|
||||
src/PiPedalModel.tsx
|
||||
src/PluginPresetSelector.tsx
|
||||
src/Utility.tsx
|
||||
src/SelectMidiChannelsDialog.tsx
|
||||
src/App.test.tsx
|
||||
src/MidiBindingView.tsx
|
||||
src/SplitUiControls.tsx
|
||||
src/PluginClass.tsx
|
||||
src/ObservableProperty.tsx
|
||||
src/Pedal.tsx
|
||||
src/GxTunerControl.tsx
|
||||
src/DraggableGrid.tsx
|
||||
src/ToobMLView.tsx
|
||||
src/SettingsDialog.tsx
|
||||
src/PiPedalSocket.tsx
|
||||
src/ToobFrequencyResponseView.tsx
|
||||
src/ControlViewFactory.tsx
|
||||
src/Utility.tsx
|
||||
src/ToobToneStackView.tsx
|
||||
src/SelectHoverBackground.tsx
|
||||
src/MidiBindingsDialog.tsx
|
||||
src/TemporaryDrawer.tsx
|
||||
src/GxTunerView.tsx
|
||||
src/ToobInputStageView.tsx
|
||||
src/DraggableGrid.tsx
|
||||
src/JackStatusView.tsx
|
||||
src/PluginControl.tsx
|
||||
src/XxxSnippet.tsx
|
||||
src/PluginPreset.tsx
|
||||
src/Jack.tsx
|
||||
src/AlsaDeviceInfo.tsx
|
||||
src/MidiBinding.tsx
|
||||
src/PiPedalError.tsx
|
||||
src/IControlViewFactory.tsx
|
||||
src/Lv2Plugin.tsx
|
||||
src/PedalBoard.tsx
|
||||
src/PedalBoardView.tsx
|
||||
src/PresetDialog.tsx
|
||||
src/AppThemed.tsx
|
||||
src/ZoomedDial.tsx
|
||||
src/RenameDialog.tsx
|
||||
src/SplitUiControls.tsx
|
||||
src/GovernorSettings.tsx
|
||||
src/AboutDialog.tsx
|
||||
src/ToobSpectrumResponseView.tsx
|
||||
src/PluginControlView.tsx
|
||||
src/NoChangePassword.tsx
|
||||
src/ToobSpectrumAnalyzerView.tsx
|
||||
src/MidiBindingView.tsx
|
||||
src/GxTunerControl.tsx
|
||||
src/Banks.tsx
|
||||
src/PluginPresetsDialog.tsx
|
||||
src/BankDialog.tsx
|
||||
src/UploadDialog.tsx
|
||||
src/ToobPowerStage2View.tsx
|
||||
src/index.tsx
|
||||
src/Units.tsx
|
||||
src/VuMeter.tsx
|
||||
src/App.test.tsx
|
||||
src/DialogEx.tsx
|
||||
src/StringBuilder.tsx
|
||||
src/SelectChannelsDialog.tsx
|
||||
src/Draggable.tsx
|
||||
src/ZoomedUiControl.tsx
|
||||
src/Rect.tsx
|
||||
src/PluginClass.tsx
|
||||
src/PluginIcon.tsx
|
||||
src/App.tsx
|
||||
src/ResizeResponsiveComponent.tsx
|
||||
src/SvgPathBuilder.tsx
|
||||
src/NumericInput.tsx
|
||||
src/JackServerSettings.tsx
|
||||
src/ListSelectDialog.tsx
|
||||
src/JackServerSettingsDialog.tsx
|
||||
src/ObservableProperty.tsx
|
||||
src/SelectMidiChannelsDialog.tsx
|
||||
src/WifiChannel.tsx
|
||||
src/LoadPluginDialog.tsx
|
||||
src/WifiConfigDialog.tsx
|
||||
src/PluginInfoDialog.tsx
|
||||
src/ToobWaveShapeView.tsx
|
||||
src/ToobCabSimView.tsx
|
||||
src/PresetSelector.tsx
|
||||
|
||||
+57
-6
@@ -49,6 +49,40 @@ pipedal::last_modified(const std::filesystem::path &path)
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getHostName()
|
||||
{
|
||||
char buff[512];
|
||||
if (gethostname(buff,sizeof(buff)) == 0)
|
||||
{
|
||||
buff[511] = '\0';
|
||||
return buff;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getIpv4Address(const std::string interface)
|
||||
{
|
||||
int fd = -1;
|
||||
struct ifreq ifr;
|
||||
memset(&ifr,0,sizeof(ifr));
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
/* I want to get an IPv4 IP address */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
/* I want an IP address attached to "eth0" */
|
||||
strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ-1);
|
||||
|
||||
int result = ioctl(fd, SIOCGIFADDR, &ifr);
|
||||
if (result == -1) return "";
|
||||
|
||||
|
||||
close(fd);
|
||||
char *name = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
|
||||
if (name == nullptr) return "";
|
||||
return name;
|
||||
}
|
||||
static std::map<std::string, std::string> extensionsToMimeType = {
|
||||
{".htm", "text/html; charset=UTF-8"},
|
||||
{".html", "text/html; charset=UTF-8"},
|
||||
@@ -192,7 +226,8 @@ namespace pipedal
|
||||
webSocket(webSocket)
|
||||
{
|
||||
uri requestUri(webSocket->get_uri()->str().c_str());
|
||||
fromAddress = requestUri.authority();
|
||||
fromAddress = SS(webSocket->get_socket().remote_endpoint());
|
||||
|
||||
|
||||
auto pFactory = pServer->GetSocketFactory(requestUri);
|
||||
if (!pFactory)
|
||||
@@ -364,11 +399,14 @@ namespace pipedal
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto requestHandler : this->request_handlers)
|
||||
{
|
||||
|
||||
if (requestHandler->wants(req.method(), requestUri))
|
||||
{
|
||||
std::string fromAddress = SS(con->get_remote_endpoint());
|
||||
|
||||
try
|
||||
{
|
||||
if (req.method() == HttpVerb::head)
|
||||
@@ -377,7 +415,7 @@ namespace pipedal
|
||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||
res.set(HttpField::access_control_allow_origin, origin);
|
||||
|
||||
requestHandler->head_response(requestUri, req, res, ec);
|
||||
requestHandler->head_response(fromAddress,requestUri, req, res, ec);
|
||||
res.keepAlive(req.keepAlive());
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
{
|
||||
@@ -401,7 +439,7 @@ namespace pipedal
|
||||
|
||||
res.set(HttpField::cache_control, "max-age: 31104000"); // cache for a year.
|
||||
|
||||
requestHandler->get_response(requestUri, req, res, ec);
|
||||
requestHandler->get_response(fromAddress,requestUri, req, res, ec);
|
||||
res.keepAlive(req.keepAlive());
|
||||
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
@@ -425,7 +463,7 @@ namespace pipedal
|
||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||
res.set(HttpField::access_control_allow_origin, origin);
|
||||
|
||||
requestHandler->post_response(requestUri, req, res, ec);
|
||||
requestHandler->post_response(fromAddress,requestUri, req, res, ec);
|
||||
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
{
|
||||
@@ -547,15 +585,28 @@ namespace pipedal
|
||||
m_endpoint.set_close_handler(bind(&BeastServerImpl::on_close, this, _1));
|
||||
m_endpoint.set_http_handler(bind(&BeastServerImpl::on_http, this, _1));
|
||||
|
||||
std::string hostName = getHostName();
|
||||
if (hostName.length() != 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Listening on " << this->address << ":" << this->port;
|
||||
ss << "Listening on " << hostName << ".local:" << this->port;
|
||||
Lv2Log::info(ss.str());
|
||||
}
|
||||
std::string ipv4Address = getIpv4Address("eth0");
|
||||
if (ipv4Address.length() != 0)
|
||||
{
|
||||
Lv2Log::info(SS("Listening on " << ipv4Address << ":" << this->port));
|
||||
}
|
||||
std::string wifiAddress = getIpv4Address("wlan0");
|
||||
if (wifiAddress.length() != 0)
|
||||
{
|
||||
Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port));
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << port;
|
||||
m_endpoint.listen(this->address, ss.str());
|
||||
// m_endpoint.listen(this->address, ss.str());
|
||||
m_endpoint.listen(tcp::v6(),(uint16_t)port);
|
||||
m_endpoint.start_accept();
|
||||
|
||||
// Start IOC service threads.
|
||||
|
||||
+34
-1
@@ -3,7 +3,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/network_v4.hpp>
|
||||
#include <boost/asio/ip/network_v6.hpp>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@@ -164,12 +164,34 @@ public:
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) = 0;
|
||||
|
||||
virtual void head_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) {
|
||||
head_response(request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void get_response(
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) = 0;
|
||||
|
||||
virtual void get_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
get_response(request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
|
||||
virtual void post_response(
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
@@ -178,6 +200,17 @@ public:
|
||||
{
|
||||
get_response(request_uri,req,res,ec);
|
||||
}
|
||||
virtual void post_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
post_response(
|
||||
request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BeastServer {
|
||||
|
||||
+5
-1
@@ -102,7 +102,10 @@ add_custom_command(
|
||||
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
CpuGovernor.cpp CpuGovernor.hpp
|
||||
GovernorSettings.cpp GovernorSettings.hpp
|
||||
SysExec.cpp SysExec.hpp
|
||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||
@@ -233,6 +236,7 @@ add_executable(pipedalshutdownd ShutdownMain.cpp CommandLineParser.hpp
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
CpuGovernor.cpp CpuGovernor.hpp
|
||||
asan_options.cpp
|
||||
)
|
||||
target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd)
|
||||
|
||||
+6
-5
@@ -650,7 +650,7 @@ int main(int argc, char **argv)
|
||||
<< " (only valid with the -install option). Usually determined " << endl
|
||||
<< " automatically." << endl
|
||||
<< endl
|
||||
<< " --uninstall Remove installed services and service accounts." << endl
|
||||
<< " --uninstall Remove installed services." << endl
|
||||
<< endl
|
||||
<< " --enable Start the pipedal service at boot time." << endl
|
||||
<< endl
|
||||
@@ -668,10 +668,11 @@ int main(int argc, char **argv)
|
||||
<< " web server will listen on 0.0.0.0 (any)." << endl
|
||||
<< endl
|
||||
<< " --enable_ap <country_code> <ssid> <wep_password> <channel>" << endl
|
||||
<< " Enable the Wi-Fi access point. <country_code> is the 2-letter " << endl
|
||||
<< " ISO-3166 country code for the country in which you are currently" << endl
|
||||
<< " located. The country code determines which channels may be legally" << endl
|
||||
<< " used in (and which features need to be enabled) in order to use a " << endl
|
||||
<< " Enable the Wi-Fi access point. <country_code> is the " << endl
|
||||
<< " 2-letter ISO-3166 country code for the country in " << endl
|
||||
<< " which you are currently located. The country code " << endl
|
||||
<< " determines which channels may be legally used in (and " << endl
|
||||
<< " which features need to be enabled) in order to use a " << endl
|
||||
<< " Wi-Fi channel in your legislative regime." << endl
|
||||
<< endl
|
||||
<< " --disable_ap Disabled the Wi-Fi access point." << endl
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "CpuGovernor.hpp"
|
||||
#include "ss.hpp"
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include "PiPedalException.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
// not a feature on Win32.
|
||||
void pipedal::SetCpuGovernor(const std::string &governor) { }
|
||||
std::vector<std::string> pipedal::GetAvailableGovernors() { return std::vector<std::string>(); }
|
||||
|
||||
#else
|
||||
|
||||
static const int SYSFS_RETRIES = 3;
|
||||
|
||||
|
||||
std::string pipedal::GetCpuGovernor()
|
||||
{
|
||||
std::string result;
|
||||
try {
|
||||
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
||||
f >> result;
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static bool writeAndVerify(std::filesystem::path&sysfsPath, const std::string &value)
|
||||
{
|
||||
// return if the value has already been set.
|
||||
{
|
||||
std::ifstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(f,line);
|
||||
if (!f.fail() && value == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < SYSFS_RETRIES; ++i)
|
||||
{
|
||||
{
|
||||
// write the value.
|
||||
// write the value.
|
||||
std::ofstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
f << value;
|
||||
} else {
|
||||
std::cout << SS("Can't open " << sysfsPath << " for writing.") << std::endl;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// verify that we wrote it
|
||||
{
|
||||
std::ifstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(f,line);
|
||||
if (value == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
std::cout << "Read value: " << line << "Expected value: " << value << std::endl;
|
||||
}
|
||||
std::cout << "Failed to update " << sysfsPath << std::endl;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void pipedal::SetCpuGovernor(const std::string &governor) {
|
||||
// using sysfs
|
||||
int nCpu = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::filesystem::path base = SS("/sys/devices/system/cpu/cpu" << nCpu);
|
||||
if (!std::filesystem::is_directory(base))
|
||||
break;
|
||||
|
||||
std::filesystem::path sysFsPath = SS("/sys/devices/system/cpu/cpu" << nCpu << "/cpufreq/scaling_governor");
|
||||
|
||||
if (!writeAndVerify(sysFsPath,governor))
|
||||
{
|
||||
throw PiPedalException(SS("Write to " << sysFsPath << " failed."));
|
||||
break;
|
||||
}
|
||||
++nCpu;
|
||||
}
|
||||
}
|
||||
std::vector<std::string> pipedal::GetAvailableGovernors() {
|
||||
return std::vector<std::string> {
|
||||
"performance",
|
||||
"ondemand",
|
||||
"powersave"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void SetCpuGovernor(const std::string &governor);
|
||||
|
||||
std::vector<std::string> GetAvailableGovernors();
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pipedal {
|
||||
std::string GetCpuGovernor();
|
||||
|
||||
void SetCpuGovernor(const std::string &governor);
|
||||
|
||||
std::vector<std::string> GetAvailableGovernors();
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "GovernorSettings.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
JSON_MAP_BEGIN(GovernorSettings)
|
||||
JSON_MAP_REFERENCE(GovernorSettings, governor)
|
||||
JSON_MAP_REFERENCE(GovernorSettings, governors)
|
||||
JSON_MAP_END()
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class GovernorSettings {
|
||||
public:
|
||||
std::string governor_;
|
||||
std::vector<std::string> governors_;
|
||||
|
||||
DECLARE_JSON_MAP(GovernorSettings);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "Ipv6Helpers.hpp"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ss.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <memory.h>
|
||||
#include <exception>
|
||||
#include <netdb.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress);
|
||||
|
||||
static bool IsIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||
{
|
||||
return IN6_IS_ADDR_V4MAPPED(&inetAddr6) != 0;
|
||||
}
|
||||
static uint32_t GetIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||
{
|
||||
if (!IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t *p = (uint8_t *)&inetAddr6;
|
||||
return htonl(*(uint32_t *)(p + 12));
|
||||
}
|
||||
static bool ipv6NetmaskCompare(const struct in6_addr &left, const struct in6_addr &right, const struct in6_addr &mask)
|
||||
{
|
||||
uint8_t *pLeft = (uint8_t *)&left;
|
||||
uint8_t *pRight = (uint8_t *)&right;
|
||||
uint8_t *pMask = (uint8_t *)&mask;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if ((pLeft[i] & pMask[i]) != (pRight[i] & pMask[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsIpv4OnLocalSubnet(uint32_t ipv4Addres)
|
||||
{
|
||||
bool result = false;
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return false;
|
||||
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & ipv4Addres))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string StripPortNumber(const std::string &fromAddress)
|
||||
{
|
||||
std::string address = fromAddress;
|
||||
|
||||
if (address.size() == 0)
|
||||
return fromAddress;
|
||||
|
||||
char lastChar = address[address.size() - 1];
|
||||
size_t pos = address.find_last_of(':');
|
||||
|
||||
// if ipv6, make sure we found an actual port address.
|
||||
size_t posBracket = address.find_last_of(']');
|
||||
if (posBracket != std::string::npos && pos != std::string::npos)
|
||||
{
|
||||
if (posBracket > pos)
|
||||
{
|
||||
pos = std::string::npos;
|
||||
}
|
||||
}
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
bool pipedal::IsOnLocalSubnet(const std::string &fromAddress)
|
||||
{
|
||||
std::string address = StripPortNumber(fromAddress);
|
||||
if (address.length() == 0)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
if (address[0] != '[')
|
||||
{
|
||||
// ipv4
|
||||
struct in_addr inetAddr;
|
||||
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||
{
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
|
||||
result = IsIpv4OnLocalSubnet(remoteAddress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ipv6
|
||||
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||
return false;
|
||||
address = address.substr(1, address.length() - 2);
|
||||
// strip scope if neccessary.
|
||||
auto pos = address.find_last_of('%');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
|
||||
struct in6_addr inetAddr6;
|
||||
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||
{
|
||||
int32_t remoteAddress = -1;
|
||||
// cases:
|
||||
// [::FFFF:ipv4 address]
|
||||
// [FE80:: ] link local.
|
||||
// [FEC0:: ] site local.
|
||||
// others?
|
||||
if (IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||
return IsIpv4OnLocalSubnet(remoteAddress);
|
||||
}
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#if JUNK
|
||||
// if the address is global, we have to reject it.
|
||||
// no point in going further.
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return false;
|
||||
|
||||
const int SITE_LOCAL_SCOPE = 5;
|
||||
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{
|
||||
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||
if (pAddr->sin6_scope_id <= SITE_LOCAL_SCOPE)
|
||||
{
|
||||
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetInterfaceForIp4Address(uint32_t ipv4Address)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & ipv4Address))
|
||||
{
|
||||
result = p->ifa_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetInterfaceForIp6Address(const in6_addr inetAddr6)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||
{
|
||||
result = p->ifa_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetLinkLocalAddressForInterface(const std::string &name)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&(pAddr->sin6_addr)))
|
||||
{
|
||||
if (name.length() == 0 || name == p->ifa_name)
|
||||
{
|
||||
const int BUFSIZE = 128;
|
||||
char host[BUFSIZE];
|
||||
if (getnameinfo(p->ifa_addr, sizeof(struct sockaddr_in6), host, BUFSIZE, NULL, 0, NI_NUMERICHOST) == 0)
|
||||
{
|
||||
host[BUFSIZE - 1] = '\0';
|
||||
|
||||
// trim the interface spec if present
|
||||
for (char *p = host; *p != 0; ++p)
|
||||
{
|
||||
if (*p == '%')
|
||||
{
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = SS('[' << host << ']');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress)
|
||||
{
|
||||
std::string address = StripPortNumber(fromAddress);
|
||||
|
||||
std::string result;
|
||||
if (address[0] != '[')
|
||||
{
|
||||
// ipv4
|
||||
struct in_addr inetAddr;
|
||||
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||
{
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
std::string interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ipv6
|
||||
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||
throw std::invalid_argument("Bad address.");
|
||||
address = address.substr(1, address.length() - 2);
|
||||
// strip scope if neccessary.
|
||||
auto pos = address.find_last_of('%');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
|
||||
struct in6_addr inetAddr6;
|
||||
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||
{
|
||||
int32_t remoteAddress = -1;
|
||||
// cases:
|
||||
// [::FFFF:ipv4 address]
|
||||
// [FE80:: ] link local.
|
||||
// [FEC0:: ] site local.
|
||||
// others?
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||
{
|
||||
return address;
|
||||
}
|
||||
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
std::string interfaceName;
|
||||
if (IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||
interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
interfaceName = GetInterfaceForIp6Address(inetAddr6);
|
||||
}
|
||||
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||
}
|
||||
}
|
||||
if (result == "")
|
||||
{
|
||||
result = GetLinkLocalAddressForInterface("");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
std::string GetLinkLocalAddress(const std::string fromAddress);
|
||||
|
||||
bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||
|
||||
|
||||
}
|
||||
+2
-9
@@ -33,6 +33,7 @@ using namespace pipedal;
|
||||
#include <thread>
|
||||
#include <semaphore.h>
|
||||
#include "VuUpdate.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
|
||||
#include "RingBuffer.hpp"
|
||||
#include "RingBufferReader.hpp"
|
||||
@@ -99,15 +100,7 @@ static void GetCpuFrequency(uint64_t*freqMin,uint64_t*freqMax)
|
||||
}
|
||||
static std::string GetGovernor()
|
||||
{
|
||||
std::string result;
|
||||
try {
|
||||
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
||||
f >> result;
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
return pipedal::GetCpuGovernor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+59
-8
@@ -26,6 +26,7 @@
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "SplitEffect.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
|
||||
#ifndef NO_MLOCK
|
||||
#include <sys/mman.h>
|
||||
@@ -76,14 +77,31 @@ void PiPedalModel::Close()
|
||||
|
||||
PiPedalModel::~PiPedalModel()
|
||||
{
|
||||
CurrentPreset currentPreset;
|
||||
currentPreset.modified_ = this->hasPresetChanged;
|
||||
currentPreset.preset_ = this->pedalBoard;
|
||||
storage.SaveCurrentPreset(currentPreset);
|
||||
|
||||
if (jackHost)
|
||||
try {
|
||||
ShutdownClient::UnmonitorGovernor();
|
||||
} catch (...) // noexcept here!
|
||||
{
|
||||
jackHost->Close();
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
CurrentPreset currentPreset;
|
||||
currentPreset.modified_ = this->hasPresetChanged;
|
||||
currentPreset.preset_ = this->pedalBoard;
|
||||
storage.SaveCurrentPreset(currentPreset);
|
||||
} catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
if (jackHost)
|
||||
{
|
||||
jackHost->Close();
|
||||
}
|
||||
} catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +152,7 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
this->webRoot = configuration.GetWebRoot();
|
||||
this->jackServerSettings.ReadJackConfiguration();
|
||||
|
||||
|
||||
ShutdownClient::MonitorGovernor(storage.GetGovernorSettings());
|
||||
|
||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||
|
||||
@@ -594,6 +612,39 @@ bool PiPedalModel::RenamePreset(int64_t clientId, int64_t instanceId, const std:
|
||||
}
|
||||
}
|
||||
|
||||
GovernorSettings PiPedalModel::GetGovernorSettings()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
GovernorSettings result;
|
||||
result.governor_ = storage.GetGovernorSettings();
|
||||
result.governors_ = pipedal::GetAvailableGovernors();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
ShutdownClient::SetGovernorSettings(governor);
|
||||
|
||||
this->storage.SetGovernorSettings(governor);
|
||||
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
{
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
}
|
||||
size_t n = this->subscribers.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->OnGovernorSettingsChanged(governor);
|
||||
}
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include "Lv2Host.hpp"
|
||||
#include "GovernorSettings.hpp"
|
||||
#include "PedalBoard.hpp"
|
||||
#include "Storage.hpp"
|
||||
#include "Banks.hpp"
|
||||
@@ -57,6 +58,7 @@ public:
|
||||
virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0;
|
||||
virtual void OnNotifyAtomOutput(int64_t clientModel,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) = 0;
|
||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0;
|
||||
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
@@ -193,6 +195,9 @@ public:
|
||||
|
||||
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
||||
WifiConfigSettings GetWifiConfigSettings();
|
||||
|
||||
void SetGovernorSettings(const std::string& governor);
|
||||
GovernorSettings GetGovernorSettings();
|
||||
|
||||
|
||||
|
||||
|
||||
+20
-1
@@ -28,6 +28,7 @@
|
||||
#include "JackConfiguration.hpp"
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
@@ -804,6 +805,17 @@ public:
|
||||
this->Reply(replyTo,"setJackserverSettings");
|
||||
|
||||
}
|
||||
else if (message == "setGovernorSettings") {
|
||||
std::string governor;
|
||||
pReader->read(&governor);
|
||||
std::string fromAddress = this->getFromAddress();
|
||||
if (!IsOnLocalSubnet(fromAddress))
|
||||
{
|
||||
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||
}
|
||||
this->model.SetGovernorSettings(governor);
|
||||
this->Reply(replyTo,"setGovernorSettings");
|
||||
}
|
||||
else if (message == "setWifiConfigSettings") {
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
pReader->read(&wifiConfigSettings);
|
||||
@@ -812,7 +824,7 @@ public:
|
||||
throw PiPedalException("Can't change server settings when running interactively.");
|
||||
}
|
||||
std::string fromAddress = this->getFromAddress();
|
||||
if (!ShutdownClient::IsOnLocalSubnet(fromAddress))
|
||||
if (!IsOnLocalSubnet(fromAddress))
|
||||
{
|
||||
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||
}
|
||||
@@ -824,6 +836,10 @@ public:
|
||||
else if (message == "getWifiConfigSettings") {
|
||||
this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings());
|
||||
|
||||
}
|
||||
else if (message == "getGovernorSettings") {
|
||||
this->Reply(replyTo, "getGovernorSettings", model.GetGovernorSettings());
|
||||
|
||||
}
|
||||
|
||||
else if (message == "getJackServerSettings") {
|
||||
@@ -1461,6 +1477,9 @@ public:
|
||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) {
|
||||
Send("onWifiConfigSettingsChanged",wifiConfigSettings);
|
||||
}
|
||||
virtual void OnGovernorSettingsChanged(const std::string& governor) {
|
||||
Send("onGovernorSettingsChanged",governor);
|
||||
}
|
||||
|
||||
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard)
|
||||
{
|
||||
|
||||
+52
-46
@@ -27,6 +27,7 @@
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
|
||||
using namespace pipedal;
|
||||
@@ -165,57 +166,12 @@ bool ShutdownClient::SetJackServerConfiguration(const JackServerSettings & jackS
|
||||
return WriteMessage(s.str().c_str());
|
||||
}
|
||||
|
||||
bool ShutdownClient::IsOnLocalSubnet(const std::string&fromAddress)
|
||||
{
|
||||
std::string address = fromAddress;
|
||||
if (address.size() == 0) return false;
|
||||
char lastChar = address[address.size()-1];
|
||||
if (address[0] != '[' || lastChar != ']') // i.e. not an ipv6 address;
|
||||
{
|
||||
size_t pos = address.find_last_of(':');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0,pos);
|
||||
}
|
||||
}
|
||||
if (address[0] == '[') return false;
|
||||
|
||||
char buf[512];
|
||||
|
||||
struct in_addr inetAddr;
|
||||
|
||||
memset(&inetAddr,0,sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET,address.c_str(),&inetAddr) == 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0) return false;
|
||||
|
||||
bool result = false;
|
||||
for (ifaddrs*p = ifap; p != nullptr; p = p->ifa_next) {
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr) { // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in*)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in*)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & remoteAddress))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||
throw PiPedalException("Can't perform this operation when debugging.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiConfigSettings ";
|
||||
@@ -227,3 +183,53 @@ void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownClient::SetGovernorSettings(const std::string & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "GovernorSettings ";
|
||||
json_writer writer(cmd,true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownClient::MonitorGovernor(const std::string &governor)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "MonitorGovernor ";
|
||||
json_writer writer(cmd,true);
|
||||
writer.write(governor);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
|
||||
}
|
||||
void ShutdownClient::UnmonitorGovernor()
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "UnmonitorGovernor";
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,17 @@
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
class ShutdownClient {
|
||||
static bool WriteMessage(const char*message);
|
||||
public:
|
||||
static bool CanUseShutdownClient();
|
||||
static bool RequestShutdown(bool restart);
|
||||
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||
static bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||
static void SetWifiConfig(const WifiConfigSettings & settings);
|
||||
static void SetGovernorSettings(const std::string & governor);
|
||||
static void MonitorGovernor(const std::string &governor);
|
||||
static void UnmonitorGovernor();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
+212
-103
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -40,7 +41,10 @@
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "SysExec.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
@@ -50,15 +54,122 @@ using ip::tcp;
|
||||
|
||||
const size_t MAX_LENGTH = 128;
|
||||
|
||||
|
||||
|
||||
static bool startsWith(const std::string&s, const char*text)
|
||||
class GovernorMonitorThread
|
||||
{
|
||||
if (s.length() < strlen(text)) return false;
|
||||
const char*sp = s.c_str();
|
||||
public:
|
||||
~GovernorMonitorThread()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
void Start(std::string governor)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (!pThread)
|
||||
{
|
||||
this->governor = governor;
|
||||
cancelled = false;
|
||||
wake = false;
|
||||
pThread = std::make_unique<std::thread>([this]()
|
||||
{ this->ServiceProc(); });
|
||||
} else {
|
||||
this->governor = governor;
|
||||
wake = true;
|
||||
|
||||
lock.unlock();
|
||||
cv.notify_one();
|
||||
}
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (pThread)
|
||||
{
|
||||
wake = true;
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
|
||||
cv.notify_one();
|
||||
pThread->join();
|
||||
pThread.reset();
|
||||
}
|
||||
}
|
||||
void SetGovernor(const std::string &governor)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
wake = true;
|
||||
this->governor = governor;
|
||||
}
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
bool wake = false;
|
||||
bool cancelled = false;
|
||||
std::string savedGovernor;
|
||||
void ServiceProc()
|
||||
{
|
||||
savedGovernor = pipedal::GetCpuGovernor();
|
||||
pipedal::SetCpuGovernor(this->governor);
|
||||
while (true)
|
||||
{
|
||||
bool cancelled;
|
||||
std::string governor;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
auto timeToWaitFor = std::chrono::system_clock::now() + 5000ms;
|
||||
cv.wait_until(
|
||||
lock,
|
||||
timeToWaitFor,
|
||||
[this]()
|
||||
{ return wake; });
|
||||
wake = false;
|
||||
governor = this->governor;
|
||||
cancelled = this->cancelled;
|
||||
}
|
||||
if (cancelled) {
|
||||
break;
|
||||
}
|
||||
std::string activeGovernor = pipedal::GetCpuGovernor();
|
||||
if (activeGovernor != governor)
|
||||
{
|
||||
// somebody set it so they must have wanted it.
|
||||
// save the value so that we can restore it when done.
|
||||
savedGovernor = activeGovernor;
|
||||
|
||||
// but insist on using ours!!
|
||||
pipedal::SetCpuGovernor(governor);
|
||||
}
|
||||
}
|
||||
pipedal::SetCpuGovernor(savedGovernor);
|
||||
}
|
||||
std::unique_ptr<std::thread> pThread;
|
||||
std::string governor;
|
||||
std::mutex mutex;
|
||||
bool canceled;
|
||||
std::condition_variable cv;
|
||||
};
|
||||
|
||||
GovernorMonitorThread governorMonitorThread;
|
||||
|
||||
void StopGovernorMonitorThread()
|
||||
{
|
||||
governorMonitorThread.Stop();
|
||||
}
|
||||
void StartGovernorMonitorThread(const std::string&governor)
|
||||
{
|
||||
governorMonitorThread.Start(governor);
|
||||
}
|
||||
|
||||
static bool startsWith(const std::string &s, const char *text)
|
||||
{
|
||||
if (s.length() < strlen(text))
|
||||
return false;
|
||||
const char *sp = s.c_str();
|
||||
while (*text)
|
||||
{
|
||||
if (*text++ != *sp++) return false;
|
||||
if (*text++ != *sp++)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -67,7 +178,7 @@ static std::vector<std::string> tokenize(std::string value)
|
||||
std::vector<std::string> result;
|
||||
std::stringstream s(value);
|
||||
std::string item;
|
||||
while (std::getline(s,item,' '))
|
||||
while (std::getline(s, item, ' '))
|
||||
{
|
||||
if (item.length() != 0)
|
||||
result.push_back(item);
|
||||
@@ -75,26 +186,17 @@ static std::vector<std::string> tokenize(std::string value)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void CaptureAccessPoint(const std::string gatewayAddress)
|
||||
{
|
||||
|
||||
}
|
||||
static void ReleaseAccessPoint(const std::string gatewayAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void delayedRestartProc()
|
||||
static void delayedRestartProc()
|
||||
{
|
||||
sleep(1); // give a chance for websocket messages to propagate.
|
||||
Lv2Log::error("Delayed Restart");
|
||||
std::string pipedalConfigPath = std::filesystem::path(getSelfExePath()).parent_path() / "pipedalconfig";
|
||||
|
||||
std::stringstream s;
|
||||
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
||||
if (::system(s.str().c_str())!= EXIT_SUCCESS)
|
||||
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
||||
if (::system(s.str().c_str()) != EXIT_SUCCESS)
|
||||
{
|
||||
Lv2Log::error("Delayed Restart failed.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +212,6 @@ bool setJackConfiguration(JackServerSettings serverSettings)
|
||||
std::thread delayedRestartThread(delayedRestartProc);
|
||||
delayedRestartThread.detach();
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Reader : public std::enable_shared_from_this<Reader>
|
||||
@@ -162,7 +262,7 @@ private:
|
||||
return;
|
||||
}
|
||||
socket.async_write_some(
|
||||
boost::asio::buffer(response.c_str()+ writePosition, response.length()-writePosition),
|
||||
boost::asio::buffer(response.c_str() + writePosition, response.length() - writePosition),
|
||||
boost::bind(&Reader::HandleWrite,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
@@ -185,7 +285,7 @@ private:
|
||||
if (c == '\n')
|
||||
{
|
||||
std::string command = message.str();
|
||||
cout << "Received command: " << command << endl;
|
||||
cout << command << endl;
|
||||
HandleCommand(command);
|
||||
socket.close();
|
||||
return;
|
||||
@@ -202,59 +302,88 @@ private:
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
void HandleCommand(const std::string &s)
|
||||
void HandleCommand(const std::string &text)
|
||||
{
|
||||
int result = -1;
|
||||
try {
|
||||
if (startsWith(s,"WifiConfigSettings "))
|
||||
std::string command;
|
||||
std::string args;
|
||||
auto pos = text.find_first_of(' ');
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
command = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = text.substr(0, pos);
|
||||
args = text.substr(pos + 1);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (command == "UnmonitorGovernor")
|
||||
{
|
||||
std::string json = s.substr(strlen("WifiConfigSettings "));
|
||||
std::stringstream ss(json);
|
||||
StopGovernorMonitorThread();
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "MonitorGovernor")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
std::string governor;
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&governor);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
StartGovernorMonitorThread(governor);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "GovernorSettings")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
std::string governor;
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&governor);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
governorMonitorThread.SetGovernor(governor);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "WifiConfigSettings ")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
WifiConfigSettings settings;
|
||||
try {
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&settings);
|
||||
} catch (const std::exception &e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
pipedal::SetWifiConfig(settings);
|
||||
result = 0;
|
||||
|
||||
} else if (startsWith(s,"release_ap "))
|
||||
{
|
||||
std::vector<std::string> argv = tokenize(s);
|
||||
if (argv.size() == 2) {
|
||||
ReleaseAccessPoint(argv[1]);
|
||||
result = 0;
|
||||
} else {
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
|
||||
} else if (startsWith(s,"capture_ap "))
|
||||
{
|
||||
std::vector<std::string> argv = tokenize(s);
|
||||
if (argv.size() == 2) {
|
||||
CaptureAccessPoint(argv[1]);
|
||||
result = 0;
|
||||
} else {
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
|
||||
|
||||
} else if (s == "shutdown")
|
||||
}
|
||||
else if (command == "shutdown")
|
||||
{
|
||||
result = sysExec("/usr/sbin/shutdown -P now");
|
||||
}
|
||||
else if (s == "restart")
|
||||
else if (command == "restart")
|
||||
{
|
||||
result = sysExec("/usr/sbin/shutdown -r now");
|
||||
} else if (startsWith(s,"setJackConfiguration "))
|
||||
}
|
||||
else if (command == "setJackConfiguration")
|
||||
{
|
||||
auto remainder = s.substr(strlen("setJackConfiguration "));
|
||||
|
||||
|
||||
std::stringstream input(remainder);
|
||||
std::stringstream input(args);
|
||||
JackServerSettings serverSettings;
|
||||
json_reader reader(input);
|
||||
|
||||
@@ -263,12 +392,18 @@ private:
|
||||
if (input.fail())
|
||||
{
|
||||
result = -1;
|
||||
} else {
|
||||
result = setJackConfiguration(serverSettings) ? 0: -1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
result = setJackConfiguration(serverSettings) ? 0 : -1;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e)
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument(SS("Unknown command:" << command));
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::stringstream t;
|
||||
t << "-2 " << e.what() << "\n";
|
||||
@@ -284,7 +419,6 @@ private:
|
||||
this->writePosition = 0;
|
||||
WriteSome();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Server
|
||||
@@ -314,16 +448,16 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
//constructor for accepting connection from client
|
||||
// constructor for accepting connection from client
|
||||
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
|
||||
: acceptor_(io_service, endpoint),
|
||||
io_service(io_service)
|
||||
io_service(io_service)
|
||||
|
||||
{
|
||||
StartAccept();
|
||||
}
|
||||
~Server() {
|
||||
|
||||
~Server()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -332,29 +466,26 @@ void runServer(uint16_t port)
|
||||
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
|
||||
asio::io_service ios;
|
||||
|
||||
try {
|
||||
Server server(ios,endpoint);
|
||||
try
|
||||
{
|
||||
Server server(ios, endpoint);
|
||||
ios.run();
|
||||
cout << "Processing terminated." << endl;
|
||||
} catch (const std::exception & e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
cout << "Error: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Lv2Log::set_logger(MakeLv2SystemdLogger());
|
||||
CommandLineParser parser;
|
||||
|
||||
uint16_t port = 0;
|
||||
std::string captureAccessPoint;
|
||||
std::string releaseAccessPoint;
|
||||
|
||||
parser.AddOption("-port", &port);
|
||||
parser.AddOption("-captureAP",&captureAccessPoint);
|
||||
parser.AddOption("-releaseAP",&releaseAccessPoint);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -369,34 +500,12 @@ int main(int argc, char **argv)
|
||||
cout << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (captureAccessPoint.length() != 0)
|
||||
if (port == 0)
|
||||
{
|
||||
try{
|
||||
CaptureAccessPoint(captureAccessPoint);
|
||||
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Access point captured." << std::endl;
|
||||
} else if (releaseAccessPoint.length() != 0)
|
||||
{
|
||||
try{
|
||||
ReleaseAccessPoint(releaseAccessPoint);
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Access point released." << std::endl;
|
||||
|
||||
} else {
|
||||
if (port == 0) {
|
||||
std::cerr << "Error: port not specified." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
runServer(port);
|
||||
std::cerr << "Error: port not specified." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
runServer(port);
|
||||
governorMonitorThread.Stop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ const char *BANK_EXTENSION = ".bank";
|
||||
const char *BANKS_FILENAME = "index.banks";
|
||||
|
||||
#define WIFI_CONFIG_SETTINGS_FILENAME "wifiConfigSettings.json";
|
||||
#define GOVERNOR_SETTINGS_FILENAME "governorSettings.json";
|
||||
|
||||
Storage::Storage()
|
||||
{
|
||||
@@ -182,6 +183,7 @@ void Storage::Initialize()
|
||||
{
|
||||
}
|
||||
LoadWifiConfigSettings();
|
||||
LoadGovernorSettings();
|
||||
}
|
||||
|
||||
|
||||
@@ -802,6 +804,25 @@ int64_t Storage::UploadBank(BankFile&bankFile,int64_t uploadAfter)
|
||||
return lastBank;
|
||||
}
|
||||
|
||||
void Storage::SetGovernorSettings(const std::string & governor)
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||
{
|
||||
std::ofstream f(path);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||
}
|
||||
json_writer writer(f);
|
||||
writer.write(governor);
|
||||
this->governorSettings = governor;
|
||||
}
|
||||
}
|
||||
std::string Storage::GetGovernorSettings() const
|
||||
{
|
||||
return this->governorSettings;
|
||||
}
|
||||
|
||||
|
||||
void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings)
|
||||
{
|
||||
@@ -839,7 +860,30 @@ void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSetting
|
||||
}
|
||||
this->wifiConfigSettings = copyToStore;
|
||||
}
|
||||
void Storage::LoadGovernorSettings()
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||
|
||||
try {
|
||||
if (std::filesystem::is_regular_file(path))
|
||||
{
|
||||
std::ifstream f(path);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||
}
|
||||
json_reader reader(f);
|
||||
std::string governorSettings;
|
||||
reader.read(&governorSettings);
|
||||
this->governorSettings = governorSettings;
|
||||
}
|
||||
} catch (const std::exception&)
|
||||
{
|
||||
this->governorSettings = "performance";
|
||||
}
|
||||
this->wifiConfigSettings.valid_ = true;
|
||||
|
||||
}
|
||||
void Storage::LoadWifiConfigSettings()
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
|
||||
@@ -1137,6 +1181,7 @@ uint64_t Storage::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId
|
||||
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(CurrentPreset)
|
||||
JSON_MAP_REFERENCE(CurrentPreset,modified)
|
||||
JSON_MAP_REFERENCE(CurrentPreset,preset)
|
||||
|
||||
@@ -72,6 +72,7 @@ private:
|
||||
bool isJackChannelSelectionValid = false;
|
||||
JackChannelSelection jackChannelSelection;
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
std::string governorSettings = "performance";
|
||||
public:
|
||||
Storage();
|
||||
void Initialize();
|
||||
@@ -85,6 +86,7 @@ public:
|
||||
|
||||
|
||||
void LoadWifiConfigSettings();
|
||||
void LoadGovernorSettings();
|
||||
void LoadBank(int64_t instanceId);
|
||||
const PedalBoard& GetCurrentPreset();
|
||||
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
||||
@@ -116,6 +118,10 @@ public:
|
||||
void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
|
||||
WifiConfigSettings GetWifiConfigSettings();
|
||||
|
||||
void SetGovernorSettings(const std::string & governor);
|
||||
std::string GetGovernorSettings() const;
|
||||
|
||||
|
||||
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
||||
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
||||
|
||||
|
||||
+35
-5
@@ -27,12 +27,13 @@
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <filesystem>
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "Shutdown.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "Lv2SystemdLogger.hpp"
|
||||
#include <sys/stat.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include "HtmlHelper.hpp"
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
#include <signal.h>
|
||||
#include <semaphore.h>
|
||||
@@ -406,19 +407,26 @@ public:
|
||||
class InterceptConfig : public RequestHandler
|
||||
{
|
||||
private:
|
||||
std::string response;
|
||||
uint64_t maxUploadSize;
|
||||
int portNumber;
|
||||
|
||||
public:
|
||||
InterceptConfig(int portNumber, uint64_t maxUploadSize)
|
||||
: RequestHandler("/var/config.json"),
|
||||
maxUploadSize(maxUploadSize)
|
||||
maxUploadSize(maxUploadSize),
|
||||
portNumber(portNumber)
|
||||
{
|
||||
}
|
||||
std::string GetConfig(const std::string&fromAddress)
|
||||
{
|
||||
std::string linkLocalAddress = GetLinkLocalAddress(fromAddress);
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
s << "{ \"socket_server_port\": " << portNumber
|
||||
<< ", \"socket_server_address\": \"*\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
response = s.str();
|
||||
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
virtual ~InterceptConfig() {}
|
||||
|
||||
@@ -428,6 +436,17 @@ public:
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. See the other overload.
|
||||
}
|
||||
|
||||
virtual void head_response(
|
||||
const std::string &fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::string response = GetConfig(fromAddress);
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(response.length());
|
||||
@@ -439,7 +458,18 @@ public:
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. see the other overload.
|
||||
}
|
||||
|
||||
virtual void get_response(
|
||||
const std::string&fromAddress,
|
||||
const uri &request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::string response = GetConfig(fromAddress);
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(response.length());
|
||||
|
||||
@@ -53,5 +53,4 @@ template <typename T> class TypeDisplay;
|
||||
#include "lv2/parameters.lv2/parameters.h"
|
||||
#include "lv2/units.lv2/units.h"
|
||||
*/
|
||||
|
||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||
#include "ss.hpp"
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// usage: SS("xyz" << 123 << 45.6) returning a std::string rvalue.
|
||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||
Reference in New Issue
Block a user