mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
@@ -30,7 +30,7 @@
|
|||||||
"@mui/material": "^5.15.19",
|
"@mui/material": "^5.15.19",
|
||||||
"@table-library/react-table-library": "4.1.7",
|
"@table-library/react-table-library": "4.1.7",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^20.14.1",
|
"@types/node": "^20.14.2",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.6",
|
"@babel/core": "^7.24.7",
|
||||||
"@eslint/js": "^9.4.0",
|
"@eslint/js": "^9.4.0",
|
||||||
"@preact/compat": "^17.1.2",
|
"@preact/compat": "^17.1.2",
|
||||||
"@preact/preset-vite": "^2.8.2",
|
"@preact/preset-vite": "^2.8.2",
|
||||||
@@ -60,11 +60,11 @@
|
|||||||
"eslint": "^9.4.0",
|
"eslint": "^9.4.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"preact": "^10.22.0",
|
"preact": "^10.22.0",
|
||||||
"prettier": "^3.3.0",
|
"prettier": "^3.3.1",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"terser": "^5.31.0",
|
"terser": "^5.31.1",
|
||||||
"typescript-eslint": "^7.12.0",
|
"typescript-eslint": "^7.12.0",
|
||||||
"vite": "^5.2.12",
|
"vite": "^5.2.13",
|
||||||
"vite-plugin-imagemin": "^0.6.1",
|
"vite-plugin-imagemin": "^0.6.1",
|
||||||
"vite-tsconfig-paths": "^4.3.2"
|
"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 PermScanWifiIcon from '@mui/icons-material/PermScanWifi';
|
||||||
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
|
import RouterIcon from '@mui/icons-material/Router';
|
||||||
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
import SettingsInputAntennaIcon from '@mui/icons-material/SettingsInputAntenna';
|
||||||
import TimerIcon from '@mui/icons-material/Timer';
|
import TimerIcon from '@mui/icons-material/Timer';
|
||||||
|
import WifiIcon from '@mui/icons-material/Wifi';
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
Box,
|
||||||
@@ -38,7 +40,7 @@ import ListMenuItem from 'components/layout/ListMenuItem';
|
|||||||
import { AuthenticatedContext } from 'contexts/authentication';
|
import { AuthenticatedContext } from 'contexts/authentication';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
import { busConnectionStatus } from 'project/types';
|
import { busConnectionStatus } from 'project/types';
|
||||||
import { NTPSyncStatus } from 'types';
|
import { NTPSyncStatus, NetworkConnectionStatus } from 'types';
|
||||||
|
|
||||||
import RestartMonitor from './RestartMonitor';
|
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) =>
|
const activeHighlight = (value: boolean) =>
|
||||||
value ? theme.palette.success.main : theme.palette.info.main;
|
value ? theme.palette.success.main : theme.palette.info.main;
|
||||||
|
|
||||||
@@ -296,7 +338,7 @@ const SystemStatus: FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
startIcon={<PowerSettingsNewIcon />}
|
startIcon={<PowerSettingsNewIcon />}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
color="primary"
|
color="error"
|
||||||
onClick={() => setConfirmRestart(true)}
|
onClick={() => setConfirmRestart(true)}
|
||||||
>
|
>
|
||||||
{LL.RESTART()}
|
{LL.RESTART()}
|
||||||
@@ -355,6 +397,20 @@ const SystemStatus: FC = () => {
|
|||||||
/>
|
/>
|
||||||
<Divider variant="inset" component="li" />
|
<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
|
<ListMenuItem
|
||||||
disabled={!me.admin}
|
disabled={!me.admin}
|
||||||
icon={DeviceHubIcon}
|
icon={DeviceHubIcon}
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const de: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default de;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const en: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings',
|
||||||
SECURITY_1: 'Add or remove users',
|
SECURITY_1: 'Add or remove users',
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware',
|
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;
|
export default en;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const fr: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default fr;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const it: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default it;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const nl: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Applicatie-instellingen wijzigen',
|
APPLICATION_SETTINGS_1: 'Applicatie-instellingen wijzigen',
|
||||||
SECURITY_1: 'Gebruikers toevoegen of verwijderen',
|
SECURITY_1: 'Gebruikers toevoegen of verwijderen',
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload-/downloadinstellingen en firmware',
|
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;
|
export default nl;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const no: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default no;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const pl: BaseTranslation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
APPLICATION_SETTINGS_1: 'Modyfikacja ustawień aplikacji EMS-ESP',
|
||||||
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
SECURITY_1: 'Dodawanie i usuwanie użytkowników',
|
||||||
UPLOAD_DOWNLOAD_1: 'Wysyłanie/pobieranie ustawień i firmware',
|
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;
|
export default pl;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const sk: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default sk;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const sv: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default sv;
|
||||||
|
|||||||
@@ -325,7 +325,10 @@ const tr: Translation = {
|
|||||||
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
APPLICATION_SETTINGS_1: 'Modify EMS-ESP Application Settings', // TODO translate
|
||||||
SECURITY_1: 'Add or remove users', // TODO translate
|
SECURITY_1: 'Add or remove users', // TODO translate
|
||||||
UPLOAD_DOWNLOAD_1: 'Upload/Download Settings and Firmware', // 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;
|
export default tr;
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import { useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { useBlocker } from 'react-router-dom';
|
import { useBlocker } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import CircleIcon from '@mui/icons-material/Circle';
|
import CircleIcon from '@mui/icons-material/Circle';
|
||||||
|
import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew';
|
||||||
import WarningIcon from '@mui/icons-material/Warning';
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import { Box, Button, Typography } from '@mui/material';
|
import { Box, Button, Typography } from '@mui/material';
|
||||||
|
|
||||||
|
import * as SystemApi from 'api/system';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Cell,
|
Cell,
|
||||||
@@ -23,19 +26,28 @@ import {
|
|||||||
BlockNavigation,
|
BlockNavigation,
|
||||||
ButtonRow,
|
ButtonRow,
|
||||||
FormLoader,
|
FormLoader,
|
||||||
|
MessageBox,
|
||||||
SectionContent,
|
SectionContent,
|
||||||
useLayoutTitle
|
useLayoutTitle
|
||||||
} from 'components';
|
} from 'components';
|
||||||
|
import RestartMonitor from 'framework/system/RestartMonitor';
|
||||||
import { useI18nContext } from 'i18n/i18n-react';
|
import { useI18nContext } from 'i18n/i18n-react';
|
||||||
|
|
||||||
import * as EMSESP from './api';
|
import * as EMSESP from './api';
|
||||||
|
import ModulesDialog from './ModulesDialog';
|
||||||
import type { ModuleItem, Modules } from './types';
|
import type { ModuleItem, Modules } from './types';
|
||||||
|
|
||||||
const Modules: FC = () => {
|
const Modules: FC = () => {
|
||||||
const { LL } = useI18nContext();
|
const { LL } = useI18nContext();
|
||||||
const [numChanges, setNumChanges] = useState<number>(0);
|
const [numChanges, setNumChanges] = useState<number>(0);
|
||||||
|
const [licenseChanges, setLicenseChanges] = useState<number>(0);
|
||||||
const blocker = useBlocker(numChanges !== 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 {
|
const {
|
||||||
data: modules,
|
data: modules,
|
||||||
send: fetchModules,
|
send: fetchModules,
|
||||||
@@ -44,6 +56,17 @@ const Modules: FC = () => {
|
|||||||
initialData: []
|
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(
|
const { send: writeModules } = useRequest(
|
||||||
(data: Modules) => EMSESP.writeModules(data),
|
(data: Modules) => EMSESP.writeModules(data),
|
||||||
{
|
{
|
||||||
@@ -53,7 +76,7 @@ const Modules: FC = () => {
|
|||||||
|
|
||||||
const modules_theme = useTheme({
|
const modules_theme = useTheme({
|
||||||
Table: `
|
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: `
|
BaseRow: `
|
||||||
font-size: 14px;
|
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 () => {
|
const onCancel = async () => {
|
||||||
await fetchModules().then(() => {
|
await fetchModules().then(() => {
|
||||||
setNumChanges(0);
|
setNumChanges(0);
|
||||||
@@ -100,16 +137,20 @@ const Modules: FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function hasModulesChanged(mi: ModuleItem) {
|
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) => {
|
function hasModuleLicenseChanged(mi: ModuleItem) {
|
||||||
updatedItem.enabled = !updatedItem.enabled;
|
return mi.license !== mi.o_license;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateModuleItem = (updatedItem: ModuleItem) => {
|
||||||
updateState('modules', (data: ModuleItem[]) => {
|
updateState('modules', (data: ModuleItem[]) => {
|
||||||
const new_data = data.map((mi) =>
|
const new_data = data.map((mi) =>
|
||||||
mi.id === updatedItem.id ? { ...mi, ...updatedItem } : mi
|
mi.id === updatedItem.id ? { ...mi, ...updatedItem } : mi
|
||||||
);
|
);
|
||||||
setNumChanges(new_data.filter((mi) => hasModulesChanged(mi)).length);
|
setNumChanges(new_data.filter((mi) => hasModulesChanged(mi)).length);
|
||||||
|
setLicenseChanges(new_data.filter((mi) => hasModuleLicenseChanged(mi)).length);
|
||||||
return new_data;
|
return new_data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -117,12 +158,13 @@ const Modules: FC = () => {
|
|||||||
const saveModules = async () => {
|
const saveModules = async () => {
|
||||||
await writeModules({
|
await writeModules({
|
||||||
modules: modules.map((condensed_mi) => ({
|
modules: modules.map((condensed_mi) => ({
|
||||||
name: condensed_mi.name,
|
key: condensed_mi.key,
|
||||||
enabled: condensed_mi.enabled
|
enabled: condensed_mi.enabled,
|
||||||
|
license: condensed_mi.license
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.success('Modules saved');
|
toast.success(LL.MODULES_UPDATED());
|
||||||
})
|
})
|
||||||
.catch((error: Error) => {
|
.catch((error: Error) => {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
@@ -130,24 +172,36 @@ const Modules: FC = () => {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
setNumChanges(0);
|
setNumChanges(0);
|
||||||
});
|
});
|
||||||
|
setRestartNeeded(licenseChanges > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderModules = () => {
|
const renderContent = () => {
|
||||||
if (!modules) {
|
if (!modules) {
|
||||||
return <FormLoader onRetry={fetchModules} errorMessage={error?.message} />;
|
return <FormLoader onRetry={fetchModules} errorMessage={error?.message} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
useLayoutTitle('Modules');
|
useLayoutTitle(LL.MODULES());
|
||||||
|
|
||||||
if (modules.length === 0) {
|
if (modules.length === 0) {
|
||||||
return (
|
return (
|
||||||
<Typography variant="body2" color="error">
|
<Typography variant="body2" color="error">
|
||||||
No modules detected
|
{LL.MODULES_NONE()}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const colorStatus = (status: number) => {
|
||||||
|
if (status === 1) {
|
||||||
|
return <div style={{ color: 'red' }}>Pending Activation</div>;
|
||||||
|
}
|
||||||
|
return <div style={{ color: '#00FF7F' }}>Activated</div>;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Box mb={2} color="warning.main">
|
||||||
|
<Typography variant="body2">{LL.MODULES_DESCRIPTION()}</Typography>
|
||||||
|
</Box>
|
||||||
<Table
|
<Table
|
||||||
data={{ nodes: modules }}
|
data={{ nodes: modules }}
|
||||||
theme={modules_theme}
|
theme={modules_theme}
|
||||||
@@ -158,15 +212,16 @@ const Modules: FC = () => {
|
|||||||
<Header>
|
<Header>
|
||||||
<HeaderRow>
|
<HeaderRow>
|
||||||
<HeaderCell />
|
<HeaderCell />
|
||||||
<HeaderCell stiff>{LL.NAME(0)}</HeaderCell>
|
<HeaderCell>{LL.NAME(0)}</HeaderCell>
|
||||||
<HeaderCell stiff>Author</HeaderCell>
|
<HeaderCell>Author</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.VERSION()}</HeaderCell>
|
<HeaderCell>{LL.VERSION()}</HeaderCell>
|
||||||
<HeaderCell stiff>{LL.STATUS_OF('')}</HeaderCell>
|
<HeaderCell>Message</HeaderCell>
|
||||||
|
<HeaderCell>{LL.STATUS_OF('')}</HeaderCell>
|
||||||
</HeaderRow>
|
</HeaderRow>
|
||||||
</Header>
|
</Header>
|
||||||
<Body>
|
<Body>
|
||||||
{tableList.map((mi: ModuleItem) => (
|
{tableList.map((mi: ModuleItem) => (
|
||||||
<Row key={mi.id} item={mi} onClick={() => selectModule(mi)}>
|
<Row key={mi.id} item={mi} onClick={() => editModuleItem(mi)}>
|
||||||
<Cell stiff>
|
<Cell stiff>
|
||||||
{mi.enabled ? (
|
{mi.enabled ? (
|
||||||
<CircleIcon
|
<CircleIcon
|
||||||
@@ -183,27 +238,27 @@ const Modules: FC = () => {
|
|||||||
<Cell>{mi.name}</Cell>
|
<Cell>{mi.name}</Cell>
|
||||||
<Cell>{mi.author}</Cell>
|
<Cell>{mi.author}</Cell>
|
||||||
<Cell>{mi.version}</Cell>
|
<Cell>{mi.version}</Cell>
|
||||||
<Cell>{mi.status}</Cell>
|
<Cell>{mi.message}</Cell>
|
||||||
|
<Cell>{colorStatus(mi.status)}</Cell>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
</Body>
|
</Body>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Table>
|
</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()}
|
|
||||||
|
|
||||||
|
{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 mt={1} display="flex" flexWrap="wrap">
|
||||||
<Box flexGrow={1}>
|
<Box flexGrow={1}>
|
||||||
{numChanges !== 0 && (
|
{numChanges !== 0 && (
|
||||||
@@ -228,6 +283,23 @@ const Modules: FC = () => {
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SectionContent>
|
||||||
|
{blocker ? <BlockNavigation blocker={blocker} /> : null}
|
||||||
|
{restarting ? <RestartMonitor /> : renderContent()}
|
||||||
|
{selectedModuleItem && (
|
||||||
|
<ModulesDialog
|
||||||
|
open={dialogOpen}
|
||||||
|
onClose={onDialogClose}
|
||||||
|
onSave={onDialogSave}
|
||||||
|
selectedItem={selectedModuleItem}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</SectionContent>
|
</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) {
|
transformData(data) {
|
||||||
return (data as Modules).modules.map((mi: ModuleItem) => ({
|
return (data as Modules).modules.map((mi: ModuleItem) => ({
|
||||||
...mi,
|
...mi,
|
||||||
o_enabled: mi.enabled
|
o_enabled: mi.enabled,
|
||||||
|
o_license: mi.license
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -310,12 +310,16 @@ export interface Schedule {
|
|||||||
|
|
||||||
export interface ModuleItem {
|
export interface ModuleItem {
|
||||||
id: number; // unique index
|
id: number; // unique index
|
||||||
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
author: string;
|
author: string;
|
||||||
version: string;
|
version: string;
|
||||||
status: string;
|
status: number;
|
||||||
|
message: string;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
license: string;
|
||||||
o_enabled?: boolean;
|
o_enabled?: boolean;
|
||||||
|
o_license?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Modules {
|
export interface Modules {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { busConnectionStatus } from 'project/types';
|
import type { busConnectionStatus } from 'project/types';
|
||||||
|
|
||||||
|
import type { NetworkConnectionStatus } from './network';
|
||||||
|
|
||||||
export interface ESPSystemStatus {
|
export interface ESPSystemStatus {
|
||||||
emsesp_version: string;
|
emsesp_version: string;
|
||||||
esp_platform: string;
|
esp_platform: string;
|
||||||
@@ -37,6 +39,8 @@ export interface SystemStatus {
|
|||||||
ntp_status: number;
|
ntp_status: number;
|
||||||
mqtt_status: boolean;
|
mqtt_status: boolean;
|
||||||
ap_status: boolean;
|
ap_status: boolean;
|
||||||
|
network_status: NetworkConnectionStatus;
|
||||||
|
wifi_rssi: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum LogLevel {
|
export enum LogLevel {
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/code-frame@npm:^7.24.6":
|
"@babel/code-frame@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/code-frame@npm:7.24.6"
|
resolution: "@babel/code-frame@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/highlight": "npm:^7.24.6"
|
"@babel/highlight": "npm:^7.24.7"
|
||||||
picocolors: "npm:^1.0.0"
|
picocolors: "npm:^1.0.0"
|
||||||
checksum: 10c0/c93c6d1763530f415218c31d07359364397f19b70026abdff766164c21ed352a931cf07f3102c5fb9e04792de319e332d68bcb1f7debef601a02197f90f9ba24
|
checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -56,10 +56,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/compat-data@npm:^7.24.6":
|
"@babel/compat-data@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/compat-data@npm:7.24.6"
|
resolution: "@babel/compat-data@npm:7.24.7"
|
||||||
checksum: 10c0/f50abbd4008eb2a5d12139c578809cebbeaeb8e660fb12d546eb2e7c2108ae1836ab8339184a5f5ce0e95bf81bb91e18edce86b387c59db937b01693ec0bc774
|
checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -86,26 +86,26 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/core@npm:^7.24.6":
|
"@babel/core@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/core@npm:7.24.6"
|
resolution: "@babel/core@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ampproject/remapping": "npm:^2.2.0"
|
"@ampproject/remapping": "npm:^2.2.0"
|
||||||
"@babel/code-frame": "npm:^7.24.6"
|
"@babel/code-frame": "npm:^7.24.7"
|
||||||
"@babel/generator": "npm:^7.24.6"
|
"@babel/generator": "npm:^7.24.7"
|
||||||
"@babel/helper-compilation-targets": "npm:^7.24.6"
|
"@babel/helper-compilation-targets": "npm:^7.24.7"
|
||||||
"@babel/helper-module-transforms": "npm:^7.24.6"
|
"@babel/helper-module-transforms": "npm:^7.24.7"
|
||||||
"@babel/helpers": "npm:^7.24.6"
|
"@babel/helpers": "npm:^7.24.7"
|
||||||
"@babel/parser": "npm:^7.24.6"
|
"@babel/parser": "npm:^7.24.7"
|
||||||
"@babel/template": "npm:^7.24.6"
|
"@babel/template": "npm:^7.24.7"
|
||||||
"@babel/traverse": "npm:^7.24.6"
|
"@babel/traverse": "npm:^7.24.7"
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
convert-source-map: "npm:^2.0.0"
|
convert-source-map: "npm:^2.0.0"
|
||||||
debug: "npm:^4.1.0"
|
debug: "npm:^4.1.0"
|
||||||
gensync: "npm:^1.0.0-beta.2"
|
gensync: "npm:^1.0.0-beta.2"
|
||||||
json5: "npm:^2.2.3"
|
json5: "npm:^2.2.3"
|
||||||
semver: "npm:^6.3.1"
|
semver: "npm:^6.3.1"
|
||||||
checksum: 10c0/e0762a8daef7f417494d555929418cfacd6848c7fc3310ec00e6dd8cecac20b7f590e760bfc9365d2af07874a3f5599832f9c9ff7f1a9d126a168f77ba67945a
|
checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -132,15 +132,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/generator@npm:^7.24.6":
|
"@babel/generator@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/generator@npm:7.24.6"
|
resolution: "@babel/generator@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
"@jridgewell/gen-mapping": "npm:^0.3.5"
|
"@jridgewell/gen-mapping": "npm:^0.3.5"
|
||||||
"@jridgewell/trace-mapping": "npm:^0.3.25"
|
"@jridgewell/trace-mapping": "npm:^0.3.25"
|
||||||
jsesc: "npm:^2.5.1"
|
jsesc: "npm:^2.5.1"
|
||||||
checksum: 10c0/8d71a17b386536582354afba53cc784396458a88cc9f05f0c6de0ec99475f6f539943b3566b2e733820c4928236952473831765e483c25d68cc007a6e604d782
|
checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -166,16 +166,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@npm:^7.24.6":
|
"@babel/helper-compilation-targets@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-compilation-targets@npm:7.24.6"
|
resolution: "@babel/helper-compilation-targets@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/compat-data": "npm:^7.24.6"
|
"@babel/compat-data": "npm:^7.24.7"
|
||||||
"@babel/helper-validator-option": "npm:^7.24.6"
|
"@babel/helper-validator-option": "npm:^7.24.7"
|
||||||
browserslist: "npm:^4.22.2"
|
browserslist: "npm:^4.22.2"
|
||||||
lru-cache: "npm:^5.1.1"
|
lru-cache: "npm:^5.1.1"
|
||||||
semver: "npm:^6.3.1"
|
semver: "npm:^6.3.1"
|
||||||
checksum: 10c0/4d41150086959f5f4d72d27bae29204192e943537ecb71df1711d1f5d8791358a44f3a5882ed3c8238ba0c874b0b55213af43767e14771765f13b8d15b262432
|
checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -186,10 +186,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-environment-visitor@npm:^7.24.6":
|
"@babel/helper-environment-visitor@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-environment-visitor@npm:7.24.6"
|
resolution: "@babel/helper-environment-visitor@npm:7.24.7"
|
||||||
checksum: 10c0/fdcd18ac505ed71f40c05cc992b648a4495b0aa5310a774492a0f74d8dcf3579691102f516561a651d3de6c3a44fe64bfb3049d11c14c5857634ef1823ea409a
|
dependencies:
|
||||||
|
"@babel/types": "npm:^7.24.7"
|
||||||
|
checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -203,13 +205,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-function-name@npm:^7.24.6":
|
"@babel/helper-function-name@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-function-name@npm:7.24.6"
|
resolution: "@babel/helper-function-name@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/template": "npm:^7.24.6"
|
"@babel/template": "npm:^7.24.7"
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
checksum: 10c0/5ba2f8db789b3f5a2b2239300a217aa212e303cd7bfad9c8b90563807f49215e8c679e8f8f177b6aaca2038038e29bc702b83839e1f7b4896d79c44a75cac97a
|
checksum: 10c0/e5e41e6cf86bd0f8bf272cbb6e7c5ee0f3e9660414174435a46653efba4f2479ce03ce04abff2aa2ef9359cf057c79c06cb7b134a565ad9c0e8a50dcdc3b43c4
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -222,12 +224,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-hoist-variables@npm:^7.24.6":
|
"@babel/helper-hoist-variables@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-hoist-variables@npm:7.24.6"
|
resolution: "@babel/helper-hoist-variables@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
checksum: 10c0/e10ec6b864aaa419ec4934f5fcb5d0cfcc9d0657584a1b6c3c42ada949d44ca6bffcdab433a90ada4396c747e551cca31ba0e565ea005ab3f50964e3817bf6cf
|
checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -240,12 +242,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-module-imports@npm:^7.24.6":
|
"@babel/helper-module-imports@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-module-imports@npm:7.24.6"
|
resolution: "@babel/helper-module-imports@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/traverse": "npm:^7.24.7"
|
||||||
checksum: 10c0/e0db3fbfcd963d138f0792ff626f940a576fcf212d02b8fe6478dccf3421bd1c2a76f8e69c7450c049985e7b63b30be309a24eeeb6ad7c2137a31b676a095a84
|
"@babel/types": "npm:^7.24.7"
|
||||||
|
checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -264,18 +267,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-module-transforms@npm:^7.24.6":
|
"@babel/helper-module-transforms@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-module-transforms@npm:7.24.6"
|
resolution: "@babel/helper-module-transforms@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-environment-visitor": "npm:^7.24.6"
|
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||||
"@babel/helper-module-imports": "npm:^7.24.6"
|
"@babel/helper-module-imports": "npm:^7.24.7"
|
||||||
"@babel/helper-simple-access": "npm:^7.24.6"
|
"@babel/helper-simple-access": "npm:^7.24.7"
|
||||||
"@babel/helper-split-export-declaration": "npm:^7.24.6"
|
"@babel/helper-split-export-declaration": "npm:^7.24.7"
|
||||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
"@babel/core": ^7.0.0
|
"@babel/core": ^7.0.0
|
||||||
checksum: 10c0/9e2e3d0ddb397b36b9e8c7d94e175a36be8cb888ef370cefef2cdfd53ae1f87d567b268bd90ed9a6c706485a8de3da19cac577657613e9cd17210b91cbdfb00b
|
checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -295,12 +298,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-simple-access@npm:^7.24.6":
|
"@babel/helper-simple-access@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-simple-access@npm:7.24.6"
|
resolution: "@babel/helper-simple-access@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/traverse": "npm:^7.24.7"
|
||||||
checksum: 10c0/b17e404dd6c9787fc7d558aea5222471a77e29596705f0d10b4c2a58b9d71ff7eae915094204848cc1af99b771553caa69337a768b9abdd82b54a0050ba83eb9
|
"@babel/types": "npm:^7.24.7"
|
||||||
|
checksum: 10c0/7230e419d59a85f93153415100a5faff23c133d7442c19e0cd070da1784d13cd29096ee6c5a5761065c44e8164f9f80e3a518c41a0256df39e38f7ad6744fed7
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -313,12 +317,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-split-export-declaration@npm:^7.24.6":
|
"@babel/helper-split-export-declaration@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-split-export-declaration@npm:7.24.6"
|
resolution: "@babel/helper-split-export-declaration@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
checksum: 10c0/53a5dd8691fdffc89cc7fcf5aed0ad1d8bc39796a5782a3d170dcbf249eb5c15cc8a290e8d09615711d18798ad04a7d0694ab5195d35fa651abbc1b9c885d6a8
|
checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -329,10 +333,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-string-parser@npm:^7.24.6":
|
"@babel/helper-string-parser@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-string-parser@npm:7.24.6"
|
resolution: "@babel/helper-string-parser@npm:7.24.7"
|
||||||
checksum: 10c0/95115bf676e92c4e99166395649108d97447e6cabef1fabaec8cdbc53a43f27b5df2268ff6534439d405bc1bd06685b163eb3b470455bd49f69159dada414145
|
checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -343,10 +347,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-validator-identifier@npm:^7.24.6":
|
"@babel/helper-validator-identifier@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-validator-identifier@npm:7.24.6"
|
resolution: "@babel/helper-validator-identifier@npm:7.24.7"
|
||||||
checksum: 10c0/d29d2e3fca66c31867a009014169b93f7bc21c8fc1dd7d0b9d85d7a4000670526ff2222d966febb75a6e12f9859a31d1e75b558984e28ecb69651314dd0a6fd1
|
checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -357,10 +361,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helper-validator-option@npm:^7.24.6":
|
"@babel/helper-validator-option@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helper-validator-option@npm:7.24.6"
|
resolution: "@babel/helper-validator-option@npm:7.24.7"
|
||||||
checksum: 10c0/787268dff5cf77f3b704454b96ab7b58aa4f43b2808247e51859a103a1c28a9c252100f830433f4b37a73f4a61ba745bbeef4cdccbab48c1e9adf037f4ca3491
|
checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -375,13 +379,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/helpers@npm:^7.24.6":
|
"@babel/helpers@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/helpers@npm:7.24.6"
|
resolution: "@babel/helpers@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/template": "npm:^7.24.6"
|
"@babel/template": "npm:^7.24.7"
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
checksum: 10c0/e5b5c0919fd6fa56ae11c15a72962d8de0ac19db524849554af28cf08ac32f9ae5aee49a43146eb150f54418cefb8e890fa2b2f33d029434dc7777dbcdfd5bac
|
checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -397,15 +401,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/highlight@npm:^7.24.6":
|
"@babel/highlight@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/highlight@npm:7.24.6"
|
resolution: "@babel/highlight@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||||
chalk: "npm:^2.4.2"
|
chalk: "npm:^2.4.2"
|
||||||
js-tokens: "npm:^4.0.0"
|
js-tokens: "npm:^4.0.0"
|
||||||
picocolors: "npm:^1.0.0"
|
picocolors: "npm:^1.0.0"
|
||||||
checksum: 10c0/5bbc31695e5d44e97feb267f7aaf4c52908560d184ffeb2e2e57aae058d40125592931883889413e19def3326895ddb41ff45e090fa90b459d8c294b4ffc238c
|
checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -418,12 +422,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/parser@npm:^7.24.6":
|
"@babel/parser@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/parser@npm:7.24.6"
|
resolution: "@babel/parser@npm:7.24.7"
|
||||||
bin:
|
bin:
|
||||||
parser: ./bin/babel-parser.js
|
parser: ./bin/babel-parser.js
|
||||||
checksum: 10c0/cbef70923078a20fe163b03f4a6482be65ed99d409a57f3091a23ce3a575ee75716c30e7ea9f40b692ac5660f34055f4cbeb66a354fad15a6cf1fca35c3496c5
|
checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -484,14 +488,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/template@npm:^7.24.6":
|
"@babel/template@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/template@npm:7.24.6"
|
resolution: "@babel/template@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame": "npm:^7.24.6"
|
"@babel/code-frame": "npm:^7.24.7"
|
||||||
"@babel/parser": "npm:^7.24.6"
|
"@babel/parser": "npm:^7.24.7"
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
checksum: 10c0/a4d5805770de908b445f7cdcebfcb6eaa07b1ec9c7b78fd3f375a911b1522c249bddae6b96bc4aac24247cc603e3e6cffcf2fe50b4c929dfeb22de289b517525
|
checksum: 10c0/95b0b3ee80fcef685b7f4426f5713a855ea2cd5ac4da829b213f8fb5afe48a2a14683c2ea04d446dbc7f711c33c5cd4a965ef34dcbe5bc387c9e966b67877ae3
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -531,21 +535,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/traverse@npm:^7.24.6":
|
"@babel/traverse@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/traverse@npm:7.24.6"
|
resolution: "@babel/traverse@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame": "npm:^7.24.6"
|
"@babel/code-frame": "npm:^7.24.7"
|
||||||
"@babel/generator": "npm:^7.24.6"
|
"@babel/generator": "npm:^7.24.7"
|
||||||
"@babel/helper-environment-visitor": "npm:^7.24.6"
|
"@babel/helper-environment-visitor": "npm:^7.24.7"
|
||||||
"@babel/helper-function-name": "npm:^7.24.6"
|
"@babel/helper-function-name": "npm:^7.24.7"
|
||||||
"@babel/helper-hoist-variables": "npm:^7.24.6"
|
"@babel/helper-hoist-variables": "npm:^7.24.7"
|
||||||
"@babel/helper-split-export-declaration": "npm:^7.24.6"
|
"@babel/helper-split-export-declaration": "npm:^7.24.7"
|
||||||
"@babel/parser": "npm:^7.24.6"
|
"@babel/parser": "npm:^7.24.7"
|
||||||
"@babel/types": "npm:^7.24.6"
|
"@babel/types": "npm:^7.24.7"
|
||||||
debug: "npm:^4.3.1"
|
debug: "npm:^4.3.1"
|
||||||
globals: "npm:^11.1.0"
|
globals: "npm:^11.1.0"
|
||||||
checksum: 10c0/39027d5fc7a241c6b71bb5872c2bdcec53743cd7ef3c151bbe6fd7cf874d15f4bc09e5d7e19e2f534b0eb2c115f5368553885fa4253aa1bc9441c6e5bf9efdaf
|
checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -570,14 +574,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/types@npm:^7.24.6":
|
"@babel/types@npm:^7.24.7":
|
||||||
version: 7.24.6
|
version: 7.24.7
|
||||||
resolution: "@babel/types@npm:7.24.6"
|
resolution: "@babel/types@npm:7.24.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-string-parser": "npm:^7.24.6"
|
"@babel/helper-string-parser": "npm:^7.24.7"
|
||||||
"@babel/helper-validator-identifier": "npm:^7.24.6"
|
"@babel/helper-validator-identifier": "npm:^7.24.7"
|
||||||
to-fast-properties: "npm:^2.0.0"
|
to-fast-properties: "npm:^2.0.0"
|
||||||
checksum: 10c0/1d94d92d97ef49030ad7f9e14cfccfeb70b1706dabcaa69037e659ec9d2c3178fb005d2088cce40d88dfc1306153d9157fe038a79ea2be92e5e6b99a59ef80cc
|
checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1738,12 +1742,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@types/node@npm:^20.14.1":
|
"@types/node@npm:^20.14.2":
|
||||||
version: 20.14.1
|
version: 20.14.2
|
||||||
resolution: "@types/node@npm:20.14.1"
|
resolution: "@types/node@npm:20.14.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: "npm:~5.26.4"
|
undici-types: "npm:~5.26.4"
|
||||||
checksum: 10c0/12b7879047f50cc217bbea3add7c45e542070f6e9fb2092be97542152b7022512bcb2bf848d04f77e295c4c8699acd484e79a4a4dbe9bcfa4e89dd543d530611
|
checksum: 10c0/2d86e5f2227aaa42212e82ea0affe72799111b888ff900916376450b02b09b963ca888b20d9c332d8d2b833ed4781987867a38eaa2e4863fa8439071468b0a6f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1962,7 +1966,7 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@alova/adapter-xhr": "npm:^1.0.6"
|
"@alova/adapter-xhr": "npm:^1.0.6"
|
||||||
"@alova/scene-react": "npm:^1.5.0"
|
"@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/react": "npm:^11.11.4"
|
||||||
"@emotion/styled": "npm:^11.11.5"
|
"@emotion/styled": "npm:^11.11.5"
|
||||||
"@eslint/js": "npm:^9.4.0"
|
"@eslint/js": "npm:^9.4.0"
|
||||||
@@ -1974,7 +1978,7 @@ __metadata:
|
|||||||
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
|
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
|
||||||
"@types/babel__core": "npm:^7"
|
"@types/babel__core": "npm:^7"
|
||||||
"@types/lodash-es": "npm:^4.17.12"
|
"@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": "npm:^18.3.3"
|
||||||
"@types/react-dom": "npm:^18.3.0"
|
"@types/react-dom": "npm:^18.3.0"
|
||||||
"@types/react-router-dom": "npm:^5.3.3"
|
"@types/react-router-dom": "npm:^5.3.3"
|
||||||
@@ -1988,7 +1992,7 @@ __metadata:
|
|||||||
lodash-es: "npm:^4.17.21"
|
lodash-es: "npm:^4.17.21"
|
||||||
mime-types: "npm:^2.1.35"
|
mime-types: "npm:^2.1.35"
|
||||||
preact: "npm:^10.22.0"
|
preact: "npm:^10.22.0"
|
||||||
prettier: "npm:^3.3.0"
|
prettier: "npm:^3.3.1"
|
||||||
react: "npm:latest"
|
react: "npm:latest"
|
||||||
react-dom: "npm:latest"
|
react-dom: "npm:latest"
|
||||||
react-dropzone: "npm:^14.2.3"
|
react-dropzone: "npm:^14.2.3"
|
||||||
@@ -1996,11 +2000,11 @@ __metadata:
|
|||||||
react-router-dom: "npm:^6.23.1"
|
react-router-dom: "npm:^6.23.1"
|
||||||
react-toastify: "npm:^10.0.5"
|
react-toastify: "npm:^10.0.5"
|
||||||
rollup-plugin-visualizer: "npm:^5.12.0"
|
rollup-plugin-visualizer: "npm:^5.12.0"
|
||||||
terser: "npm:^5.31.0"
|
terser: "npm:^5.31.1"
|
||||||
typesafe-i18n: "npm:^5.26.2"
|
typesafe-i18n: "npm:^5.26.2"
|
||||||
typescript: "npm:^5.4.5"
|
typescript: "npm:^5.4.5"
|
||||||
typescript-eslint: "npm:^7.12.0"
|
typescript-eslint: "npm:^7.12.0"
|
||||||
vite: "npm:^5.2.12"
|
vite: "npm:^5.2.13"
|
||||||
vite-plugin-imagemin: "npm:^0.6.1"
|
vite-plugin-imagemin: "npm:^0.6.1"
|
||||||
vite-tsconfig-paths: "npm:^4.3.2"
|
vite-tsconfig-paths: "npm:^4.3.2"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
@@ -5932,12 +5936,12 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"prettier@npm:^3.3.0":
|
"prettier@npm:^3.3.1":
|
||||||
version: 3.3.0
|
version: 3.3.1
|
||||||
resolution: "prettier@npm:3.3.0"
|
resolution: "prettier@npm:3.3.1"
|
||||||
bin:
|
bin:
|
||||||
prettier: bin/prettier.cjs
|
prettier: bin/prettier.cjs
|
||||||
checksum: 10c0/d033c356320aa2e468bf29c931b094ac730d2f4defd5eb2989d8589313dec901d2fc866e3788f3d161e420b142ea4ec3dda535dbe0169ef4d0026397a68ba9cf
|
checksum: 10c0/c25a709c9f0be670dc6bcb190b622347e1dbeb6c3e7df8b0711724cb64d8647c60b839937a4df4df18e9cfb556c2b08ca9d24d9645eb5488a7fc032a2c4d5cb3
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6968,9 +6972,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"terser@npm:^5.31.0":
|
"terser@npm:^5.31.1":
|
||||||
version: 5.31.0
|
version: 5.31.1
|
||||||
resolution: "terser@npm:5.31.0"
|
resolution: "terser@npm:5.31.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/source-map": "npm:^0.3.3"
|
"@jridgewell/source-map": "npm:^0.3.3"
|
||||||
acorn: "npm:^8.8.2"
|
acorn: "npm:^8.8.2"
|
||||||
@@ -6978,7 +6982,7 @@ __metadata:
|
|||||||
source-map-support: "npm:~0.5.20"
|
source-map-support: "npm:~0.5.20"
|
||||||
bin:
|
bin:
|
||||||
terser: bin/terser
|
terser: bin/terser
|
||||||
checksum: 10c0/cb127a579b03fb9dcee0d293ff24814deedcd430f447933b618e8593b7454f615b5c8493c68e86a4b0188769d5ea2af5251b5d507edb208114f7e8aebdc7c850
|
checksum: 10c0/4d49a58f64c11f3742e779a0a03aff69972ca5739decb361d909d22c8f3f7d8e2ec982a928d987d56737ad50229e8ab3f62d8ba993e4b5f360a53ed487d3c06c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -7318,9 +7322,9 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vite@npm:^5.2.12":
|
"vite@npm:^5.2.13":
|
||||||
version: 5.2.12
|
version: 5.2.13
|
||||||
resolution: "vite@npm:5.2.12"
|
resolution: "vite@npm:5.2.13"
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: "npm:^0.20.1"
|
esbuild: "npm:^0.20.1"
|
||||||
fsevents: "npm:~2.3.3"
|
fsevents: "npm:~2.3.3"
|
||||||
@@ -7354,7 +7358,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
bin:
|
bin:
|
||||||
vite: bin/vite.js
|
vite: bin/vite.js
|
||||||
checksum: 10c0/f03fdfc320adea3397df3e327029fd875f8220779f679ab183a3a994e8788b4ce531fee28f830361fb274f3cf08ed9adb9429496ecefdc3faf535b38da7ea8b1
|
checksum: 10c0/f7a99da71884e69cc581dcfb43d73c8d56d73b9668d6980131603c544d6323c6003a20f376531dc0cfcf36bf5009bc465f89e6c5f8bd9d22868987aba4e4af1b
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ extern "C" {
|
|||||||
//If core is not defined, then we are running in Arduino or PIO
|
//If core is not defined, then we are running in Arduino or PIO
|
||||||
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
|
#ifndef CONFIG_ASYNC_TCP_RUNNING_CORE
|
||||||
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
|
#define CONFIG_ASYNC_TCP_RUNNING_CORE -1 //any available core
|
||||||
// Note default was 1 and previously set to 0 for EMS-ESP32
|
// Note default was 1 and previously set to 0 for EMS-ESP
|
||||||
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
|
#define CONFIG_ASYNC_TCP_USE_WDT 1 //if enabled, adds between 33us and 200us per event
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -56,13 +56,13 @@ extern "C" {
|
|||||||
#define CONFIG_ASYNC_TCP_TASK_PRIORITY 5
|
#define CONFIG_ASYNC_TCP_TASK_PRIORITY 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// EMS-ESP32: stack usage measured: ESP32: ~2.3K, ESP32S3: ~3.5k
|
// EMS-ESP: stack usage measured: ESP32: ~2.3K, ESP32S3: ~3.5k
|
||||||
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
|
#ifndef CONFIG_ASYNC_TCP_STACK_SIZE
|
||||||
#define CONFIG_ASYNC_TCP_STACK_SIZE 5120
|
#define CONFIG_ASYNC_TCP_STACK_SIZE 5120
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// EMS-ESP32: maybe enlarge queue to 64 or 128 see https://github.com/emsesp/EMS-ESP32/issues/177
|
// EMS-ESP: maybe enlarge queue to 64 or 128 see https://github.com/emsesp/EMS-ESP32/issues/177
|
||||||
#ifndef CONFIG_ASYNC_TCP_QUEUE
|
#ifndef CONFIG_ASYNC_TCP_QUEUE
|
||||||
#define CONFIG_ASYNC_TCP_QUEUE 32
|
#define CONFIG_ASYNC_TCP_QUEUE 32
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -101,12 +101,15 @@ class AsyncWebSocketMessageBuffer {
|
|||||||
AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
|
AsyncWebSocketMessageBuffer(uint8_t * data, size_t size);
|
||||||
~AsyncWebSocketMessageBuffer();
|
~AsyncWebSocketMessageBuffer();
|
||||||
bool reserve(size_t size);
|
bool reserve(size_t size);
|
||||||
uint8_t* get() { return _buffer->data(); }
|
uint8_t * get() {
|
||||||
size_t length() const { return _buffer->size(); }
|
return _buffer->data();
|
||||||
|
}
|
||||||
|
size_t length() const {
|
||||||
|
return _buffer->size();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncWebSocketMessage
|
class AsyncWebSocketMessage {
|
||||||
{
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<std::vector<uint8_t>> _WSbuffer;
|
std::shared_ptr<std::vector<uint8_t>> _WSbuffer;
|
||||||
uint8_t _opcode{WS_TEXT};
|
uint8_t _opcode{WS_TEXT};
|
||||||
@@ -119,8 +122,12 @@ private:
|
|||||||
public:
|
public:
|
||||||
AsyncWebSocketMessage(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode = WS_TEXT, bool mask = false);
|
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 finished() const {
|
||||||
bool betweenFrames() const { return _acked == _ack; }
|
return _status != WS_MSG_SENDING;
|
||||||
|
}
|
||||||
|
bool betweenFrames() const {
|
||||||
|
return _acked == _ack;
|
||||||
|
}
|
||||||
|
|
||||||
void ack(size_t len, uint32_t time);
|
void ack(size_t len, uint32_t time);
|
||||||
size_t send(AsyncClient * client);
|
size_t send(AsyncClient * client);
|
||||||
@@ -137,6 +144,7 @@ class AsyncWebSocketClient {
|
|||||||
|
|
||||||
std::deque<AsyncWebSocketControl> _controlQueue;
|
std::deque<AsyncWebSocketControl> _controlQueue;
|
||||||
std::deque<AsyncWebSocketMessage> _messageQueue;
|
std::deque<AsyncWebSocketMessage> _messageQueue;
|
||||||
|
bool closeWhenFull = true;
|
||||||
|
|
||||||
uint8_t _pstate;
|
uint8_t _pstate;
|
||||||
AwsFrameInfo _pinfo;
|
AwsFrameInfo _pinfo;
|
||||||
@@ -156,18 +164,59 @@ class AsyncWebSocketClient {
|
|||||||
~AsyncWebSocketClient();
|
~AsyncWebSocketClient();
|
||||||
|
|
||||||
//client id increments for the given server
|
//client id increments for the given server
|
||||||
uint32_t id() const { return _clientId; }
|
uint32_t id() const {
|
||||||
AwsClientStatus status() const { return _status; }
|
return _clientId;
|
||||||
AsyncClient* client() { return _client; }
|
}
|
||||||
const AsyncClient* client() const { return _client; }
|
AwsClientStatus status() const {
|
||||||
AsyncWebSocket *server(){ return _server; }
|
return _status;
|
||||||
const AsyncWebSocket *server() const { return _server; }
|
}
|
||||||
AwsFrameInfo const &pinfo() const { return _pinfo; }
|
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;
|
IPAddress remoteIP() const;
|
||||||
uint16_t remotePort() const;
|
uint16_t remotePort() const;
|
||||||
|
|
||||||
bool shouldBeDeleted() const { return !_client; }
|
bool shouldBeDeleted() const {
|
||||||
|
return !_client;
|
||||||
|
}
|
||||||
|
|
||||||
//control frames
|
//control frames
|
||||||
void close(uint16_t code = 0, const char * message = NULL);
|
void close(uint16_t code = 0, const char * message = NULL);
|
||||||
@@ -182,7 +231,9 @@ class AsyncWebSocketClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//data packets
|
//data packets
|
||||||
void message(std::shared_ptr<std::vector<uint8_t>> buffer, uint8_t opcode=WS_TEXT, bool mask=false) { _queueMessage(buffer, opcode, mask); }
|
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;
|
bool queueIsFull() const;
|
||||||
size_t queueLen() const;
|
size_t queueLen() const;
|
||||||
|
|
||||||
@@ -235,15 +286,23 @@ class AsyncWebSocket: public AsyncWebHandler {
|
|||||||
public:
|
public:
|
||||||
AsyncWebSocket(const String & url);
|
AsyncWebSocket(const String & url);
|
||||||
~AsyncWebSocket();
|
~AsyncWebSocket();
|
||||||
const char * url() const { return _url.c_str(); }
|
const char * url() const {
|
||||||
void enable(bool e){ _enabled = e; }
|
return _url.c_str();
|
||||||
bool enabled() const { return _enabled; }
|
}
|
||||||
|
void enable(bool e) {
|
||||||
|
_enabled = e;
|
||||||
|
}
|
||||||
|
bool enabled() const {
|
||||||
|
return _enabled;
|
||||||
|
}
|
||||||
bool availableForWriteAll();
|
bool availableForWriteAll();
|
||||||
bool availableForWrite(uint32_t id);
|
bool availableForWrite(uint32_t id);
|
||||||
|
|
||||||
size_t count() const;
|
size_t count() const;
|
||||||
AsyncWebSocketClient * client(uint32_t id);
|
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 close(uint32_t id, uint16_t code = 0, const char * message = NULL);
|
||||||
void closeAll(uint16_t code = 0, const char * message = NULL);
|
void closeAll(uint16_t code = 0, const char * message = NULL);
|
||||||
@@ -257,28 +316,32 @@ class AsyncWebSocket: public AsyncWebHandler {
|
|||||||
void text(uint32_t id, const char * message);
|
void text(uint32_t id, const char * message);
|
||||||
void text(uint32_t id, const String & message);
|
void text(uint32_t id, const String & message);
|
||||||
void text(uint32_t id, const __FlashStringHelper * 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, size_t len);
|
||||||
void textAll(const char * message);
|
void textAll(const char * message);
|
||||||
void textAll(const String & message);
|
void textAll(const String & message);
|
||||||
void textAll(const __FlashStringHelper *message); // need to convert
|
void textAll(const __FlashStringHelper * message);
|
||||||
void textAll(AsyncWebSocketMessageBuffer * buffer);
|
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 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, size_t len);
|
||||||
void binary(uint32_t id, const char * message);
|
void binary(uint32_t id, const char * message);
|
||||||
void binary(uint32_t id, const String & 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 __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(std::shared_ptr<std::vector<uint8_t>> buffer);
|
|
||||||
void binaryAll(const uint8_t * message, size_t len);
|
void binaryAll(const uint8_t * message, size_t len);
|
||||||
void binaryAll(const char * message, size_t len);
|
void binaryAll(const char * message, size_t len);
|
||||||
void binaryAll(const char * message);
|
void binaryAll(const char * message);
|
||||||
void binaryAll(const String & message);
|
void binaryAll(const String & message);
|
||||||
void binaryAll(const __FlashStringHelper * message, size_t len);
|
void binaryAll(const __FlashStringHelper * message, size_t len);
|
||||||
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
|
void binaryAll(AsyncWebSocketMessageBuffer * buffer);
|
||||||
|
void binaryAll(std::shared_ptr<std::vector<uint8_t>> buffer);
|
||||||
|
|
||||||
size_t printf(uint32_t id, const char * format, ...) __attribute__((format(printf, 3, 4)));
|
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 printfAll(const char * format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
@@ -298,7 +361,9 @@ class AsyncWebSocket: public AsyncWebHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//system callbacks (do not call)
|
//system callbacks (do not call)
|
||||||
uint32_t _getNextId(){ return _cNextId++; }
|
uint32_t _getNextId() {
|
||||||
|
return _cNextId++;
|
||||||
|
}
|
||||||
AsyncWebSocketClient * _newClient(AsyncWebServerRequest * request);
|
AsyncWebSocketClient * _newClient(AsyncWebServerRequest * request);
|
||||||
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len);
|
void _handleEvent(AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len);
|
||||||
virtual bool canHandle(AsyncWebServerRequest * request) override final;
|
virtual bool canHandle(AsyncWebServerRequest * request) override final;
|
||||||
@@ -309,7 +374,9 @@ class AsyncWebSocket: public AsyncWebHandler {
|
|||||||
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
|
AsyncWebSocketMessageBuffer * makeBuffer(size_t size = 0);
|
||||||
AsyncWebSocketMessageBuffer * makeBuffer(uint8_t * data, size_t size);
|
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
|
//WebServer response to authenticate the socket and detach the tcp client from the web server request
|
||||||
@@ -317,11 +384,14 @@ class AsyncWebSocketResponse: public AsyncWebServerResponse {
|
|||||||
private:
|
private:
|
||||||
String _content;
|
String _content;
|
||||||
AsyncWebSocket * _server;
|
AsyncWebSocket * _server;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncWebSocketResponse(const String & key, AsyncWebSocket * server);
|
AsyncWebSocketResponse(const String & key, AsyncWebSocket * server);
|
||||||
void _respond(AsyncWebServerRequest * request);
|
void _respond(AsyncWebServerRequest * request);
|
||||||
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
size_t _ack(AsyncWebServerRequest * request, size_t len, uint32_t time);
|
||||||
bool _sourceValid() const { return true; }
|
bool _sourceValid() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
|
||||||
#include <ArduinoJson.h> // added by proddy
|
#include <ArduinoJson.h> // added by proddy for EMS-ESP
|
||||||
|
|
||||||
#include "StringArray.h"
|
#include "StringArray.h"
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ class AsyncWebServerRequest {
|
|||||||
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
|
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, const uint8_t * content, size_t len, AwsTemplateProcessor callback = nullptr);
|
||||||
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
AsyncWebServerResponse * beginResponse_P(int code, const String & contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
|
||||||
|
|
||||||
// added by proddy
|
// added by proddy for EMS-ESP
|
||||||
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len);
|
AsyncWebServerResponse * beginResponse(const String & contentType, const uint8_t * content, size_t len);
|
||||||
|
|
||||||
size_t headers() const; // get header count
|
size_t headers() const; // get header count
|
||||||
@@ -532,7 +532,7 @@ typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFun
|
|||||||
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
||||||
|
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy
|
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy for EMS-ESP
|
||||||
|
|
||||||
class AsyncWebServer {
|
class AsyncWebServer {
|
||||||
protected:
|
protected:
|
||||||
@@ -566,7 +566,7 @@ class AsyncWebServer {
|
|||||||
AsyncCallbackWebHandler &
|
AsyncCallbackWebHandler &
|
||||||
on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
|
on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload, ArBodyHandlerFunction onBody);
|
||||||
|
|
||||||
void on(const char * uri, ArJsonRequestHandlerFunction onRequest); // added by proddy
|
void on(const char * uri, ArJsonRequestHandlerFunction onRequest); // added by proddy for EMS-ESP
|
||||||
|
|
||||||
AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
|
AsyncStaticWebHandler & serveStatic(const char * uri, fs::FS & fs, const char * path, const char * cache_control = NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "WebAuthentication.h"
|
#include "WebAuthentication.h"
|
||||||
#include <libb64/cencode.h>
|
#include <libb64/cencode.h>
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include "mbedtls/md5.h"
|
#include <MD5Builder.h>
|
||||||
#else
|
#else
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -66,36 +66,29 @@ bool checkBasicAuthentication(const char * hash, const char * username, const ch
|
|||||||
|
|
||||||
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
|
#ifdef ESP32
|
||||||
mbedtls_md5_context _ctx;
|
MD5Builder md5;
|
||||||
|
md5.begin();
|
||||||
|
md5.add(data, len);
|
||||||
|
md5.calculate();
|
||||||
|
md5.getChars(output);
|
||||||
#else
|
#else
|
||||||
md5_context_t _ctx;
|
md5_context_t _ctx;
|
||||||
#endif
|
|
||||||
uint8_t i;
|
|
||||||
uint8_t * _buf = (uint8_t *)malloc(16);
|
uint8_t * _buf = (uint8_t *)malloc(16);
|
||||||
if (_buf == NULL)
|
if (_buf == NULL)
|
||||||
return false;
|
return false;
|
||||||
memset(_buf, 0x00, 16);
|
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);
|
MD5Init(&_ctx);
|
||||||
MD5Update(&_ctx, data, len);
|
MD5Update(&_ctx, data, len);
|
||||||
MD5Final(_buf, &_ctx);
|
MD5Final(_buf, &_ctx);
|
||||||
#endif
|
|
||||||
for(i = 0; i < 16; i++) {
|
for (uint8_t i = 0; i < 16; i++) {
|
||||||
sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]);
|
sprintf_P(output + (i * 2), PSTR("%02x"), _buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(_buf);
|
free(_buf);
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +147,15 @@ String requestDigestAuthentication(const char * realm){
|
|||||||
return 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){
|
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) {
|
if (username == NULL || password == NULL || header == NULL || method == NULL) {
|
||||||
//os_printf("AUTH FAIL: missing requred fields\n");
|
//os_printf("AUTH FAIL: missing requred fields\n");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ AsyncCallbackWebHandler & AsyncWebServer::on(const char * uri, ArRequestHandlerF
|
|||||||
return *handler;
|
return *handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// added by proddy
|
// added by proddy for EMS-ESP
|
||||||
void AsyncWebServer::on(const char * uri, ArJsonRequestHandlerFunction onRequest) {
|
void AsyncWebServer::on(const char * uri, ArJsonRequestHandlerFunction onRequest) {
|
||||||
auto * handler = new AsyncCallbackJsonWebHandler(uri, onRequest);
|
auto * handler = new AsyncCallbackJsonWebHandler(uri, onRequest);
|
||||||
addHandler(handler);
|
addHandler(handler);
|
||||||
|
|||||||
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
|
||||||
@@ -3,50 +3,16 @@
|
|||||||
MQTT client library for the Espressif devices ESP8266 and ESP32 on the Arduino framework.
|
MQTT client library for the Espressif devices ESP8266 and ESP32 on the Arduino framework.
|
||||||
Aims to be a non-blocking, fully compliant MQTT 3.1.1 client.
|
Aims to be a non-blocking, fully compliant MQTT 3.1.1 client.
|
||||||
|
|
||||||

|
Copy of <https://github.com/bertmelis/espMqttClient>
|
||||||

|
|
||||||

|
|
||||||
[](https://registry.platformio.org/libraries/bertmelis/espMqttClient)
|
|
||||||
|
|
||||||
# Features
|
Based on Version 1.7.0 - <https://github.com/bertmelis/espMqttClient/tree/v1.7.0>
|
||||||
|
|
||||||
- MQTT 3.1.1 compliant library
|
with additional changes to support EMS-ESP such as compiling with Tasmota and not using `SecureWifiClient` in these two files:
|
||||||
- Sending and receiving at all QoS levels
|
|
||||||
- TCP and TCP/TLS using standard WiFiClient and WiFiClientSecure connections
|
|
||||||
- Virtually unlimited incoming and outgoing payload sizes
|
|
||||||
- Readable and understandable code
|
|
||||||
- Fully async clients available via [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) or [ESPAsnycTCP](https://github.com/me-no-dev/ESPAsyncTCP) (no TLS supported)
|
|
||||||
- Supported platforms:
|
|
||||||
- Espressif ESP8266 and ESP32 using the Arduino framework
|
|
||||||
- Basic Linux compatibility*. This includes WSL on Windows
|
|
||||||
|
|
||||||
> Linux compatibility is mainly for automatic testing. It relies on a quick and dirty Arduino-style `Client` with a POSIX TCP client underneath and Arduino-style `IPAddress` class. These are lacking many features needed for proper Linux support.
|
```
|
||||||
|
src/espMqttClient.cpp
|
||||||
# Documentation
|
src/Transport/ClientSecureSync.h
|
||||||
|
```
|
||||||
See [documentation](https://www.emelis.net/espMqttClient/) and the [examples](examples/).
|
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
### MQTT 3.1.1 Compliancy
|
|
||||||
|
|
||||||
Outgoing messages and session data are not stored in non-volatile memory. Any events like loss of power or sudden resets result in loss of data. Despite this limitation, one could still consider this library as fully complaint based on the non normative remark in point 4.1.1 of the specification.
|
|
||||||
|
|
||||||
### Non-blocking
|
|
||||||
|
|
||||||
This library aims to be fully non-blocking. It is however limited by the underlying `WiFiClient` library which is part of the Arduino framework and has a blocking `connect` method. This is not an issue on ESP32 because the call is offloaded to a separate task. On ESP8266 however, connecting will block until succesful or until the connection timeouts.
|
|
||||||
|
|
||||||
If you need a fully asynchronous MQTT client, you can use `espMqttClientAsync` which uses AsyncTCP/ESPAsyncTCP under the hood. These underlying libraries do not support TLS (anymore). I will not provide support TLS for the async client.
|
|
||||||
|
|
||||||
# Bugs and feature requests
|
|
||||||
|
|
||||||
Please use Github's facilities to get in touch.
|
|
||||||
|
|
||||||
# About this library
|
|
||||||
|
|
||||||
This client wouldn't exist without [Async-mqtt-client](https://github.com/marvinroger/async-mqtt-client). It has been my go-to MQTT client for many years. It was fast, reliable and had features that were non-existing in alternative libraries. However, the underlying async TCP libraries are lacking updates, especially updates related to secure connections. Adapting this library to use up-to-date TCP clients would not be trivial. I eventually decided to write my own MQTT library, from scratch.
|
|
||||||
|
|
||||||
The result is an almost non-blocking library with no external dependencies. The library is almost a drop-in replacement for the async-mqtt-client except a few parameter type changes (eg. `uint8_t*` instead of `char*` for payloads).
|
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
@@ -8,12 +8,8 @@ the LICENSE file.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef TASMOTA_SDK
|
|
||||||
#define EMC_CLIENT_SECURE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef EMC_TX_TIMEOUT
|
#ifndef EMC_TX_TIMEOUT
|
||||||
#define EMC_TX_TIMEOUT 2000
|
#define EMC_TX_TIMEOUT 10000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef EMC_RX_BUFFER_SIZE
|
#ifndef EMC_RX_BUFFER_SIZE
|
||||||
@@ -64,3 +60,16 @@ the LICENSE file.
|
|||||||
#ifndef EMC_USE_WATCHDOG
|
#ifndef EMC_USE_WATCHDOG
|
||||||
#define EMC_USE_WATCHDOG 0
|
#define EMC_USE_WATCHDOG 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef EMC_USE_MEMPOOL
|
||||||
|
#define EMC_USE_MEMPOOL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
#ifndef EMC_NUM_POOL_ELEMENTS
|
||||||
|
#define EMC_NUM_POOL_ELEMENTS 32
|
||||||
|
#endif
|
||||||
|
#ifndef EMC_SIZE_POOL_ELEMENTS
|
||||||
|
#define EMC_SIZE_POOL_ELEMENTS 128
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|||||||
21
lib/espMqttClient/src/MemoryPool/LICENSE
Normal file
21
lib/espMqttClient/src/MemoryPool/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Bert Melis
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
105
lib/espMqttClient/src/MemoryPool/README.md
Normal file
105
lib/espMqttClient/src/MemoryPool/README.md
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
# Memory Pool
|
||||||
|
|
||||||
|
EARLY VERSION. USE AT OWN RISK.
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
This is a simple memory pool that doesn't solve the fragmentation problem but contains it. Inside the pool you will still suffer memory fragmentation. The upside is that you're not restricted on memory size. As long as it fits in the pool, you can request any size!
|
||||||
|
|
||||||
|
For applications where the (maximum) size to allocate is known, a simple fixed block size memory pool is available. There is no memory fragmentation happening in this case. The downside is wastage of memory if you need less then the specified blocksize.
|
||||||
|
|
||||||
|
#### Features
|
||||||
|
|
||||||
|
- pool memory is statically allocated
|
||||||
|
- pool size adjusts on architecture
|
||||||
|
- no size calculation required: input number of blocks and size of block
|
||||||
|
- header-only library
|
||||||
|
- Variable size pool: no restriction on allocated size
|
||||||
|
- Variable size pool: malloc and free are O(n); The number of allocated blocks affects lookup.
|
||||||
|
- Fixed size pool: malloc and free are O(1).
|
||||||
|
|
||||||
|
[](https://github.com/bertmelis/MemoryPool/actions/workflows/test-platformio.yml)
|
||||||
|
[](https://github.com/bertmelis/MemoryPool/actions/workflows/cpplint.yml)
|
||||||
|
<!---[](https://github.com/bertmelis/MemoryPool/actions/workflows/cppcheck.yml)--->
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
#### Variable size pool
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <MemoryPool.h>
|
||||||
|
|
||||||
|
Struct MyStruct {
|
||||||
|
unsigned int id;
|
||||||
|
std::size_t size;
|
||||||
|
unsigned char data[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
// pool will be able to hold 10 blocks the size of MyStruct
|
||||||
|
MemoryPool::Variable<10, sizeof(MyStruct)> pool;
|
||||||
|
|
||||||
|
// you can allocate the specified blocksize
|
||||||
|
// allocation is done in number of 'unsigned char'
|
||||||
|
MyStruct* s = reinterpret_cast<MyStruct*>(pool.malloc(sizeof(MyStruct)));
|
||||||
|
|
||||||
|
// you can allocate less than the specified blocksize
|
||||||
|
int* i = reinterpret_cast<int*>(pool.malloc(sizeof(int)));
|
||||||
|
|
||||||
|
// you can allocate more than the specified blocksize
|
||||||
|
unsigned char* m = reinterpret_cast<unsigned char*>(pool.malloc(400));
|
||||||
|
|
||||||
|
pool.free(s);
|
||||||
|
pool.free(i);
|
||||||
|
pool.free(m);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Fixed size pool
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <MemoryPool.h>
|
||||||
|
|
||||||
|
Struct MyStruct {
|
||||||
|
unsigned int id;
|
||||||
|
std::size_t size;
|
||||||
|
unsigned char data[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
// pool will be able to hold 10 blocks the size of MyStruct
|
||||||
|
MemoryPool::Fixed<10, sizeof(MyStruct)> pool;
|
||||||
|
|
||||||
|
// there is no size argument in the malloc function!
|
||||||
|
MyStruct* s = reinterpret_cast<MyStruct*>(pool.malloc());
|
||||||
|
|
||||||
|
// you can allocate less than the specified blocksize
|
||||||
|
int* i = reinterpret_cast<int*>(pool.malloc());
|
||||||
|
|
||||||
|
pool.free(s);
|
||||||
|
pool.free(i);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### How it works
|
||||||
|
|
||||||
|
##### Variable size pool
|
||||||
|
|
||||||
|
Free blocks are organized as a linked list with their header (contains pointer to next and size). An allocated block also has this header with it's pointer set to `nullptr`. Therefore, each allocation wastes memory the size of the header (`sizeof(void*) + sizeof(std::size_t)`). On creation, the pool calculations the needed space to store the number of blocks wich each their header.
|
||||||
|
|
||||||
|
However, memory allocation isn't restricted the the specified blocksize. So in reality, you can allocate more if you allocate larger chunks because less memory blocks means less headers. After all, memory needs to be contiguous.
|
||||||
|
|
||||||
|
If you inspect the pool you'll see that a free pool only has one big block.
|
||||||
|
|
||||||
|
Allocation is linear: the pool is iterated until a suitable spot is found.
|
||||||
|
Freeing is also linear as the pool is traversed to insert the chunk in the linked list of free blocks
|
||||||
|
|
||||||
|
When freeing, free blocks which are adjacent are combined into one.
|
||||||
|
|
||||||
|
##### Fixed size pool
|
||||||
|
|
||||||
|
The fixed size pool is implemented as an array. Free blocks are saved as a linked list in this array.
|
||||||
|
|
||||||
|
### Bugs and feature requests
|
||||||
|
|
||||||
|
Please use Github's facilities to get in touch.
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
This library is released under the MIT Licence. A copy is included in the repo.
|
||||||
16
lib/espMqttClient/src/MemoryPool/keywords.txt
Normal file
16
lib/espMqttClient/src/MemoryPool/keywords.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
Fixed KEYWORD1
|
||||||
|
Variable KEYWORD1
|
||||||
|
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
malloc KEYWORD2
|
||||||
|
free KEYWORD2
|
||||||
|
freeMemory KEYWORD2
|
||||||
|
maxBlockSize KEYWORD2
|
||||||
|
print KEYWORD2
|
||||||
|
|
||||||
|
# Structures (KEYWORD3)
|
||||||
|
# structure KEYWORD3
|
||||||
|
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
MemoryPool LITERAL1
|
||||||
21
lib/espMqttClient/src/MemoryPool/library.json
Normal file
21
lib/espMqttClient/src/MemoryPool/library.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "MemoryPool",
|
||||||
|
"keywords": "memory",
|
||||||
|
"description": "A simple memory pool for fixed and variable sizes",
|
||||||
|
"authors":
|
||||||
|
{
|
||||||
|
"name": "Bert Melis",
|
||||||
|
"url": "https://github.com/bertmelis"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://github.com/bertmelis/MemoryPool",
|
||||||
|
"repository":
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/bertmelis/MemoryPool.git"
|
||||||
|
},
|
||||||
|
"version": "0.1.0",
|
||||||
|
"frameworks": "*",
|
||||||
|
"platforms": "*",
|
||||||
|
"headers": ["MemoryPool.h"]
|
||||||
|
}
|
||||||
10
lib/espMqttClient/src/MemoryPool/library.properties
Normal file
10
lib/espMqttClient/src/MemoryPool/library.properties
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
name=MemoryPool
|
||||||
|
version=0.1.0
|
||||||
|
author=Bert Melis
|
||||||
|
maintainer=Bert Melis
|
||||||
|
sentence=A simple memory pool for fixed and variable sizes
|
||||||
|
paragraph=
|
||||||
|
category=Other
|
||||||
|
url=https://github.com/bertmelis/MemoryPool
|
||||||
|
architectures=*
|
||||||
|
includes=MemoryPool.h
|
||||||
119
lib/espMqttClient/src/MemoryPool/src/Fixed.h
Normal file
119
lib/espMqttClient/src/MemoryPool/src/Fixed.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2024 Bert Melis. All rights reserved.
|
||||||
|
|
||||||
|
This work is licensed under the terms of the MIT license.
|
||||||
|
For a copy, see <https://opensource.org/licenses/MIT> or
|
||||||
|
the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // std::size_t
|
||||||
|
#include <cassert> // assert
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
#include <mutex> // NOLINT [build/c++11] std::mutex, std::lock_guard
|
||||||
|
#else
|
||||||
|
#warning "The memory pool is not thread safe"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MemoryPool {
|
||||||
|
|
||||||
|
template <std::size_t nrBlocks, std::size_t blocksize>
|
||||||
|
class Fixed {
|
||||||
|
public:
|
||||||
|
Fixed() // cppcheck-suppress uninitMemberVar
|
||||||
|
: _buffer{0}
|
||||||
|
, _head(_buffer) {
|
||||||
|
unsigned char* b = _head;
|
||||||
|
std::size_t adjustedBlocksize = sizeof(std::size_t) > blocksize ? sizeof(std::size_t) : blocksize;
|
||||||
|
for (std::size_t i = 0; i < nrBlocks - 1; ++i) {
|
||||||
|
*reinterpret_cast<unsigned char**>(b) = b + adjustedBlocksize;
|
||||||
|
b += adjustedBlocksize;
|
||||||
|
}
|
||||||
|
*reinterpret_cast<unsigned char**>(b) = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no copy nor move
|
||||||
|
Fixed (const Fixed&) = delete;
|
||||||
|
Fixed& operator= (const Fixed&) = delete;
|
||||||
|
|
||||||
|
void* malloc() {
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
if (_head) {
|
||||||
|
void* retVal = _head;
|
||||||
|
_head = *reinterpret_cast<unsigned char**>(_head);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr) {
|
||||||
|
if (!ptr) return;
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
*reinterpret_cast<unsigned char**>(ptr) = _head;
|
||||||
|
_head = reinterpret_cast<unsigned char*>(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t freeMemory() {
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
unsigned char* i = _head;
|
||||||
|
std::size_t retVal = 0;
|
||||||
|
while (i) {
|
||||||
|
retVal += blocksize;
|
||||||
|
i = reinterpret_cast<unsigned char**>(i)[0];
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
void print() {
|
||||||
|
std::size_t adjustedBlocksize = sizeof(std::size_t) > blocksize ? sizeof(std::size_t) : blocksize;
|
||||||
|
std::cout << "+--------------------" << std::endl;
|
||||||
|
std::cout << "|start:" << reinterpret_cast<void*>(_buffer) << std::endl;
|
||||||
|
std::cout << "|blocks:" << nrBlocks << std::endl;
|
||||||
|
std::cout << "|blocksize:" << adjustedBlocksize << std::endl;
|
||||||
|
std::cout << "|head: " << reinterpret_cast<void*>(_head) << std::endl;
|
||||||
|
unsigned char* currentBlock = _buffer;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < nrBlocks; ++i) {
|
||||||
|
std::cout << "|" << i + 1 << ": " << reinterpret_cast<void*>(currentBlock) << std::endl;
|
||||||
|
if (_isFree(currentBlock)) {
|
||||||
|
std::cout << "| free" << std::endl;
|
||||||
|
std::cout << "| next: " << reinterpret_cast<void*>(*reinterpret_cast<unsigned char**>(currentBlock)) << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "| allocated" << std::endl;
|
||||||
|
}
|
||||||
|
currentBlock += adjustedBlocksize;
|
||||||
|
}
|
||||||
|
std::cout << "+--------------------" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isFree(const unsigned char* ptr) {
|
||||||
|
unsigned char* b = _head;
|
||||||
|
while (b) {
|
||||||
|
if (b == ptr) return true;
|
||||||
|
b = *reinterpret_cast<unsigned char**>(b);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char _buffer[nrBlocks * (sizeof(std::size_t) > blocksize ? sizeof(std::size_t) : blocksize)];
|
||||||
|
unsigned char* _head;
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
std::mutex _mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace MemoryPool
|
||||||
12
lib/espMqttClient/src/MemoryPool/src/MemoryPool.h
Normal file
12
lib/espMqttClient/src/MemoryPool/src/MemoryPool.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2024 Bert Melis. All rights reserved.
|
||||||
|
|
||||||
|
This work is licensed under the terms of the MIT license.
|
||||||
|
For a copy, see <https://opensource.org/licenses/MIT> or
|
||||||
|
the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Variable.h"
|
||||||
|
#include "Fixed.h"
|
||||||
242
lib/espMqttClient/src/MemoryPool/src/Variable.h
Normal file
242
lib/espMqttClient/src/MemoryPool/src/Variable.h
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2024 Bert Melis. All rights reserved.
|
||||||
|
|
||||||
|
This work is licensed under the terms of the MIT license.
|
||||||
|
For a copy, see <https://opensource.org/licenses/MIT> or
|
||||||
|
the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef> // std::size_t
|
||||||
|
#include <cassert> // assert
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
#include <mutex> // NOLINT [build/c++11] std::mutex, std::lock_guard
|
||||||
|
#else
|
||||||
|
#warning "The memory pool is not thread safe"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MemoryPool {
|
||||||
|
|
||||||
|
template <std::size_t nrBlocks, std::size_t blocksize>
|
||||||
|
class Variable {
|
||||||
|
public:
|
||||||
|
Variable()
|
||||||
|
: _buffer{0}
|
||||||
|
, _head(nullptr)
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
, _bufferSize(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
std::size_t _normBlocksize = blocksize / sizeof(BlockHeader) + ((blocksize % sizeof(BlockHeader)) ? 1 : 0);
|
||||||
|
size_t nrBlocksToAlloc = nrBlocks * (_normBlocksize + 1);
|
||||||
|
BlockHeader* h = reinterpret_cast<BlockHeader*>(_buffer);
|
||||||
|
h->next = nullptr;
|
||||||
|
h->size = nrBlocksToAlloc;
|
||||||
|
_head = h;
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
_bufferSize = nrBlocksToAlloc;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// no copy nor move
|
||||||
|
Variable (const Variable&) = delete;
|
||||||
|
Variable& operator= (const Variable&) = delete;
|
||||||
|
|
||||||
|
void* malloc(size_t size) {
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
if (size == 0) return nullptr;
|
||||||
|
|
||||||
|
size = (size / sizeof(BlockHeader) + (size % sizeof(BlockHeader) != 0)) + 1; // count by BlockHeader size, add 1 for header
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
std::cout << "malloc (raw) " << size << std::endl;
|
||||||
|
std::cout << "malloc (adj) " << size << " - ";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BlockHeader* currentBlock = _head;
|
||||||
|
BlockHeader* previousBlock = nullptr;
|
||||||
|
void* retVal = nullptr;
|
||||||
|
|
||||||
|
// iterate through linked free blocks
|
||||||
|
while (currentBlock) {
|
||||||
|
// consume whole block is size equals required size
|
||||||
|
if (currentBlock->size == size) {
|
||||||
|
if (previousBlock) previousBlock->next = currentBlock->next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// split block if size is larger and add second part to list of free blocks
|
||||||
|
} else if (currentBlock->size > size) {
|
||||||
|
BlockHeader* newBlock = currentBlock + size;
|
||||||
|
if (previousBlock) previousBlock->next = newBlock;
|
||||||
|
newBlock->next = currentBlock->next;
|
||||||
|
newBlock->size = currentBlock->size - size;
|
||||||
|
currentBlock->next = newBlock;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
previousBlock = currentBlock;
|
||||||
|
currentBlock = currentBlock->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentBlock) {
|
||||||
|
if (currentBlock == _head) {
|
||||||
|
_head = currentBlock->next;
|
||||||
|
}
|
||||||
|
currentBlock->size = size;
|
||||||
|
currentBlock->next = nullptr; // used when freeing memory
|
||||||
|
retVal = currentBlock + 1;
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
std::cout << "ok" << std::endl;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
std::cout << "nok" << std::endl;
|
||||||
|
#endif
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr) {
|
||||||
|
if (!ptr) return;
|
||||||
|
// check if ptr points to region in _buffer
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
std::cout << "free " << static_cast<void*>(reinterpret_cast<BlockHeader*>(ptr) - 1) << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BlockHeader* toFree = reinterpret_cast<BlockHeader*>(ptr) - 1;
|
||||||
|
BlockHeader* previous = reinterpret_cast<BlockHeader*>(_buffer);
|
||||||
|
BlockHeader* next = _head;
|
||||||
|
|
||||||
|
// toFree is the only free block
|
||||||
|
if (!next) {
|
||||||
|
_head = toFree;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (previous) {
|
||||||
|
if (!next || toFree < next) {
|
||||||
|
// 1. add block to linked list of free blocks
|
||||||
|
if (toFree < _head) {
|
||||||
|
toFree->next = _head;
|
||||||
|
_head = toFree;
|
||||||
|
} else {
|
||||||
|
previous->next = toFree;
|
||||||
|
toFree->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. merge with previous if adjacent
|
||||||
|
if (toFree > _head && toFree == previous + previous->size) {
|
||||||
|
previous->size += toFree->size;
|
||||||
|
previous->next = toFree->next;
|
||||||
|
toFree = previous; // used in next check
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. merge with next if adjacent
|
||||||
|
if (toFree + toFree->size == next) {
|
||||||
|
toFree->size += next->size;
|
||||||
|
toFree->next = next->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
previous = next;
|
||||||
|
next = next->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t freeMemory() {
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
size_t retVal = 0;
|
||||||
|
BlockHeader* currentBlock = reinterpret_cast<BlockHeader*>(_head);
|
||||||
|
|
||||||
|
while (currentBlock) {
|
||||||
|
retVal += currentBlock->size - 1;
|
||||||
|
currentBlock = currentBlock->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal * sizeof(BlockHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t maxBlockSize() {
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
const std::lock_guard<std::mutex> lockGuard(_mutex);
|
||||||
|
#endif
|
||||||
|
size_t retVal = 0;
|
||||||
|
BlockHeader* currentBlock = reinterpret_cast<BlockHeader*>(_head);
|
||||||
|
|
||||||
|
while (currentBlock) {
|
||||||
|
retVal = (currentBlock->size - 1 > retVal) ? currentBlock->size - 1 : retVal;
|
||||||
|
currentBlock = currentBlock->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal * sizeof(BlockHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
void print() {
|
||||||
|
std::cout << "+--------------------" << std::endl;
|
||||||
|
std::cout << "|start:" << static_cast<void*>(_buffer) << std::endl;
|
||||||
|
std::cout << "|size:" << _bufferSize << std::endl;
|
||||||
|
std::cout << "|headersize:" << sizeof(BlockHeader) << std::endl;
|
||||||
|
std::cout << "|head: " << static_cast<void*>(_head) << std::endl;
|
||||||
|
BlockHeader* nextFreeBlock = _head;
|
||||||
|
BlockHeader* currentBlock = reinterpret_cast<BlockHeader*>(_buffer);
|
||||||
|
size_t blockNumber = 1;
|
||||||
|
while (currentBlock < reinterpret_cast<BlockHeader*>(_buffer) + _bufferSize) {
|
||||||
|
std::cout << "|" << blockNumber << ": " << static_cast<void*>(currentBlock) << std::endl;
|
||||||
|
std::cout << "| " << static_cast<void*>(currentBlock->next) << std::endl;
|
||||||
|
std::cout << "| " << currentBlock->size << std::endl;
|
||||||
|
if (currentBlock == nextFreeBlock) {
|
||||||
|
std::cout << "| free" << std::endl;
|
||||||
|
nextFreeBlock = nextFreeBlock->next;
|
||||||
|
} else {
|
||||||
|
std::cout << "| allocated" << std::endl;
|
||||||
|
}
|
||||||
|
++blockNumber;
|
||||||
|
currentBlock += currentBlock->size;
|
||||||
|
}
|
||||||
|
std::cout << "+--------------------" << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct BlockHeader {
|
||||||
|
BlockHeader* next;
|
||||||
|
std::size_t size;
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
pool size is aligned to sizeof(BlockHeader).
|
||||||
|
requested blocksize is therefore multiple of blockheader (rounded up)
|
||||||
|
total size = nr requested blocks * multiplier * blockheadersize
|
||||||
|
|
||||||
|
see constructor for calculation
|
||||||
|
*/
|
||||||
|
unsigned char _buffer[(nrBlocks * ((blocksize / sizeof(BlockHeader) + ((blocksize % sizeof(BlockHeader)) ? 1 : 0)) + 1)) * sizeof(BlockHeader)];
|
||||||
|
BlockHeader* _head;
|
||||||
|
#if _GLIBCXX_HAS_GTHREADS
|
||||||
|
std::mutex _mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MEMPOL_DEBUG
|
||||||
|
std::size_t _bufferSize;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace MemoryPool
|
||||||
@@ -87,14 +87,12 @@ MqttClient::~MqttClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MqttClient::connected() const {
|
bool MqttClient::connected() const {
|
||||||
if (_state == State::connected)
|
if (_state == State::connected) return true;
|
||||||
return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MqttClient::disconnected() const {
|
bool MqttClient::disconnected() const {
|
||||||
if (_state == State::disconnected)
|
if (_state == State::disconnected) return true;
|
||||||
return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,16 +111,17 @@ bool MqttClient::connect() {
|
|||||||
(uint16_t)(_keepAlive / 1000), // 32b to 16b doesn't overflow because it comes from 16b orignally
|
(uint16_t)(_keepAlive / 1000), // 32b to 16b doesn't overflow because it comes from 16b orignally
|
||||||
_clientId)) {
|
_clientId)) {
|
||||||
result = true;
|
result = true;
|
||||||
_state = State::connectingTcp1;
|
_setState(State::connectingTcp1);
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||||
vTaskResume(_taskHandle);
|
vTaskResume(_taskHandle);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
emc_log_e("Could not create CONNECT packet");
|
emc_log_e("Could not create CONNECT packet");
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onError(0, Error::OUT_OF_MEMORY);
|
_onError(0, Error::OUT_OF_MEMORY);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
EMC_SEMAPHORE_GIVE();
|
||||||
}
|
}
|
||||||
@@ -131,11 +130,11 @@ bool MqttClient::connect() {
|
|||||||
|
|
||||||
bool MqttClient::disconnect(bool force) {
|
bool MqttClient::disconnect(bool force) {
|
||||||
if (force && _state != State::disconnected && _state != State::disconnectingTcp1 && _state != State::disconnectingTcp2) {
|
if (force && _state != State::disconnected && _state != State::disconnectingTcp1 && _state != State::disconnectingTcp2) {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!force && _state == State::connected) {
|
if (!force && _state == State::connected) {
|
||||||
_state = State::disconnectingMqtt1;
|
_setState(State::disconnectingMqtt1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -153,7 +152,9 @@ uint16_t MqttClient::publish(const char * topic, uint8_t qos, bool retain, const
|
|||||||
uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1;
|
uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1;
|
||||||
if (!_addPacket(packetId, topic, payload, length, qos, retain)) {
|
if (!_addPacket(packetId, topic, payload, length, qos, retain)) {
|
||||||
emc_log_e("Could not create PUBLISH packet");
|
emc_log_e("Could not create PUBLISH packet");
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onError(packetId, Error::OUT_OF_MEMORY);
|
_onError(packetId, Error::OUT_OF_MEMORY);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
packetId = 0;
|
packetId = 0;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
EMC_SEMAPHORE_GIVE();
|
||||||
@@ -177,7 +178,9 @@ uint16_t MqttClient::publish(const char * topic, uint8_t qos, bool retain, espMq
|
|||||||
uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1;
|
uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1;
|
||||||
if (!_addPacket(packetId, topic, callback, length, qos, retain)) {
|
if (!_addPacket(packetId, topic, callback, length, qos, retain)) {
|
||||||
emc_log_e("Could not create PUBLISH packet");
|
emc_log_e("Could not create PUBLISH packet");
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onError(packetId, Error::OUT_OF_MEMORY);
|
_onError(packetId, Error::OUT_OF_MEMORY);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
packetId = 0;
|
packetId = 0;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
EMC_SEMAPHORE_GIVE();
|
||||||
@@ -185,7 +188,9 @@ uint16_t MqttClient::publish(const char * topic, uint8_t qos, bool retain, espMq
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::clearQueue(bool deleteSessionData) {
|
void MqttClient::clearQueue(bool deleteSessionData) {
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
_clearQueue(deleteSessionData ? 2 : 0);
|
_clearQueue(deleteSessionData ? 2 : 0);
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* MqttClient::getClientId() const {
|
const char* MqttClient::getClientId() const {
|
||||||
@@ -201,7 +206,7 @@ size_t MqttClient::queueSize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::loop() {
|
void MqttClient::loop() {
|
||||||
switch ((State)_state) { // modified by proddy for EMS-ESP compiling standalone
|
switch (_state) {
|
||||||
case State::disconnected:
|
case State::disconnected:
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
if (_useInternalTask == espMqttClientTypes::UseInternalTask::YES) {
|
||||||
@@ -211,9 +216,9 @@ void MqttClient::loop() {
|
|||||||
break;
|
break;
|
||||||
case State::connectingTcp1:
|
case State::connectingTcp1:
|
||||||
if (_useIp ? _transport->connect(_ip, _port) : _transport->connect(_host, _port)) {
|
if (_useIp ? _transport->connect(_ip, _port) : _transport->connect(_host, _port)) {
|
||||||
_state = State::connectingTcp2;
|
_setState(State::connectingTcp2);
|
||||||
} else {
|
} else {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -223,17 +228,22 @@ void MqttClient::loop() {
|
|||||||
if (_transport->connected()) {
|
if (_transport->connected()) {
|
||||||
_parser.reset();
|
_parser.reset();
|
||||||
_lastClientActivity = _lastServerActivity = millis();
|
_lastClientActivity = _lastServerActivity = millis();
|
||||||
_state = State::connectingMqtt;
|
_setState(State::connectingMqtt);
|
||||||
|
} else if (_transport->disconnected()) { // sync: implemented as "not connected"; async: depending on state of pcb in underlying lib
|
||||||
|
_setState(State::disconnectingTcp1);
|
||||||
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State::connectingMqtt:
|
case State::connectingMqtt:
|
||||||
#if EMC_WAIT_FOR_CONNACK
|
#if EMC_WAIT_FOR_CONNACK
|
||||||
if (_transport->connected()) {
|
if (_transport->connected()) {
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
_sendPacket();
|
_sendPacket();
|
||||||
_checkIncoming();
|
_checkIncoming();
|
||||||
_checkPing();
|
_checkPing();
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
} else {
|
} else {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -248,12 +258,14 @@ void MqttClient::loop() {
|
|||||||
case State::disconnectingMqtt2:
|
case State::disconnectingMqtt2:
|
||||||
if (_transport->connected()) {
|
if (_transport->connected()) {
|
||||||
// CONNECT packet is first in the queue
|
// CONNECT packet is first in the queue
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
_checkOutbox();
|
_checkOutbox();
|
||||||
_checkIncoming();
|
_checkIncoming();
|
||||||
_checkPing();
|
_checkPing();
|
||||||
_checkTimeout();
|
_checkTimeout();
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
} else {
|
} else {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -264,28 +276,32 @@ void MqttClient::loop() {
|
|||||||
EMC_SEMAPHORE_GIVE();
|
EMC_SEMAPHORE_GIVE();
|
||||||
emc_log_e("Could not create DISCONNECT packet");
|
emc_log_e("Could not create DISCONNECT packet");
|
||||||
_onError(0, Error::OUT_OF_MEMORY);
|
_onError(0, Error::OUT_OF_MEMORY);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
} else {
|
} else {
|
||||||
_state = State::disconnectingMqtt2;
|
_setState(State::disconnectingMqtt2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
_checkOutbox();
|
_checkOutbox();
|
||||||
_checkIncoming();
|
_checkIncoming();
|
||||||
_checkPing();
|
_checkPing();
|
||||||
_checkTimeout();
|
_checkTimeout();
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
break;
|
break;
|
||||||
case State::disconnectingTcp1:
|
case State::disconnectingTcp1:
|
||||||
_transport->stop();
|
_transport->stop();
|
||||||
_state = State::disconnectingTcp2;
|
_setState(State::disconnectingTcp2);
|
||||||
break; // keep break to accomodate async clients
|
break; // keep break to accomodate async clients
|
||||||
case State::disconnectingTcp2:
|
case State::disconnectingTcp2:
|
||||||
if (_transport->disconnected()) {
|
if (_transport->disconnected()) {
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
_clearQueue(0);
|
_clearQueue(0);
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_bytesSent = 0;
|
_bytesSent = 0;
|
||||||
_state = State::disconnected;
|
_setState(State::disconnected);
|
||||||
if (_onDisconnectCallback)
|
if (_onDisconnectCallback) {
|
||||||
_onDisconnectCallback(_disconnectReason);
|
_onDisconnectCallback(_disconnectReason);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
// all cases covered, no default case
|
// all cases covered, no default case
|
||||||
}
|
}
|
||||||
@@ -315,10 +331,14 @@ void MqttClient::_loop(MqttClient * c) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline void MqttClient::_setState(State newState) {
|
||||||
|
emc_log_i("state %i --> %i", static_cast<std::underlying_type<State>::type>(_state.load()), static_cast<std::underlying_type<State>::type>(newState));
|
||||||
|
_state = newState;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t MqttClient::_getNextPacketId() {
|
uint16_t MqttClient::_getNextPacketId() {
|
||||||
++_packetId;
|
++_packetId;
|
||||||
if (_packetId == 0)
|
if (_packetId == 0) ++_packetId;
|
||||||
++_packetId;
|
|
||||||
return _packetId;
|
return _packetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,14 +351,12 @@ void MqttClient::_checkOutbox() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int MqttClient::_sendPacket() {
|
int MqttClient::_sendPacket() {
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
OutgoingPacket* packet = _outbox.getCurrent();
|
OutgoingPacket* packet = _outbox.getCurrent();
|
||||||
|
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
if (packet) {
|
if (packet) {
|
||||||
size_t wantToWrite = packet->packet.available(_bytesSent);
|
size_t wantToWrite = packet->packet.available(_bytesSent);
|
||||||
if (wantToWrite == 0) {
|
if (wantToWrite == 0) {
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
written = _transport->write(packet->packet.data(_bytesSent), wantToWrite);
|
written = _transport->write(packet->packet.data(_bytesSent), wantToWrite);
|
||||||
@@ -347,30 +365,26 @@ int MqttClient::_sendPacket() {
|
|||||||
_bytesSent += written;
|
_bytesSent += written;
|
||||||
emc_log_i("tx %zu/%zu (%02x)", _bytesSent, packet->packet.size(), packet->packet.packetType());
|
emc_log_i("tx %zu/%zu (%02x)", _bytesSent, packet->packet.size(), packet->packet.packetType());
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MqttClient::_advanceOutbox() {
|
bool MqttClient::_advanceOutbox() {
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
OutgoingPacket* packet = _outbox.getCurrent();
|
OutgoingPacket* packet = _outbox.getCurrent();
|
||||||
if (packet && _bytesSent == packet->packet.size()) {
|
if (packet && _bytesSent == packet->packet.size()) {
|
||||||
if ((packet->packet.packetType()) == PacketType.DISCONNECT) {
|
if ((packet->packet.packetType()) == PacketType.DISCONNECT) {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::USER_OK;
|
_disconnectReason = DisconnectReason::USER_OK;
|
||||||
}
|
}
|
||||||
if (packet->packet.removable()) {
|
if (packet->packet.removable()) {
|
||||||
_outbox.removeCurrent();
|
_outbox.removeCurrent();
|
||||||
} else {
|
} else {
|
||||||
// we already set 'dup' here, in case we have to retry
|
// we already set 'dup' here, in case we have to retry
|
||||||
if ((packet->packet.packetType()) == PacketType.PUBLISH)
|
if ((packet->packet.packetType()) == PacketType.PUBLISH) packet->packet.setDup();
|
||||||
packet->packet.setDup();
|
|
||||||
_outbox.next();
|
_outbox.next();
|
||||||
}
|
}
|
||||||
packet = _outbox.getCurrent();
|
packet = _outbox.getCurrent();
|
||||||
_bytesSent = 0;
|
_bytesSent = 0;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,10 +401,10 @@ void MqttClient::_checkIncoming() {
|
|||||||
espMqttClientInternals::MQTTPacketType packetType = _parser.getPacket().fixedHeader.packetType & 0xF0;
|
espMqttClientInternals::MQTTPacketType packetType = _parser.getPacket().fixedHeader.packetType & 0xF0;
|
||||||
if (_state == State::connectingMqtt && packetType != PacketType.CONNACK) {
|
if (_state == State::connectingMqtt && packetType != PacketType.CONNACK) {
|
||||||
emc_log_w("Disconnecting, expected CONNACK - protocol error");
|
emc_log_w("Disconnecting, expected CONNACK - protocol error");
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (packetType & 0xF0) {
|
switch (packetType) {
|
||||||
case PacketType.CONNACK:
|
case PacketType.CONNACK:
|
||||||
_onConnack();
|
_onConnack();
|
||||||
if (_state != State::connected) {
|
if (_state != State::connected) {
|
||||||
@@ -398,8 +412,7 @@ void MqttClient::_checkIncoming() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketType.PUBLISH:
|
case PacketType.PUBLISH:
|
||||||
if (_state >= State::disconnectingMqtt1)
|
if (_state >= State::disconnectingMqtt1) break; // stop processing incoming once user has called disconnect
|
||||||
break; // stop processing incoming once user has called disconnect
|
|
||||||
_onPublish();
|
_onPublish();
|
||||||
break;
|
break;
|
||||||
case PacketType.PUBACK:
|
case PacketType.PUBACK:
|
||||||
@@ -426,7 +439,7 @@ void MqttClient::_checkIncoming() {
|
|||||||
}
|
}
|
||||||
} else if (result == espMqttClientInternals::ParserResult::protocolError) {
|
} else if (result == espMqttClientInternals::ParserResult::protocolError) {
|
||||||
emc_log_w("Disconnecting, protocol error");
|
emc_log_w("Disconnecting, protocol error");
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -439,35 +452,32 @@ void MqttClient::_checkIncoming() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_checkPing() {
|
void MqttClient::_checkPing() {
|
||||||
if (_keepAlive == 0)
|
if (_keepAlive == 0) return; // keepalive is disabled
|
||||||
return; // keepalive is disabled
|
|
||||||
|
|
||||||
uint32_t currentMillis = millis();
|
uint32_t currentMillis = millis();
|
||||||
|
|
||||||
// disconnect when server was inactive for twice the keepalive time
|
// disconnect when server was inactive for twice the keepalive time
|
||||||
if (currentMillis - _lastServerActivity > 2 * _keepAlive) {
|
if (currentMillis - _lastServerActivity > 2 * _keepAlive) {
|
||||||
emc_log_w("Disconnecting, server exceeded keepalive");
|
emc_log_w("Disconnecting, server exceeded keepalive");
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
_disconnectReason = DisconnectReason::TCP_DISCONNECTED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send ping when client was inactive during the keepalive time
|
// send ping when client was inactive during the keepalive time
|
||||||
// or when server hasn't responded within keepalive time (typically due to QOS 0)
|
// or when server hasn't responded within keepalive time (typically due to QOS 0)
|
||||||
if (!_pingSent && ((currentMillis - _lastClientActivity > _keepAlive) || (currentMillis - _lastServerActivity > _keepAlive))) {
|
if (!_pingSent &&
|
||||||
EMC_SEMAPHORE_TAKE();
|
((currentMillis - _lastClientActivity > _keepAlive) ||
|
||||||
|
(currentMillis - _lastServerActivity > _keepAlive))) {
|
||||||
if (!_addPacket(PacketType.PINGREQ)) {
|
if (!_addPacket(PacketType.PINGREQ)) {
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
emc_log_e("Could not create PING packet");
|
emc_log_e("Could not create PING packet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
_pingSent = true;
|
_pingSent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_checkTimeout() {
|
void MqttClient::_checkTimeout() {
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
// check that we're not busy sending
|
// check that we're not busy sending
|
||||||
// don't check when first item hasn't been sent yet
|
// don't check when first item hasn't been sent yet
|
||||||
@@ -477,22 +487,23 @@ void MqttClient::_checkTimeout() {
|
|||||||
_outbox.resetCurrent();
|
_outbox.resetCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_onConnack() {
|
void MqttClient::_onConnack() {
|
||||||
if (_parser.getPacket().variableHeader.fixed.connackVarHeader.returnCode == 0x00) {
|
if (_parser.getPacket().variableHeader.fixed.connackVarHeader.returnCode == 0x00) {
|
||||||
_pingSent = false; // reset after keepalive timeout disconnect
|
_pingSent = false; // reset after keepalive timeout disconnect
|
||||||
_state = State::connected;
|
_setState(State::connected);
|
||||||
_advanceOutbox();
|
_advanceOutbox();
|
||||||
if (_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent == 0) {
|
if (_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent == 0) {
|
||||||
_clearQueue(1);
|
_clearQueue(1);
|
||||||
}
|
}
|
||||||
if (_onConnectCallback) {
|
if (_onConnectCallback) {
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onConnectCallback(_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent);
|
_onConnectCallback(_parser.getPacket().variableHeader.fixed.connackVarHeader.sessionPresent);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_state = State::disconnectingTcp1;
|
_setState(State::disconnectingTcp1);
|
||||||
// cast is safe because the parser already checked for a valid return code
|
// cast is safe because the parser already checked for a valid return code
|
||||||
_disconnectReason = static_cast<DisconnectReason>(_parser.getPacket().variableHeader.fixed.connackVarHeader.returnCode);
|
_disconnectReason = static_cast<DisconnectReason>(_parser.getPacket().variableHeader.fixed.connackVarHeader.returnCode);
|
||||||
}
|
}
|
||||||
@@ -507,19 +518,15 @@ void MqttClient::_onPublish() {
|
|||||||
bool callback = true;
|
bool callback = true;
|
||||||
if (qos == 1) {
|
if (qos == 1) {
|
||||||
if (p.payload.index + p.payload.length == p.payload.total) {
|
if (p.payload.index + p.payload.length == p.payload.total) {
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
if (!_addPacket(PacketType.PUBACK, packetId)) {
|
if (!_addPacket(PacketType.PUBACK, packetId)) {
|
||||||
emc_log_e("Could not create PUBACK packet");
|
emc_log_e("Could not create PUBACK packet");
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
} else if (qos == 2) {
|
} else if (qos == 2) {
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
while (it) {
|
while (it) {
|
||||||
if ((it.get()->packet.packetType()) == PacketType.PUBREC && it.get()->packet.packetId() == packetId) {
|
if ((it.get()->packet.packetType()) == PacketType.PUBREC && it.get()->packet.packetId() == packetId) {
|
||||||
callback = false;
|
callback = false;
|
||||||
_outbox.remove(it);
|
|
||||||
emc_log_e("QoS2 packet previously delivered");
|
emc_log_e("QoS2 packet previously delivered");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -530,16 +537,22 @@ void MqttClient::_onPublish() {
|
|||||||
emc_log_e("Could not create PUBREC packet");
|
emc_log_e("Could not create PUBREC packet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
if (callback && _onMessageCallback)
|
if (callback && _onMessageCallback) {
|
||||||
_onMessageCallback({qos, dup, retain, packetId}, p.variableHeader.topic, p.payload.data, p.payload.length, p.payload.index, p.payload.total);
|
EMC_SEMAPHORE_GIVE();
|
||||||
|
_onMessageCallback({qos, dup, retain, packetId},
|
||||||
|
p.variableHeader.topic,
|
||||||
|
p.payload.data,
|
||||||
|
p.payload.length,
|
||||||
|
p.payload.index,
|
||||||
|
p.payload.total);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_onPuback() {
|
void MqttClient::_onPuback() {
|
||||||
bool callback = false;
|
bool callback = false;
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
while (it) {
|
while (it) {
|
||||||
// PUBACKs come in the order PUBs are sent. So we only check the first PUB packet in outbox
|
// PUBACKs come in the order PUBs are sent. So we only check the first PUB packet in outbox
|
||||||
@@ -555,10 +568,12 @@ void MqttClient::_onPuback() {
|
|||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
if (_onPublishCallback)
|
if (_onPublishCallback) {
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onPublishCallback(idToMatch);
|
_onPublishCallback(idToMatch);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emc_log_w("No matching PUBLISH packet found");
|
emc_log_w("No matching PUBLISH packet found");
|
||||||
}
|
}
|
||||||
@@ -567,12 +582,11 @@ void MqttClient::_onPuback() {
|
|||||||
void MqttClient::_onPubrec() {
|
void MqttClient::_onPubrec() {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
while (it) {
|
while (it) {
|
||||||
// PUBRECs come in the order PUBs are sent. So we only check the first PUB packet in outbox
|
// PUBRECs come in the order PUBs are sent. So we only check the first PUB packet in outbox
|
||||||
// if it doesn't match the ID, return
|
// if it doesn't match the ID, return
|
||||||
if ((it.get()->packet.packetType()) == PacketType.PUBLISH || (it.get()->packet.packetType()) == PacketType.PUBREL) {
|
if ((it.get()->packet.packetType()) == PacketType.PUBLISH) {
|
||||||
if (it.get()->packet.packetId() == idToMatch) {
|
if (it.get()->packet.packetId() == idToMatch) {
|
||||||
if (!_addPacket(PacketType.PUBREL, idToMatch)) {
|
if (!_addPacket(PacketType.PUBREL, idToMatch)) {
|
||||||
emc_log_e("Could not create PUBREL packet");
|
emc_log_e("Could not create PUBREL packet");
|
||||||
@@ -589,13 +603,11 @@ void MqttClient::_onPubrec() {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
emc_log_w("No matching PUBLISH packet found");
|
emc_log_w("No matching PUBLISH packet found");
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_onPubrel() {
|
void MqttClient::_onPubrel() {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
while (it) {
|
while (it) {
|
||||||
// PUBRELs come in the order PUBRECs are sent. So we only check the first PUBREC packet in outbox
|
// PUBRELs come in the order PUBRECs are sent. So we only check the first PUBREC packet in outbox
|
||||||
@@ -617,12 +629,10 @@ void MqttClient::_onPubrel() {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
emc_log_w("No matching PUBREC packet found");
|
emc_log_w("No matching PUBREC packet found");
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_onPubcomp() {
|
void MqttClient::_onPubcomp() {
|
||||||
bool callback = false;
|
bool callback = false;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
while (it) {
|
while (it) {
|
||||||
@@ -639,10 +649,12 @@ void MqttClient::_onPubcomp() {
|
|||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
if (_onPublishCallback)
|
if (_onPublishCallback) {
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onPublishCallback(idToMatch);
|
_onPublishCallback(idToMatch);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emc_log_w("No matching PUBREL packet found");
|
emc_log_w("No matching PUBREL packet found");
|
||||||
}
|
}
|
||||||
@@ -651,7 +663,6 @@ void MqttClient::_onPubcomp() {
|
|||||||
void MqttClient::_onSuback() {
|
void MqttClient::_onSuback() {
|
||||||
bool callback = false;
|
bool callback = false;
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
while (it) {
|
while (it) {
|
||||||
if (((it.get()->packet.packetType()) == PacketType.SUBSCRIBE) && it.get()->packet.packetId() == idToMatch) {
|
if (((it.get()->packet.packetType()) == PacketType.SUBSCRIBE) && it.get()->packet.packetId() == idToMatch) {
|
||||||
@@ -661,12 +672,12 @@ void MqttClient::_onSuback() {
|
|||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
if (_onSubscribeCallback)
|
if (_onSubscribeCallback) {
|
||||||
_onSubscribeCallback(idToMatch,
|
EMC_SEMAPHORE_GIVE();
|
||||||
reinterpret_cast<const espMqttClientTypes::SubscribeReturncode *>(_parser.getPacket().payload.data),
|
_onSubscribeCallback(idToMatch, reinterpret_cast<const espMqttClientTypes::SubscribeReturncode*>(_parser.getPacket().payload.data), _parser.getPacket().payload.total);
|
||||||
_parser.getPacket().payload.total);
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emc_log_w("received SUBACK without SUB");
|
emc_log_w("received SUBACK without SUB");
|
||||||
}
|
}
|
||||||
@@ -674,7 +685,6 @@ void MqttClient::_onSuback() {
|
|||||||
|
|
||||||
void MqttClient::_onUnsuback() {
|
void MqttClient::_onUnsuback() {
|
||||||
bool callback = false;
|
bool callback = false;
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
uint16_t idToMatch = _parser.getPacket().variableHeader.fixed.packetId;
|
||||||
while (it) {
|
while (it) {
|
||||||
@@ -685,10 +695,12 @@ void MqttClient::_onUnsuback() {
|
|||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
if (_onUnsubscribeCallback)
|
if (_onUnsubscribeCallback) {
|
||||||
|
EMC_SEMAPHORE_GIVE();
|
||||||
_onUnsubscribeCallback(idToMatch);
|
_onUnsubscribeCallback(idToMatch);
|
||||||
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emc_log_w("received UNSUBACK without UNSUB");
|
emc_log_w("received UNSUBACK without UNSUB");
|
||||||
}
|
}
|
||||||
@@ -696,7 +708,6 @@ void MqttClient::_onUnsuback() {
|
|||||||
|
|
||||||
void MqttClient::_clearQueue(int clearData) {
|
void MqttClient::_clearQueue(int clearData) {
|
||||||
emc_log_i("clearing queue (clear session: %d)", clearData);
|
emc_log_i("clearing queue (clear session: %d)", clearData);
|
||||||
EMC_SEMAPHORE_TAKE();
|
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.front();
|
||||||
if (clearData == 0) {
|
if (clearData == 0) {
|
||||||
// keep PUB (qos > 0, aka packetID != 0), PUBREC and PUBREL
|
// keep PUB (qos > 0, aka packetID != 0), PUBREC and PUBREL
|
||||||
@@ -704,7 +715,9 @@ void MqttClient::_clearQueue(int clearData) {
|
|||||||
// and stores the packet id in the PUBREC packet. So we also must keep PUBREC.
|
// and stores the packet id in the PUBREC packet. So we also must keep PUBREC.
|
||||||
while (it) {
|
while (it) {
|
||||||
espMqttClientInternals::MQTTPacketType type = it.get()->packet.packetType();
|
espMqttClientInternals::MQTTPacketType type = it.get()->packet.packetType();
|
||||||
if (type == PacketType.PUBREC || type == PacketType.PUBREL || (type == PacketType.PUBLISH && it.get()->packet.packetId() != 0)) {
|
if (type == PacketType.PUBREC ||
|
||||||
|
type == PacketType.PUBREL ||
|
||||||
|
(type == PacketType.PUBLISH && it.get()->packet.packetId() != 0)) {
|
||||||
++it;
|
++it;
|
||||||
} else {
|
} else {
|
||||||
_outbox.remove(it);
|
_outbox.remove(it);
|
||||||
@@ -724,7 +737,6 @@ void MqttClient::_clearQueue(int clearData) {
|
|||||||
_outbox.remove(it);
|
_outbox.remove(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EMC_SEMAPHORE_GIVE();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttClient::_onError(uint16_t packetId, espMqttClientTypes::Error error) {
|
void MqttClient::_onError(uint16_t packetId, espMqttClientTypes::Error error) {
|
||||||
|
|||||||
@@ -32,11 +32,12 @@ class MqttClient {
|
|||||||
bool disconnect(bool force = false);
|
bool disconnect(bool force = false);
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
uint16_t subscribe(const char* topic, uint8_t qos, Args&&... args) {
|
uint16_t subscribe(const char* topic, uint8_t qos, Args&&... args) {
|
||||||
uint16_t packetId = _getNextPacketId();
|
uint16_t packetId = 0;
|
||||||
if (_state != State::connected) {
|
if (_state != State::connected) {
|
||||||
packetId = 0;
|
return packetId;
|
||||||
} else {
|
} else {
|
||||||
EMC_SEMAPHORE_TAKE();
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
packetId = _getNextPacketId();
|
||||||
if (!_addPacket(packetId, topic, qos, std::forward<Args>(args) ...)) {
|
if (!_addPacket(packetId, topic, qos, std::forward<Args>(args) ...)) {
|
||||||
emc_log_e("Could not create SUBSCRIBE packet");
|
emc_log_e("Could not create SUBSCRIBE packet");
|
||||||
packetId = 0;
|
packetId = 0;
|
||||||
@@ -47,11 +48,12 @@ class MqttClient {
|
|||||||
}
|
}
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
uint16_t unsubscribe(const char* topic, Args&&... args) {
|
uint16_t unsubscribe(const char* topic, Args&&... args) {
|
||||||
uint16_t packetId = _getNextPacketId();
|
uint16_t packetId = 0;
|
||||||
if (_state != State::connected) {
|
if (_state != State::connected) {
|
||||||
packetId = 0;
|
return packetId;
|
||||||
} else {
|
} else {
|
||||||
EMC_SEMAPHORE_TAKE();
|
EMC_SEMAPHORE_TAKE();
|
||||||
|
packetId = _getNextPacketId();
|
||||||
if (!_addPacket(packetId, topic, std::forward<Args>(args) ...)) {
|
if (!_addPacket(packetId, topic, std::forward<Args>(args) ...)) {
|
||||||
emc_log_e("Could not create UNSUBSCRIBE packet");
|
emc_log_e("Could not create UNSUBSCRIBE packet");
|
||||||
packetId = 0;
|
packetId = 0;
|
||||||
@@ -111,6 +113,7 @@ class MqttClient {
|
|||||||
disconnectingTcp2 = 8
|
disconnectingTcp2 = 8
|
||||||
};
|
};
|
||||||
std::atomic<State> _state;
|
std::atomic<State> _state;
|
||||||
|
inline void _setState(State newState);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char _generatedClientId[EMC_CLIENTID_LENGTH];
|
char _generatedClientId[EMC_CLIENTID_LENGTH];
|
||||||
@@ -123,7 +126,7 @@ class MqttClient {
|
|||||||
#elif defined(ARDUINO_ARCH_ESP8266) && EMC_ESP8266_MULTITHREADING
|
#elif defined(ARDUINO_ARCH_ESP8266) && EMC_ESP8266_MULTITHREADING
|
||||||
std::atomic<bool> _xSemaphore = false;
|
std::atomic<bool> _xSemaphore = false;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
mutable std::mutex mtx; // modified by proddy for EMS-ESP compiling standalone
|
std::mutex mtx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint8_t _rxBuffer[EMC_RX_BUFFER_SIZE];
|
uint8_t _rxBuffer[EMC_RX_BUFFER_SIZE];
|
||||||
@@ -131,11 +134,9 @@ class MqttClient {
|
|||||||
uint32_t timeSent;
|
uint32_t timeSent;
|
||||||
espMqttClientInternals::Packet packet;
|
espMqttClientInternals::Packet packet;
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
OutgoingPacket(uint32_t t, espMqttClientTypes::Error & error, Args &&... args)
|
OutgoingPacket(uint32_t t, espMqttClientTypes::Error& error, Args&&... args) : // NOLINT(runtime/references)
|
||||||
: // NOLINT(runtime/references)
|
timeSent(t),
|
||||||
timeSent(t)
|
packet(error, std::forward<Args>(args) ...) {}
|
||||||
, packet(error, std::forward<Args>(args)...) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
espMqttClientInternals::Outbox<OutgoingPacket> _outbox;
|
espMqttClientInternals::Outbox<OutgoingPacket> _outbox;
|
||||||
size_t _bytesSent;
|
size_t _bytesSent;
|
||||||
@@ -154,8 +155,7 @@ class MqttClient {
|
|||||||
if (it && error == espMqttClientTypes::Error::SUCCESS) {
|
if (it && error == espMqttClientTypes::Error::SUCCESS) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (it)
|
if (it) _outbox.remove(it);
|
||||||
_outbox.remove(it);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -167,8 +167,7 @@ class MqttClient {
|
|||||||
if (it && error == espMqttClientTypes::Error::SUCCESS) {
|
if (it && error == espMqttClientTypes::Error::SUCCESS) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (it)
|
if (it) _outbox.remove(it);
|
||||||
_outbox.remove(it);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ the LICENSE file.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
#include "MemoryPool/src/MemoryPool.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#else
|
||||||
#include <new> // new (std::nothrow)
|
#include <new> // new (std::nothrow)
|
||||||
|
#endif
|
||||||
#include <utility> // std::forward
|
#include <utility> // std::forward
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
@@ -28,11 +33,20 @@ class Outbox {
|
|||||||
: _first(nullptr)
|
: _first(nullptr)
|
||||||
, _last(nullptr)
|
, _last(nullptr)
|
||||||
, _current(nullptr)
|
, _current(nullptr)
|
||||||
, _prev(nullptr) {}
|
, _prev(nullptr)
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
, _memPool()
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
~Outbox() {
|
~Outbox() {
|
||||||
while (_first) {
|
while (_first) {
|
||||||
Node* n = _first->next;
|
Node* n = _first->next;
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
_first->~Node();
|
||||||
|
_memPool.free(_first);
|
||||||
|
#else
|
||||||
delete _first;
|
delete _first;
|
||||||
|
#endif
|
||||||
_first = n;
|
_first = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +93,15 @@ class Outbox {
|
|||||||
template <class... Args>
|
template <class... Args>
|
||||||
Iterator emplace(Args&&... args) {
|
Iterator emplace(Args&&... args) {
|
||||||
Iterator it;
|
Iterator it;
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
void* buf = _memPool.malloc();
|
||||||
|
Node* node = nullptr;
|
||||||
|
if (buf) {
|
||||||
|
node = new(buf) Node(std::forward<Args>(args) ...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
Node* node = new(std::nothrow) Node(std::forward<Args>(args) ...);
|
Node* node = new(std::nothrow) Node(std::forward<Args>(args) ...);
|
||||||
|
#endif
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
if (!_first) {
|
if (!_first) {
|
||||||
// queue is empty
|
// queue is empty
|
||||||
@@ -103,7 +125,15 @@ class Outbox {
|
|||||||
template <class... Args>
|
template <class... Args>
|
||||||
Iterator emplaceFront(Args&&... args) {
|
Iterator emplaceFront(Args&&... args) {
|
||||||
Iterator it;
|
Iterator it;
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
void* buf = _memPool.malloc();
|
||||||
|
Node* node = nullptr;
|
||||||
|
if (buf) {
|
||||||
|
node = new(buf) Node(std::forward<Args>(args) ...);
|
||||||
|
}
|
||||||
|
#else
|
||||||
Node* node = new(std::nothrow) Node(std::forward<Args>(args) ...);
|
Node* node = new(std::nothrow) Node(std::forward<Args>(args) ...);
|
||||||
|
#endif
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
if (!_first) {
|
if (!_first) {
|
||||||
// queue is empty
|
// queue is empty
|
||||||
@@ -178,6 +208,9 @@ class Outbox {
|
|||||||
Node* _last;
|
Node* _last;
|
||||||
Node* _current;
|
Node* _current;
|
||||||
Node* _prev; // element just before _current
|
Node* _prev; // element just before _current
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
MemoryPool::Fixed<EMC_NUM_POOL_ELEMENTS, sizeof(Node)> _memPool;
|
||||||
|
#endif
|
||||||
|
|
||||||
void _remove(Node* prev, Node* node) {
|
void _remove(Node* prev, Node* node) {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@@ -210,7 +243,12 @@ class Outbox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finally, delete the node
|
// finally, delete the node
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
node->~Node();
|
||||||
|
_memPool.free(node);
|
||||||
|
#else
|
||||||
delete node;
|
delete node;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,24 +10,28 @@ the LICENSE file.
|
|||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
MemoryPool::Variable<EMC_NUM_POOL_ELEMENTS, EMC_SIZE_POOL_ELEMENTS> Packet::_memPool;
|
||||||
|
#endif
|
||||||
|
|
||||||
Packet::~Packet() {
|
Packet::~Packet() {
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
_memPool.free(_data);
|
||||||
|
#else
|
||||||
free(_data);
|
free(_data);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Packet::available(size_t index) {
|
size_t Packet::available(size_t index) {
|
||||||
if (index >= _size)
|
if (index >= _size) return 0;
|
||||||
return 0;
|
if (!_getPayload) return _size - index;
|
||||||
if (!_getPayload)
|
|
||||||
return _size - index;
|
|
||||||
return _chunkedAvailable(index);
|
return _chunkedAvailable(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t* Packet::data(size_t index) const {
|
const uint8_t* Packet::data(size_t index) const {
|
||||||
if (!_getPayload) {
|
if (!_getPayload) {
|
||||||
if (!_data)
|
if (!_data) return nullptr;
|
||||||
return nullptr;
|
if (index >= _size) return nullptr;
|
||||||
if (index >= _size)
|
|
||||||
return nullptr;
|
|
||||||
return &_data[index];
|
return &_data[index];
|
||||||
}
|
}
|
||||||
return _chunkedData(index);
|
return _chunkedData(index);
|
||||||
@@ -38,12 +42,9 @@ size_t Packet::size() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Packet::setDup() {
|
void Packet::setDup() {
|
||||||
if (!_data)
|
if (!_data) return;
|
||||||
return;
|
if (packetType() != PacketType.PUBLISH) return;
|
||||||
if (packetType() != PacketType.PUBLISH)
|
if (_packetId == 0) return;
|
||||||
return;
|
|
||||||
if (_packetId == 0)
|
|
||||||
return;
|
|
||||||
_data[0] |= 0x08;
|
_data[0] |= 0x08;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,16 +53,13 @@ uint16_t Packet::packetId() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MQTTPacketType Packet::packetType() const {
|
MQTTPacketType Packet::packetType() const {
|
||||||
if (_data)
|
if (_data) return static_cast<MQTTPacketType>(_data[0] & 0xF0);
|
||||||
return static_cast<MQTTPacketType>(_data[0] & 0xF0);
|
|
||||||
return static_cast<MQTTPacketType>(0);
|
return static_cast<MQTTPacketType>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Packet::removable() const {
|
bool Packet::removable() const {
|
||||||
if (_packetId == 0)
|
if (_packetId == 0) return true;
|
||||||
return true;
|
if ((packetType() == PacketType.PUBACK) || (packetType() == PacketType.PUBCOMP)) return true;
|
||||||
if ((packetType() == PacketType.PUBACK) || (packetType() == PacketType.PUBCOMP))
|
|
||||||
return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +97,15 @@ Packet::Packet(espMqttClientTypes::Error & error,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate size
|
// Calculate size
|
||||||
size_t remainingLength = 6 + // protocol
|
size_t remainingLength =
|
||||||
|
6 + // protocol
|
||||||
1 + // protocol level
|
1 + // protocol level
|
||||||
1 + // connect flags
|
1 + // connect flags
|
||||||
2 + // keepalive
|
2 + // keepalive
|
||||||
2 + strlen(clientId) + (willTopic ? 2 + strlen(willTopic) + 2 + willPayloadLength : 0) + (username ? 2 + strlen(username) : 0)
|
2 + strlen(clientId) +
|
||||||
+ (password ? 2 + strlen(password) : 0);
|
(willTopic ? 2 + strlen(willTopic) + 2 + willPayloadLength : 0) +
|
||||||
|
(username ? 2 + strlen(username) : 0) +
|
||||||
|
(password ? 2 + strlen(password) : 0);
|
||||||
|
|
||||||
// allocate memory
|
// allocate memory
|
||||||
if (!_allocate(remainingLength, false)) {
|
if (!_allocate(remainingLength, false)) {
|
||||||
@@ -121,16 +122,12 @@ Packet::Packet(espMqttClientTypes::Error & error,
|
|||||||
pos += encodeString(PROTOCOL, &_data[pos]);
|
pos += encodeString(PROTOCOL, &_data[pos]);
|
||||||
_data[pos++] = PROTOCOL_LEVEL;
|
_data[pos++] = PROTOCOL_LEVEL;
|
||||||
uint8_t connectFlags = 0;
|
uint8_t connectFlags = 0;
|
||||||
if (cleanSession)
|
if (cleanSession) connectFlags |= espMqttClientInternals::ConnectFlag.CLEAN_SESSION;
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.CLEAN_SESSION;
|
if (username != nullptr) connectFlags |= espMqttClientInternals::ConnectFlag.USERNAME;
|
||||||
if (username != nullptr)
|
if (password != nullptr) connectFlags |= espMqttClientInternals::ConnectFlag.PASSWORD;
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.USERNAME;
|
|
||||||
if (password != nullptr)
|
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.PASSWORD;
|
|
||||||
if (willTopic != nullptr) {
|
if (willTopic != nullptr) {
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.WILL;
|
connectFlags |= espMqttClientInternals::ConnectFlag.WILL;
|
||||||
if (willRetain)
|
if (willRetain) connectFlags |= espMqttClientInternals::ConnectFlag.WILL_RETAIN;
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.WILL_RETAIN;
|
|
||||||
switch (willQos) {
|
switch (willQos) {
|
||||||
case 0:
|
case 0:
|
||||||
connectFlags |= espMqttClientInternals::ConnectFlag.WILL_QOS0;
|
connectFlags |= espMqttClientInternals::ConnectFlag.WILL_QOS0;
|
||||||
@@ -159,15 +156,19 @@ Packet::Packet(espMqttClientTypes::Error & error,
|
|||||||
pos += willPayloadLength;
|
pos += willPayloadLength;
|
||||||
}
|
}
|
||||||
// credentials
|
// credentials
|
||||||
if (username != nullptr)
|
if (username != nullptr) pos += encodeString(username, &_data[pos]);
|
||||||
pos += encodeString(username, &_data[pos]);
|
if (password != nullptr) encodeString(password, &_data[pos]);
|
||||||
if (password != nullptr)
|
|
||||||
encodeString(password, &_data[pos]);
|
|
||||||
|
|
||||||
error = espMqttClientTypes::Error::SUCCESS;
|
error = espMqttClientTypes::Error::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet::Packet(espMqttClientTypes::Error & error, uint16_t packetId, const char * topic, const uint8_t * payload, size_t payloadLength, uint8_t qos, bool retain)
|
Packet::Packet(espMqttClientTypes::Error& error,
|
||||||
|
uint16_t packetId,
|
||||||
|
const char* topic,
|
||||||
|
const uint8_t* payload,
|
||||||
|
size_t payloadLength,
|
||||||
|
uint8_t qos,
|
||||||
|
bool retain)
|
||||||
: _packetId(packetId)
|
: _packetId(packetId)
|
||||||
, _data(nullptr)
|
, _data(nullptr)
|
||||||
, _size(0)
|
, _size(0)
|
||||||
@@ -175,7 +176,8 @@ Packet::Packet(espMqttClientTypes::Error & error, uint16_t packetId, const char
|
|||||||
, _payloadStartIndex(0)
|
, _payloadStartIndex(0)
|
||||||
, _payloadEndIndex(0)
|
, _payloadEndIndex(0)
|
||||||
, _getPayload(nullptr) {
|
, _getPayload(nullptr) {
|
||||||
size_t remainingLength = 2 + strlen(topic) + // topic length + topic
|
size_t remainingLength =
|
||||||
|
2 + strlen(topic) + // topic length + topic
|
||||||
2 + // packet ID
|
2 + // packet ID
|
||||||
payloadLength;
|
payloadLength;
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ Packet::Packet(espMqttClientTypes::Error & error, uint16_t packetId, const char
|
|||||||
_packetId = 0;
|
_packetId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_allocate(remainingLength)) {
|
if (!_allocate(remainingLength, true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -211,7 +213,8 @@ Packet::Packet(espMqttClientTypes::Error & error,
|
|||||||
, _payloadStartIndex(0)
|
, _payloadStartIndex(0)
|
||||||
, _payloadEndIndex(0)
|
, _payloadEndIndex(0)
|
||||||
, _getPayload(payloadCallback) {
|
, _getPayload(payloadCallback) {
|
||||||
size_t remainingLength = 2 + strlen(topic) + // topic length + topic
|
size_t remainingLength =
|
||||||
|
2 + strlen(topic) + // topic length + topic
|
||||||
2 + // packet ID
|
2 + // packet ID
|
||||||
payloadLength;
|
payloadLength;
|
||||||
|
|
||||||
@@ -220,7 +223,7 @@ Packet::Packet(espMqttClientTypes::Error & error,
|
|||||||
_packetId = 0;
|
_packetId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_allocate(remainingLength - payloadLength + std::min(payloadLength, static_cast<size_t>(EMC_RX_BUFFER_SIZE)))) {
|
if (!_allocate(remainingLength - payloadLength + std::min(payloadLength, static_cast<size_t>(EMC_RX_BUFFER_SIZE)), true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -244,7 +247,7 @@ Packet::Packet(espMqttClientTypes::Error & error, uint16_t packetId, const char
|
|||||||
, _payloadStartIndex(0)
|
, _payloadStartIndex(0)
|
||||||
, _payloadEndIndex(0)
|
, _payloadEndIndex(0)
|
||||||
, _getPayload(nullptr) {
|
, _getPayload(nullptr) {
|
||||||
SubscribeItem list[1] = {{topic, qos}};
|
SubscribeItem list[1] = {topic, qos};
|
||||||
_createSubscribe(error, list, 1);
|
_createSubscribe(error, list, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +259,7 @@ Packet::Packet(espMqttClientTypes::Error & error, MQTTPacketType type, uint16_t
|
|||||||
, _payloadStartIndex(0)
|
, _payloadStartIndex(0)
|
||||||
, _payloadEndIndex(0)
|
, _payloadEndIndex(0)
|
||||||
, _getPayload(nullptr) {
|
, _getPayload(nullptr) {
|
||||||
if (!_allocate(2)) {
|
if (!_allocate(2, true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -295,7 +298,7 @@ Packet::Packet(espMqttClientTypes::Error & error, MQTTPacketType type)
|
|||||||
, _payloadStartIndex(0)
|
, _payloadStartIndex(0)
|
||||||
, _payloadEndIndex(0)
|
, _payloadEndIndex(0)
|
||||||
, _getPayload(nullptr) {
|
, _getPayload(nullptr) {
|
||||||
if (!_allocate(0)) {
|
if (!_allocate(0, true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -306,12 +309,20 @@ Packet::Packet(espMqttClientTypes::Error & error, MQTTPacketType type)
|
|||||||
|
|
||||||
|
|
||||||
bool Packet::_allocate(size_t remainingLength, bool check) {
|
bool Packet::_allocate(size_t remainingLength, bool check) {
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
(void) check;
|
||||||
|
#else
|
||||||
if (check && EMC_GET_FREE_MEMORY() < EMC_MIN_FREE_MEMORY) {
|
if (check && EMC_GET_FREE_MEMORY() < EMC_MIN_FREE_MEMORY) {
|
||||||
emc_log_w("Packet buffer not allocated: low memory");
|
emc_log_w("Packet buffer not allocated: low memory");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
_size = 1 + remainingLengthLength(remainingLength) + remainingLength;
|
_size = 1 + remainingLengthLength(remainingLength) + remainingLength;
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
_data = reinterpret_cast<uint8_t*>(_memPool.malloc(_size));
|
||||||
|
#else
|
||||||
_data = reinterpret_cast<uint8_t*>(malloc(_size));
|
_data = reinterpret_cast<uint8_t*>(malloc(_size));
|
||||||
|
#endif
|
||||||
if (!_data) {
|
if (!_data) {
|
||||||
_size = 0;
|
_size = 0;
|
||||||
emc_log_w("Alloc failed (l:%zu)", _size);
|
emc_log_w("Alloc failed (l:%zu)", _size);
|
||||||
@@ -322,13 +333,16 @@ bool Packet::_allocate(size_t remainingLength, bool check) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Packet::_fillPublishHeader(uint16_t packetId, const char * topic, size_t remainingLength, uint8_t qos, bool retain) {
|
size_t Packet::_fillPublishHeader(uint16_t packetId,
|
||||||
|
const char* topic,
|
||||||
|
size_t remainingLength,
|
||||||
|
uint8_t qos,
|
||||||
|
bool retain) {
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
|
||||||
// FIXED HEADER
|
// FIXED HEADER
|
||||||
_data[index] = PacketType.PUBLISH;
|
_data[index] = PacketType.PUBLISH;
|
||||||
if (retain)
|
if (retain) _data[index] |= HeaderFlag.PUBLISH_RETAIN;
|
||||||
_data[index] |= HeaderFlag.PUBLISH_RETAIN;
|
|
||||||
if (qos == 0) {
|
if (qos == 0) {
|
||||||
_data[index++] |= HeaderFlag.PUBLISH_QOS0;
|
_data[index++] |= HeaderFlag.PUBLISH_QOS0;
|
||||||
} else if (qos == 1) {
|
} else if (qos == 1) {
|
||||||
@@ -348,7 +362,9 @@ size_t Packet::_fillPublishHeader(uint16_t packetId, const char * topic, size_t
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packet::_createSubscribe(espMqttClientTypes::Error & error, SubscribeItem * list, size_t numberTopics) {
|
void Packet::_createSubscribe(espMqttClientTypes::Error& error,
|
||||||
|
SubscribeItem* list,
|
||||||
|
size_t numberTopics) {
|
||||||
// Calculate size
|
// Calculate size
|
||||||
size_t payload = 0;
|
size_t payload = 0;
|
||||||
for (size_t i = 0; i < numberTopics; ++i) {
|
for (size_t i = 0; i < numberTopics; ++i) {
|
||||||
@@ -357,7 +373,7 @@ void Packet::_createSubscribe(espMqttClientTypes::Error & error, SubscribeItem *
|
|||||||
size_t remainingLength = 2 + payload; // packetId + payload
|
size_t remainingLength = 2 + payload; // packetId + payload
|
||||||
|
|
||||||
// allocate memory
|
// allocate memory
|
||||||
if (!_allocate(remainingLength)) {
|
if (!_allocate(remainingLength, true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -376,7 +392,9 @@ void Packet::_createSubscribe(espMqttClientTypes::Error & error, SubscribeItem *
|
|||||||
error = espMqttClientTypes::Error::SUCCESS;
|
error = espMqttClientTypes::Error::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Packet::_createUnsubscribe(espMqttClientTypes::Error & error, const char ** list, size_t numberTopics) {
|
void Packet::_createUnsubscribe(espMqttClientTypes::Error& error,
|
||||||
|
const char** list,
|
||||||
|
size_t numberTopics) {
|
||||||
// Calculate size
|
// Calculate size
|
||||||
size_t payload = 0;
|
size_t payload = 0;
|
||||||
for (size_t i = 0; i < numberTopics; ++i) {
|
for (size_t i = 0; i < numberTopics; ++i) {
|
||||||
@@ -385,7 +403,7 @@ void Packet::_createUnsubscribe(espMqttClientTypes::Error & error, const char **
|
|||||||
size_t remainingLength = 2 + payload; // packetId + payload
|
size_t remainingLength = 2 + payload; // packetId + payload
|
||||||
|
|
||||||
// allocate memory
|
// allocate memory
|
||||||
if (!_allocate(remainingLength)) {
|
if (!_allocate(remainingLength, true)) {
|
||||||
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
error = espMqttClientTypes::Error::OUT_OF_MEMORY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ the LICENSE file.
|
|||||||
#include "../Helpers.h"
|
#include "../Helpers.h"
|
||||||
#include "../Logging.h"
|
#include "../Logging.h"
|
||||||
#include "RemainingLength.h"
|
#include "RemainingLength.h"
|
||||||
#include "String.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
#include "MemoryPool/src/MemoryPool.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
@@ -133,7 +137,7 @@ class Packet {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// pass remainingLength = total size - header - remainingLengthLength!
|
// pass remainingLength = total size - header - remainingLengthLength!
|
||||||
bool _allocate(size_t remainingLength, bool check = true);
|
bool _allocate(size_t remainingLength, bool check);
|
||||||
|
|
||||||
// fills header and returns index of next available byte in buffer
|
// fills header and returns index of next available byte in buffer
|
||||||
size_t _fillPublishHeader(uint16_t packetId,
|
size_t _fillPublishHeader(uint16_t packetId,
|
||||||
@@ -150,6 +154,10 @@ class Packet {
|
|||||||
|
|
||||||
size_t _chunkedAvailable(size_t index);
|
size_t _chunkedAvailable(size_t index);
|
||||||
const uint8_t* _chunkedData(size_t index) const;
|
const uint8_t* _chunkedData(size_t index) const;
|
||||||
|
|
||||||
|
#if EMC_USE_MEMPOOL
|
||||||
|
static MemoryPool::Variable<EMC_NUM_POOL_ELEMENTS, EMC_SIZE_POOL_ELEMENTS> _memPool;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace espMqttClientInternals
|
} // end namespace espMqttClientInternals
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ For a copy, see <https://opensource.org/licenses/MIT> or
|
|||||||
the LICENSE file.
|
the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "String.h"
|
#include "StringUtil.h"
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
@@ -38,9 +38,10 @@ bool ClientPosix::connect(IPAddress ip, uint16_t port) {
|
|||||||
memset(&_host, 0, sizeof(_host));
|
memset(&_host, 0, sizeof(_host));
|
||||||
_host.sin_family = AF_INET;
|
_host.sin_family = AF_INET;
|
||||||
_host.sin_addr.s_addr = htonl(uint32_t(ip));
|
_host.sin_addr.s_addr = htonl(uint32_t(ip));
|
||||||
_host.sin_port = htons(port); // modified by proddy for EMS-ESP compiling standalone
|
_host.sin_port = ::htons(port);
|
||||||
|
|
||||||
int ret = ::connect(_sockfd, reinterpret_cast<sockaddr*>(&_host), sizeof(_host));
|
int ret = ::connect(_sockfd, reinterpret_cast<sockaddr*>(&_host), sizeof(_host));
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
emc_log_e("Error connecting: %d - (%d) %s", ret, errno, strerror(errno));
|
emc_log_e("Error connecting: %d - (%d) %s", ret, errno, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ the LICENSE file.
|
|||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
|
||||||
#include "IPAddress.h"
|
#include "ClientPosixIPAddress.h"
|
||||||
|
|
||||||
IPAddress::IPAddress()
|
IPAddress::IPAddress()
|
||||||
: _address(0) {
|
: _address(0) {
|
||||||
@@ -17,7 +17,6 @@ the LICENSE file.
|
|||||||
#else
|
#else
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
@@ -32,6 +31,7 @@ class ClientSecureSync : public Transport {
|
|||||||
void stop() override;
|
void stop() override;
|
||||||
bool connected() override;
|
bool connected() override;
|
||||||
bool disconnected() override;
|
bool disconnected() override;
|
||||||
|
// added for EMS-ESP
|
||||||
#if defined(EMC_CLIENT_SECURE)
|
#if defined(EMC_CLIENT_SECURE)
|
||||||
WiFiClientSecure client;
|
WiFiClientSecure client;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ the LICENSE file.
|
|||||||
|
|
||||||
#include <stddef.h> // size_t
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
#include "IPAddress.h"
|
#include "ClientPosixIPAddress.h"
|
||||||
|
|
||||||
namespace espMqttClientInternals {
|
namespace espMqttClientInternals {
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// compare_flash_string added by Proddy
|
// compare_flash_string added by Proddy for EMS-ESP
|
||||||
|
|
||||||
#ifndef UUID_COMMON_H_
|
#ifndef UUID_COMMON_H_
|
||||||
#define UUID_COMMON_H_
|
#define UUID_COMMON_H_
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace uuid {
|
|||||||
* - <a href="https://mcu-uuid-log.readthedocs.io/">Documentation</a>
|
* - <a href="https://mcu-uuid-log.readthedocs.io/">Documentation</a>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ANSI Colors - added by Proddy
|
// ANSI Colors - added by Proddy for EMS-ESP
|
||||||
// See https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html
|
// See https://www.lihaoyi.com/post/BuildyourownCommandLinewithANSIescapecodes.html
|
||||||
#define COLOR_RESET "\x1B[0m"
|
#define COLOR_RESET "\x1B[0m"
|
||||||
#define COLOR_BLACK "\x1B[0;30m"
|
#define COLOR_BLACK "\x1B[0;30m"
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class AsyncWebServerResponse {
|
|||||||
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
|
||||||
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy
|
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy for EMS-ESP
|
||||||
|
|
||||||
class AsyncWebServer {
|
class AsyncWebServer {
|
||||||
protected:
|
protected:
|
||||||
@@ -233,7 +233,7 @@ class AsyncWebServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {};
|
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest) {};
|
||||||
void on(const char * uri, ArJsonRequestHandlerFunction onRequest){}; // added by proddy
|
void on(const char * uri, ArJsonRequestHandlerFunction onRequest) {}; // added by proddy for EMS-ESP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <IPAddress.h>
|
#include <ClientPosixIPAddress.h>
|
||||||
|
|
||||||
#define WiFiMode_t wifi_mode_t
|
#define WiFiMode_t wifi_mode_t
|
||||||
#define WIFI_OFF WIFI_MODE_NULL
|
#define WIFI_OFF WIFI_MODE_NULL
|
||||||
|
|||||||
@@ -381,7 +381,11 @@ const system_status = {
|
|||||||
free_heap: 143,
|
free_heap: 143,
|
||||||
ntp_status: 2,
|
ntp_status: 2,
|
||||||
mqtt_status: true,
|
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 = {
|
let security_settings = {
|
||||||
@@ -2134,19 +2138,26 @@ let emsesp_modules = {
|
|||||||
"modules": [
|
"modules": [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
|
"key": "ModuleTest1",
|
||||||
"name": "Module Test 1",
|
"name": "Module Test 1",
|
||||||
"author": "proddy",
|
"author": "proddy",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"status": "active"
|
"status": 1,
|
||||||
|
"message": "Ready",
|
||||||
|
"license": "1234567890"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
"key": "ModuleTest2",
|
||||||
"name": "Module Test 2",
|
"name": "Module Test 2",
|
||||||
"author": "proddy",
|
"author": "proddy",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"status": "active"
|
"status": 2,
|
||||||
|
"message": "Ready",
|
||||||
|
"license": "ABCDEFGHIJKL"
|
||||||
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -2386,7 +2397,9 @@ router
|
|||||||
return status(200);
|
return status(200);
|
||||||
})
|
})
|
||||||
.get(VERIFY_AUTHORIZATION_ENDPOINT, () => verify_authentication)
|
.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(FACTORY_RESET_ENDPOINT, () => status(200))
|
||||||
.post(SIGN_IN_ENDPOINT, () => signin)
|
.post(SIGN_IN_ENDPOINT, () => signin)
|
||||||
.get(GENERATE_TOKEN_ENDPOINT, () => generate_token);
|
.get(GENERATE_TOKEN_ENDPOINT, () => generate_token);
|
||||||
@@ -2514,10 +2527,11 @@ router
|
|||||||
const content = await request.json();
|
const content = await request.json();
|
||||||
let modules = content.modules;
|
let modules = content.modules;
|
||||||
for (let i = 0; i < modules.length; i++) {
|
for (let i = 0; i < modules.length; i++) {
|
||||||
const name = modules[i].name;
|
const key = modules[i].key;
|
||||||
const objIndex = emsesp_modules.modules.findIndex((obj: any) => obj.name === name);
|
const objIndex = emsesp_modules.modules.findIndex((obj: any) => obj.key === key);
|
||||||
if (objIndex !== -1) {
|
if (objIndex !== -1) {
|
||||||
emsesp_modules.modules[objIndex].enabled = modules[i].enabled;
|
emsesp_modules.modules[objIndex].enabled = modules[i].enabled;
|
||||||
|
emsesp_modules.modules[objIndex].license = modules[i].license;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('modules updated', emsesp_modules);
|
console.log('modules updated', emsesp_modules);
|
||||||
|
|||||||
@@ -32,55 +32,62 @@ WebModulesService::WebModulesService(AsyncWebServer * server, FS * fs, SecurityM
|
|||||||
// load the settings when the service starts
|
// load the settings when the service starts
|
||||||
void WebModulesService::begin() {
|
void WebModulesService::begin() {
|
||||||
EMSESP::logger().info("Starting Modules service");
|
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() {
|
void WebModulesService::loop() {
|
||||||
moduleLibrary.loop(); // loop the external library modules
|
moduleLibrary.loop(); // loop the external library modules
|
||||||
}
|
}
|
||||||
|
|
||||||
// this creates the modules file, saving it to the FS
|
// this creates the modules settings file, saving it to the file system
|
||||||
// and also calls when the Modules web page is refreshed
|
// 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) {
|
void WebModules::read(WebModules & webModules, JsonObject root) {
|
||||||
#ifdef EMSESP_DEBUG
|
emsesp_->logger().err("debug: in WebModules::read()"); // TODO remove
|
||||||
EMSESP::logger().debug("module read called");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JsonDocument doc_modules;
|
JsonDocument doc_modules;
|
||||||
JsonObject root_modules = doc_modules.to<JsonObject>();
|
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>();
|
JsonArray modules = root["modules"].to<JsonArray>();
|
||||||
uint8_t counter = 0;
|
uint8_t counter = 0;
|
||||||
for (const JsonObject module : root_modules["modules"].as<JsonArray>()) {
|
for (const JsonObject module : root_modules["modules"].as<JsonArray>()) {
|
||||||
JsonObject mi = modules.add<JsonObject>();
|
JsonObject mi = modules.add<JsonObject>();
|
||||||
mi["id"] = counter++; // id is only used to render the table and must be unique
|
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["name"] = module["name"].as<std::string>();
|
||||||
mi["author"] = module["author"].as<std::string>();
|
mi["author"] = module["author"].as<std::string>();
|
||||||
mi["version"] = module["version"].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["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
|
// read any Module settings from the settings file
|
||||||
// and then apply the enable/disable
|
// and then apply the enable/disable that is set by the user
|
||||||
// it's also called on a save
|
// 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) {
|
StateUpdateResult WebModules::update(JsonObject root, WebModules & webModules) {
|
||||||
#ifdef EMSESP_DEBUG
|
|
||||||
EMSESP::logger().debug("module update called");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (root["modules"].is<JsonArray>()) {
|
if (root["modules"].is<JsonArray>()) {
|
||||||
for (const JsonObject module : root["modules"].as<JsonArray>()) {
|
for (const JsonObject module : root["modules"].as<JsonArray>()) {
|
||||||
// set enabled/disabled
|
auto key = module["key"].as<const char *>();
|
||||||
moduleLibrary.enable(module["name"], module["enabled"].as<bool>());
|
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
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
|||||||
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
|
settings.analog_enabled = root["analog_enabled"] | EMSESP_DEFAULT_ANALOG_ENABLED;
|
||||||
check_flag(prev, settings.analog_enabled, ChangeFlags::ADC);
|
check_flag(prev, settings.analog_enabled, ChangeFlags::ADC);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// these need system restarts first before settings are activated...
|
// 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...
|
// without checks or necessary restarts...
|
||||||
//
|
//
|
||||||
|
|
||||||
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
settings.trace_raw = root["trace_raw"] | EMSESP_DEFAULT_TRACELOG_RAW;
|
||||||
EMSESP::trace_raw(settings.trace_raw);
|
EMSESP::trace_raw(settings.trace_raw);
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,14 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) {
|
|||||||
|
|
||||||
root["ap_status"] = EMSESP::esp8266React.apStatus();
|
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();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user