Created error table, provided error handling

This commit is contained in:
Noe 2023-11-15 17:22:42 +01:00
parent 22dd4222ca
commit 6a18e56cf7
21 changed files with 318 additions and 205 deletions

View File

@ -226,8 +226,8 @@
<ItemGroup>
<Folder Include="DbBackups\" />
</ItemGroup>
</Project>

View File

@ -54,6 +54,8 @@ public class Controller : ControllerBase
: Unauthorized();
}
[HttpGet(nameof(CreateWebSocket))]
public async Task CreateWebSocket(Token authToken)
{
@ -82,6 +84,23 @@ public class Controller : ControllerBase
await WebsocketManager.HandleWebSocketConnection(webSocket);
}
[HttpGet(nameof(GetAllErrorsForInstallation))]
public ActionResult<IEnumerable<Error>> GetAllErrorsForInstallation(Int64 id, Token authToken)
{
var user = Db.GetSession(authToken)?.User;
if (user == null)
return Unauthorized();
var installation = Db.GetInstallationById(id);
if (installation is null || !user.HasAccessTo(installation))
return Unauthorized();
return Db.Errors
.Where(error => error.InstallationId == id)
.ToList();
}
[HttpGet(nameof(GetUserById))]
public ActionResult<User> GetUserById(Int64 id, Token authToken)
{

View File

@ -0,0 +1,14 @@
using SQLite;
namespace InnovEnergy.App.Backend.DataTypes;
public class Error
{
[PrimaryKey, AutoIncrement]
public Int64 Id { get; set; }
public Int64 InstallationId { get; set; }
public String ErrorDescription { get; set; } = null!;
public DateTime CreatedAt { get; set; }
public String DeviceCreatedTheError { get; set; } = null!;
public Boolean Seen { get; set; }
}

View File

@ -5,7 +5,6 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods;
public static class FolderMethods
{
public static IEnumerable<User> UsersWithAccess(this Folder folder)
{
var direct = folder.UsersWithDirectAccess();

View File

@ -141,7 +141,7 @@ public static class InstallationMethods
foreach (var orderNumber in installation.OrderNumbers.Split(","))
{
var rel = relations.FirstOrDefault(i => i.OrderNumber == orderNumber);
if ( rel != null) relations.Remove(rel);
if ( rel != null) {relations.Remove(rel); continue;}
var o2I = new OrderNumber2Installation
{
OrderNumber = orderNumber,

View File

@ -5,7 +5,7 @@ namespace InnovEnergy.App.Backend.DataTypes;
public abstract partial class TreeNode
{
[PrimaryKey, AutoIncrement]
public virtual Int64 Id { get; set; }
public Int64 Id { get; set; }
public virtual String Name { get; set; } = ""; // overridden by User (unique)
public String Information { get; set; } = ""; // unstructured random info

View File

@ -20,6 +20,11 @@ public static partial class Db
return Insert(installation);
}
public static Boolean Create(Error error)
{
return Insert(error);
}
public static Boolean Create(Folder folder)
{
return Insert(folder);
@ -49,4 +54,30 @@ public static partial class Db
{
return Insert(o2i);
}
public static void HandleError(Error newError,int installationId)
{
//Find the total number of errors for this installation
var totalErrors = Errors.Count(error => error.InstallationId == installationId);
//If there are 100 errors, remove the one with the oldest timestamp
if (totalErrors == 100)
{
var oldestError =
Errors.Where(error => error.InstallationId == installationId)
.OrderBy(error => error.CreatedAt)
.FirstOrDefault();
//Remove the old error
Delete(oldestError);
//Add the new error
Create(newError);
}
else
{
Console.WriteLine("---------------Added the new Error to the database-----------------");
Create(newError);
}
}
}

View File

@ -15,21 +15,36 @@ namespace InnovEnergy.App.Backend.Database;
public static partial class Db
{
// internal const String DbPath = "./db.sqlite";
private static SQLiteConnection Connection { get; } = InitConnection();
private static SQLiteConnection Connection { get; } = ((Func<SQLiteConnection>)(() =>
private static SQLiteConnection InitConnection()
{
var latestDb = new DirectoryInfo(@"DbBackups").GetFiles()
.OrderBy(f => f.LastWriteTime)
.Last().Name;
var latestDb = new DirectoryInfo("DbBackups")
.GetFiles()
.OrderBy(f => f.LastWriteTime)
.Last().Name;
var fileConnection = new SQLiteConnection("DbBackups/"+latestDb);
//This is the file connection from the DbBackups folder
var fileConnection = new SQLiteConnection("DbBackups/" + latestDb);
Console.Out.Write(latestDb);
//Create a table if it does not exist
fileConnection.CreateTable<User>();
fileConnection.CreateTable<Installation>();
fileConnection.CreateTable<Folder>();
fileConnection.CreateTable<FolderAccess>();
fileConnection.CreateTable<InstallationAccess>();
fileConnection.CreateTable<Session>();
fileConnection.CreateTable<OrderNumber2Installation>();
fileConnection.CreateTable<Error>();
return CopyDbToMemory(fileConnection);
}
private static SQLiteConnection CopyDbToMemory(SQLiteConnection fileConnection)
{
var memoryConnection = new SQLiteConnection(":memory:");
// fileConnection.Backup(memoryConnection.DatabasePath);
//Create a table if it does not exist in main memory
memoryConnection.CreateTable<User>();
memoryConnection.CreateTable<Installation>();
memoryConnection.CreateTable<Folder>();
@ -37,17 +52,20 @@ public static partial class Db
memoryConnection.CreateTable<InstallationAccess>();
memoryConnection.CreateTable<Session>();
memoryConnection.CreateTable<OrderNumber2Installation>();
memoryConnection.CreateTable<Error>();
fileConnection.Table<Session> ().ForEach(memoryConnection.Insert);
fileConnection.Table<Folder> ().ForEach(memoryConnection.Insert);
fileConnection.Table<Installation> ().ForEach(memoryConnection.Insert);
fileConnection.Table<User> ().ForEach(memoryConnection.Insert);
fileConnection.Table<FolderAccess> ().ForEach(memoryConnection.Insert);
fileConnection.Table<InstallationAccess> ().ForEach(memoryConnection.Insert);
//Copy all the existing tables from the disk to main memory
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
fileConnection.Table<Folder>().ForEach(memoryConnection.Insert);
fileConnection.Table<Installation>().ForEach(memoryConnection.Insert);
fileConnection.Table<User>().ForEach(memoryConnection.Insert);
fileConnection.Table<FolderAccess>().ForEach(memoryConnection.Insert);
fileConnection.Table<InstallationAccess>().ForEach(memoryConnection.Insert);
fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert);
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
return memoryConnection;
}))();
}
public static void BackupDatabase()
{
@ -62,17 +80,16 @@ public static partial class Db
public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>();
public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();
public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>();
public static TableQuery<Error> Errors => Connection.Table<Error>();
public static void Init()
{
public static void Init(){
// used to force static constructor
//Since this class is static, we call Init method from the Program.cs to initialize all the fields of the class
}
//This is the constructor of the class
static Db()
{
// on startup create/migrate tables
Connection.RunInTransaction(() =>
{
Connection.CreateTable<User>();
@ -82,6 +99,7 @@ public static partial class Db
Connection.CreateTable<InstallationAccess>();
Connection.CreateTable<Session>();
Connection.CreateTable<OrderNumber2Installation>();
Connection.CreateTable<Error>();
});
Observable.Interval(TimeSpan.FromHours(0.5))

View File

@ -35,6 +35,20 @@ public static partial class Db
}
}
public static Boolean Delete(Error errorToDelete)
{
var deleteSuccess = RunTransaction(DeleteError);
if (deleteSuccess)
BackupDatabase();
return deleteSuccess;
Boolean DeleteError()
{
return Errors.Delete(error => error.Id == errorToDelete.Id) >0;
}
}
public static Boolean Delete(Installation installation)
{
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);

View File

@ -33,7 +33,4 @@ public static partial class Db
return Update(obj: user);
}
}

View File

@ -1,6 +1,9 @@
public class StatusMessage
{
public required int InstallationId { get; init; }
public required int Status { get; init; }
public required int InstallationId { get; init; }
public required int Status { get; init; }
public DateTime CreatedAt { get; set; }
public String Error { get; init; } = null!;
public String DeviceCreatedTheError { get; init; } = null!;
}

View File

@ -5,6 +5,7 @@ using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using InnovEnergy.App.Backend.Database;
using InnovEnergy.App.Backend.DataTypes;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
@ -19,7 +20,6 @@ public static class WebsocketManager
public static void InformInstallationsToSubscribeToRabbitMq()
{
//var installationIps = new List<string> { "10.2.3.115" };
var installationIps = Db.Installations.Select(inst => inst.VpnIp).ToList();
Console.WriteLine("Count is "+installationIps.Count);
var maxRetransmissions = 2;
@ -83,7 +83,7 @@ public static class WebsocketManager
lock (InstallationConnections)
{
// Process the received message
//Consumer received a message
if (receivedStatusMessage != null)
{
Console.WriteLine("Received a message from installation: " + receivedStatusMessage.InstallationId + " and status is: " + receivedStatusMessage.Status);
@ -91,6 +91,24 @@ public static class WebsocketManager
Console.WriteLine("Update installation connection table");
var installationId = receivedStatusMessage.InstallationId;
//This is an error message
if (receivedStatusMessage.Status==2)
{
Console.WriteLine("-----------------------New error-----------------------");
Error newError = new Error
{
InstallationId = receivedStatusMessage.InstallationId,
ErrorDescription = receivedStatusMessage.Error,
CreatedAt = receivedStatusMessage.CreatedAt,
DeviceCreatedTheError = receivedStatusMessage.DeviceCreatedTheError,
Seen = false
};
//Create a new error and add it to the database
Db.HandleError(newError,receivedStatusMessage.InstallationId);
}
if (!InstallationConnections.ContainsKey(installationId))
{
Console.WriteLine("Create new empty list for installation: " + installationId);

View File

@ -3,6 +3,10 @@ namespace InnovEnergy.App.SaliMax.MiddlewareClasses;
public class StatusMessage
{
public required int InstallationId { get; init; }
public required int Status { get; init; }
public required int InstallationId { get; init; }
public required int Status { get; init; }
public DateTime CreatedAt { get; set; }
public String Error { get; set; } = null!;
public String DeviceCreatedTheError { get; set; } = null!;
}

View File

@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
@ -265,10 +266,14 @@ internal static class Program
{
_subscribeToQueueForTheFirstTime = true;
SubscribeToQueue(currentSalimaxState, s3Bucket);
}
if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
{
_prevSalimaxState = currentSalimaxState;
}
}
//If already subscribed to the queue and the status has been changed, update the queue
if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
else if (_subscribedToQueue && currentSalimaxState != _prevSalimaxState)
{
_prevSalimaxState = currentSalimaxState;
if (s3Bucket != null)
@ -343,13 +348,19 @@ internal static class Program
private static void InformMiddleware(String? bucket, int status)
{
int.TryParse(bucket[0].ToString(), out var installationId);
var jsonObject = new StatusMessage
{
InstallationId = installationId,
Status = status
Status = status,
};
if (status == 2)
{
jsonObject.CreatedAt = DateTime.Now;
jsonObject.Error = "Battery Temperature High";
jsonObject.DeviceCreatedTheError = "Battery/1";
}
var message = JsonSerializer.Serialize(jsonObject);
var body = Encoding.UTF8.GetBytes(message);

View File

@ -1,3 +1,4 @@
using System.ComponentModel;
using InnovEnergy.Lib.Devices.Trumpf.SystemControl;
using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc.DataTypes;
using InnovEnergy.Lib.Units.Composite;
@ -18,6 +19,9 @@ public class AcDcDevicesRecord
public SystemControlRegisters? SystemControl { get; }
public IReadOnlyList<AcDcRecord> Devices { get; init; }
//public IEnumerable<AlarmMessage> Alarms => new []{AlarmMessage.BatteryOvervoltage}; //Devices.SelectMany(d => d.Status.Alarms).Distinct();
//public IEnumerable<WarningMessage> Warnings => new []{WarningMessage.TempDerating}; //Devices.SelectMany(d => d.Status.Warnings).Distinct();
public IEnumerable<AlarmMessage> Alarms => Devices.SelectMany(d => d.Status.Alarms).Distinct();
public IEnumerable<WarningMessage> Warnings => Devices.SelectMany(d => d.Status.Warnings).Distinct();

View File

@ -10,7 +10,7 @@ public enum WarningMessage : UInt16
{
NoWarning = 00000,
/*
// these warnings are not official (not in the manual), and they seem to collide with the DCDC warnings
// so I commented them
@ -28,5 +28,5 @@ public enum WarningMessage : UInt16
RuntimeEeprom = 11023, //AC-DC module warning
Overcurrent = 11024 //Overcurrent handling is active
*/
}

View File

@ -1,13 +1,13 @@
import axios from 'axios';
export const axiosConfigWithoutToken = axios.create({
baseURL: 'https://monitor.innov.energy/api'
// baseURL: 'http://127.0.0.1:7087/api'
//baseURL: 'https://monitor.innov.energy/api'
baseURL: 'http://127.0.0.1:7087/api'
});
const axiosConfig = axios.create({
baseURL: 'https://monitor.innov.energy/api'
//baseURL: 'http://127.0.0.1:7087/api'
//baseURL: 'https://monitor.innov.energy/api'
baseURL: 'http://127.0.0.1:7087/api'
});
axiosConfig.defaults.params = {};

View File

@ -28,7 +28,6 @@ import {
extractValues,
TopologyValues
} from 'src/content/dashboards/Log/graph.util';
import { Notification } from 'src/interfaces/S3Types';
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
import Topology from '../Topology/Topology';
import { FormattedMessage } from 'react-intl';
@ -62,8 +61,6 @@ function Installation(props: singleInstallationProps) {
deleteInstallation
} = installationContext;
const [warnings, setWarnings] = useState<Notification[]>([]);
const [errors, setErrors] = useState<Notification[]>([]);
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
const webSocketsContext = useContext(WebSocketContext);
const { getStatus } = webSocketsContext;
@ -153,9 +150,6 @@ function Installation(props: singleInstallationProps) {
return;
}
const newWarnings: Notification[] = [];
const newErrors: Notification[] = [];
if (
res === FetchResult.notAvailable ||
res === FetchResult.tryLater
@ -681,9 +675,8 @@ function Installation(props: singleInstallationProps) {
{currentTab === 'live' && <Topology values={values}></Topology>}
{currentTab === 'log' && (
<Log
warnings={warnings}
errors={errors}
errorLoadingS3Data={errorLoadingS3Data}
id={props.current_installation.id}
></Log>
)}
</Grid>

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useContext, useEffect, useState } from 'react';
import {
Alert,
Card,
@ -14,26 +14,49 @@ import {
TableRow,
useTheme
} from '@mui/material';
import WarningIcon from '@mui/icons-material/Warning';
import Typography from '@mui/material/Typography';
import { Notification } from 'src/interfaces/S3Types';
import { FormattedMessage } from 'react-intl';
import ErrorIcon from '@mui/icons-material/Error';
import axiosConfig from '../../../Resources/axiosConfig';
import { AxiosError, AxiosResponse } from 'axios/index';
import routes from '../../../Resources/routes.json';
import { useNavigate } from 'react-router-dom';
import { TokenContext } from '../../../contexts/tokenContext';
import { ErrorMessage } from '../../../interfaces/S3Types';
interface LogProps {
warnings: Notification[];
errors: Notification[];
errorLoadingS3Data: boolean;
id: number;
}
function Log(props: LogProps) {
const theme = useTheme();
//const [warnings, setWarnings] = useState<Notification[]>([]);
const [errors, setErrors] = useState<ErrorMessage[]>([]);
const navigate = useNavigate();
const tokencontext = useContext(TokenContext);
const { removeToken } = tokencontext;
useEffect(() => {
axiosConfig
.get(`/GetAllErrorsForInstallation?id=${props.id}`)
.then((res: AxiosResponse<ErrorMessage[]>) => {
setErrors(res.data);
})
.catch((err: AxiosError) => {
if (err.response && err.response.status == 401) {
removeToken();
navigate(routes.login);
}
});
}, []);
return (
<Container maxWidth="xl">
<Grid container>
<Grid item xs={12} md={12}>
{(props.errors.length > 0 || props.warnings.length > 0) && (
{/* IT SHOULD BE {(errors.length > 0 || props.warnings.length > 0) && (*/}
{errors.length > 0 && (
<Card sx={{ marginTop: '10px' }}>
<Divider />
<TableContainer>
@ -43,25 +66,26 @@ function Log(props: LogProps) {
<TableCell>
<FormattedMessage id="type" defaultMessage="Type" />
</TableCell>
<TableCell>
<FormattedMessage id="device" defaultMessage="Device" />
</TableCell>
<TableCell>
<FormattedMessage
id="description"
defaultMessage="Description"
/>
</TableCell>
<TableCell>
<FormattedMessage id="device" defaultMessage="Device" />
</TableCell>
<TableCell>
<FormattedMessage id="date" defaultMessage="Date" />
</TableCell>
<TableCell>
<FormattedMessage id="time" defaultMessage="Time" />
<FormattedMessage id="seen" defaultMessage="Seen" />
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{props.errors.map((error, index) => {
{errors.map((error, index) => {
return (
<TableRow hover key={index}>
<TableCell>
@ -82,9 +106,9 @@ function Log(props: LogProps) {
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '5px' }}
sx={{ marginTop: '5px', marginLeft: '-40px' }}
>
{error.device}
{error.errorDescription}
</Typography>
</TableCell>
<TableCell>
@ -96,7 +120,7 @@ function Log(props: LogProps) {
noWrap
sx={{ marginTop: '5px' }}
>
{error.description}
{error.deviceCreatedTheError}
</Typography>
</TableCell>
<TableCell>
@ -106,9 +130,9 @@ function Log(props: LogProps) {
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '5px' }}
sx={{ marginTop: '5px', marginLeft: '-40px' }}
>
{error.date}
{error.createdAt}
</Typography>
</TableCell>
<TableCell>
@ -118,87 +142,87 @@ function Log(props: LogProps) {
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '5px' }}
sx={{ marginTop: '5px', marginLeft: '10px' }}
>
{error.time}
{error.seen == false ? 'No' : 'Yes'}
</Typography>
</TableCell>
</TableRow>
);
})}
{props.warnings.map((warning, index) => {
return (
<TableRow hover key={index}>
<TableCell>
<WarningIcon
sx={{
color: '#ffc04d',
width: 25,
height: 25,
marginLeft: '5px',
marginTop: '8px'
}}
/>
</TableCell>
<TableCell>
<Typography
variant="body1"
fontWeight="bold"
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '10px' }}
>
{warning.device}
</Typography>
</TableCell>
<TableCell>
<Typography
variant="body1"
fontWeight="bold"
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '10px' }}
>
{warning.description}
</Typography>
</TableCell>
<TableCell>
<Typography
variant="body1"
fontWeight="bold"
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '10px' }}
>
{warning.date}
</Typography>
</TableCell>
<TableCell>
<Typography
variant="body1"
fontWeight="bold"
color="text.primary"
gutterBottom
noWrap
sx={{ marginTop: '10px' }}
>
{warning.time}
</Typography>
</TableCell>
</TableRow>
);
})}
{/*{props.warnings.map((warning, index) => {*/}
{/* return (*/}
{/* <TableRow hover key={index}>*/}
{/* <TableCell>*/}
{/* <WarningIcon*/}
{/* sx={{*/}
{/* color: '#ffc04d',*/}
{/* width: 25,*/}
{/* height: 25,*/}
{/* marginLeft: '5px',*/}
{/* marginTop: '8px'*/}
{/* }}*/}
{/* />*/}
{/* </TableCell>*/}
{/* <TableCell>*/}
{/* <Typography*/}
{/* variant="body1"*/}
{/* fontWeight="bold"*/}
{/* color="text.primary"*/}
{/* gutterBottom*/}
{/* noWrap*/}
{/* sx={{ marginTop: '10px' }}*/}
{/* >*/}
{/* {warning.device}*/}
{/* </Typography>*/}
{/* </TableCell>*/}
{/* <TableCell>*/}
{/* <Typography*/}
{/* variant="body1"*/}
{/* fontWeight="bold"*/}
{/* color="text.primary"*/}
{/* gutterBottom*/}
{/* noWrap*/}
{/* sx={{ marginTop: '10px' }}*/}
{/* >*/}
{/* {warning.description}*/}
{/* </Typography>*/}
{/* </TableCell>*/}
{/* <TableCell>*/}
{/* <Typography*/}
{/* variant="body1"*/}
{/* fontWeight="bold"*/}
{/* color="text.primary"*/}
{/* gutterBottom*/}
{/* noWrap*/}
{/* sx={{ marginTop: '10px' }}*/}
{/* >*/}
{/* {warning.date}*/}
{/* </Typography>*/}
{/* </TableCell>*/}
{/* <TableCell>*/}
{/* <Typography*/}
{/* variant="body1"*/}
{/* fontWeight="bold"*/}
{/* color="text.primary"*/}
{/* gutterBottom*/}
{/* noWrap*/}
{/* sx={{ marginTop: '10px' }}*/}
{/* >*/}
{/* {warning.time}*/}
{/* </Typography>*/}
{/* </TableCell>*/}
{/* </TableRow>*/}
{/* );*/}
{/*})}*/}
</TableBody>
</Table>
</TableContainer>
</Card>
)}
{!props.errorLoadingS3Data && props.errors.length == 0 && (
{!props.errorLoadingS3Data && errors.length == 0 && (
<Alert
severity="error"
sx={{
@ -242,27 +266,27 @@ function Log(props: LogProps) {
</Alert>
)}
{!props.errorLoadingS3Data && props.warnings.length == 0 && (
<Alert
severity="error"
sx={{
display: 'flex',
alignItems: 'center',
//marginBottom: '20px'
marginTop: '20px'
}}
>
<FormattedMessage
id="nowarnings"
defaultMessage="There are no warnings"
/>
<IconButton
color="inherit"
size="small"
sx={{ marginLeft: '4px' }}
></IconButton>
</Alert>
)}
{/*{!props.errorLoadingS3Data && props.warnings.length == 0 && (*/}
{/* <Alert*/}
{/* severity="error"*/}
{/* sx={{*/}
{/* display: 'flex',*/}
{/* alignItems: 'center',*/}
{/* //marginBottom: '20px'*/}
{/* marginTop: '20px'*/}
{/* }}*/}
{/* >*/}
{/* <FormattedMessage*/}
{/* id="nowarnings"*/}
{/* defaultMessage="There are no warnings"*/}
{/* />*/}
{/* <IconButton*/}
{/* color="inherit"*/}
{/* size="small"*/}
{/* sx={{ marginLeft: '4px' }}*/}
{/* ></IconButton>*/}
{/* </Alert>*/}
{/*)}*/}
</Grid>
</Grid>
</Container>

View File

@ -1,37 +0,0 @@
import { UnixTime } from '../../../dataCache/time';
import { I_S3Credentials } from '../../../interfaces/S3Types';
import { FetchResult } from '../../../dataCache/dataCache';
import { DataRecord } from '../../../dataCache/data';
import { S3Access } from '../../../dataCache/S3/S3Access';
import { parseCsv } from './graph.util';
export const fetchData = (
timestamp: UnixTime,
s3Credentials?: I_S3Credentials
): Promise<FetchResult<DataRecord>> => {
const s3Path = `${timestamp.ticks}.csv`;
if (s3Credentials && s3Credentials.s3Bucket) {
const s3Access = new S3Access(
s3Credentials.s3Bucket,
s3Credentials.s3Region,
s3Credentials.s3Provider,
s3Credentials.s3Key,
s3Credentials.s3Secret
);
return s3Access
.get(s3Path)
.then(async (r) => {
if (r.status === 404) {
return Promise.resolve(FetchResult.notAvailable);
} else if (r.status === 200) {
const text = await r.text();
return parseCsv(text);
} else {
return Promise.resolve(FetchResult.notAvailable);
}
})
.catch((e) => {
return Promise.resolve(FetchResult.tryLater);
});
}
};

View File

@ -6,9 +6,10 @@ export interface I_S3Credentials {
s3Bucket?: string;
}
export interface Notification {
device: string;
description: string;
date: string;
time: string;
export interface ErrorMessage {
installationId: number;
createdAt: Date;
errorDescription: string;
deviceCreatedTheError: string;
seen: boolean;
}