mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
add module license
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
"@mui/material": "^5.15.19",
|
||||
"@table-library/react-table-library": "4.1.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.14.1",
|
||||
"@types/node": "^20.14.2",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
@@ -50,7 +50,7 @@
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.6",
|
||||
"@babel/core": "^7.24.7",
|
||||
"@eslint/js": "^9.4.0",
|
||||
"@preact/compat": "^17.1.2",
|
||||
"@preact/preset-vite": "^2.8.2",
|
||||
@@ -60,11 +60,11 @@
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"preact": "^10.22.0",
|
||||
"prettier": "^3.3.0",
|
||||
"prettier": "^3.3.1",
|
||||
"rollup-plugin-visualizer": "^5.12.0",
|
||||
"terser": "^5.31.0",
|
||||
"terser": "^5.31.1",
|
||||
"typescript-eslint": "^7.12.0",
|
||||
"vite": "^5.2.12",
|
||||
"vite": "^5.2.13",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
},
|
||||
|
||||
@@ -10,8 +10,10 @@ import MemoryIcon from '@mui/icons-material/Memory';
|
||||
import PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||
import RouterIcon from '@mui/icons-material/Router';
|
||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||
import TimerIcon from '@mui/icons-material/Timer';
|
||||
import WifiIcon from '@mui/icons-material/Wifi';
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
@@ -38,7 +40,7 @@ import ListMenuItem from 'components/layout/ListMenuItem';
|
||||
import { AuthenticatedContext } from 'contexts/authentication';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { busConnectionStatus } from 'project/types';
|
||||
import { NTPSyncStatus } from 'types';
|
||||
import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
|
||||
|
||||
import RestartMonitor from './RestartMonitor';
|
||||
|
||||
@@ -151,6 +153,46 @@ const SystemStatus: FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const networkStatusHighlight = () => {
|
||||
switch (data.network_status) {
|
||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||
return theme.palette.info.main;
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||
return theme.palette.success.main;
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||
return theme.palette.error.main;
|
||||
default:
|
||||
return theme.palette.warning.main;
|
||||
}
|
||||
};
|
||||
|
||||
const networkStatus = () => {
|
||||
switch (data.network_status) {
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
|
||||
return LL.INACTIVE(1);
|
||||
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
|
||||
return LL.IDLE();
|
||||
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
|
||||
return 'No SSID Available';
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
|
||||
return LL.CONNECTED(0) + ' (WiFi, ' + data.wifi_rssi + ' dBm)';
|
||||
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
|
||||
return LL.CONNECTED(0) + ' (Ethernet)';
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
|
||||
return LL.CONNECTED(1) + ' ' + LL.FAILED(0);
|
||||
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
|
||||
return LL.CONNECTED(1) + ' ' + LL.LOST();
|
||||
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
|
||||
return LL.DISCONNECTED();
|
||||
default:
|
||||
return LL.UNKNOWN();
|
||||
}
|
||||
};
|
||||
|
||||
const activeHighlight = (value: boolean) =>
|
||||
value ? theme.palette.success.main : theme.palette.info.main;
|
||||
|
||||
@@ -296,7 +338,7 @@ const SystemStatus: FC = () => {
|
||||
<Button
|
||||
startIcon={<PowerSettingsNewIcon />}
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
color="error"
|
||||
onClick={() => setConfirmRestart(true)}
|
||||
>
|
||||
{LL.RESTART()}
|
||||
@@ -355,6 +397,20 @@ const SystemStatus: FC = () => {
|
||||
/>
|
||||
<Divider variant="inset" component="li" />
|
||||
|
||||
<ListMenuItem
|
||||
disabled={!me.admin}
|
||||
icon={
|
||||
data.network_status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED
|
||||
? WifiIcon
|
||||
: RouterIcon
|
||||
}
|
||||
bgcolor={networkStatusHighlight()}
|
||||
label={LL.STATUS_OF(LL.NETWORK(1))}
|
||||
text={networkStatus()}
|
||||
to="/settings/network/status"
|
||||
/>
|
||||
<Divider variant="inset" component="li" />
|
||||
|
||||
<ListMenuItem
|
||||
disabled={!me.admin}
|
||||
icon={DeviceHubIcon}
|
||||
|
||||
@@ -325,7 +325,10 @@ const de: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Module'
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default de;
|
||||
|
||||
@@ -325,7 +325,10 @@ const en: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
||||
SECURITY_1: 'Add or remove users',
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware',
|
||||
MODULES: 'Modules'
|
||||
MODULES: 'Modules',
|
||||
MODULES_UPDATED: 'Modules updated',
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules',
|
||||
MODULES_NONE: 'No external modules detected'
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
@@ -325,7 +325,10 @@ const fr: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default fr;
|
||||
|
||||
@@ -325,7 +325,10 @@ const it: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default it;
|
||||
|
||||
@@ -325,7 +325,10 @@ const nl: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Applicatie-instellingen wijzigen',
|
||||
SECURITY_1: 'Gebruikers toevoegen of verwijderen',
|
||||
UPLOAD_DOWNLOAD_1: 'Upload-/downloadinstellingen en firmware',
|
||||
MODULES: 'Modules'
|
||||
MODULES: 'Module',
|
||||
MODULES_UPDATED: 'Modules geüpdatet',
|
||||
MODULES_DESCRIPTION: 'Klik op de module om EMS-ESP library modules te activeren of te deactiveren',
|
||||
MODULES_NONE: 'Geen externe modules gedetecteerd'
|
||||
};
|
||||
|
||||
export default nl;
|
||||
|
||||
@@ -325,7 +325,10 @@ const no: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default no;
|
||||
|
||||
@@ -325,7 +325,10 @@ const pl: BaseTranslation = {
|
||||
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
||||
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
||||
UPLOAD_DOWNLOAD_1: 'Wysyłanie/pobieranie ustawień i firmware',
|
||||
MODULES: 'Moduły'
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default pl;
|
||||
|
||||
@@ -325,7 +325,10 @@ const sk: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default sk;
|
||||
|
||||
@@ -325,7 +325,10 @@ const sv: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default sv;
|
||||
|
||||
@@ -325,7 +325,10 @@ const tr: Translation = {
|
||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||
SECURITY_1: 'Add or remove users', // TODO translate
|
||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // TODO translate
|
||||
MODULES: 'Modules' // TODO translate
|
||||
MODULES: 'Module', // TODO translate
|
||||
MODULES_UPDATED: 'Modules updated', // TODO translate
|
||||
MODULES_DESCRIPTION: 'Click on the Module to Activate or de-activate EMS-ESP library modules', // TODO translate
|
||||
MODULES_NONE: 'No external modules detected' // TODO translate
|
||||
};
|
||||
|
||||
export default tr;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import type { FC } from 'react';
|
||||
import { useBlocker } from 'react-router-dom';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import CircleIcon from '@mui/icons-material/Circle';
|
||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import { Box, Button, Typography } from '@mui/material';
|
||||
|
||||
import * as SystemApi from 'api/system';
|
||||
|
||||
import {
|
||||
Body,
|
||||
Cell,
|
||||
@@ -23,19 +26,28 @@ import {
|
||||
BlockNavigation,
|
||||
ButtonRow,
|
||||
FormLoader,
|
||||
MessageBox,
|
||||
SectionContent,
|
||||
useLayoutTitle
|
||||
} from 'components';
|
||||
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
|
||||
import * as EMSESP from './api';
|
||||
import ModulesDialog from './ModulesDialog';
|
||||
import type { ModuleItem, Modules } from './types';
|
||||
|
||||
const Modules: FC = () => {
|
||||
const { LL } = useI18nContext();
|
||||
const [numChanges, setNumChanges] = useState<number>(0);
|
||||
const [licenseChanges, setLicenseChanges] = useState<number>(0);
|
||||
const blocker = useBlocker(numChanges !== 0);
|
||||
|
||||
const [selectedModuleItem, setSelectedModuleItem] = useState<ModuleItem>();
|
||||
const [dialogOpen, setDialogOpen] = useState<boolean>(false);
|
||||
const [restarting, setRestarting] = useState<boolean>(false);
|
||||
const [restartNeeded, setRestartNeeded] = useState<boolean>(false);
|
||||
|
||||
const {
|
||||
data: modules,
|
||||
send: fetchModules,
|
||||
@@ -44,6 +56,17 @@ const Modules: FC = () => {
|
||||
initialData: []
|
||||
});
|
||||
|
||||
const { send: restartCommand } = useRequest(SystemApi.restart(), {
|
||||
immediate: false
|
||||
});
|
||||
|
||||
const restart = async () => {
|
||||
await restartCommand().catch((error: Error) => {
|
||||
toast.error(error.message);
|
||||
});
|
||||
setRestarting(true);
|
||||
};
|
||||
|
||||
const { send: writeModules } = useRequest(
|
||||
(data: Modules) => EMSESP.writeModules(data),
|
||||
{
|
||||
@@ -53,7 +76,7 @@ const Modules: FC = () => {
|
||||
|
||||
const modules_theme = useTheme({
|
||||
Table: `
|
||||
--data-table-library_grid-template-columns: 48px 180px 120px 100px repeat(1, minmax(160px, 1fr));
|
||||
--data-table-library_grid-template-columns: 48px 180px 120px 100px repeat(1, minmax(160px, 1fr)) 180px;
|
||||
`,
|
||||
BaseRow: `
|
||||
font-size: 14px;
|
||||
@@ -93,6 +116,20 @@ const Modules: FC = () => {
|
||||
`
|
||||
});
|
||||
|
||||
const onDialogClose = () => {
|
||||
setDialogOpen(false);
|
||||
};
|
||||
|
||||
const onDialogSave = (updatedItem: ModuleItem) => {
|
||||
setDialogOpen(false);
|
||||
updateModuleItem(updatedItem);
|
||||
};
|
||||
|
||||
const editModuleItem = useCallback((mi: ModuleItem) => {
|
||||
setSelectedModuleItem(mi);
|
||||
setDialogOpen(true);
|
||||
}, []);
|
||||
|
||||
const onCancel = async () => {
|
||||
await fetchModules().then(() => {
|
||||
setNumChanges(0);
|
||||
@@ -100,16 +137,20 @@ const Modules: FC = () => {
|
||||
};
|
||||
|
||||
function hasModulesChanged(mi: ModuleItem) {
|
||||
return mi.enabled !== mi.o_enabled;
|
||||
return mi.enabled !== mi.o_enabled || mi.license !== mi.o_license;
|
||||
}
|
||||
|
||||
const selectModule = (updatedItem: ModuleItem) => {
|
||||
updatedItem.enabled = !updatedItem.enabled;
|
||||
function hasModuleLicenseChanged(mi: ModuleItem) {
|
||||
return mi.license !== mi.o_license;
|
||||
}
|
||||
|
||||
const updateModuleItem = (updatedItem: ModuleItem) => {
|
||||
updateState('modules', (data: ModuleItem[]) => {
|
||||
const new_data = data.map((mi) =>
|
||||
mi.id === updatedItem.id ? { ...mi, ...updatedItem } : mi
|
||||
);
|
||||
setNumChanges(new_data.filter((mi) => hasModulesChanged(mi)).length);
|
||||
setLicenseChanges(new_data.filter((mi) => hasModuleLicenseChanged(mi)).length);
|
||||
return new_data;
|
||||
});
|
||||
};
|
||||
@@ -117,12 +158,13 @@ const Modules: FC = () => {
|
||||
const saveModules = async () => {
|
||||
await writeModules({
|
||||
modules: modules.map((condensed_mi) => ({
|
||||
name: condensed_mi.name,
|
||||
enabled: condensed_mi.enabled
|
||||
key: condensed_mi.key,
|
||||
enabled: condensed_mi.enabled,
|
||||
license: condensed_mi.license
|
||||
}))
|
||||
})
|
||||
.then(() => {
|
||||
toast.success('Modules saved');
|
||||
toast.success(LL.MODULES_UPDATED());
|
||||
})
|
||||
.catch((error: Error) => {
|
||||
toast.error(error.message);
|
||||
@@ -130,104 +172,134 @@ const Modules: FC = () => {
|
||||
.finally(() => {
|
||||
setNumChanges(0);
|
||||
});
|
||||
setRestartNeeded(licenseChanges > 0);
|
||||
};
|
||||
|
||||
const renderModules = () => {
|
||||
const renderContent = () => {
|
||||
if (!modules) {
|
||||
return <FormLoader onRetry={fetchModules} errorMessage={error?.message} />;
|
||||
}
|
||||
|
||||
useLayoutTitle('Modules');
|
||||
useLayoutTitle(LL.MODULES());
|
||||
|
||||
if (modules.length === 0) {
|
||||
return (
|
||||
<Typography variant="body2" color="error">
|
||||
No modules detected
|
||||
{LL.MODULES_NONE()}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const colorStatus = (status: number) => {
|
||||
if (status === 1) {
|
||||
return <div style={{ color: 'red' }}>Pending Activation</div>;
|
||||
}
|
||||
return <div style={{ color: '#00FF7F' }}>Activated</div>;
|
||||
};
|
||||
|
||||
return (
|
||||
<Table
|
||||
data={{ nodes: modules }}
|
||||
theme={modules_theme}
|
||||
layout={{ custom: true }}
|
||||
>
|
||||
{(tableList: ModuleItem[]) => (
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell />
|
||||
<HeaderCell stiff>{LL.NAME(0)}</HeaderCell>
|
||||
<HeaderCell stiff>Author</HeaderCell>
|
||||
<HeaderCell stiff>{LL.VERSION()}</HeaderCell>
|
||||
<HeaderCell stiff>{LL.STATUS_OF('')}</HeaderCell>
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((mi: ModuleItem) => (
|
||||
<Row key={mi.id} item={mi} onClick={() => selectModule(mi)}>
|
||||
<Cell stiff>
|
||||
{mi.enabled ? (
|
||||
<CircleIcon
|
||||
color="success"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
) : (
|
||||
<CircleIcon
|
||||
color="error"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
)}
|
||||
</Cell>
|
||||
<Cell>{mi.name}</Cell>
|
||||
<Cell>{mi.author}</Cell>
|
||||
<Cell>{mi.version}</Cell>
|
||||
<Cell>{mi.status}</Cell>
|
||||
</Row>
|
||||
))}
|
||||
</Body>
|
||||
</>
|
||||
<>
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body2">{LL.MODULES_DESCRIPTION()}</Typography>
|
||||
</Box>
|
||||
<Table
|
||||
data={{ nodes: modules }}
|
||||
theme={modules_theme}
|
||||
layout={{ custom: true }}
|
||||
>
|
||||
{(tableList: ModuleItem[]) => (
|
||||
<>
|
||||
<Header>
|
||||
<HeaderRow>
|
||||
<HeaderCell />
|
||||
<HeaderCell>{LL.NAME(0)}</HeaderCell>
|
||||
<HeaderCell>Author</HeaderCell>
|
||||
<HeaderCell>{LL.VERSION()}</HeaderCell>
|
||||
<HeaderCell>Message</HeaderCell>
|
||||
<HeaderCell>{LL.STATUS_OF('')}</HeaderCell>
|
||||
</HeaderRow>
|
||||
</Header>
|
||||
<Body>
|
||||
{tableList.map((mi: ModuleItem) => (
|
||||
<Row key={mi.id} item={mi} onClick={() => editModuleItem(mi)}>
|
||||
<Cell stiff>
|
||||
{mi.enabled ? (
|
||||
<CircleIcon
|
||||
color="success"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
) : (
|
||||
<CircleIcon
|
||||
color="error"
|
||||
sx={{ fontSize: 16, verticalAlign: 'middle' }}
|
||||
/>
|
||||
)}
|
||||
</Cell>
|
||||
<Cell>{mi.name}</Cell>
|
||||
<Cell>{mi.author}</Cell>
|
||||
<Cell>{mi.version}</Cell>
|
||||
<Cell>{mi.message}</Cell>
|
||||
<Cell>{colorStatus(mi.status)}</Cell>
|
||||
</Row>
|
||||
))}
|
||||
</Body>
|
||||
</>
|
||||
)}
|
||||
</Table>
|
||||
|
||||
{restartNeeded ? (
|
||||
<MessageBox my={2} level="warning" message={LL.RESTART_TEXT(0)}>
|
||||
<Button
|
||||
startIcon={<PowerSettingsNewIcon />}
|
||||
variant="contained"
|
||||
color="error"
|
||||
onClick={restart}
|
||||
>
|
||||
{LL.RESTART()}
|
||||
</Button>
|
||||
</MessageBox>
|
||||
) : (
|
||||
<Box mt={1} display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={onCancel}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="contained"
|
||||
color="info"
|
||||
onClick={saveModules}
|
||||
>
|
||||
{LL.APPLY_CHANGES(numChanges)}
|
||||
</Button>
|
||||
</ButtonRow>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SectionContent>
|
||||
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||
<Box mb={2} color="warning.main">
|
||||
<Typography variant="body2">
|
||||
Activate or de-activate EMS-ESP library modules by selecting (**
|
||||
experimental **)
|
||||
</Typography>
|
||||
</Box>
|
||||
{renderModules()}
|
||||
|
||||
<Box mt={1} display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1}>
|
||||
{numChanges !== 0 && (
|
||||
<ButtonRow>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={onCancel}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<WarningIcon color="warning" />}
|
||||
variant="contained"
|
||||
color="info"
|
||||
onClick={saveModules}
|
||||
>
|
||||
{LL.APPLY_CHANGES(numChanges)}
|
||||
</Button>
|
||||
</ButtonRow>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
{restarting ? <RestartMonitor /> : renderContent()}
|
||||
{selectedModuleItem && (
|
||||
<ModulesDialog
|
||||
open={dialogOpen}
|
||||
onClose={onDialogClose}
|
||||
onSave={onDialogSave}
|
||||
selectedItem={selectedModuleItem}
|
||||
/>
|
||||
)}
|
||||
</SectionContent>
|
||||
);
|
||||
};
|
||||
|
||||
108
interface/src/project/ModulesDialog.tsx
Normal file
108
interface/src/project/ModulesDialog.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid,
|
||||
TextField
|
||||
} from '@mui/material';
|
||||
|
||||
import { dialogStyle } from 'CustomTheme';
|
||||
import { BlockFormControlLabel } from 'components';
|
||||
import { useI18nContext } from 'i18n/i18n-react';
|
||||
import { updateValue } from 'utils';
|
||||
|
||||
import type { ModuleItem } from './types';
|
||||
|
||||
interface ModulesDialogProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (mi: ModuleItem) => void;
|
||||
selectedItem: ModuleItem;
|
||||
}
|
||||
|
||||
const ModulesDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
onSave,
|
||||
selectedItem
|
||||
}: ModulesDialogProps) => {
|
||||
const { LL } = useI18nContext();
|
||||
const [editItem, setEditItem] = useState<ModuleItem>(selectedItem);
|
||||
|
||||
const updateFormValue = updateValue(setEditItem);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setEditItem(selectedItem);
|
||||
}
|
||||
}, [open, selectedItem]);
|
||||
|
||||
const close = () => {
|
||||
onClose();
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
onSave(editItem);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog sx={dialogStyle} open={open} onClose={onClose}>
|
||||
<DialogTitle>
|
||||
{LL.EDIT() + ' ' + LL.MODULES() + ' : ' + editItem.key}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<Grid container>
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={editItem.enabled}
|
||||
onChange={updateFormValue}
|
||||
name="enabled"
|
||||
/>
|
||||
}
|
||||
label={LL.ACTIVE()}
|
||||
/>
|
||||
</Grid>
|
||||
<Box mt={1} mb={1}>
|
||||
<TextField
|
||||
name="license"
|
||||
label="License Key"
|
||||
multiline
|
||||
rows={6}
|
||||
fullWidth
|
||||
value={editItem.license}
|
||||
onChange={updateFormValue}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
startIcon={<CancelIcon />}
|
||||
variant="outlined"
|
||||
onClick={close}
|
||||
color="secondary"
|
||||
>
|
||||
{LL.CANCEL()}
|
||||
</Button>
|
||||
<Button
|
||||
startIcon={<DoneIcon />}
|
||||
variant="outlined"
|
||||
onClick={save}
|
||||
color="primary"
|
||||
>
|
||||
{LL.UPDATE()}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModulesDialog;
|
||||
@@ -113,7 +113,8 @@ export const readModules = () =>
|
||||
transformData(data) {
|
||||
return (data as Modules).modules.map((mi: ModuleItem) => ({
|
||||
...mi,
|
||||
o_enabled: mi.enabled
|
||||
o_enabled: mi.enabled,
|
||||
o_license: mi.license
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -310,12 +310,16 @@ export interface Schedule {
|
||||
|
||||
export interface ModuleItem {
|
||||
id: number; // unique index
|
||||
key: string;
|
||||
name: string;
|
||||
author: string;
|
||||
version: string;
|
||||
status: string;
|
||||
status: number;
|
||||
message: string;
|
||||
enabled: boolean;
|
||||
license: string;
|
||||
o_enabled?: boolean;
|
||||
o_license?: string;
|
||||
}
|
||||
|
||||
export interface Modules {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { busConnectionStatus } from 'project/types';
|
||||
|
||||
import type { NetworkConnectionStatus } from './network';
|
||||
|
||||
export interface ESPSystemStatus {
|
||||
emsesp_version: string;
|
||||
esp_platform: string;
|
||||
@@ -37,6 +39,8 @@ export interface SystemStatus {
|
||||
ntp_status: number;
|
||||
mqtt_status: boolean;
|
||||
ap_status: boolean;
|
||||
network_status: NetworkConnectionStatus;
|
||||
wifi_rssi: number;
|
||||
}
|
||||
|
||||
export enum LogLevel {
|
||||
|
||||
@@ -39,13 +39,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/code-frame@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/code-frame@npm:7.24.6"
|
||||
"@babel/code-frame@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/code-frame@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/highlight": "npm:^7.24.6"
|
||||
"@babel/highlight": "npm:^7.24.7"
|
||||
picocolors: "npm:^1.0.0"
|
||||
checksum: 10c0/c93c6d1763530f415218c31d07359364397f19b70026abdff766164c21ed352a931cf07f3102c5fb9e04792de319e332d68bcb1f7debef601a02197f90f9ba24
|
||||
checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -56,10 +56,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/compat-data@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/compat-data@npm:7.24.6"
|
||||
checksum: 10c0/f50abbd4008eb2a5d12139c578809cebbeaeb8e660fb12d546eb2e7c2108ae1836ab8339184a5f5ce0e95bf81bb91e18edce86b387c59db937b01693ec0bc774
|
||||
"@babel/compat-data@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/compat-data@npm:7.24.7"
|
||||
checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -86,26 +86,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/core@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/core@npm:7.24.6"
|
||||
"@babel/core@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/core@npm:7.24.7"
|
||||
dependencies:
|
||||
"@ampproject/remapping": "npm:^2.2.0"
|
||||
"@babel/code-frame": "npm:^7.24.6"
|
||||
"@babel/generator": "npm:^7.24.6"
|
||||
"@babel/helper-compilation-targets": "npm:^7.24.6"
|
||||
"@babel/helper-module-transforms": "npm:^7.24.6"
|
||||
"@babel/helpers": "npm:^7.24.6"
|
||||
"@babel/parser": "npm:^7.24.6"
|
||||
"@babel/template": "npm:^7.24.6"
|
||||
"@babel/traverse": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
"@babel/code-frame": "npm:^7.24.7"
|
||||
"@babel/generator": "npm:^7.24.7"
|
||||
"@babel/helper-compilation-targets": "npm:^7.24.7"
|
||||
"@babel/helper-module-transforms": "npm:^7.24.7"
|
||||
"@babel/helpers": "npm:^7.24.7"
|
||||
"@babel/parser": "npm:^7.24.7"
|
||||
"@babel/template": "npm:^7.24.7"
|
||||
"@babel/traverse": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
convert-source-map: "npm:^2.0.0"
|
||||
debug: "npm:^4.1.0"
|
||||
gensync: "npm:^1.0.0-beta.2"
|
||||
json5: "npm:^2.2.3"
|
||||
semver: "npm:^6.3.1"
|
||||
checksum: 10c0/e0762a8daef7f417494d555929418cfacd6848c7fc3310ec00e6dd8cecac20b7f590e760bfc9365d2af07874a3f5599832f9c9ff7f1a9d126a168f77ba67945a
|
||||
checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -132,15 +132,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/generator@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/generator@npm:7.24.6"
|
||||
"@babel/generator@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/generator@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
"@jridgewell/gen-mapping": "npm:^0.3.5"
|
||||
"@jridgewell/trace-mapping": "npm:^0.3.25"
|
||||
jsesc: "npm:^2.5.1"
|
||||
checksum: 10c0/8d71a17b386536582354afba53cc784396458a88cc9f05f0c6de0ec99475f6f539943b3566b2e733820c4928236952473831765e483c25d68cc007a6e604d782
|
||||
checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -166,16 +166,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-compilation-targets@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-compilation-targets@npm:7.24.6"
|
||||
"@babel/helper-compilation-targets@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-compilation-targets@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/compat-data": "npm:^7.24.6"
|
||||
"@babel/helper-validator-option": "npm:^7.24.6"
|
||||
"@babel/compat-data": "npm:^7.24.7"
|
||||
"@babel/helper-validator-option": "npm:^7.24.7"
|
||||
browserslist: "npm:^4.22.2"
|
||||
lru-cache: "npm:^5.1.1"
|
||||
semver: "npm:^6.3.1"
|
||||
checksum: 10c0/4d41150086959f5f4d72d27bae29204192e943537ecb71df1711d1f5d8791358a44f3a5882ed3c8238ba0c874b0b55213af43767e14771765f13b8d15b262432
|
||||
checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -186,10 +186,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-environment-visitor@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-environment-visitor@npm:7.24.6"
|
||||
checksum: 10c0/fdcd18ac505ed71f40c05cc992b648a4495b0aa5310a774492a0f74d8dcf3579691102f516561a651d3de6c3a44fe64bfb3049d11c14c5857634ef1823ea409a
|
||||
"@babel/helper-environment-visitor@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-environment-visitor@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -203,13 +205,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-function-name@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-function-name@npm:7.24.6"
|
||||
"@babel/helper-function-name@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-function-name@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/template": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/5ba2f8db789b3f5a2b2239300a217aa212e303cd7bfad9c8b90563807f49215e8c679e8f8f177b6aaca2038038e29bc702b83839e1f7b4896d79c44a75cac97a
|
||||
"@babel/template": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/e5e41e6cf86bd0f8bf272cbb6e7c5ee0f3e9660414174435a46653efba4f2479ce03ce04abff2aa2ef9359cf057c79c06cb7b134a565ad9c0e8a50dcdc3b43c4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -222,12 +224,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-hoist-variables@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-hoist-variables@npm:7.24.6"
|
||||
"@babel/helper-hoist-variables@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-hoist-variables@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/e10ec6b864aaa419ec4934f5fcb5d0cfcc9d0657584a1b6c3c42ada949d44ca6bffcdab433a90ada4396c747e551cca31ba0e565ea005ab3f50964e3817bf6cf
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -240,12 +242,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-module-imports@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-module-imports@npm:7.24.6"
|
||||
"@babel/helper-module-imports@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-module-imports@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/e0db3fbfcd963d138f0792ff626f940a576fcf212d02b8fe6478dccf3421bd1c2a76f8e69c7450c049985e7b63b30be309a24eeeb6ad7c2137a31b676a095a84
|
||||
"@babel/traverse": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -264,18 +267,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-module-transforms@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-module-transforms@npm:7.24.6"
|
||||
"@babel/helper-module-transforms@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-module-transforms@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.6"
|
||||
"@babel/helper-module-imports": "npm:^7.24.6"
|
||||
"@babel/helper-simple-access": "npm:^7.24.6"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.24.6"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||
"@babel/helper-module-imports": "npm:^7.24.7"
|
||||
"@babel/helper-simple-access": "npm:^7.24.7"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.24.7"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0
|
||||
checksum: 10c0/9e2e3d0ddb397b36b9e8c7d94e175a36be8cb888ef370cefef2cdfd53ae1f87d567b268bd90ed9a6c706485a8de3da19cac577657613e9cd17210b91cbdfb00b
|
||||
checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -295,12 +298,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-simple-access@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-simple-access@npm:7.24.6"
|
||||
"@babel/helper-simple-access@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-simple-access@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/b17e404dd6c9787fc7d558aea5222471a77e29596705f0d10b4c2a58b9d71ff7eae915094204848cc1af99b771553caa69337a768b9abdd82b54a0050ba83eb9
|
||||
"@babel/traverse": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/7230e419d59a85f93153415100a5faff23c133d7442c19e0cd070da1784d13cd29096ee6c5a5761065c44e8164f9f80e3a518c41a0256df39e38f7ad6744fed7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -313,12 +317,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-split-export-declaration@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-split-export-declaration@npm:7.24.6"
|
||||
"@babel/helper-split-export-declaration@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-split-export-declaration@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/53a5dd8691fdffc89cc7fcf5aed0ad1d8bc39796a5782a3d170dcbf249eb5c15cc8a290e8d09615711d18798ad04a7d0694ab5195d35fa651abbc1b9c885d6a8
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -329,10 +333,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-string-parser@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-string-parser@npm:7.24.6"
|
||||
checksum: 10c0/95115bf676e92c4e99166395649108d97447e6cabef1fabaec8cdbc53a43f27b5df2268ff6534439d405bc1bd06685b163eb3b470455bd49f69159dada414145
|
||||
"@babel/helper-string-parser@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-string-parser@npm:7.24.7"
|
||||
checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -343,10 +347,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-validator-identifier@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-validator-identifier@npm:7.24.6"
|
||||
checksum: 10c0/d29d2e3fca66c31867a009014169b93f7bc21c8fc1dd7d0b9d85d7a4000670526ff2222d966febb75a6e12f9859a31d1e75b558984e28ecb69651314dd0a6fd1
|
||||
"@babel/helper-validator-identifier@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-validator-identifier@npm:7.24.7"
|
||||
checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -357,10 +361,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-validator-option@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helper-validator-option@npm:7.24.6"
|
||||
checksum: 10c0/787268dff5cf77f3b704454b96ab7b58aa4f43b2808247e51859a103a1c28a9c252100f830433f4b37a73f4a61ba745bbeef4cdccbab48c1e9adf037f4ca3491
|
||||
"@babel/helper-validator-option@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helper-validator-option@npm:7.24.7"
|
||||
checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -375,13 +379,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helpers@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/helpers@npm:7.24.6"
|
||||
"@babel/helpers@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/helpers@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/template": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/e5b5c0919fd6fa56ae11c15a72962d8de0ac19db524849554af28cf08ac32f9ae5aee49a43146eb150f54418cefb8e890fa2b2f33d029434dc7777dbcdfd5bac
|
||||
"@babel/template": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -397,15 +401,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/highlight@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/highlight@npm:7.24.6"
|
||||
"@babel/highlight@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/highlight@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||
chalk: "npm:^2.4.2"
|
||||
js-tokens: "npm:^4.0.0"
|
||||
picocolors: "npm:^1.0.0"
|
||||
checksum: 10c0/5bbc31695e5d44e97feb267f7aaf4c52908560d184ffeb2e2e57aae058d40125592931883889413e19def3326895ddb41ff45e090fa90b459d8c294b4ffc238c
|
||||
checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -418,12 +422,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/parser@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/parser@npm:7.24.6"
|
||||
"@babel/parser@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/parser@npm:7.24.7"
|
||||
bin:
|
||||
parser: ./bin/babel-parser.js
|
||||
checksum: 10c0/cbef70923078a20fe163b03f4a6482be65ed99d409a57f3091a23ce3a575ee75716c30e7ea9f40b692ac5660f34055f4cbeb66a354fad15a6cf1fca35c3496c5
|
||||
checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -484,14 +488,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/template@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/template@npm:7.24.6"
|
||||
"@babel/template@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/template@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.24.6"
|
||||
"@babel/parser": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
checksum: 10c0/a4d5805770de908b445f7cdcebfcb6eaa07b1ec9c7b78fd3f375a911b1522c249bddae6b96bc4aac24247cc603e3e6cffcf2fe50b4c929dfeb22de289b517525
|
||||
"@babel/code-frame": "npm:^7.24.7"
|
||||
"@babel/parser": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
checksum: 10c0/95b0b3ee80fcef685b7f4426f5713a855ea2cd5ac4da829b213f8fb5afe48a2a14683c2ea04d446dbc7f711c33c5cd4a965ef34dcbe5bc387c9e966b67877ae3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -531,21 +535,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/traverse@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/traverse@npm:7.24.6"
|
||||
"@babel/traverse@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/traverse@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.24.6"
|
||||
"@babel/generator": "npm:^7.24.6"
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.6"
|
||||
"@babel/helper-function-name": "npm:^7.24.6"
|
||||
"@babel/helper-hoist-variables": "npm:^7.24.6"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.24.6"
|
||||
"@babel/parser": "npm:^7.24.6"
|
||||
"@babel/types": "npm:^7.24.6"
|
||||
"@babel/code-frame": "npm:^7.24.7"
|
||||
"@babel/generator": "npm:^7.24.7"
|
||||
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||
"@babel/helper-function-name": "npm:^7.24.7"
|
||||
"@babel/helper-hoist-variables": "npm:^7.24.7"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.24.7"
|
||||
"@babel/parser": "npm:^7.24.7"
|
||||
"@babel/types": "npm:^7.24.7"
|
||||
debug: "npm:^4.3.1"
|
||||
globals: "npm:^11.1.0"
|
||||
checksum: 10c0/39027d5fc7a241c6b71bb5872c2bdcec53743cd7ef3c151bbe6fd7cf874d15f4bc09e5d7e19e2f534b0eb2c115f5368553885fa4253aa1bc9441c6e5bf9efdaf
|
||||
checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -570,14 +574,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/types@npm:^7.24.6":
|
||||
version: 7.24.6
|
||||
resolution: "@babel/types@npm:7.24.6"
|
||||
"@babel/types@npm:^7.24.7":
|
||||
version: 7.24.7
|
||||
resolution: "@babel/types@npm:7.24.7"
|
||||
dependencies:
|
||||
"@babel/helper-string-parser": "npm:^7.24.6"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
||||
"@babel/helper-string-parser": "npm:^7.24.7"
|
||||
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||
to-fast-properties: "npm:^2.0.0"
|
||||
checksum: 10c0/1d94d92d97ef49030ad7f9e14cfccfeb70b1706dabcaa69037e659ec9d2c3178fb005d2088cce40d88dfc1306153d9157fe038a79ea2be92e5e6b99a59ef80cc
|
||||
checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1738,12 +1742,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^20.14.1":
|
||||
version: 20.14.1
|
||||
resolution: "@types/node@npm:20.14.1"
|
||||
"@types/node@npm:^20.14.2":
|
||||
version: 20.14.2
|
||||
resolution: "@types/node@npm:20.14.2"
|
||||
dependencies:
|
||||
undici-types: "npm:~5.26.4"
|
||||
checksum: 10c0/12b7879047f50cc217bbea3add7c45e542070f6e9fb2092be97542152b7022512bcb2bf848d04f77e295c4c8699acd484e79a4a4dbe9bcfa4e89dd543d530611
|
||||
checksum: 10c0/2d86e5f2227aaa42212e82ea0affe72799111b888ff900916376450b02b09b963ca888b20d9c332d8d2b833ed4781987867a38eaa2e4863fa8439071468b0a6f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1962,7 +1966,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@alova/adapter-xhr": "npm:^1.0.6"
|
||||
"@alova/scene-react": "npm:^1.5.0"
|
||||
"@babel/core": "npm:^7.24.6"
|
||||
"@babel/core": "npm:^7.24.7"
|
||||
"@emotion/react": "npm:^11.11.4"
|
||||
"@emotion/styled": "npm:^11.11.5"
|
||||
"@eslint/js": "npm:^9.4.0"
|
||||
@@ -1974,7 +1978,7 @@ __metadata:
|
||||
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
|
||||
"@types/babel__core": "npm:^7"
|
||||
"@types/lodash-es": "npm:^4.17.12"
|
||||
"@types/node": "npm:^20.14.1"
|
||||
"@types/node": "npm:^20.14.2"
|
||||
"@types/react": "npm:^18.3.3"
|
||||
"@types/react-dom": "npm:^18.3.0"
|
||||
"@types/react-router-dom": "npm:^5.3.3"
|
||||
@@ -1988,7 +1992,7 @@ __metadata:
|
||||
lodash-es: "npm:^4.17.21"
|
||||
mime-types: "npm:^2.1.35"
|
||||
preact: "npm:^10.22.0"
|
||||
prettier: "npm:^3.3.0"
|
||||
prettier: "npm:^3.3.1"
|
||||
react: "npm:latest"
|
||||
react-dom: "npm:latest"
|
||||
react-dropzone: "npm:^14.2.3"
|
||||
@@ -1996,11 +2000,11 @@ __metadata:
|
||||
react-router-dom: "npm:^6.23.1"
|
||||
react-toastify: "npm:^10.0.5"
|
||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||
terser: "npm:^5.31.0"
|
||||
terser: "npm:^5.31.1"
|
||||
typesafe-i18n: "npm:^5.26.2"
|
||||
typescript: "npm:^5.4.5"
|
||||
typescript-eslint: "npm:^7.12.0"
|
||||
vite: "npm:^5.2.12"
|
||||
vite: "npm:^5.2.13"
|
||||
vite-plugin-imagemin: "npm:^0.6.1"
|
||||
vite-tsconfig-paths: "npm:^4.3.2"
|
||||
languageName: unknown
|
||||
@@ -5932,12 +5936,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"prettier@npm:^3.3.0":
|
||||
version: 3.3.0
|
||||
resolution: "prettier@npm:3.3.0"
|
||||
"prettier@npm:^3.3.1":
|
||||
version: 3.3.1
|
||||
resolution: "prettier@npm:3.3.1"
|
||||
bin:
|
||||
prettier: bin/prettier.cjs
|
||||
checksum: 10c0/d033c356320aa2e468bf29c931b094ac730d2f4defd5eb2989d8589313dec901d2fc866e3788f3d161e420b142ea4ec3dda535dbe0169ef4d0026397a68ba9cf
|
||||
checksum: 10c0/c25a709c9f0be670dc6bcb190b622347e1dbeb6c3e7df8b0711724cb64d8647c60b839937a4df4df18e9cfb556c2b08ca9d24d9645eb5488a7fc032a2c4d5cb3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6968,9 +6972,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"terser@npm:^5.31.0":
|
||||
version: 5.31.0
|
||||
resolution: "terser@npm:5.31.0"
|
||||
"terser@npm:^5.31.1":
|
||||
version: 5.31.1
|
||||
resolution: "terser@npm:5.31.1"
|
||||
dependencies:
|
||||
"@jridgewell/source-map": "npm:^0.3.3"
|
||||
acorn: "npm:^8.8.2"
|
||||
@@ -6978,7 +6982,7 @@ __metadata:
|
||||
source-map-support: "npm:~0.5.20"
|
||||
bin:
|
||||
terser: bin/terser
|
||||
checksum: 10c0/cb127a579b03fb9dcee0d293ff24814deedcd430f447933b618e8593b7454f615b5c8493c68e86a4b0188769d5ea2af5251b5d507edb208114f7e8aebdc7c850
|
||||
checksum: 10c0/4d49a58f64c11f3742e779a0a03aff69972ca5739decb361d909d22c8f3f7d8e2ec982a928d987d56737ad50229e8ab3f62d8ba993e4b5f360a53ed487d3c06c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7318,9 +7322,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^5.2.12":
|
||||
version: 5.2.12
|
||||
resolution: "vite@npm:5.2.12"
|
||||
"vite@npm:^5.2.13":
|
||||
version: 5.2.13
|
||||
resolution: "vite@npm:5.2.13"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.20.1"
|
||||
fsevents: "npm:~2.3.3"
|
||||
@@ -7354,7 +7358,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/f03fdfc320adea3397df3e327029fd875f8220779f679ab183a3a994e8788b4ce531fee28f830361fb274f3cf08ed9adb9429496ecefdc3faf535b38da7ea8b1
|
||||
checksum: 10c0/f7a99da71884e69cc581dcfb43d73c8d56d73b9668d6980131603c544d6323c6003a20f376531dc0cfcf36bf5009bc465f89e6c5f8bd9d22868987aba4e4af1b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -89,8 +89,8 @@ typedef enum { WS_MSG_SENDING, WS_MSG_SENT, WS_MSG_ERROR } AwsMessageStatus;
|
||||
typedef enum { WS_EVT_CONNECT, WS_EVT_DISCONNECT, WS_EVT_PONG, WS_EVT_ERROR, WS_EVT_DATA } AwsEventType;
|
||||
|
||||
class AsyncWebSocketMessageBuffer {
|
||||
friend AsyncWebSocket;
|
||||
friend AsyncWebSocketClient;
|
||||
friend AsyncWebSocket;
|
||||
friend AsyncWebSocketClient;
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::vector<uint8_t>> _buffer;
|
||||
@@ -98,114 +98,165 @@ class AsyncWebSocketMessageBuffer {
|
||||
public:
|
||||
AsyncWebSocketMessageBuffer();
|
||||
AsyncWebSocketMessageBuffer(size_t size);
|
||||
AsyncWebSocketMessageBuffer(uint8_t* data, size_t size);
|
||||
AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
|
||||
~AsyncWebSocketMessageBuffer();
|
||||
bool reserve(size_t size);
|
||||
uint8_t* get() { return _buffer->data(); }
|
||||
size_t length() const { return _buffer->size(); }
|
||||
bool reserve(size_t size);
|
||||
uint8_t * get() {
|
||||
return _buffer->data();
|
||||
}
|
||||
size_t length() const {
|
||||
return _buffer->size();
|
||||
}
|
||||
};
|
||||
|
||||
class AsyncWebSocketMessage
|
||||
{
|
||||
private:
|
||||
class AsyncWebSocketMessage {
|
||||
private:
|
||||
std::shared_ptr<std::vector<uint8_t>> _WSbuffer;
|
||||
uint8_t _opcode{WS_TEXT};
|
||||
bool _mask{false};
|
||||
AwsMessageStatus _status{WS_MSG_ERROR};
|
||||
size_t _sent{};
|
||||
size_t _ack{};
|
||||
size_t _acked{};
|
||||
uint8_t _opcode{WS_TEXT};
|
||||
bool _mask{false};
|
||||
AwsMessageStatus _status{WS_MSG_ERROR};
|
||||
size_t _sent{};
|
||||
size_t _ack{};
|
||||
size_t _acked{};
|
||||
|
||||
public:
|
||||
AsyncWebSocketMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false);
|
||||
public:
|
||||
AsyncWebSocketMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
||||
|
||||
bool finished() const { return _status != WS_MSG_SENDING; }
|
||||
bool betweenFrames() const { return _acked == _ack; }
|
||||
bool finished() const {
|
||||
return _status != WS_MSG_SENDING;
|
||||
}
|
||||
bool betweenFrames() const {
|
||||
return _acked == _ack;
|
||||
}
|
||||
|
||||
void ack(size_t len, uint32_t time);
|
||||
size_t send(AsyncClient *client);
|
||||
void ack(size_t len, uint32_t time);
|
||||
size_t send(AsyncClient * client);
|
||||
};
|
||||
|
||||
class AsyncWebSocketClient {
|
||||
private:
|
||||
AsyncClient *_client;
|
||||
AsyncWebSocket *_server;
|
||||
uint32_t _clientId;
|
||||
AwsClientStatus _status;
|
||||
AsyncClient * _client;
|
||||
AsyncWebSocket * _server;
|
||||
uint32_t _clientId;
|
||||
AwsClientStatus _status;
|
||||
|
||||
AsyncWebLock _lock;
|
||||
|
||||
std::deque<AsyncWebSocketControl> _controlQueue;
|
||||
std::deque<AsyncWebSocketMessage> _messageQueue;
|
||||
bool closeWhenFull = true;
|
||||
|
||||
uint8_t _pstate;
|
||||
uint8_t _pstate;
|
||||
AwsFrameInfo _pinfo;
|
||||
|
||||
uint32_t _lastMessageTime;
|
||||
uint32_t _keepAlivePeriod;
|
||||
|
||||
void _queueControl(uint8_t opcode, const uint8_t *data=NULL, size_t len=0, bool mask=false);
|
||||
void _queueMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false);
|
||||
void _queueControl(uint8_t opcode, const uint8_t * data = NULL, size_t len = 0, bool mask = false);
|
||||
void _queueMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
||||
void _runQueue();
|
||||
void _clearQueue();
|
||||
|
||||
public:
|
||||
void *_tempObject;
|
||||
void * _tempObject;
|
||||
|
||||
AsyncWebSocketClient(AsyncWebServerRequest *request, AsyncWebSocket *server);
|
||||
AsyncWebSocketClient(AsyncWebServerRequest * request, AsyncWebSocket * server);
|
||||
~AsyncWebSocketClient();
|
||||
|
||||
//client id increments for the given server
|
||||
uint32_t id() const { return _clientId; }
|
||||
AwsClientStatus status() const { return _status; }
|
||||
AsyncClient* client() { return _client; }
|
||||
const AsyncClient* client() const { return _client; }
|
||||
AsyncWebSocket *server(){ return _server; }
|
||||
const AsyncWebSocket *server() const { return _server; }
|
||||
AwsFrameInfo const &pinfo() const { return _pinfo; }
|
||||
uint32_t id() const {
|
||||
return _clientId;
|
||||
}
|
||||
AwsClientStatus status() const {
|
||||
return _status;
|
||||
}
|
||||
AsyncClient * client() {
|
||||
return _client;
|
||||
}
|
||||
const AsyncClient * client() const {
|
||||
return _client;
|
||||
}
|
||||
AsyncWebSocket * server() {
|
||||
return _server;
|
||||
}
|
||||
const AsyncWebSocket * server() const {
|
||||
return _server;
|
||||
}
|
||||
AwsFrameInfo const & pinfo() const {
|
||||
return _pinfo;
|
||||
}
|
||||
|
||||
// - If "true" (default), the connection will be closed if the message queue is full.
|
||||
// This is the default behavior in yubox-node-org, which is not silently discarding messages but instead closes the connection.
|
||||
// The big issue with this behavior is that is can cause the UI to automatically re-create a new WS connection, which can be filled again,
|
||||
// and so on, causing a resource exhaustion.
|
||||
//
|
||||
// - If "false", the incoming message will be discarded if the queue is full.
|
||||
// This is the default behavior in the original ESPAsyncWebServer library from me-no-dev.
|
||||
// This behavior allows the best performance at the expense of unreliable message delivery in case the queue is full (some messages may be lost).
|
||||
//
|
||||
// - In any case, when the queue is full, a message is logged.
|
||||
// - IT is recommended to use the methods queueIsFull(), availableForWriteAll(), availableForWrite(clientId) to check if the queue is full before sending a message.
|
||||
//
|
||||
// Usage:
|
||||
// - can be set in the onEvent listener when connecting (event type is: WS_EVT_CONNECT)
|
||||
//
|
||||
// Use cases:,
|
||||
// - if using websocket to send logging messages, maybe some loss is acceptable.
|
||||
// - But if using websocket to send UI update messages, maybe the connection should be closed and the UI redrawn.
|
||||
void setCloseClientOnQueueFull(bool close) {
|
||||
closeWhenFull = close;
|
||||
}
|
||||
bool willCloseClientOnQueueFull() const {
|
||||
return closeWhenFull;
|
||||
}
|
||||
|
||||
IPAddress remoteIP() const;
|
||||
uint16_t remotePort() const;
|
||||
|
||||
bool shouldBeDeleted() const { return !_client; }
|
||||
bool shouldBeDeleted() const {
|
||||
return !_client;
|
||||
}
|
||||
|
||||
//control frames
|
||||
void close(uint16_t code=0, const char * message=NULL);
|
||||
void ping(const uint8_t *data=NULL, size_t len=0);
|
||||
void close(uint16_t code = 0, const char * message = NULL);
|
||||
void ping(const uint8_t * data = NULL, size_t len = 0);
|
||||
|
||||
//set auto-ping period in seconds. disabled if zero (default)
|
||||
void keepAlivePeriod(uint16_t seconds){
|
||||
_keepAlivePeriod = seconds * 1000;
|
||||
void keepAlivePeriod(uint16_t seconds) {
|
||||
_keepAlivePeriod = seconds * 1000;
|
||||
}
|
||||
uint16_t keepAlivePeriod(){
|
||||
return (uint16_t)(_keepAlivePeriod / 1000);
|
||||
uint16_t keepAlivePeriod() {
|
||||
return (uint16_t)(_keepAlivePeriod / 1000);
|
||||
}
|
||||
|
||||
//data packets
|
||||
void message(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false) { _queueMessage(buffer, opcode, mask); }
|
||||
bool queueIsFull() const;
|
||||
void message(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false) {
|
||||
_queueMessage(buffer, opcode, mask);
|
||||
}
|
||||
bool queueIsFull() const;
|
||||
size_t queueLen() const;
|
||||
|
||||
size_t printf(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t printf(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
||||
#ifndef ESP32
|
||||
size_t printf_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t printf_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
||||
#endif
|
||||
|
||||
void text(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
void text(const uint8_t *message, size_t len);
|
||||
void text(const char *message, size_t len);
|
||||
void text(const char *message);
|
||||
void text(const String &message);
|
||||
void text(const __FlashStringHelper *message);
|
||||
void text(AsyncWebSocketMessageBuffer *buffer);
|
||||
void text(const uint8_t * message, size_t len);
|
||||
void text(const char * message, size_t len);
|
||||
void text(const char * message);
|
||||
void text(const String & message);
|
||||
void text(const __FlashStringHelper * message);
|
||||
void text(AsyncWebSocketMessageBuffer * buffer);
|
||||
|
||||
void binary(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
void binary(const uint8_t *message, size_t len);
|
||||
void binary(const uint8_t * message, size_t len);
|
||||
void binary(const char * message, size_t len);
|
||||
void binary(const char * message);
|
||||
void binary(const String &message);
|
||||
void binary(const __FlashStringHelper *message, size_t len);
|
||||
void binary(AsyncWebSocketMessageBuffer *buffer);
|
||||
void binary(const String & message);
|
||||
void binary(const __FlashStringHelper * message, size_t len);
|
||||
void binary(AsyncWebSocketMessageBuffer * buffer);
|
||||
|
||||
bool canSend() const;
|
||||
|
||||
@@ -215,113 +266,132 @@ class AsyncWebSocketClient {
|
||||
void _onPoll();
|
||||
void _onTimeout(uint32_t time);
|
||||
void _onDisconnect();
|
||||
void _onData(void *pbuf, size_t plen);
|
||||
void _onData(void * pbuf, size_t plen);
|
||||
};
|
||||
|
||||
typedef std::function<bool(AsyncWebServerRequest *request)> AwsHandshakeHandler;
|
||||
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)> AwsEventHandler;
|
||||
typedef std::function<bool(AsyncWebServerRequest * request)> AwsHandshakeHandler;
|
||||
typedef std::function<void(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len)> AwsEventHandler;
|
||||
|
||||
//WebServer Handler implementation that plays the role of a socket server
|
||||
class AsyncWebSocket: public AsyncWebHandler {
|
||||
class AsyncWebSocket : public AsyncWebHandler {
|
||||
private:
|
||||
String _url;
|
||||
String _url;
|
||||
std::list<AsyncWebSocketClient> _clients;
|
||||
uint32_t _cNextId;
|
||||
AwsEventHandler _eventHandler;
|
||||
AwsHandshakeHandler _handshakeHandler;
|
||||
bool _enabled;
|
||||
AsyncWebLock _lock;
|
||||
uint32_t _cNextId;
|
||||
AwsEventHandler _eventHandler;
|
||||
AwsHandshakeHandler _handshakeHandler;
|
||||
bool _enabled;
|
||||
AsyncWebLock _lock;
|
||||
|
||||
public:
|
||||
AsyncWebSocket(const String& url);
|
||||
AsyncWebSocket(const String & url);
|
||||
~AsyncWebSocket();
|
||||
const char * url() const { return _url.c_str(); }
|
||||
void enable(bool e){ _enabled = e; }
|
||||
bool enabled() const { return _enabled; }
|
||||
const char * url() const {
|
||||
return _url.c_str();
|
||||
}
|
||||
void enable(bool e) {
|
||||
_enabled = e;
|
||||
}
|
||||
bool enabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
bool availableForWriteAll();
|
||||
bool availableForWrite(uint32_t id);
|
||||
|
||||
size_t count() const;
|
||||
size_t count() const;
|
||||
AsyncWebSocketClient * client(uint32_t id);
|
||||
bool hasClient(uint32_t id){ return client(id) != NULL; }
|
||||
bool hasClient(uint32_t id) {
|
||||
return client(id) != NULL;
|
||||
}
|
||||
|
||||
void close(uint32_t id, uint16_t code=0, const char * message=NULL);
|
||||
void closeAll(uint16_t code=0, const char * message=NULL);
|
||||
void close(uint32_t id, uint16_t code = 0, const char * message = NULL);
|
||||
void closeAll(uint16_t code = 0, const char * message = NULL);
|
||||
void cleanupClients(uint16_t maxClients = DEFAULT_MAX_WS_CLIENTS);
|
||||
|
||||
void ping(uint32_t id, const uint8_t *data=NULL, size_t len=0);
|
||||
void pingAll(const uint8_t *data=NULL, size_t len=0); // done
|
||||
void ping(uint32_t id, const uint8_t * data = NULL, size_t len = 0);
|
||||
void pingAll(const uint8_t * data = NULL, size_t len = 0); // done
|
||||
|
||||
void text(uint32_t id, const uint8_t * message, size_t len);
|
||||
void text(uint32_t id, const char *message, size_t len);
|
||||
void text(uint32_t id, const char *message);
|
||||
void text(uint32_t id, const String &message);
|
||||
void text(uint32_t id, const __FlashStringHelper *message);
|
||||
void text(uint32_t id, const char * message, size_t len);
|
||||
void text(uint32_t id, const char * message);
|
||||
void text(uint32_t id, const String & message);
|
||||
void text(uint32_t id, const __FlashStringHelper * message);
|
||||
void text(uint32_t id, AsyncWebSocketMessageBuffer * buffer);
|
||||
void text(uint32_t id, std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
|
||||
void textAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
void textAll(const uint8_t *message, size_t len);
|
||||
void textAll(const uint8_t * message, size_t len);
|
||||
void textAll(const char * message, size_t len);
|
||||
void textAll(const char * message);
|
||||
void textAll(const String &message);
|
||||
void textAll(const __FlashStringHelper *message); // need to convert
|
||||
void textAll(AsyncWebSocketMessageBuffer *buffer);
|
||||
void textAll(const String & message);
|
||||
void textAll(const __FlashStringHelper * message);
|
||||
void textAll(AsyncWebSocketMessageBuffer * buffer);
|
||||
void textAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
|
||||
void binary(uint32_t id, const uint8_t *message, size_t len);
|
||||
void binary(uint32_t id, const char *message, size_t len);
|
||||
void binary(uint32_t id, const char *message);
|
||||
void binary(uint32_t id, const String &message);
|
||||
void binary(uint32_t id, const __FlashStringHelper *message, size_t len);
|
||||
void binary(uint32_t id, const uint8_t * message, size_t len);
|
||||
void binary(uint32_t id, const char * message, size_t len);
|
||||
void binary(uint32_t id, const char * message);
|
||||
void binary(uint32_t id, const String & message);
|
||||
void binary(uint32_t id, const __FlashStringHelper * message, size_t len);
|
||||
void binary(uint32_t id, AsyncWebSocketMessageBuffer * buffer);
|
||||
void binary(uint32_t id, std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
|
||||
void binaryAll(const uint8_t * message, size_t len);
|
||||
void binaryAll(const char * message, size_t len);
|
||||
void binaryAll(const char * message);
|
||||
void binaryAll(const String & message);
|
||||
void binaryAll(const __FlashStringHelper * message, size_t len);
|
||||
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
|
||||
void binaryAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||
void binaryAll(const uint8_t *message, size_t len);
|
||||
void binaryAll(const char *message, size_t len);
|
||||
void binaryAll(const char *message);
|
||||
void binaryAll(const String &message);
|
||||
void binaryAll(const __FlashStringHelper *message, size_t len);
|
||||
void binaryAll(AsyncWebSocketMessageBuffer *buffer);
|
||||
|
||||
size_t printf(uint32_t id, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
size_t printfAll(const char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t printf(uint32_t id, const char * format, ...) __attribute__((format(printf, 3, 4)));
|
||||
size_t printfAll(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
||||
#ifndef ESP32
|
||||
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
size_t printf_P(uint32_t id, PGM_P formatP, ...) __attribute__((format(printf, 3, 4)));
|
||||
#endif
|
||||
size_t printfAll_P(PGM_P formatP, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t printfAll_P(PGM_P formatP, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
//event listener
|
||||
void onEvent(AwsEventHandler handler){
|
||||
_eventHandler = handler;
|
||||
void onEvent(AwsEventHandler handler) {
|
||||
_eventHandler = handler;
|
||||
}
|
||||
|
||||
// Handshake Handler
|
||||
void handleHandshake(AwsHandshakeHandler handler){
|
||||
_handshakeHandler = handler;
|
||||
void handleHandshake(AwsHandshakeHandler handler) {
|
||||
_handshakeHandler = handler;
|
||||
}
|
||||
|
||||
//system callbacks (do not call)
|
||||
uint32_t _getNextId(){ return _cNextId++; }
|
||||
AsyncWebSocketClient *_newClient(AsyncWebServerRequest *request);
|
||||
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||
uint32_t _getNextId() {
|
||||
return _cNextId++;
|
||||
}
|
||||
AsyncWebSocketClient * _newClient(AsyncWebServerRequest * request);
|
||||
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len);
|
||||
virtual bool canHandle(AsyncWebServerRequest * request) override final;
|
||||
virtual void handleRequest(AsyncWebServerRequest * request) override final;
|
||||
|
||||
|
||||
// messagebuffer functions/objects.
|
||||
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
|
||||
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);
|
||||
|
||||
const std::list<AsyncWebSocketClient> &getClients() const { return _clients; }
|
||||
const std::list<AsyncWebSocketClient> & getClients() const {
|
||||
return _clients;
|
||||
}
|
||||
};
|
||||
|
||||
//WebServer response to authenticate the socket and detach the tcp client from the web server request
|
||||
class AsyncWebSocketResponse: public AsyncWebServerResponse {
|
||||
class AsyncWebSocketResponse : public AsyncWebServerResponse {
|
||||
private:
|
||||
String _content;
|
||||
AsyncWebSocket *_server;
|
||||
String _content;
|
||||
AsyncWebSocket * _server;
|
||||
|
||||
public:
|
||||
AsyncWebSocketResponse(const String& key, AsyncWebSocket *server);
|
||||
void _respond(AsyncWebServerRequest *request);
|
||||
size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time);
|
||||
bool _sourceValid() const { return true; }
|
||||
AsyncWebSocketResponse(const String & key, AsyncWebSocket * server);
|
||||
void _respond(AsyncWebServerRequest * request);
|
||||
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
||||
bool _sourceValid() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "WebAuthentication.h"
|
||||
#include <libb64/cencode.h>
|
||||
#ifdef ESP32
|
||||
#include "mbedtls/md5.h"
|
||||
#include <MD5Builder.h>
|
||||
#else
|
||||
#include "md5.h"
|
||||
#endif
|
||||
@@ -29,220 +29,221 @@
|
||||
|
||||
// Basic Auth hash = base64("username:password")
|
||||
|
||||
bool checkBasicAuthentication(const char * hash, const char * username, const char * password){
|
||||
if(username == NULL || password == NULL || hash == NULL)
|
||||
return false;
|
||||
bool checkBasicAuthentication(const char * hash, const char * username, const char * password) {
|
||||
if (username == NULL || password == NULL || hash == NULL)
|
||||
return false;
|
||||
|
||||
size_t toencodeLen = strlen(username)+strlen(password)+1;
|
||||
size_t encodedLen = base64_encode_expected_len(toencodeLen);
|
||||
if(strlen(hash) != encodedLen)
|
||||
size_t toencodeLen = strlen(username) + strlen(password) + 1;
|
||||
size_t encodedLen = base64_encode_expected_len(toencodeLen);
|
||||
if (strlen(hash) != encodedLen)
|
||||
// Fix from https://github.com/me-no-dev/ESPAsyncWebServer/issues/667
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
if(strlen(hash) != encodedLen)
|
||||
if (strlen(hash) != encodedLen)
|
||||
#else
|
||||
if (strlen(hash) != encodedLen - 1)
|
||||
if (strlen(hash) != encodedLen - 1)
|
||||
#endif
|
||||
return false;
|
||||
return false;
|
||||
|
||||
char *toencode = new char[toencodeLen+1];
|
||||
if(toencode == NULL){
|
||||
return false;
|
||||
}
|
||||
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
|
||||
if(encoded == NULL){
|
||||
delete[] toencode;
|
||||
return false;
|
||||
}
|
||||
sprintf_P(toencode, PSTR("%s:%s"), username, password);
|
||||
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0){
|
||||
char * toencode = new char[toencodeLen + 1];
|
||||
if (toencode == NULL) {
|
||||
return false;
|
||||
}
|
||||
char * encoded = new char[base64_encode_expected_len(toencodeLen) + 1];
|
||||
if (encoded == NULL) {
|
||||
delete[] toencode;
|
||||
return false;
|
||||
}
|
||||
sprintf_P(toencode, PSTR("%s:%s"), username, password);
|
||||
if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && memcmp(hash, encoded, encodedLen) == 0) {
|
||||
delete[] toencode;
|
||||
delete[] encoded;
|
||||
return true;
|
||||
}
|
||||
delete[] toencode;
|
||||
delete[] encoded;
|
||||
return true;
|
||||
}
|
||||
delete[] toencode;
|
||||
delete[] encoded;
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool getMD5(uint8_t * data, uint16_t len, char * output){//33 bytes or more
|
||||
static bool getMD5(uint8_t * data, uint16_t len, char * output) { //33 bytes or more
|
||||
#ifdef ESP32
|
||||
mbedtls_md5_context _ctx;
|
||||
MD5Builder md5;
|
||||
md5.begin();
|
||||
md5.add(data, len);
|
||||
md5.calculate();
|
||||
md5.getChars(output);
|
||||
#else
|
||||
md5_context_t _ctx;
|
||||
#endif
|
||||
uint8_t i;
|
||||
uint8_t * _buf = (uint8_t*)malloc(16);
|
||||
if(_buf == NULL)
|
||||
return false;
|
||||
memset(_buf, 0x00, 16);
|
||||
#ifdef ESP32
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
mbedtls_md5_init(&_ctx);
|
||||
mbedtls_md5_starts_ret(&_ctx);
|
||||
mbedtls_md5_update_ret(&_ctx, data, len);
|
||||
mbedtls_md5_finish_ret(&_ctx, _buf);
|
||||
#else
|
||||
mbedtls_md5_init(&_ctx);
|
||||
mbedtls_md5_starts(&_ctx);
|
||||
mbedtls_md5_update(&_ctx, data, len);
|
||||
mbedtls_md5_finish(&_ctx, _buf);
|
||||
#endif
|
||||
#else
|
||||
MD5Init(&_ctx);
|
||||
MD5Update(&_ctx, data, len);
|
||||
MD5Final(_buf, &_ctx);
|
||||
#endif
|
||||
for(i = 0; i < 16; i++) {
|
||||
sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]);
|
||||
}
|
||||
free(_buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
static String genRandomMD5(){
|
||||
#ifdef ESP8266
|
||||
uint32_t r = RANDOM_REG32;
|
||||
#else
|
||||
uint32_t r = rand();
|
||||
#endif
|
||||
char * out = (char*)malloc(33);
|
||||
if(out == NULL || !getMD5((uint8_t*)(&r), 4, out))
|
||||
return emptyString;
|
||||
String res = String(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
uint8_t * _buf = (uint8_t *)malloc(16);
|
||||
if (_buf == NULL)
|
||||
return false;
|
||||
memset(_buf, 0x00, 16);
|
||||
|
||||
static String stringMD5(const String& in){
|
||||
char * out = (char*)malloc(33);
|
||||
if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
|
||||
return emptyString;
|
||||
String res = String(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
MD5Init(&_ctx);
|
||||
MD5Update(&_ctx, data, len);
|
||||
MD5Final(_buf, &_ctx);
|
||||
|
||||
String generateDigestHash(const char * username, const char * password, const char * realm){
|
||||
if(username == NULL || password == NULL || realm == NULL){
|
||||
return emptyString;
|
||||
}
|
||||
char * out = (char*)malloc(33);
|
||||
String res = String(username);
|
||||
res += ':';
|
||||
res.concat(realm);
|
||||
res += ':';
|
||||
String in = res;
|
||||
in.concat(password);
|
||||
if(out == NULL || !getMD5((uint8_t*)(in.c_str()), in.length(), out))
|
||||
return emptyString;
|
||||
res.concat(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
|
||||
String requestDigestAuthentication(const char * realm){
|
||||
String header = F("realm=\"");
|
||||
if(realm == NULL)
|
||||
header.concat(F("asyncesp"));
|
||||
else
|
||||
header.concat(realm);
|
||||
header.concat(F("\", qop=\"auth\", nonce=\""));
|
||||
header.concat(genRandomMD5());
|
||||
header.concat(F("\", opaque=\""));
|
||||
header.concat(genRandomMD5());
|
||||
header += '"';
|
||||
return header;
|
||||
}
|
||||
|
||||
bool checkDigestAuthentication(const char * header, const __FlashStringHelper *method, const char * username, const char * password, const char * realm, bool passwordIsHash, const char * nonce, const char * opaque, const char * uri){
|
||||
if(username == NULL || password == NULL || header == NULL || method == NULL){
|
||||
//os_printf("AUTH FAIL: missing requred fields\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
String myHeader = String(header);
|
||||
int nextBreak = myHeader.indexOf(',');
|
||||
if(nextBreak < 0){
|
||||
//os_printf("AUTH FAIL: no variables\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
String myUsername = String();
|
||||
String myRealm = String();
|
||||
String myNonce = String();
|
||||
String myUri = String();
|
||||
String myResponse = String();
|
||||
String myQop = String();
|
||||
String myNc = String();
|
||||
String myCnonce = String();
|
||||
|
||||
myHeader += F(", ");
|
||||
do {
|
||||
String avLine = myHeader.substring(0, nextBreak);
|
||||
avLine.trim();
|
||||
myHeader = myHeader.substring(nextBreak+1);
|
||||
nextBreak = myHeader.indexOf(',');
|
||||
|
||||
int eqSign = avLine.indexOf('=');
|
||||
if(eqSign < 0){
|
||||
//os_printf("AUTH FAIL: no = sign\n");
|
||||
return false;
|
||||
}
|
||||
String varName = avLine.substring(0, eqSign);
|
||||
avLine = avLine.substring(eqSign + 1);
|
||||
if(avLine.startsWith(String('"'))){
|
||||
avLine = avLine.substring(1, avLine.length() - 1);
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]);
|
||||
}
|
||||
|
||||
if(varName.equals(F("username"))){
|
||||
if(!avLine.equals(username)){
|
||||
//os_printf("AUTH FAIL: username\n");
|
||||
return false;
|
||||
}
|
||||
myUsername = avLine;
|
||||
} else if(varName.equals(F("realm"))){
|
||||
if(realm != NULL && !avLine.equals(realm)){
|
||||
//os_printf("AUTH FAIL: realm\n");
|
||||
return false;
|
||||
}
|
||||
myRealm = avLine;
|
||||
} else if(varName.equals(F("nonce"))){
|
||||
if(nonce != NULL && !avLine.equals(nonce)){
|
||||
//os_printf("AUTH FAIL: nonce\n");
|
||||
return false;
|
||||
}
|
||||
myNonce = avLine;
|
||||
} else if(varName.equals(F("opaque"))){
|
||||
if(opaque != NULL && !avLine.equals(opaque)){
|
||||
//os_printf("AUTH FAIL: opaque\n");
|
||||
return false;
|
||||
}
|
||||
} else if(varName.equals(F("uri"))){
|
||||
if(uri != NULL && !avLine.equals(uri)){
|
||||
//os_printf("AUTH FAIL: uri\n");
|
||||
return false;
|
||||
}
|
||||
myUri = avLine;
|
||||
} else if(varName.equals(F("response"))){
|
||||
myResponse = avLine;
|
||||
} else if(varName.equals(F("qop"))){
|
||||
myQop = avLine;
|
||||
} else if(varName.equals(F("nc"))){
|
||||
myNc = avLine;
|
||||
} else if(varName.equals(F("cnonce"))){
|
||||
myCnonce = avLine;
|
||||
}
|
||||
} while(nextBreak > 0);
|
||||
|
||||
String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + String(password));
|
||||
String ha2 = String(method) + ':' + myUri;
|
||||
String response = ha1 + ':' + myNonce + ':' + myNc + ':' + myCnonce + ':' + myQop + ':' + stringMD5(ha2);
|
||||
|
||||
if(myResponse.equals(stringMD5(response))){
|
||||
//os_printf("AUTH SUCCESS\n");
|
||||
free(_buf);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//os_printf("AUTH FAIL: password\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static String genRandomMD5() {
|
||||
#ifdef ESP8266
|
||||
uint32_t r = RANDOM_REG32;
|
||||
#else
|
||||
uint32_t r = rand();
|
||||
#endif
|
||||
char * out = (char *)malloc(33);
|
||||
if (out == NULL || !getMD5((uint8_t *)(&r), 4, out))
|
||||
return emptyString;
|
||||
String res = String(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
|
||||
static String stringMD5(const String & in) {
|
||||
char * out = (char *)malloc(33);
|
||||
if (out == NULL || !getMD5((uint8_t *)(in.c_str()), in.length(), out))
|
||||
return emptyString;
|
||||
String res = String(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
|
||||
String generateDigestHash(const char * username, const char * password, const char * realm) {
|
||||
if (username == NULL || password == NULL || realm == NULL) {
|
||||
return emptyString;
|
||||
}
|
||||
char * out = (char *)malloc(33);
|
||||
String res = String(username);
|
||||
res += ':';
|
||||
res.concat(realm);
|
||||
res += ':';
|
||||
String in = res;
|
||||
in.concat(password);
|
||||
if (out == NULL || !getMD5((uint8_t *)(in.c_str()), in.length(), out))
|
||||
return emptyString;
|
||||
res.concat(out);
|
||||
free(out);
|
||||
return res;
|
||||
}
|
||||
|
||||
String requestDigestAuthentication(const char * realm) {
|
||||
String header = F("realm=\"");
|
||||
if (realm == NULL)
|
||||
header.concat(F("asyncesp"));
|
||||
else
|
||||
header.concat(realm);
|
||||
header.concat(F("\", qop=\"auth\", nonce=\""));
|
||||
header.concat(genRandomMD5());
|
||||
header.concat(F("\", opaque=\""));
|
||||
header.concat(genRandomMD5());
|
||||
header += '"';
|
||||
return header;
|
||||
}
|
||||
|
||||
bool checkDigestAuthentication(const char * header,
|
||||
const __FlashStringHelper * method,
|
||||
const char * username,
|
||||
const char * password,
|
||||
const char * realm,
|
||||
bool passwordIsHash,
|
||||
const char * nonce,
|
||||
const char * opaque,
|
||||
const char * uri) {
|
||||
if (username == NULL || password == NULL || header == NULL || method == NULL) {
|
||||
//os_printf("AUTH FAIL: missing requred fields\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
String myHeader = String(header);
|
||||
int nextBreak = myHeader.indexOf(',');
|
||||
if (nextBreak < 0) {
|
||||
//os_printf("AUTH FAIL: no variables\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
String myUsername = String();
|
||||
String myRealm = String();
|
||||
String myNonce = String();
|
||||
String myUri = String();
|
||||
String myResponse = String();
|
||||
String myQop = String();
|
||||
String myNc = String();
|
||||
String myCnonce = String();
|
||||
|
||||
myHeader += F(", ");
|
||||
do {
|
||||
String avLine = myHeader.substring(0, nextBreak);
|
||||
avLine.trim();
|
||||
myHeader = myHeader.substring(nextBreak + 1);
|
||||
nextBreak = myHeader.indexOf(',');
|
||||
|
||||
int eqSign = avLine.indexOf('=');
|
||||
if (eqSign < 0) {
|
||||
//os_printf("AUTH FAIL: no = sign\n");
|
||||
return false;
|
||||
}
|
||||
String varName = avLine.substring(0, eqSign);
|
||||
avLine = avLine.substring(eqSign + 1);
|
||||
if (avLine.startsWith(String('"'))) {
|
||||
avLine = avLine.substring(1, avLine.length() - 1);
|
||||
}
|
||||
|
||||
if (varName.equals(F("username"))) {
|
||||
if (!avLine.equals(username)) {
|
||||
//os_printf("AUTH FAIL: username\n");
|
||||
return false;
|
||||
}
|
||||
myUsername = avLine;
|
||||
} else if (varName.equals(F("realm"))) {
|
||||
if (realm != NULL && !avLine.equals(realm)) {
|
||||
//os_printf("AUTH FAIL: realm\n");
|
||||
return false;
|
||||
}
|
||||
myRealm = avLine;
|
||||
} else if (varName.equals(F("nonce"))) {
|
||||
if (nonce != NULL && !avLine.equals(nonce)) {
|
||||
//os_printf("AUTH FAIL: nonce\n");
|
||||
return false;
|
||||
}
|
||||
myNonce = avLine;
|
||||
} else if (varName.equals(F("opaque"))) {
|
||||
if (opaque != NULL && !avLine.equals(opaque)) {
|
||||
//os_printf("AUTH FAIL: opaque\n");
|
||||
return false;
|
||||
}
|
||||
} else if (varName.equals(F("uri"))) {
|
||||
if (uri != NULL && !avLine.equals(uri)) {
|
||||
//os_printf("AUTH FAIL: uri\n");
|
||||
return false;
|
||||
}
|
||||
myUri = avLine;
|
||||
} else if (varName.equals(F("response"))) {
|
||||
myResponse = avLine;
|
||||
} else if (varName.equals(F("qop"))) {
|
||||
myQop = avLine;
|
||||
} else if (varName.equals(F("nc"))) {
|
||||
myNc = avLine;
|
||||
} else if (varName.equals(F("cnonce"))) {
|
||||
myCnonce = avLine;
|
||||
}
|
||||
} while (nextBreak > 0);
|
||||
|
||||
String ha1 = (passwordIsHash) ? String(password) : stringMD5(myUsername + ':' + myRealm + ':' + String(password));
|
||||
String ha2 = String(method) + ':' + myUri;
|
||||
String response = ha1 + ':' + myNonce + ':' + myNc + ':' + myCnonce + ':' + myQop + ':' + stringMD5(ha2);
|
||||
|
||||
if (myResponse.equals(stringMD5(response))) {
|
||||
//os_printf("AUTH SUCCESS\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
//os_printf("AUTH FAIL: password\n");
|
||||
return false;
|
||||
}
|
||||
284
lib/ESPAsyncWebServer/src/port/SHA1Builder.cpp
Normal file
284
lib/ESPAsyncWebServer/src/port/SHA1Builder.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* FIPS-180-1 compliant SHA-1 implementation
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
* Modified for esp32 by Lucas Saavedra Vaz on 11 Jan 2024
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#if ESP_IDF_VERSION_MAJOR < 5
|
||||
|
||||
#include "SHA1Builder.h"
|
||||
|
||||
// 32-bit integer manipulation macros (big endian)
|
||||
|
||||
#ifndef GET_UINT32_BE
|
||||
#define GET_UINT32_BE(n, b, i) \
|
||||
{ (n) = ((uint32_t)(b)[(i)] << 24) | ((uint32_t)(b)[(i) + 1] << 16) | ((uint32_t)(b)[(i) + 2] << 8) | ((uint32_t)(b)[(i) + 3]); }
|
||||
#endif
|
||||
|
||||
#ifndef PUT_UINT32_BE
|
||||
#define PUT_UINT32_BE(n, b, i) \
|
||||
{ \
|
||||
(b)[(i)] = (uint8_t)((n) >> 24); \
|
||||
(b)[(i) + 1] = (uint8_t)((n) >> 16); \
|
||||
(b)[(i) + 2] = (uint8_t)((n) >> 8); \
|
||||
(b)[(i) + 3] = (uint8_t)((n)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constants
|
||||
|
||||
static const uint8_t sha1_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
// Private methods
|
||||
|
||||
void SHA1Builder::process(const uint8_t * data) {
|
||||
uint32_t temp, W[16], A, B, C, D, E;
|
||||
|
||||
GET_UINT32_BE(W[0], data, 0);
|
||||
GET_UINT32_BE(W[1], data, 4);
|
||||
GET_UINT32_BE(W[2], data, 8);
|
||||
GET_UINT32_BE(W[3], data, 12);
|
||||
GET_UINT32_BE(W[4], data, 16);
|
||||
GET_UINT32_BE(W[5], data, 20);
|
||||
GET_UINT32_BE(W[6], data, 24);
|
||||
GET_UINT32_BE(W[7], data, 28);
|
||||
GET_UINT32_BE(W[8], data, 32);
|
||||
GET_UINT32_BE(W[9], data, 36);
|
||||
GET_UINT32_BE(W[10], data, 40);
|
||||
GET_UINT32_BE(W[11], data, 44);
|
||||
GET_UINT32_BE(W[12], data, 48);
|
||||
GET_UINT32_BE(W[13], data, 52);
|
||||
GET_UINT32_BE(W[14], data, 56);
|
||||
GET_UINT32_BE(W[15], data, 60);
|
||||
|
||||
#define sha1_S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
|
||||
|
||||
#define sha1_R(t) (temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ W[(t - 14) & 0x0F] ^ W[t & 0x0F], (W[t & 0x0F] = sha1_S(temp, 1)))
|
||||
|
||||
#define sha1_P(a, b, c, d, e, x) \
|
||||
{ \
|
||||
e += sha1_S(a, 5) + sha1_F(b, c, d) + sha1_K + x; \
|
||||
b = sha1_S(b, 30); \
|
||||
}
|
||||
|
||||
A = state[0];
|
||||
B = state[1];
|
||||
C = state[2];
|
||||
D = state[3];
|
||||
E = state[4];
|
||||
|
||||
#define sha1_F(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define sha1_K 0x5A827999
|
||||
|
||||
sha1_P(A, B, C, D, E, W[0]);
|
||||
sha1_P(E, A, B, C, D, W[1]);
|
||||
sha1_P(D, E, A, B, C, W[2]);
|
||||
sha1_P(C, D, E, A, B, W[3]);
|
||||
sha1_P(B, C, D, E, A, W[4]);
|
||||
sha1_P(A, B, C, D, E, W[5]);
|
||||
sha1_P(E, A, B, C, D, W[6]);
|
||||
sha1_P(D, E, A, B, C, W[7]);
|
||||
sha1_P(C, D, E, A, B, W[8]);
|
||||
sha1_P(B, C, D, E, A, W[9]);
|
||||
sha1_P(A, B, C, D, E, W[10]);
|
||||
sha1_P(E, A, B, C, D, W[11]);
|
||||
sha1_P(D, E, A, B, C, W[12]);
|
||||
sha1_P(C, D, E, A, B, W[13]);
|
||||
sha1_P(B, C, D, E, A, W[14]);
|
||||
sha1_P(A, B, C, D, E, W[15]);
|
||||
sha1_P(E, A, B, C, D, sha1_R(16));
|
||||
sha1_P(D, E, A, B, C, sha1_R(17));
|
||||
sha1_P(C, D, E, A, B, sha1_R(18));
|
||||
sha1_P(B, C, D, E, A, sha1_R(19));
|
||||
|
||||
#undef sha1_K
|
||||
#undef sha1_F
|
||||
|
||||
#define sha1_F(x, y, z) (x ^ y ^ z)
|
||||
#define sha1_K 0x6ED9EBA1
|
||||
|
||||
sha1_P(A, B, C, D, E, sha1_R(20));
|
||||
sha1_P(E, A, B, C, D, sha1_R(21));
|
||||
sha1_P(D, E, A, B, C, sha1_R(22));
|
||||
sha1_P(C, D, E, A, B, sha1_R(23));
|
||||
sha1_P(B, C, D, E, A, sha1_R(24));
|
||||
sha1_P(A, B, C, D, E, sha1_R(25));
|
||||
sha1_P(E, A, B, C, D, sha1_R(26));
|
||||
sha1_P(D, E, A, B, C, sha1_R(27));
|
||||
sha1_P(C, D, E, A, B, sha1_R(28));
|
||||
sha1_P(B, C, D, E, A, sha1_R(29));
|
||||
sha1_P(A, B, C, D, E, sha1_R(30));
|
||||
sha1_P(E, A, B, C, D, sha1_R(31));
|
||||
sha1_P(D, E, A, B, C, sha1_R(32));
|
||||
sha1_P(C, D, E, A, B, sha1_R(33));
|
||||
sha1_P(B, C, D, E, A, sha1_R(34));
|
||||
sha1_P(A, B, C, D, E, sha1_R(35));
|
||||
sha1_P(E, A, B, C, D, sha1_R(36));
|
||||
sha1_P(D, E, A, B, C, sha1_R(37));
|
||||
sha1_P(C, D, E, A, B, sha1_R(38));
|
||||
sha1_P(B, C, D, E, A, sha1_R(39));
|
||||
|
||||
#undef sha1_K
|
||||
#undef sha1_F
|
||||
|
||||
#define sha1_F(x, y, z) ((x & y) | (z & (x | y)))
|
||||
#define sha1_K 0x8F1BBCDC
|
||||
|
||||
sha1_P(A, B, C, D, E, sha1_R(40));
|
||||
sha1_P(E, A, B, C, D, sha1_R(41));
|
||||
sha1_P(D, E, A, B, C, sha1_R(42));
|
||||
sha1_P(C, D, E, A, B, sha1_R(43));
|
||||
sha1_P(B, C, D, E, A, sha1_R(44));
|
||||
sha1_P(A, B, C, D, E, sha1_R(45));
|
||||
sha1_P(E, A, B, C, D, sha1_R(46));
|
||||
sha1_P(D, E, A, B, C, sha1_R(47));
|
||||
sha1_P(C, D, E, A, B, sha1_R(48));
|
||||
sha1_P(B, C, D, E, A, sha1_R(49));
|
||||
sha1_P(A, B, C, D, E, sha1_R(50));
|
||||
sha1_P(E, A, B, C, D, sha1_R(51));
|
||||
sha1_P(D, E, A, B, C, sha1_R(52));
|
||||
sha1_P(C, D, E, A, B, sha1_R(53));
|
||||
sha1_P(B, C, D, E, A, sha1_R(54));
|
||||
sha1_P(A, B, C, D, E, sha1_R(55));
|
||||
sha1_P(E, A, B, C, D, sha1_R(56));
|
||||
sha1_P(D, E, A, B, C, sha1_R(57));
|
||||
sha1_P(C, D, E, A, B, sha1_R(58));
|
||||
sha1_P(B, C, D, E, A, sha1_R(59));
|
||||
|
||||
#undef sha1_K
|
||||
#undef sha1_F
|
||||
|
||||
#define sha1_F(x, y, z) (x ^ y ^ z)
|
||||
#define sha1_K 0xCA62C1D6
|
||||
|
||||
sha1_P(A, B, C, D, E, sha1_R(60));
|
||||
sha1_P(E, A, B, C, D, sha1_R(61));
|
||||
sha1_P(D, E, A, B, C, sha1_R(62));
|
||||
sha1_P(C, D, E, A, B, sha1_R(63));
|
||||
sha1_P(B, C, D, E, A, sha1_R(64));
|
||||
sha1_P(A, B, C, D, E, sha1_R(65));
|
||||
sha1_P(E, A, B, C, D, sha1_R(66));
|
||||
sha1_P(D, E, A, B, C, sha1_R(67));
|
||||
sha1_P(C, D, E, A, B, sha1_R(68));
|
||||
sha1_P(B, C, D, E, A, sha1_R(69));
|
||||
sha1_P(A, B, C, D, E, sha1_R(70));
|
||||
sha1_P(E, A, B, C, D, sha1_R(71));
|
||||
sha1_P(D, E, A, B, C, sha1_R(72));
|
||||
sha1_P(C, D, E, A, B, sha1_R(73));
|
||||
sha1_P(B, C, D, E, A, sha1_R(74));
|
||||
sha1_P(A, B, C, D, E, sha1_R(75));
|
||||
sha1_P(E, A, B, C, D, sha1_R(76));
|
||||
sha1_P(D, E, A, B, C, sha1_R(77));
|
||||
sha1_P(C, D, E, A, B, sha1_R(78));
|
||||
sha1_P(B, C, D, E, A, sha1_R(79));
|
||||
|
||||
#undef sha1_K
|
||||
#undef sha1_F
|
||||
|
||||
state[0] += A;
|
||||
state[1] += B;
|
||||
state[2] += C;
|
||||
state[3] += D;
|
||||
state[4] += E;
|
||||
}
|
||||
|
||||
// Public methods
|
||||
|
||||
void SHA1Builder::begin(void) {
|
||||
total[0] = 0;
|
||||
total[1] = 0;
|
||||
|
||||
state[0] = 0x67452301;
|
||||
state[1] = 0xEFCDAB89;
|
||||
state[2] = 0x98BADCFE;
|
||||
state[3] = 0x10325476;
|
||||
state[4] = 0xC3D2E1F0;
|
||||
|
||||
memset(buffer, 0x00, sizeof(buffer));
|
||||
memset(hash, 0x00, sizeof(hash));
|
||||
}
|
||||
|
||||
void SHA1Builder::add(const uint8_t * data, size_t len) {
|
||||
size_t fill;
|
||||
uint32_t left;
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
left = total[0] & 0x3F;
|
||||
fill = 64 - left;
|
||||
|
||||
total[0] += (uint32_t)len;
|
||||
total[0] &= 0xFFFFFFFF;
|
||||
|
||||
if (total[0] < (uint32_t)len) {
|
||||
total[1]++;
|
||||
}
|
||||
|
||||
if (left && len >= fill) {
|
||||
memcpy((void *)(buffer + left), data, fill);
|
||||
process(buffer);
|
||||
data += fill;
|
||||
len -= fill;
|
||||
left = 0;
|
||||
}
|
||||
|
||||
while (len >= 64) {
|
||||
process(data);
|
||||
data += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
memcpy((void *)(buffer + left), data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void SHA1Builder::calculate(void) {
|
||||
uint32_t last, padn;
|
||||
uint32_t high, low;
|
||||
uint8_t msglen[8];
|
||||
|
||||
high = (total[0] >> 29) | (total[1] << 3);
|
||||
low = (total[0] << 3);
|
||||
|
||||
PUT_UINT32_BE(high, msglen, 0);
|
||||
PUT_UINT32_BE(low, msglen, 4);
|
||||
|
||||
last = total[0] & 0x3F;
|
||||
padn = (last < 56) ? (56 - last) : (120 - last);
|
||||
|
||||
add((uint8_t *)sha1_padding, padn);
|
||||
add(msglen, 8);
|
||||
|
||||
PUT_UINT32_BE(state[0], hash, 0);
|
||||
PUT_UINT32_BE(state[1], hash, 4);
|
||||
PUT_UINT32_BE(state[2], hash, 8);
|
||||
PUT_UINT32_BE(state[3], hash, 12);
|
||||
PUT_UINT32_BE(state[4], hash, 16);
|
||||
}
|
||||
|
||||
void SHA1Builder::getBytes(uint8_t * output) {
|
||||
memcpy(output, hash, SHA1_HASH_SIZE);
|
||||
}
|
||||
|
||||
#endif // ESP_IDF_VERSION_MAJOR < 5
|
||||
39
lib/ESPAsyncWebServer/src/port/SHA1Builder.h
Normal file
39
lib/ESPAsyncWebServer/src/port/SHA1Builder.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef SHA1Builder_h
|
||||
#define SHA1Builder_h
|
||||
|
||||
#include <Stream.h>
|
||||
#include <WString.h>
|
||||
|
||||
#define SHA1_HASH_SIZE 20
|
||||
|
||||
class SHA1Builder {
|
||||
private:
|
||||
uint32_t total[2]; /* number of bytes processed */
|
||||
uint32_t state[5]; /* intermediate digest state */
|
||||
unsigned char buffer[64]; /* data block being processed */
|
||||
uint8_t hash[SHA1_HASH_SIZE]; /* SHA-1 result */
|
||||
|
||||
void process(const uint8_t * data);
|
||||
|
||||
public:
|
||||
void begin();
|
||||
void add(const uint8_t * data, size_t len);
|
||||
void calculate();
|
||||
void getBytes(uint8_t * output);
|
||||
};
|
||||
|
||||
#endif // SHA1Builder_h
|
||||
@@ -381,7 +381,11 @@ const system_status = {
|
||||
free_heap: 143,
|
||||
ntp_status: 2,
|
||||
mqtt_status: true,
|
||||
ap_status: false
|
||||
ap_status: false,
|
||||
network_status: 3, // wifi connected
|
||||
// network_status: 10, // ethernet connected
|
||||
// network_status: 6, // wifi disconnected
|
||||
wifi_rssi: -41
|
||||
};
|
||||
|
||||
let security_settings = {
|
||||
@@ -2134,19 +2138,26 @@ let emsesp_modules = {
|
||||
"modules": [
|
||||
{
|
||||
id: 1,
|
||||
"name": "ModuleTest1",
|
||||
"key": "ModuleTest1",
|
||||
"name": "Module Test 1",
|
||||
"author": "proddy",
|
||||
"version": "1.0.0",
|
||||
"enabled": true,
|
||||
"status": "active"
|
||||
"status": 1,
|
||||
"message": "Ready",
|
||||
"license": "1234567890"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
"name": "ModuleTest2",
|
||||
"key": "ModuleTest2",
|
||||
"name": "Module Test 2",
|
||||
"author": "proddy",
|
||||
"version": "1.0.0",
|
||||
"enabled": true,
|
||||
"status": "active"
|
||||
"status": 2,
|
||||
"message": "Ready",
|
||||
"license": "ABCDEFGHIJKL"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2386,7 +2397,9 @@ router
|
||||
return status(200);
|
||||
})
|
||||
.get(VERIFY_AUTHORIZATION_ENDPOINT, () => verify_authentication)
|
||||
.post(RESTART_ENDPOINT, () => status(200))
|
||||
.post(RESTART_ENDPOINT, () => {
|
||||
console.log('restarting...');
|
||||
return status(200);})
|
||||
.post(FACTORY_RESET_ENDPOINT, () => status(200))
|
||||
.post(SIGN_IN_ENDPOINT, () => signin)
|
||||
.get(GENERATE_TOKEN_ENDPOINT, () => generate_token);
|
||||
@@ -2514,10 +2527,11 @@ router
|
||||
const content = await request.json();
|
||||
let modules = content.modules;
|
||||
for (let i = 0; i < modules.length; i++) {
|
||||
const name = modules[i].name;
|
||||
const objIndex = emsesp_modules.modules.findIndex((obj: any) => obj.name === name);
|
||||
const key = modules[i].key;
|
||||
const objIndex = emsesp_modules.modules.findIndex((obj: any) => obj.key === key);
|
||||
if (objIndex !== -1) {
|
||||
emsesp_modules.modules[objIndex].enabled = modules[i].enabled;
|
||||
emsesp_modules.modules[objIndex].license = modules[i].license;
|
||||
}
|
||||
}
|
||||
console.log('modules updated', emsesp_modules);
|
||||
|
||||
@@ -32,55 +32,62 @@ WebModulesService::WebModulesService(AsyncWebServer * server, FS * fs, SecurityM
|
||||
// load the settings when the service starts
|
||||
void WebModulesService::begin() {
|
||||
EMSESP::logger().info("Starting Modules service");
|
||||
moduleLibrary.start(emsesp_);
|
||||
|
||||
_fsPersistence.readFromFS(); // read the file from FS
|
||||
#ifdef EMSESP_TEST
|
||||
moduleLibrary.start(emsesp_, true); // hot load the test modules as well
|
||||
#else
|
||||
moduleLibrary.start(emsesp_);
|
||||
#endif
|
||||
|
||||
_fsPersistence.readFromFS(); // read the file from FS - this will call the update function WebModules::update()
|
||||
}
|
||||
|
||||
void WebModulesService::loop() {
|
||||
moduleLibrary.loop(); // loop the external library modules
|
||||
}
|
||||
|
||||
// this creates the modules file, saving it to the FS
|
||||
// and also calls when the Modules web page is refreshed
|
||||
// this creates the modules settings file, saving it to the file system
|
||||
// it adds data to an empty 'root' json object
|
||||
// and also calls when the Modules web page is refreshed/loaded
|
||||
void WebModules::read(WebModules & webModules, JsonObject root) {
|
||||
#ifdef EMSESP_DEBUG
|
||||
EMSESP::logger().debug("module read called");
|
||||
#endif
|
||||
|
||||
emsesp_->logger().err("debug: in WebModules::read()"); // TODO remove
|
||||
JsonDocument doc_modules;
|
||||
JsonObject root_modules = doc_modules.to<JsonObject>();
|
||||
moduleLibrary.list(root_modules); // get list the external library modules, put in root json object
|
||||
moduleLibrary.list(root_modules); // get list the external library modules, put in a json object
|
||||
|
||||
JsonArray modules = root["modules"].to<JsonArray>();
|
||||
uint8_t counter = 0;
|
||||
for (const JsonObject module : root_modules["modules"].as<JsonArray>()) {
|
||||
JsonObject mi = modules.add<JsonObject>();
|
||||
mi["id"] = counter++; // id is only used to render the table and must be unique
|
||||
mi["key"] = module["key"].as<std::string>();
|
||||
mi["name"] = module["name"].as<std::string>();
|
||||
mi["author"] = module["author"].as<std::string>();
|
||||
mi["version"] = module["version"].as<std::string>();
|
||||
mi["status"] = module["status"].as<std::string>();
|
||||
mi["status"] = module["status"].as<uint8_t>();
|
||||
mi["enabled"] = module["enabled"].as<bool>();
|
||||
mi["message"] = module["message"].as<std::string>();
|
||||
mi["license"] = module["license"].as<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
// read any Module settings from the FS settings
|
||||
// and then apply the enable/disable
|
||||
// it's also called on a save
|
||||
// read any Module settings from the settings file
|
||||
// and then apply the enable/disable that is set by the user
|
||||
// This function is called when ems-esp boots and also on a save from the Modules web page
|
||||
StateUpdateResult WebModules::update(JsonObject root, WebModules & webModules) {
|
||||
#ifdef EMSESP_DEBUG
|
||||
EMSESP::logger().debug("module update called");
|
||||
#endif
|
||||
|
||||
if (root["modules"].is<JsonArray>()) {
|
||||
for (const JsonObject module : root["modules"].as<JsonArray>()) {
|
||||
// set enabled/disabled
|
||||
moduleLibrary.enable(module["name"], module["enabled"].as<bool>());
|
||||
auto key = module["key"].as<const char *>();
|
||||
auto license = module["license"].as<const char *>();
|
||||
auto enable = module["enabled"].as<bool>();
|
||||
|
||||
if (!moduleLibrary.enable(key, license, enable)) {
|
||||
return StateUpdateResult::ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StateUpdateResult::CHANGED_RESTART;
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -251,7 +251,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
|
||||
check_flag(prev, settings.analog_enabled, ChangeFlags::ADC);
|
||||
|
||||
|
||||
//
|
||||
// these need system restarts first before settings are activated...
|
||||
//
|
||||
@@ -294,7 +293,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
//
|
||||
// without checks or necessary restarts...
|
||||
//
|
||||
|
||||
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
||||
EMSESP::trace_raw(settings.trace_raw);
|
||||
|
||||
|
||||
@@ -70,6 +70,14 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
|
||||
|
||||
root["ap_status"] = EMSESP::esp8266React.apStatus();
|
||||
|
||||
if (emsesp::EMSESP::system_.ethernet_connected()) {
|
||||
root["network_status"] = 10; // custom code #10 - ETHERNET_STATUS_CONNECTED
|
||||
root["wifi_rssi"] = 0;
|
||||
} else {
|
||||
root["network_status"] = static_cast<uint8_t>(WiFi.status());
|
||||
root["wifi_rssi"] = WiFi.RSSI();
|
||||
}
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user