Hotspot UI
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
"socketServerAddress": "0.0.0.0:8080",
|
||||
|
||||
/* Number of threads to use for servicing websockets */
|
||||
"threads" : 5,
|
||||
"threads" : 3,
|
||||
|
||||
"logHttpRequests": true,
|
||||
/* { None=0,Error =1,Warning =2,Info = 3, Debug=4} */
|
||||
|
||||
@@ -1 +1 @@
|
||||
cmake --install /home/patch/src/pipedal/build --prefix /usr/local --config RelWithDebInfo
|
||||
cmake --install /home/patch/src/pipedal/build --prefix /usr/local --config Release
|
||||
|
||||
@@ -82,6 +82,20 @@ add_custom_command(
|
||||
src/NoChangePassword.tsx
|
||||
src/XxxSnippet.tsx
|
||||
|
||||
public/css/roboto.css
|
||||
public/fonts/Roboto-BlackItalic.woff2
|
||||
public/fonts/Roboto-Black.woff2
|
||||
public/fonts/Roboto-BoldItalic.woff2
|
||||
public/fonts/Roboto-Bold.woff2
|
||||
public/fonts/Roboto-Italic.woff2
|
||||
public/fonts/Roboto-LightItalic.woff2
|
||||
public/fonts/Roboto-Light.woff2
|
||||
public/fonts/Roboto-MediumItalic.woff2
|
||||
public/fonts/Roboto-Medium.woff2
|
||||
public/fonts/Roboto-Regular.woff2
|
||||
public/fonts/Roboto-ThinItalic.woff2
|
||||
public/fonts/Roboto-Thin.woff2
|
||||
|
||||
public/iso_codes.json
|
||||
public/logo512.png
|
||||
public/index.html
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Roboto-Light.woff2) format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Roboto-Regular.woff2) format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Roboto-Medium.woff2) format('woff2');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(/fonts/Roboto-Bold.woff2) format('woff2');
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,11 @@
|
||||
name="description"
|
||||
content="PiPedal Guitar Pedals"
|
||||
/>
|
||||
<!--
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
|
||||
-->
|
||||
<link rel="stylesheet" href="/css/roboto.css" />
|
||||
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
|
||||
@@ -28,7 +28,7 @@ export type CloseEventHandler = () => void;
|
||||
export type OkEventHandler = (pluginUri: string) => void;
|
||||
|
||||
const NARROW_DISPLAY_THRESHOLD = 600;
|
||||
const FILTER_STORAGE_KEY = "com.twoplay.piddle.load_dlg.filter";
|
||||
const FILTER_STORAGE_KEY = "com.twoplay.pipedal.load_dlg.filter";
|
||||
|
||||
|
||||
const pluginGridStyles = (theme: Theme) => createStyles({
|
||||
|
||||
@@ -29,7 +29,7 @@ export type CloseEventHandler = () => void;
|
||||
export type OkEventHandler = (pluginUri: string) => void;
|
||||
|
||||
const NARROW_DISPLAY_THRESHOLD = 600;
|
||||
const FILTER_STORAGE_KEY = "com.twoplay.piddle.load_dlg.filter";
|
||||
const FILTER_STORAGE_KEY = "com.twoplay.pipedal.load_dlg.filter";
|
||||
|
||||
const Transition = React.forwardRef(function Transition(
|
||||
props: TransitionProps & { children?: React.ReactElement },
|
||||
|
||||
@@ -19,6 +19,7 @@ interface NoChangePasswordProps {
|
||||
disabled?: boolean;
|
||||
helperText?: string;
|
||||
error?: boolean;
|
||||
inputRef?: React.RefObject<any>
|
||||
};
|
||||
|
||||
interface NoChangePasswordState {
|
||||
@@ -88,6 +89,7 @@ class NoChangePassword extends React.Component<NoChangePasswordProps, NoChangePa
|
||||
color="primary"
|
||||
spellCheck="false"
|
||||
autoComplete="off"
|
||||
inputRef={this.props.inputRef}
|
||||
readOnly
|
||||
id="standard-adornment-password"
|
||||
onChange={(e) => this.handleChange(e)}
|
||||
|
||||
@@ -2,8 +2,8 @@ import { PiPedalArgumentError } from './PiPedalError';
|
||||
import MidiBinding from './MidiBinding';
|
||||
|
||||
|
||||
const SPLIT_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Split";
|
||||
const EMPTY_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Empty";
|
||||
const SPLIT_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Split";
|
||||
const EMPTY_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Empty";
|
||||
|
||||
|
||||
interface Deserializable<T> {
|
||||
|
||||
@@ -16,8 +16,8 @@ import {
|
||||
PedalBoard, PedalBoardItem, PedalBoardSplitItem, SplitType,
|
||||
} from './PedalBoard';
|
||||
|
||||
const START_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#Start";
|
||||
const END_PEDALBOARD_ITEM_URI = "uri://two-play/piddle/pedalboard#End";
|
||||
const START_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#Start";
|
||||
const END_PEDALBOARD_ITEM_URI = "uri://two-play/pipedal/pedalboard#End";
|
||||
|
||||
const ENABLED_CONNECTOR_COLOR = "#666";
|
||||
const DISABLED_CONNECTOR_COLOR = "#CCC";
|
||||
|
||||
+20
-25
@@ -599,20 +599,18 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
|
||||
}
|
||||
|
||||
maxUploadSize: number = 512*1024;
|
||||
maxUploadSize: number = 512 * 1024;
|
||||
|
||||
requestConfig(): Promise<boolean> {
|
||||
const myRequest = new Request(this.varRequest('config.json'));
|
||||
return fetch(myRequest)
|
||||
.then(
|
||||
(response) =>
|
||||
{
|
||||
(response) => {
|
||||
return response.json();
|
||||
}
|
||||
)
|
||||
.then(data => {
|
||||
if (data.max_upload_size)
|
||||
{
|
||||
if (data.max_upload_size) {
|
||||
this.maxUploadSize = data.max_upload_size;
|
||||
}
|
||||
let { socket_server_port, socket_server_address } = data;
|
||||
@@ -1421,8 +1419,7 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
uploadPreset(file: File, uploadAfter: number): Promise<number> {
|
||||
let result = new Promise<number>((resolve, reject) => {
|
||||
try {
|
||||
if (file.size > this.maxUploadSize)
|
||||
{
|
||||
if (file.size > this.maxUploadSize) {
|
||||
reject("File is too large.");
|
||||
}
|
||||
let url = this.varServerUrl + "uploadPreset";
|
||||
@@ -1460,26 +1457,24 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
});
|
||||
return result;
|
||||
}
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void>
|
||||
{
|
||||
let result = new Promise<void>((resolve,reject) =>{
|
||||
setWifiConfigSettings(wifiConfigSettings: WifiConfigSettings): Promise<void> {
|
||||
let result = new Promise<void>((resolve, reject) => {
|
||||
let oldSettings = this.wifiConfigSettings.get();
|
||||
wifiConfigSettings = wifiConfigSettings.clone();
|
||||
|
||||
if ((!oldSettings.enable) && (!wifiConfigSettings.enable))
|
||||
{
|
||||
if ((!oldSettings.enable) && (!wifiConfigSettings.enable)) {
|
||||
// no effective change.
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
let countryCodeChanged = wifiConfigSettings.countryCode !== oldSettings.countryCode;
|
||||
if (!wifiConfigSettings.enable)
|
||||
{
|
||||
if (!wifiConfigSettings.enable) {
|
||||
wifiConfigSettings.hasPassword = false;
|
||||
wifiConfigSettings.hotspotName = oldSettings.hotspotName;
|
||||
} else {
|
||||
if (wifiConfigSettings.countryCode === oldSettings.countryCode
|
||||
&& wifiConfigSettings.channel === oldSettings.channel
|
||||
&& wifiConfigSettings.hotspotName === oldSettings.hotspotName) {
|
||||
if (!wifiConfigSettings.hasPassword) {
|
||||
if (wifiConfigSettings.hotspotName === oldSettings.hotspotName && !countryCodeChanged) {
|
||||
// no effective change.
|
||||
resolve();
|
||||
return;
|
||||
@@ -1488,13 +1483,14 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
}
|
||||
// save a version for the server (potentially carrying a password)
|
||||
let serverConfigSettings = wifiConfigSettings.clone();
|
||||
wifiConfigSettings.password = "";
|
||||
this.wifiConfigSettings.set(wifiConfigSettings);
|
||||
|
||||
|
||||
|
||||
// notify the server.
|
||||
let ws = this.webSocket;
|
||||
if (!ws)
|
||||
{
|
||||
if (!ws) {
|
||||
reject("Not connected.");
|
||||
return;
|
||||
}
|
||||
@@ -1502,10 +1498,10 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
"setWifiConfigSettings",
|
||||
serverConfigSettings
|
||||
)
|
||||
.then(()=> {
|
||||
.then(() => {
|
||||
resolve();
|
||||
})
|
||||
.catch((err) =>{
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
@@ -1513,18 +1509,17 @@ class PiPedalModelImpl implements PiPedalModel {
|
||||
return result;
|
||||
}
|
||||
|
||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]>
|
||||
{
|
||||
let result = new Promise<WifiChannel[]>((resolve,reject) => {
|
||||
getWifiChannels(countryIso3661: string): Promise<WifiChannel[]> {
|
||||
let result = new Promise<WifiChannel[]>((resolve, reject) => {
|
||||
if (!this.webSocket) {
|
||||
reject("Connection closed.");
|
||||
return;
|
||||
}
|
||||
this.webSocket.request<WifiChannel[]>("getWifiChannels",countryIso3661)
|
||||
this.webSocket.request<WifiChannel[]>("getWifiChannels", countryIso3661)
|
||||
.then((data) => {
|
||||
resolve(WifiChannel.deserialize_array(data));
|
||||
})
|
||||
.catch((err)=> reject(err));
|
||||
.catch((err) => reject(err));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -483,9 +483,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
|
||||
<div style={{ width: "100%" }}>
|
||||
{
|
||||
this.state.restarting ? (
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textSecondary" noWrap>Restarting...</Typography>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" color="textSecondary" noWrap>Rebooting...</Typography>
|
||||
) : (
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Restart</Typography>
|
||||
<Typography className={classes.primaryItem} display="block" variant="body2" noWrap>Reboot</Typography>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -52,11 +52,6 @@ export interface WifiConfigState {
|
||||
};
|
||||
|
||||
|
||||
let validNameRegex = /^[a-zA-Z][a-zA-Z0-9_-]*$/
|
||||
function isValidName(text: string)
|
||||
{
|
||||
return validNameRegex.test(text);
|
||||
}
|
||||
|
||||
const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
class extends ResizeResponsiveComponent<WifiConfigProps, WifiConfigState> {
|
||||
@@ -105,7 +100,10 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
this.stateWasPopped = true;
|
||||
let shouldClose = (!e.state || !e.state.WifiConfig);
|
||||
if (shouldClose) {
|
||||
this.preventPasswordPrompt();
|
||||
setTimeout(()=> {
|
||||
this.props.onClose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,16 +191,23 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
if (name.length === 0) {
|
||||
this.setState({nameError: true, nameErrorMessage: "* Required"});
|
||||
hasError = true;
|
||||
} else {
|
||||
if (!isValidName(name))
|
||||
} else if (name.length > 31)
|
||||
{
|
||||
this.setState({nameError: true, nameErrorMessage: "Invalid name"});
|
||||
hasError = true;
|
||||
} else if (name.length > 15)
|
||||
{
|
||||
this.setState({nameError: true, nameErrorMessage: "> 15 characters"});
|
||||
this.setState({nameError: true, nameErrorMessage: "> 31 characters"});
|
||||
hasError = true;
|
||||
}
|
||||
let password = this.state.newPassword;
|
||||
if (password.length > 0) {
|
||||
if (password.length < 8) {
|
||||
this.setState({passwordError: true, passwordErrorMessage: "Less than 8 characters"});
|
||||
hasError = true;
|
||||
|
||||
} else if (password.length > 63) {
|
||||
this.setState({passwordError: true, passwordErrorMessage: "> 63 characters"});
|
||||
hasError = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (this.state.enabled && (!this.props.wifiConfigSettings.hasPassword) && this.state.newPassword.length === 0)
|
||||
@@ -229,11 +234,23 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
this.setState({showWifiWarningDialog: true});
|
||||
} else {
|
||||
wifiConfigSettings.wifiWarningGiven = true;
|
||||
this.preventPasswordPrompt();
|
||||
setTimeout(()=> {
|
||||
this.props.onOk(wifiConfigSettings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
preventPasswordPrompt()
|
||||
{
|
||||
let passwordInput = this.refPassword.current;
|
||||
if (passwordInput)
|
||||
{
|
||||
passwordInput.value = "";
|
||||
passwordInput.type = "text";
|
||||
}
|
||||
}
|
||||
handleChannelChange(e: any)
|
||||
{
|
||||
let value = e.target.value as string;
|
||||
@@ -257,7 +274,10 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
let { open, onClose} = props;
|
||||
|
||||
const handleClose = () => {
|
||||
this.preventPasswordPrompt();
|
||||
setTimeout(()=> {
|
||||
onClose();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -295,7 +315,9 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })(
|
||||
disabled={!this.state.enabled}
|
||||
/>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<input type="password" style={{display:"none"}}/>
|
||||
<NoChangePassword
|
||||
inputRef={this.refPassword}
|
||||
onPasswordChange={(text): void => { this.setState({ newPassword: text, passwordError: false, passwordErrorMessage: NBSP }); }}
|
||||
hasPassword={this.props.wifiConfigSettings.hasPassword}
|
||||
label="WEP Passphrase"
|
||||
|
||||
+2
-1
@@ -88,7 +88,8 @@ std::map<std::string, std::string> extensionsToMimeType = {
|
||||
{".tif", "image/tiff"},
|
||||
{".svg", "image/svg+xml"},
|
||||
{".svgz", "image/svg+xml"},
|
||||
|
||||
{".woff", "font/woff2" },
|
||||
{".woff2", "font/woff2"}
|
||||
};
|
||||
// Return a reasonable mime type based on the extension of a file.
|
||||
std::string
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/asio/ip/network_v4.hpp>
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "Uri.hpp"
|
||||
|
||||
@@ -70,6 +70,7 @@ message (STATUS "Cxx flags: ${CMAKE_CXX_FLAGS}" )
|
||||
add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
SysExec.cpp SysExec.hpp
|
||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||
RequestHandler.hpp json.cpp json.hpp Scratch.cpp Lv2Host.hpp Lv2Host.cpp
|
||||
@@ -137,6 +138,9 @@ target_link_libraries(pipedald PRIVATE pthread atomic stdc++fs
|
||||
add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp
|
||||
jsonTest.cpp
|
||||
WifiChannelsTest.cpp
|
||||
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SystemConfigFileTest.cpp
|
||||
)
|
||||
|
||||
configure_file(config.hpp.in config.hpp)
|
||||
@@ -162,6 +166,10 @@ add_executable(pipedalconfig json.cpp json.hpp
|
||||
WriteTemplateFile.hpp WriteTemplateFile.cpp
|
||||
PiPedalException.hpp
|
||||
ConfigMain.cpp
|
||||
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(pipedalconfig PRIVATE pthread atomic stdc++fs
|
||||
@@ -171,6 +179,11 @@ add_executable(pipedalshutdownd ShutdownMain.cpp CommandLineParser.hpp
|
||||
JackServerSettings.hpp JackServerSettings.cpp
|
||||
json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp
|
||||
Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp
|
||||
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
|
||||
)
|
||||
target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd)
|
||||
|
||||
|
||||
+157
-43
@@ -5,6 +5,9 @@
|
||||
#include <stdlib.h>
|
||||
#include "WriteTemplateFile.hpp"
|
||||
#include <fstream>
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "SysExec.hpp"
|
||||
#include <sys/wait.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
@@ -12,15 +15,20 @@ using namespace pipedal;
|
||||
#define SERVICE_ACCOUNT_NAME "pipedal_d"
|
||||
#define SERVICE_GROUP_NAME "pipedal_d"
|
||||
|
||||
#define SYSTEMCTL_BIN "/usr/bin/systemctl"
|
||||
#define GROUPADD_BIN "/usr/sbin/groupadd"
|
||||
#define USERADD_BIN "/usr/sbin/useradd"
|
||||
#define USERMOD_BIN "/usr/sbin/usermod"
|
||||
#define CHGRP_BIN "/usr/bin/chgrp"
|
||||
#define CHOWN_BIN "/usr/bin/chown"
|
||||
#define CHMOD_BIN "/usr/bin/chmod"
|
||||
|
||||
|
||||
#define SERVICE_PATH "/usr/lib/systemd/system"
|
||||
#define NATIVE_SERVICE "pipedald"
|
||||
#define SHUTDOWN_SERVICE "pipedalshutdownd"
|
||||
// #define REACT_SERVICE "pipedal_react"
|
||||
|
||||
bool exec(std::stringstream &s)
|
||||
{
|
||||
return system(s.str().c_str()) == EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
std::filesystem::path GetServiceFileName(const std::string &serviceName)
|
||||
{
|
||||
@@ -54,22 +62,22 @@ std::filesystem::path findOnPath(const std::string &command)
|
||||
|
||||
void EnableService()
|
||||
{
|
||||
if (system("systemctl enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to enable the " NATIVE_SERVICE " service.";
|
||||
}
|
||||
if (system("systemctl enable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " enable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to enable the " SHUTDOWN_SERVICE " service.";
|
||||
}
|
||||
}
|
||||
void DisableService()
|
||||
{
|
||||
if (system("systemctl disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to disable the " NATIVE_SERVICE " service.";
|
||||
}
|
||||
if (system("systemctl disable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " disable " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to disable the " SHUTDOWN_SERVICE " service.";
|
||||
}
|
||||
@@ -77,11 +85,11 @@ void DisableService()
|
||||
|
||||
void StopService()
|
||||
{
|
||||
if (system("systemctl stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to stop the " NATIVE_SERVICE " service.";
|
||||
}
|
||||
if (system("systemctl stop " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " stop " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
cout << "Error: Failed to stop the " SHUTDOWN_SERVICE " service.";
|
||||
}
|
||||
@@ -89,11 +97,11 @@ void StopService()
|
||||
void StartService()
|
||||
{
|
||||
|
||||
if (system("systemctl start " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " start " NATIVE_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
throw PiPedalException("Failed to start the " NATIVE_SERVICE " service.");
|
||||
}
|
||||
if (system("systemctl start " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
if (SysExec(SYSTEMCTL_BIN " start " SHUTDOWN_SERVICE ".service") != EXIT_SUCCESS)
|
||||
{
|
||||
throw PiPedalException("Failed to start the " SHUTDOWN_SERVICE " service.");
|
||||
}
|
||||
@@ -135,17 +143,18 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
|
||||
bool authBindRequired = port < 512;
|
||||
|
||||
// Create and configur service account.
|
||||
// Create and configure service account.
|
||||
|
||||
if (system("groupadd -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
||||
if (SysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
||||
{
|
||||
throw PiPedalException("Failed to create service group.");
|
||||
}
|
||||
if (system("useradd " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -M -N -r") != EXIT_SUCCESS)
|
||||
if (SysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -M -N -r") != EXIT_SUCCESS)
|
||||
{
|
||||
// throw PiPedalException("Failed to create service account.");
|
||||
}
|
||||
system("usermod -a -G jack " SERVICE_ACCOUNT_NAME);
|
||||
SysExec(USERMOD_BIN " -a -G jack " SERVICE_ACCOUNT_NAME);
|
||||
SysExec(USERMOD_BIN " -a -G audio " SERVICE_ACCOUNT_NAME);
|
||||
|
||||
// create and configure /var directory.
|
||||
|
||||
@@ -154,24 +163,24 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "chgrp " SERVICE_GROUP_NAME " " << varDirectory;
|
||||
system(s.str().c_str());
|
||||
s << CHGRP_BIN " " SERVICE_GROUP_NAME " " << varDirectory.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "chown " SERVICE_ACCOUNT_NAME << " " << varDirectory;
|
||||
system(s.str().c_str());
|
||||
s << CHOWN_BIN << " " << SERVICE_ACCOUNT_NAME << " " << varDirectory.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "chmod 775 " << varDirectory;
|
||||
system(s.str().c_str());
|
||||
s << CHMOD_BIN << " 775 " << varDirectory.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "chmod g+s " << varDirectory; // child files/directories inherit ownership.
|
||||
system(s.str().c_str());
|
||||
s << CHMOD_BIN << " g+s " << varDirectory.c_str(); // child files/directories inherit ownership.
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
|
||||
// authbind port.
|
||||
@@ -187,19 +196,19 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
{
|
||||
// own it.
|
||||
std::stringstream s;
|
||||
s << "chown " SERVICE_ACCOUNT_NAME " " << portAuthFile;
|
||||
exec(s);
|
||||
s << CHOWN_BIN << " " SERVICE_ACCOUNT_NAME " " << portAuthFile.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
{
|
||||
// group own it.
|
||||
std::stringstream s;
|
||||
s << "chgrp " SERVICE_GROUP_NAME " " << portAuthFile;
|
||||
exec(s);
|
||||
s << CHGRP_BIN << " " SERVICE_GROUP_NAME " " << portAuthFile.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "chmod 770 " << portAuthFile;
|
||||
exec(s);
|
||||
s << CHMOD_BIN << " 770 " << portAuthFile.c_str();
|
||||
SysExec(s.str().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,9 +245,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
}
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/templateShutdown.service"), GetServiceFileName(SHUTDOWN_SERVICE));
|
||||
|
||||
|
||||
|
||||
system("systemctl daemon-reload");
|
||||
SysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
|
||||
cout << "Starting service" << endl;
|
||||
RestartService();
|
||||
@@ -247,6 +254,24 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
cout << "Complete" << endl;
|
||||
}
|
||||
|
||||
int SudoExec(char**argv) {
|
||||
int pbPid;
|
||||
int returnValue = 0;
|
||||
|
||||
if ((pbPid = fork()) == 0)
|
||||
{
|
||||
execv(argv[0], argv);
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitpid(pbPid, &returnValue, 0);
|
||||
int exitStatus = WEXITSTATUS(returnValue);
|
||||
return exitStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CommandLineParser parser;
|
||||
@@ -255,9 +280,12 @@ int main(int argc, char **argv)
|
||||
bool help = false;
|
||||
bool stop = false, start = false;
|
||||
bool enable = false, disable = false, restart = false;
|
||||
bool enable_ap = false, disable_ap = false;
|
||||
bool nopkexec = false;
|
||||
std::string prefixOption;
|
||||
std::string portOption;
|
||||
|
||||
parser.AddOption("-nopkexec", &nopkexec); // strictly a debugging aid.
|
||||
parser.AddOption("-install", &install);
|
||||
parser.AddOption("-uninstall", &uninstall);
|
||||
parser.AddOption("-stop", &stop);
|
||||
@@ -269,11 +297,13 @@ int main(int argc, char **argv)
|
||||
parser.AddOption("--help", &help);
|
||||
parser.AddOption("-prefix", &prefixOption);
|
||||
parser.AddOption("-port", &portOption);
|
||||
parser.AddOption("-enable_ap", &enable_ap);
|
||||
parser.AddOption("-disable_ap", &disable_ap);
|
||||
try
|
||||
{
|
||||
parser.Parse(argc, (const char **)argv);
|
||||
|
||||
int actionCount = install + uninstall + stop + start + enable + disable;
|
||||
int actionCount = install + uninstall + stop + start + enable + disable + enable_ap + disable_ap;
|
||||
if (actionCount > 1)
|
||||
{
|
||||
throw PiPedalException("Please provide only one action.");
|
||||
@@ -282,6 +312,23 @@ int main(int argc, char **argv)
|
||||
{
|
||||
help = true;
|
||||
}
|
||||
if (enable_ap)
|
||||
{
|
||||
if (parser.Arguments().size() != 4)
|
||||
{
|
||||
cout << "Error: "
|
||||
<< "Incorrect number of arguments supplied for -enable_ap option." << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parser.Arguments().size() != 0)
|
||||
{
|
||||
cout << "Error: Unexpected argument : " << parser.Arguments()[0] << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -290,7 +337,7 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (help || parser.Arguments().size() != 0)
|
||||
if (help)
|
||||
{
|
||||
cout << "pipedalconfig - Post-install configuration for pipdeal" << endl
|
||||
<< "Copyright (c) 2021 Robin Davies. All rights reserved." << endl
|
||||
@@ -298,20 +345,28 @@ int main(int argc, char **argv)
|
||||
<< "Syntax:" << endl
|
||||
<< " pipedalconfig [Options...]" << endl
|
||||
<< "Options: " << endl
|
||||
<< " -install Install services and service accounts." << endl
|
||||
<< " -uninstall Remove installed services and service accounts." << endl
|
||||
<< " -enable Start the pipedal at boot time." << endl
|
||||
<< " -disable Do not start the pipedal at boot time." << endl
|
||||
<< " -h --help Display this message." << endl
|
||||
<< " -install Install services and service accounts." << endl
|
||||
<< " -prefix Either /usr/local or /usr as appropriate for the install" << endl
|
||||
<< " (only valid with the -install option). Usually determined " << endl
|
||||
<< " automatically." << endl
|
||||
<< " -uninstall Remove installed services and service accounts." << endl
|
||||
<< " -enable Start the pipedal service at boot time." << endl
|
||||
<< " -disable Do not start the pipedal service at boot time." << endl
|
||||
<< " -stop Stop the pipedal services." << endl
|
||||
<< " -start Start the pipedal services." << endl
|
||||
<< " -restart Restart the pipedal services." << endl
|
||||
<< " -prefix Either /usr/local or /usr as appropriate for the install" << endl
|
||||
<< " (only valid with the -install option)." << endl
|
||||
<< " -port Port for the web server (only with -install option)." << endl
|
||||
<< " Either a port (e.g. '81'), or a full endpoint (e.g.: " << endl
|
||||
<< " '127.0.0.1:8080'). If no address is specified, the " << endl
|
||||
<< " web server will listen on 0.0.0.0 (any)." << 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
|
||||
<< " Wi-Fi channel in your legislative regime." << endl
|
||||
<< " -disable_ap Disabled the Wi-Fi access point." << endl
|
||||
<< endl
|
||||
<< "Description:" << endl
|
||||
<< " pipedalconfig performs post-install configuration of pipedal." << endl
|
||||
@@ -322,9 +377,48 @@ int main(int argc, char **argv)
|
||||
{
|
||||
cout << "Error: -port option can only be specified with the -install option." << endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto uid = getuid();
|
||||
if (uid != 0 && !nopkexec)
|
||||
{
|
||||
// re-execute with PKEXEC in order to prompt form SUDO credentials.
|
||||
std::vector<char*> args;
|
||||
std::string pkexec = "/usr/bin/pkexec"; // staged because "ISO C++ forbids converting a string constant to std::vector<char*>::value_type"(!)
|
||||
args.push_back((char*)(pkexec.c_str()));
|
||||
|
||||
std::filesystem::path path = std::filesystem::absolute(argv[0]);
|
||||
std::string sPath = path;
|
||||
args.push_back((char*)path.c_str());
|
||||
for (int arg = 1; arg < argc; ++arg)
|
||||
{
|
||||
args.push_back((char*)argv[arg]);
|
||||
}
|
||||
|
||||
std::string prefixArg; // lifetime management for the prefix arguments
|
||||
std::string prefixOptionArg;
|
||||
|
||||
if (prefixOption.length() == 0)
|
||||
{
|
||||
std::filesystem::path prefix = std::filesystem::path(argv[0]).parent_path().parent_path();
|
||||
prefixOptionArg = "-prefix";
|
||||
args.push_back((char*)(prefixOptionArg.c_str()));
|
||||
prefixArg = prefix;
|
||||
args.push_back((char*)prefixArg.c_str());
|
||||
}
|
||||
args.push_back(nullptr);
|
||||
|
||||
char**rawArgv = &args[0];
|
||||
return SudoExec(rawArgv);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (install)
|
||||
{
|
||||
std::filesystem::path prefix;
|
||||
if (prefixOption.length() != 0)
|
||||
@@ -343,8 +437,7 @@ int main(int argc, char **argv)
|
||||
throw PiPedalException(s.str());
|
||||
}
|
||||
}
|
||||
if (install)
|
||||
{
|
||||
|
||||
if (portOption == "")
|
||||
{
|
||||
portOption = "80";
|
||||
@@ -378,6 +471,27 @@ int main(int argc, char **argv)
|
||||
{
|
||||
DisableService();
|
||||
}
|
||||
else if (enable_ap)
|
||||
{
|
||||
auto argv = parser.Arguments();
|
||||
WifiConfigSettings settings;
|
||||
settings.valid_ = true;
|
||||
settings.enable_ = true;
|
||||
settings.countryCode_ = argv[0];
|
||||
settings.hotspotName_ = argv[1];
|
||||
settings.password_ = argv[2];
|
||||
settings.channel_ = argv[3];
|
||||
settings.hasPassword_ = settings.password_.length() != 0;
|
||||
|
||||
SetWifiConfig(settings);
|
||||
}
|
||||
else if (disable_ap)
|
||||
{
|
||||
WifiConfigSettings settings;
|
||||
settings.valid_ = true;
|
||||
settings.enable_ = false;
|
||||
SetWifiConfig(settings);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "lv2/log/log.h"
|
||||
#include "lv2/log/logger.h"
|
||||
#include "lv2/lv2plug.in/ns/extensions/units/units.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
|
||||
|
||||
@@ -21,9 +21,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
#include <lv2/core/lv2.h>
|
||||
#include <lv2/atom/atom.h>
|
||||
#include <lv2/midi/midi.h>
|
||||
#include <lv2/urid/urid.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace pipedal
|
||||
{
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
#include "pch.h"
|
||||
#include "OptionsFeature.hpp"
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/core/lv2_util.h"
|
||||
#include "lv2/log/log.h"
|
||||
#include "lv2/log/logger.h"
|
||||
#include "lv2/midi/midi.h"
|
||||
#include "lv2/urid/urid.h"
|
||||
#include "lv2/log/logger.h"
|
||||
#include "lv2/uri-map/uri-map.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
#include "lv2/worker/worker.h"
|
||||
#include "lv2/patch/patch.h"
|
||||
#include "lv2/parameters/parameters.h"
|
||||
#include "lv2/units/units.h"
|
||||
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
|
||||
|
||||
#include "lv2/lv2plug.in/ns/ext/buf-size/buf-size.h"
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -459,7 +459,9 @@ bool PiPedalModel::renamePreset(int64_t clientId, int64_t instanceId, const std:
|
||||
void PiPedalModel::setWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||
{
|
||||
std::lock_guard lock(this->mutex);
|
||||
// xxx Commit to local!
|
||||
|
||||
ShutdownClient::SetWifiConfig(wifiConfigSettings);
|
||||
|
||||
this->storage.SetWifiConfigSettings(wifiConfigSettings);
|
||||
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "WifiChannels.hpp"
|
||||
#include "SysExec.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
@@ -277,7 +278,7 @@ static void requestShutdown(bool restart)
|
||||
}
|
||||
s << " now";
|
||||
|
||||
if (system(s.str().c_str()) != EXIT_SUCCESS)
|
||||
if (SysExec(s.str().c_str()) != EXIT_SUCCESS)
|
||||
{
|
||||
Lv2Log::error("shutdown failed.");
|
||||
if (restart) {
|
||||
|
||||
+3
-1
@@ -3,8 +3,10 @@
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include "PiPedalException.hpp"
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define REGDB_MAGIC 0x52474442
|
||||
#define REGDB_VERSION 19
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include "SystemConfigFile.hpp"
|
||||
#include "SysExec.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
void pipedal::SetWifiConfig(const WifiConfigSettings&settings)
|
||||
{
|
||||
char band;
|
||||
if (!settings.enable_)
|
||||
{
|
||||
SysExec("/usr/bin/systemctl stop hostapd");
|
||||
SysExec("/usr/bin/systemctl disable hostapd");
|
||||
|
||||
SysExec("/usr/bin/systemctl enable wpa_supplicant");
|
||||
SysExec("/usr/bin/systemctl start wpa_supplicant");
|
||||
} else {
|
||||
boost::filesystem::path path("/etc/hostapd/hostapd.conf");
|
||||
SystemConfigFile apdConfig(path);
|
||||
apdConfig.Set("ieee80211n","1",false);
|
||||
apdConfig.Set("ieee80211d","1",false);
|
||||
apdConfig.Set("ieee80211ac","1",false);
|
||||
apdConfig.Set("ieee80211d","1",false);
|
||||
apdConfig.Set("ht_capab","[HT40][SHORT-GI-20][DSSS_CCK-40]",false);
|
||||
apdConfig.Set("rsn_pairwise","CCMP",false);
|
||||
|
||||
apdConfig.Set("wmm_enabled","1");
|
||||
apdConfig.Set("auth_algs","1");
|
||||
apdConfig.Set("wpa","2");
|
||||
|
||||
|
||||
std::string hwMode = "g";
|
||||
if (settings.channel_.length() > 0 && settings.channel_[0] == 'a') {
|
||||
hwMode = "a"; // 5G
|
||||
} else {
|
||||
hwMode = "g"; // 2.4G
|
||||
}
|
||||
std::string channel;
|
||||
if (settings.channel_[0] > '9' || settings.channel_[0] < '0')
|
||||
{
|
||||
channel = settings.channel_.substr(1);
|
||||
} else {
|
||||
channel = settings.channel_;
|
||||
int iChannel = std::stoi(channel);
|
||||
if (iChannel <= 14) {
|
||||
hwMode = "g";
|
||||
} else {
|
||||
hwMode = "a";
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.password_.length() != 0)
|
||||
{
|
||||
apdConfig.Set("wpa_passphrase",settings.password_);
|
||||
}
|
||||
apdConfig.Set("ssid",settings.hotspotName_);
|
||||
apdConfig.Set("country_code",settings.countryCode_);
|
||||
apdConfig.Set("hw_mode",hwMode);
|
||||
apdConfig.Set("channel",channel);
|
||||
apdConfig.Save();
|
||||
|
||||
SysExec("/usr/bin/systemctl daemon-reload");
|
||||
|
||||
SysExec("/usr/bin/systemctl mask wpa_supplicant");
|
||||
SysExec("/usr/bin/systemctl stop wpa_supplicant");
|
||||
|
||||
if (SysExec("/usr/bin/systemctl restart hostapd") != 0)
|
||||
{
|
||||
throw PiPedalException("Unable to start the access point.");
|
||||
|
||||
}
|
||||
if (SysExec("systemctl is-active --quiet hostapd") != 0)
|
||||
{
|
||||
throw PiPedalException("Unable to start the access point.");
|
||||
}
|
||||
SysExec("/usr/bin/systemctl enable hostapd");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "WifiConfigSettings.hpp"
|
||||
namespace pipedal {
|
||||
|
||||
void SetWifiConfig(const WifiConfigSettings&settings);
|
||||
} // namespace.
|
||||
+21
-3
@@ -90,6 +90,10 @@ bool ShutdownClient::WriteMessage(const char*message) {
|
||||
while (!eolFound)
|
||||
{
|
||||
ssize_t nRead = read(sock,pWrite,available);
|
||||
if (nRead == 0) {
|
||||
*pWrite = 0;
|
||||
break;
|
||||
}
|
||||
if (nRead <= 0) {
|
||||
Lv2Log::error("Failed to read shutdown server response.");
|
||||
close(sock);
|
||||
@@ -186,7 +190,21 @@ bool ShutdownClient::IsOnLocalSubnet(const std::string&fromAddress)
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiConfigSettings ";
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <string>
|
||||
#include "JackServerSettings.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
@@ -12,6 +13,7 @@ public:
|
||||
static bool RequestShutdown(bool restart);
|
||||
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||
static bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||
static void SetWifiConfig(const WifiConfigSettings & settings);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
+22
-3
@@ -16,6 +16,9 @@
|
||||
#include <cstdlib>
|
||||
#include "Lv2Log.hpp"
|
||||
#include "Lv2SystemdLogger.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "SysExec.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
@@ -57,6 +60,7 @@ static void ReleaseAccessPoint(const std::string gatewayAddress)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool setJackConfiguration(uint32_t sampleRate,uint32_t bufferSize,uint32_t numberOfBuffers)
|
||||
{
|
||||
bool success = true;
|
||||
@@ -174,7 +178,22 @@ private:
|
||||
{
|
||||
int result = -1;
|
||||
try {
|
||||
if (startsWith(s,"release_ap "))
|
||||
if (startsWith(s,"WifiConfigSettings "))
|
||||
{
|
||||
std::string json = s.substr(strlen("WifiConfigSettings "));
|
||||
std::stringstream ss(json);
|
||||
WifiConfigSettings settings;
|
||||
try {
|
||||
json_reader reader(ss);
|
||||
reader.read(&settings);
|
||||
} 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) {
|
||||
@@ -197,11 +216,11 @@ private:
|
||||
|
||||
} else if (s == "shutdown")
|
||||
{
|
||||
result = ::system("/usr/sbin/shutdown -P now");
|
||||
result = SysExec("/usr/sbin/shutdown -P now");
|
||||
}
|
||||
else if (s == "restart")
|
||||
{
|
||||
result = ::system("/usr/sbin/shutdown -r now");
|
||||
result = SysExec("/usr/sbin/shutdown -r now");
|
||||
} else if (startsWith(s,"setJackConfiguration "))
|
||||
{
|
||||
auto remainder = s.substr(strlen("setJackConfiguration "));
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
#include "json.hpp"
|
||||
#include <fstream>
|
||||
#include "Lv2Log.hpp"
|
||||
#include <map>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -716,7 +717,7 @@ void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSetting
|
||||
copyToStore.hasPassword_ = false;
|
||||
}
|
||||
copyToStore.password_ = "";
|
||||
copyToStore.rebootRequired_ = true;
|
||||
copyToStore.rebootRequired_ = false;
|
||||
if (copyToStore.enable_ && !copyToStore.hasPassword_)
|
||||
{
|
||||
copyToStore.hasPassword_ = this->wifiConfigSettings.hasPassword_;
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "pch.h"
|
||||
#include "SysExec.hpp"
|
||||
#include <sys/wait.h>
|
||||
#include <filesystem>
|
||||
#include "PiPedalException.hpp"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace pipedal;
|
||||
using namespace std;
|
||||
|
||||
|
||||
// find on path, but ONLY /usr/bin and /usr/sbin
|
||||
|
||||
static std::filesystem::path findOnSystemPath(const std::string &command)
|
||||
{
|
||||
if (command.length() != 0 && command[0] == '/')
|
||||
{
|
||||
return command;
|
||||
}
|
||||
std::string path = "/usr/bin:/usr/sbin";
|
||||
std::vector<std::string> paths;
|
||||
size_t t = 0;
|
||||
while (t < path.length())
|
||||
{
|
||||
size_t pos = path.find(':', t);
|
||||
if (pos == string::npos)
|
||||
{
|
||||
pos = path.length();
|
||||
}
|
||||
std::string thisPath = path.substr(t, pos - t);
|
||||
std::filesystem::path path = std::filesystem::path(thisPath) / command;
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
t = pos + 1;
|
||||
}
|
||||
std::stringstream s;
|
||||
s << "'" << command << "' is not installed.";
|
||||
throw PiPedalException(s.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
int pipedal::SysExec(const char*szCommand) {
|
||||
char*args = strdup(szCommand);
|
||||
int argc;
|
||||
std::vector<char*> argv;
|
||||
|
||||
char *p = args;
|
||||
while (*p) {
|
||||
argv.push_back(p);
|
||||
|
||||
while (*p && *p != ' ') {
|
||||
++p;
|
||||
}
|
||||
if (*p) {
|
||||
*p++ = '\0';
|
||||
while (*p && *p == ' ')
|
||||
{
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
|
||||
std::filesystem::path execPath = argv[0];
|
||||
if (execPath.is_relative())
|
||||
{
|
||||
execPath = findOnSystemPath(execPath);
|
||||
}
|
||||
if (!std::filesystem::exists(execPath))
|
||||
{
|
||||
throw PiPedalException( SS("Path does not exist: " << execPath << "."));
|
||||
}
|
||||
argv[0] = (char*)(execPath.c_str());
|
||||
|
||||
|
||||
char**rawArgv = &argv[0];
|
||||
int pbPid;
|
||||
int returnValue = 0;
|
||||
|
||||
if ((pbPid = fork()) == 0)
|
||||
{
|
||||
execv(argv[0], rawArgv);
|
||||
exit(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
free((void*)args);
|
||||
waitpid(pbPid, &returnValue, 0);
|
||||
int exitStatus = WEXITSTATUS(returnValue);
|
||||
return exitStatus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
// exec a command, returning the actual exit code (unlike execXX() or system() )
|
||||
int SysExec(const char*szCommand);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "pch.h"
|
||||
#include "SystemConfigFile.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
||||
using namespace pipedal;
|
||||
using namespace std;
|
||||
|
||||
void SystemConfigFile::Load(const boost::filesystem::path&path)
|
||||
{
|
||||
this->lines.clear();
|
||||
|
||||
ifstream f(path);
|
||||
if (!f.is_open())
|
||||
{
|
||||
stringstream s;
|
||||
s << "File not found: " << path;
|
||||
throw PiPedalException(s.str());
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::string line;
|
||||
std::getline(f,line);
|
||||
if (f.fail())
|
||||
{
|
||||
break;
|
||||
}
|
||||
lines.push_back(line);
|
||||
}
|
||||
this->currentPath = path;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int64_t SystemConfigFile::GetLine(const std::string &key) const
|
||||
{
|
||||
for (size_t i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (LineMatches(lines[i],key))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SystemConfigFile::HasValue(const std::string&key) const
|
||||
{
|
||||
return GetLine(key) != -1;
|
||||
}
|
||||
|
||||
static inline std::string ValuePart(const std::string &line)
|
||||
{
|
||||
auto pos = line.find('=');
|
||||
if (pos == std::string::npos) throw PiPedalException("Value not found.");
|
||||
return line.substr(pos+1);
|
||||
|
||||
}
|
||||
std::string SystemConfigFile::Get(const std::string&key) const
|
||||
{
|
||||
int64_t lineIndex = GetLine(key);
|
||||
if (lineIndex == -1) throw PiPedalArgumentException("Not found.");
|
||||
return ValuePart(lines[lineIndex]);
|
||||
|
||||
}
|
||||
|
||||
bool SystemConfigFile::Get(const std::string&key,std::string*pResult) const
|
||||
{
|
||||
int64_t lineIndex = GetLine(key);
|
||||
if (lineIndex == -1) return false;
|
||||
*pResult = ValuePart(lines[lineIndex]);
|
||||
return true;
|
||||
}
|
||||
void SystemConfigFile::Set(const std::string&key,const std::string &value)
|
||||
{
|
||||
stringstream s;
|
||||
s << key << "=" << value;
|
||||
std::string line = s.str();
|
||||
int lineIndex = GetLine(key);
|
||||
if (lineIndex != -1) {
|
||||
lines[lineIndex] = line;
|
||||
} else {
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemConfigFile::Erase(const std::string&key)
|
||||
{
|
||||
bool matched = false;
|
||||
for (size_t i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (LineMatches(lines[i],key))
|
||||
{
|
||||
matched = true;
|
||||
lines.erase(lines.begin()+i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
|
||||
}
|
||||
|
||||
static std::string makeLine(const std::string&key, const std::string&value) {
|
||||
stringstream s;
|
||||
s << key << "=" << value;
|
||||
return s.str();
|
||||
}
|
||||
int64_t SystemConfigFile::Insert(int64_t position, const std::string&key, const std::string&value)
|
||||
{
|
||||
if (position < 0 || position >= lines.size())
|
||||
{
|
||||
lines.push_back(makeLine(key,value));
|
||||
return (int64_t)lines.size();
|
||||
} else {
|
||||
lines.insert(lines.begin()+position,makeLine(key,value));
|
||||
return position+1;
|
||||
}
|
||||
}
|
||||
int64_t SystemConfigFile::Insert(int64_t position, const std::string&line)
|
||||
{
|
||||
if (position < 0 || position >= lines.size())
|
||||
{
|
||||
lines.push_back(line);
|
||||
return (int64_t)lines.size();
|
||||
} else {
|
||||
lines.insert(lines.begin()+position,line);
|
||||
return position+1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemConfigFile::LineMatches(const std::string &line, const std::string&key) const
|
||||
{
|
||||
// (very permissive interpretation)
|
||||
int pos = 0;
|
||||
while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t'))
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
if (line.compare(pos,pos+key.length(),key) != 0) return false;
|
||||
pos += key.length();\
|
||||
while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t'))
|
||||
{
|
||||
++pos;
|
||||
}
|
||||
return pos < line.length() && line[pos] == '=';
|
||||
}
|
||||
|
||||
void SystemConfigFile::SetLine(int64_t lineIndex,const std::string&key,const std::string &value )
|
||||
{
|
||||
stringstream s;
|
||||
s << key << "=" << value;
|
||||
if (lineIndex >= 0 && lineIndex < this->lines.size())
|
||||
{
|
||||
this->lines[lineIndex] = s.str();
|
||||
} else {
|
||||
this->lines.push_back(s.str());
|
||||
}
|
||||
}
|
||||
|
||||
void SystemConfigFile::Set(const std::string&key,const std::string &value, bool overwrite)
|
||||
{
|
||||
if (!overwrite)
|
||||
{
|
||||
if (HasValue(key)) return;
|
||||
}
|
||||
Set(key,value);
|
||||
}
|
||||
|
||||
void SystemConfigFile::Set(const std::string&key,const std::string &value, const std::string&comment)
|
||||
{
|
||||
uint64_t lineIndex = GetLine(key);
|
||||
if (lineIndex != -1)
|
||||
{
|
||||
SetLine(lineIndex, key, value);
|
||||
} else {
|
||||
lines.push_back("");
|
||||
lines.push_back("# " + comment);
|
||||
SetLine(-1,key,value);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemConfigFile::Save(std::ostream &os)
|
||||
{
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
os << lines[i] << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
void SystemConfigFile::Save(const boost::filesystem::path&path)
|
||||
{
|
||||
ofstream f(path);
|
||||
|
||||
if (!f.is_open()) {
|
||||
stringstream s;
|
||||
s << "Unable to write to " << path;
|
||||
throw PiPedalException(s.str());
|
||||
}
|
||||
Save(f);
|
||||
if (f.fail())
|
||||
{
|
||||
stringstream s;
|
||||
s << "Unable to write to " << path;
|
||||
throw PiPedalException(s.str());
|
||||
}
|
||||
}
|
||||
void SystemConfigFile::Save()
|
||||
{
|
||||
Save(this->currentPath);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class SystemConfigFile {
|
||||
boost::filesystem::path currentPath;
|
||||
std::vector<std::string> lines;
|
||||
void SetLine(int64_t lineIndex,const std::string&key,const std::string &value );
|
||||
bool LineMatches(const std::string &line, const std::string&key) const;
|
||||
public:
|
||||
SystemConfigFile() {
|
||||
|
||||
}
|
||||
SystemConfigFile(const boost::filesystem::path& path)
|
||||
{
|
||||
Load(path);
|
||||
}
|
||||
|
||||
void Load(const boost::filesystem::path&path);
|
||||
|
||||
void Save(std::ostream &os);
|
||||
void Save(const boost::filesystem::path&path);
|
||||
void Save();
|
||||
|
||||
int64_t GetLine(const std::string &key) const;
|
||||
bool HasValue(const std::string&key) const;
|
||||
bool Get(const std::string&key,std::string*pResult) const;
|
||||
std::string Get(const std::string&key) const;
|
||||
void Set(const std::string&key,const std::string &value);
|
||||
void Set(const std::string&key,const std::string &value, bool overwrite);
|
||||
void Set(const std::string&key,const std::string &value, const std::string&comment);
|
||||
bool Erase(const std::string&key);
|
||||
int64_t Insert(int64_t position, const std::string&key, const std::string&value);
|
||||
int64_t Insert(int64_t position, const std::string&line);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "pch.h"
|
||||
#include "catch.hpp"
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "PiPedalException.hpp"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#include "SystemConfigFile.hpp"
|
||||
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
TEST_CASE( "SystemConfigFile Test", "[system_config_file_test]" ) {
|
||||
boost::filesystem::path path("/etc/hostapd/hostapd.conf");
|
||||
|
||||
SystemConfigFile file(path);
|
||||
std::string driverName;
|
||||
|
||||
REQUIRE(file.Get("driver") == "nl80211");
|
||||
|
||||
file.Set("ssid","ssid","Name of the access point");
|
||||
file.Set("xx","new_feature","A new feature.");
|
||||
file.Set("ssid","newSsid");
|
||||
file.Set("country_code","FR");
|
||||
|
||||
|
||||
file.Save(std::cout);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <net/if.h>
|
||||
#include <netlink/netlink.h>
|
||||
@@ -16,6 +18,7 @@
|
||||
#include "Lv2Log.hpp"
|
||||
|
||||
#include "RegDb.hpp"
|
||||
|
||||
/*
|
||||
Heavily based on code from iw (1) command.
|
||||
https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING
|
||||
@@ -596,7 +599,7 @@ std::vector<WifiChannel> pipedal::getWifiChannels(const char*countryIso3661)
|
||||
t << " (2.4GHz)";
|
||||
|
||||
if (channel.indoorOnly) {
|
||||
t << " Indoor only";
|
||||
t << " Indoors only";
|
||||
}
|
||||
ch.channelName_ = t.str();
|
||||
result.push_back(ch);
|
||||
|
||||
@@ -10,9 +10,30 @@
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
static WifiChannel GetChannel(std::vector<WifiChannel> channels, const std::string&channelId)
|
||||
{
|
||||
for (auto &channel: channels)
|
||||
{
|
||||
if (channel.channelId_ == channelId)
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
throw PiPedalException("Channel not found.");;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_CASE( "Wifi Channel Test", "[wifi_channels_test]" ) {
|
||||
std::vector<WifiChannel> result = pipedal::getWifiChannels("CA");
|
||||
|
||||
// channel 36 is indoors only (CA)
|
||||
WifiChannel channel = GetChannel(result,"a36");
|
||||
REQUIRE(channel.channelName_.find("Indoors") != std::string::npos);
|
||||
|
||||
// channel 36 is not indoors only (US)
|
||||
result = pipedal::getWifiChannels("US");
|
||||
channel = GetChannel(result,"a36");
|
||||
REQUIRE(channel.channelName_.find("Indoors") == std::string::npos);
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +246,13 @@ private:
|
||||
|
||||
|
||||
public:
|
||||
static std::string encode_string(const std::string &text)
|
||||
{
|
||||
std::stringstream s;
|
||||
json_writer writer(s);
|
||||
writer.write(text);
|
||||
return s.str();
|
||||
}
|
||||
void write_raw(const char*text) {
|
||||
os << text;
|
||||
}
|
||||
|
||||
+1
-1
@@ -486,5 +486,5 @@ int main(int argc, char *argv[])
|
||||
Lv2Log::error(e.what());
|
||||
}
|
||||
Lv2Log::info("PiPedal terminating.");
|
||||
return EXIT_FAILURE; // only exit in response to a signal.
|
||||
return EXIT_SUCCESS; // only exit in response to a signal.
|
||||
}
|
||||
|
||||
@@ -11,16 +11,13 @@ template <typename T> class TypeDisplay;
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
#include "lv2/core/lv2.h"
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
|
||||
// #include <lilv/lilv.h>
|
||||
/*
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/core/lv2.h"
|
||||
#include "lv2/core/lv2_util.h"
|
||||
#include "lv2/log/log.h"
|
||||
#include "lv2/log/logger.h"
|
||||
@@ -34,3 +31,6 @@ template <typename T> class TypeDisplay;
|
||||
#include "lv2/parameters/parameters.h"
|
||||
#include "lv2/units/units.h"
|
||||
#include <lv2/lv2plug.in/ns/ext/worker/worker.h>
|
||||
*/
|
||||
|
||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||
|
||||
Reference in New Issue
Block a user