List of addresses in the About dialog

This commit is contained in:
Robin Davies
2022-04-26 04:47:57 -04:00
parent c31bea9ecd
commit d1b1fc1b7e
9 changed files with 156 additions and 69 deletions
+62 -42
View File
@@ -5,15 +5,16 @@ import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel'; import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar'; import Toolbar from '@mui/material/Toolbar';
import Divider from '@mui/material/Divider';
import ArrowBackIcon from '@mui/icons-material//ArrowBack'; import ArrowBackIcon from '@mui/icons-material//ArrowBack';
import JackHostStatus from './JackHostStatus'; import JackHostStatus from './JackHostStatus';
import {PiPedalError} from './PiPedalError'; import { PiPedalError } from './PiPedalError';
import DialogEx from './DialogEx'; import DialogEx from './DialogEx';
import { Theme, createStyles } from '@mui/material/styles'; import { Theme, createStyles } from '@mui/material/styles';
import { withStyles, WithStyles} from '@mui/styles'; import { withStyles, WithStyles } from '@mui/styles';
import Slide, {SlideProps} from '@mui/material/Slide'; import Slide, { SlideProps } from '@mui/material/Slide';
interface AboutDialogProps extends WithStyles<typeof styles> { interface AboutDialogProps extends WithStyles<typeof styles> {
@@ -115,7 +116,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
if (this.model.state.get() === State.Ready) { if (this.model.state.get() === State.Ready) {
this.model.getJackStatus() this.model.getJackStatus()
.then(jackStatus => { .then(jackStatus => {
this.setState({jackStatus: jackStatus}); this.setState({ jackStatus: jackStatus });
}) })
.catch(error => { /* ignore*/ }); .catch(error => { /* ignore*/ });
} }
@@ -138,30 +139,25 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
} }
} }
startFossRequest() startFossRequest() {
{ if (this.state.openSourceNotices === "") {
if (this.state.openSourceNotices === "")
{
fetch("var/notices.txt") fetch("var/notices.txt")
.then((request)=> .then((request) => {
{ if (!request.ok) {
if (!request.ok) throw new PiPedalError("notices request failed.");
{ }
throw new PiPedalError("notices request failed."); return request.text();
} })
return request.text(); .then((text) => {
}) if (this.mounted) {
.then((text) => { this.setState({ openSourceNotices: text });
if (this.mounted) }
{
this.setState({ openSourceNotices: text}); })
} .catch((err) => {
// ok in debug builds. File doesn't get placed until install time.
}) console.log("Failed to fetch open-source notices. " + err);
.catch((err) => { });
// ok in debug builds. File doesn't get placed until install time.
console.log("Failed to fetch open-source notices. " + err);
});
} }
} }
@@ -189,8 +185,8 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
return ( return (
<DialogEx tag="AboutDlg" fullScreen open={this.props.open} <DialogEx tag="AboutDlg" fullScreen open={this.props.open}
onClose={() => { this.props.onClose() }} TransitionComponent={Transition} onClose={() => { this.props.onClose() }} TransitionComponent={Transition}
style={{userSelect: "none"}} style={{ userSelect: "none" }}
> >
<div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}> <div style={{ display: "flex", flexDirection: "column", flexWrap: "nowrap", width: "100%", height: "100%", overflow: "hidden" }}>
<div style={{ flex: "0 0 auto" }}> <div style={{ flex: "0 0 auto" }}>
@@ -208,28 +204,52 @@ const AboutDialog = withStyles(styles, { withTheme: true })(
</div> </div>
<div style={{ <div style={{
flex: "1 1 auto", position: "relative", overflow: "hidden", flex: "1 1 auto", position: "relative", overflow: "hidden",
overflowX: "hidden", overflowY: "auto" , userSelect: "text" overflowX: "hidden", overflowY: "auto", userSelect: "text"
}} }}
> >
<div style={{margin: 24}}> <div style={{ margin: 24 }}>
<Typography display="block" variant="h6" color="textPrimary"> <Typography display="block" variant="h6" color="textPrimary">
PiPedal <span style={{fontSize: "0.7em"}}> PiPedal <span style={{ fontSize: "0.7em" }}>
{(this.model.serverVersion? this.model.serverVersion.serverVersion : "") {(this.model.serverVersion ? this.model.serverVersion.serverVersion : "")
+ (this.model.serverVersion?.debug ? " (Debug)": "")} + (this.model.serverVersion?.debug ? " (Debug)" : "")}
</span> </span>
</Typography> </Typography>
<Typography display="block" variant="body2" style={{marginBottom: 12}} > <Typography display="block" variant="body2" style={{ marginBottom: 12 }} >
Copyright &#169; 2022 Robin Davies. Copyright &#169; 2022 Robin Davies.
</Typography>
<Typography display="block" variant="body2" style={{marginBottom: 12}} >
{this.model.getAndroidHostVersion() }
</Typography> </Typography>
{this.model.isAndroidHosted() && (
<Typography display="block" variant="body2" style={{ marginBottom: 0 }} >
{this.model.getAndroidHostVersion()}
</Typography>
)}
{this.model.isAndroidHosted() && (
<Typography display="block" variant="body2" style={{ marginBottom: 12 }} >
Copyright &#169; 2022 Robin Davies.
</Typography>
)}
<Divider />
<Typography display="block" variant="caption" >
ADDRESSES
</Typography>
<div style={{marginBottom: 16}}>
{
this.model.serverVersion?.webAddresses.map((address) =>
(
<Typography display="block" variant="body2" style={{ marginBottom: 0, marginLeft: 24 }} >
{address}
</Typography>
))
}
</div>
<Divider />
<Typography display="block" variant="caption" > <Typography display="block" variant="caption" >
LEGAL NOTICES LEGAL NOTICES
</Typography> </Typography>
<div dangerouslySetInnerHTML={{__html: this.state.openSourceNotices}} style={{fontSize: "0.8em" }}> <div dangerouslySetInnerHTML={{ __html: this.state.openSourceNotices }} style={{ fontSize: "0.8em",maxWidth: 400 }}>
</div> </div>
</div> </div>
+13 -5
View File
@@ -537,7 +537,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
setDisplayState(newState: State): void { setDisplayState(newState: State): void {
this.updateOverscroll(); this.updateOverscroll();
this.setState({ this.setState({
displayState: newState, displayState: newState,
canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted() canFullScreen: supportsFullScreen() && !this.model_.isAndroidHosted()
}); });
@@ -576,6 +576,13 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
} }
return result; return result;
} }
handleReload() {
if (this.model_.isAndroidHosted()) {
this.model_.chooseNewDevice();
} else {
window.location.reload();
}
}
render() { render() {
const { classes } = this.props; const { classes } = this.props;
@@ -785,9 +792,10 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</DialogActions> </DialogActions>
</Dialog> </Dialog>
<JackStatusView /> <JackStatusView />
<div className={classes.errorContent} style={{ <div className={classes.errorContent} style={{
display: (this.state.displayState === State.Reconnecting || this.state.displayState === State.ApplyingChanges) display: (this.state.displayState === State.Reconnecting || this.state.displayState === State.ApplyingChanges)
? "block" : "none" }} ? "block" : "none"
}}
> >
<div className={classes.errorContentMask} /> <div className={classes.errorContentMask} />
@@ -796,7 +804,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
<CircularProgress color="inherit" className={classes.loadingBoxItem} /> <CircularProgress color="inherit" className={classes.loadingBoxItem} />
</div> </div>
<Typography variant="body2" className={classes.progressText}> <Typography variant="body2" className={classes.progressText}>
{ this.state.displayState === State.ApplyingChanges ? "Applying\u00A0changes..." : "Reconnecting..."} {this.state.displayState === State.ApplyingChanges ? "Applying\u00A0changes..." : "Reconnecting..."}
</Typography> </Typography>
</div> </div>
</div> </div>
@@ -816,7 +824,7 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent<
</div> </div>
<div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}> <div style={{ paddingTop: 50, paddingLeft: 36, textAlign: "left" }}>
<Button variant='contained' color="primary" component='button' <Button variant='contained' color="primary" component='button'
onClick={() => window.location.reload()} > onClick={() => this.handleReload()} >
Reload Reload
</Button> </Button>
+1
View File
@@ -159,6 +159,7 @@ export type PiPedalVersion = {
operatingSystem: string; operatingSystem: string;
osVersion: string; osVersion: string;
debug: boolean; debug: boolean;
webAddresses: string[];
}; };
export class PresetIndexEntry { export class PresetIndexEntry {
+29 -18
View File
@@ -86,10 +86,10 @@ static bool IsIpv4OnLocalSubnet(uint32_t ipv4Addres)
} }
bool pipedal::ParseHttpAddress(const std::string address, bool pipedal::ParseHttpAddress(const std::string address,
std::string *pUser, std::string *pUser,
std::string *pServer, std::string *pServer,
int *pPort, int *pPort,
int defaultPort) int defaultPort)
{ {
// strip user. // strip user.
auto start = address.find_first_of('@'); auto start = address.find_first_of('@');
@@ -97,10 +97,12 @@ bool pipedal::ParseHttpAddress(const std::string address,
{ {
if (pUser) if (pUser)
{ {
*pUser = address.substr(0,start); *pUser = address.substr(0, start);
} }
start = start+1; start = start + 1;
} else { }
else
{
start = 0; start = 0;
if (pUser) if (pUser)
{ {
@@ -109,9 +111,9 @@ bool pipedal::ParseHttpAddress(const std::string address,
} }
// find the port address. // find the port address.
int port = address.length(); int port = address.length();
while (port > 0 && address[port-1] != ':') while (port > 0 && address[port - 1] != ':')
{ {
if (address[port-1] != ']') if (address[port - 1] != ']')
{ {
port = address.length(); port = address.length();
break; break;
@@ -121,7 +123,7 @@ bool pipedal::ParseHttpAddress(const std::string address,
int portNumber = defaultPort; int portNumber = defaultPort;
if (port < address.length() && address[port] == ':') if (port < address.length() && address[port] == ':')
{ {
const char*p = address.c_str()+port+1; const char *p = address.c_str() + port + 1;
if (*p) if (*p)
{ {
portNumber = 0; portNumber = 0;
@@ -129,8 +131,10 @@ bool pipedal::ParseHttpAddress(const std::string address,
{ {
if (*p >= '0' && *p <= '9') if (*p >= '0' && *p <= '9')
{ {
portNumber = portNumber*10 + *p -'0'; portNumber = portNumber * 10 + *p - '0';
} else { }
else
{
return false; return false;
} }
} }
@@ -142,7 +146,7 @@ bool pipedal::ParseHttpAddress(const std::string address,
} }
if (pServer) if (pServer)
{ {
*pServer = address.substr(start,port-start); *pServer = address.substr(start, port - start);
} }
return true; return true;
} }
@@ -349,12 +353,12 @@ static std::string GetLinkLocalAddressForInterface(const std::string &name)
freeifaddrs(ifap); freeifaddrs(ifap);
return result; return result;
} }
static std::string GetLinkLocalAddressForIp4Interface(const std::string&name) static std::string GetLinkLocalAddressForIp4Interface(const std::string &name)
{ {
struct ifaddrs *ifap = nullptr; struct ifaddrs *ifap = nullptr;
if (getifaddrs(&ifap) != 0) if (getifaddrs(&ifap) != 0)
return ""; return "";
std::string result = "notlocalsubnet.error"; std::string result = "";
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next) 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) if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
@@ -423,11 +427,13 @@ std::string pipedal::GetLinkLocalAddress(const std::string fromAddress)
// others? // others?
if (IN6_IS_ADDR_V4MAPPED(&inetAddr6)) if (IN6_IS_ADDR_V4MAPPED(&inetAddr6))
{ {
int8_t*pAddr = (int8_t*)&inetAddr6; int8_t *pAddr = (int8_t *)&inetAddr6;
uint32_t remoteAddress = htonl(*(int32_t*)(pAddr+12)); uint32_t remoteAddress = htonl(*(int32_t *)(pAddr + 12));
std::string interfaceName = GetInterfaceForIp4Address(remoteAddress); std::string interfaceName = GetInterfaceForIp4Address(remoteAddress);
result = GetLinkLocalAddressForIp4Interface(interfaceName); result = GetLinkLocalAddressForIp4Interface(interfaceName);
} else { }
else
{
std::string interfaceName; std::string interfaceName;
if (IsIpv4MappedAddress(inetAddr6)) if (IsIpv4MappedAddress(inetAddr6))
@@ -449,3 +455,8 @@ std::string pipedal::GetLinkLocalAddress(const std::string fromAddress)
} }
return result; return result;
} }
std::string pipedal::GetInterfaceIpv4Address(const std::string& interfaceName)
{
return GetLinkLocalAddressForIp4Interface(interfaceName);
}
+3
View File
@@ -24,6 +24,9 @@
namespace pipedal { namespace pipedal {
std::string GetInterfaceIpv4Address(const std::string& interfaceName);
std::string GetLinkLocalAddress(const std::string fromAddress); std::string GetLinkLocalAddress(const std::string fromAddress);
bool IsOnLocalSubnet(const std::string&fromAddress); bool IsOnLocalSubnet(const std::string&fromAddress);
+1 -1
View File
@@ -154,7 +154,7 @@ public:
PiPedalModel(); PiPedalModel();
virtual ~PiPedalModel(); virtual ~PiPedalModel();
uint16_t GetWebPort() const { return webPort; }
void Close(); void Close();
void UpdateDnsSd(); void UpdateDnsSd();
+1 -1
View File
@@ -926,7 +926,7 @@ public:
} }
else if (message == "version") else if (message == "version")
{ {
PiPedalVersion version; PiPedalVersion version(this->model);
Reply(replyTo, "version", version); Reply(replyTo, "version", version);
} }
+42 -1
View File
@@ -18,8 +18,10 @@
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "pch.h" #include "pch.h"
#include "PiPedalModel.hpp"
#include "config.hpp" #include "config.hpp"
#include "PiPedalVersion.hpp" #include "PiPedalVersion.hpp"
#include "Ipv6Helpers.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include "windows.h" #include "windows.h"
@@ -36,9 +38,21 @@ JSON_MAP_BEGIN(PiPedalVersion)
JSON_MAP_REFERENCE(PiPedalVersion,operatingSystem) JSON_MAP_REFERENCE(PiPedalVersion,operatingSystem)
JSON_MAP_REFERENCE(PiPedalVersion,osVersion) JSON_MAP_REFERENCE(PiPedalVersion,osVersion)
JSON_MAP_REFERENCE(PiPedalVersion,debug) JSON_MAP_REFERENCE(PiPedalVersion,debug)
JSON_MAP_REFERENCE(PiPedalVersion,webAddresses)
JSON_MAP_END() JSON_MAP_END()
PiPedalVersion::PiPedalVersion()
static std::string MakeWebAddress(const std::string &address, uint16_t port)
{
if (port == 80)
{
return SS("http://" << address << '/');
} else {
return SS("http://" << address << ':' << port << '/');
}
}
PiPedalVersion::PiPedalVersion(PiPedalModel&model)
{ {
server_ = "PiPedal Server"; server_ = "PiPedal Server";
// defined on build command line. // defined on build command line.
@@ -71,4 +85,31 @@ PiPedalVersion::PiPedalVersion()
#else #else
debug_ = false; debug_ = false;
#endif #endif
uint16_t port = model.GetWebPort();
char hostName[512];
gethostname(hostName,sizeof(hostName));
this->webAddresses_.push_back(MakeWebAddress(SS(hostName << ".local"),port));
std::string ethAddr = GetInterfaceIpv4Address("eth0");
if (ethAddr.length() != 0)
{
this->webAddresses_.push_back(MakeWebAddress(ethAddr,port));
}
std::string wlanAddr = GetInterfaceIpv4Address("wlan0");
if (wlanAddr.length() != 0)
{
this->webAddresses_.push_back(MakeWebAddress(wlanAddr,port));
}
std::string p2pAddr = GetInterfaceIpv4Address("p2p-wlan0-0");
if (p2pAddr.length() != 0)
{
this->webAddresses_.push_back(MakeWebAddress(p2pAddr,port));
}
} }
+4 -1
View File
@@ -21,6 +21,8 @@
#include "json.hpp" #include "json.hpp"
namespace pipedal { namespace pipedal {
class PiPedalModel;
class PiPedalVersion { class PiPedalVersion {
private: private:
@@ -28,10 +30,11 @@ private:
std::string serverVersion_; std::string serverVersion_;
std::string operatingSystem_; std::string operatingSystem_;
std::string osVersion_; std::string osVersion_;
std::vector<std::string> webAddresses_;
bool debug_; bool debug_;
public: public:
PiPedalVersion(); PiPedalVersion(PiPedalModel&model);
~PiPedalVersion() = default; ~PiPedalVersion() = default;