- Implement consistent Function addition to application
- Use TYPE_XXX constants to declare function type
- Use NewXXXX() methods to call constructor correctly
- Add FunctionType list (with constructor) to Application
- Create Function by comparison to FunctionType list
- Simplify LoadConfig() and Init() methods for functions
- Combine methods into Init() method
- Pass relevant data member to Init() method
- Remove all CDataMember references on functions
- ApplicationCore:
- Split ReadParam() method from LoadConfig() method
- Split main configuration into separate files:
- config/ - main config file, general application settings
- definition/ - application definition, e.g. function blocks
- Definition and Address List files specified in config file
- Load address file in address/ branch
- Made DataTree & JSONparser private
- Made Config, Definition & Address branches public
- Removed unnecessary branch references
- Improved event logging
- DataTreeCore:
- Allow GetChFirstChild & GetChElement to create parent branches
with correct type, ie. Object/Array
- Remove unnecessary Create param from GetXxx functions
- Bug fix: Print empty objects/arrays correct, ie. empty brackets
- Bug fix: Adding element at specific index
- Bug fix: Error when get/create string value with "null"
- FunctionCore:
- Type param now set as constant via constructor
- Create empty Handles & Channels objects if none in Config
- SelectableCore:
- Add Queue length parameter to handles for UNIX and TCP sockets
- DeviceCore:
- Bug fix: missing Process() method
326 lines
8.6 KiB
C++
326 lines
8.6 KiB
C++
/*
|
|
* FileCore.cpp
|
|
*
|
|
* Created on: 1 Jun 2016
|
|
* Author: wentzelc
|
|
*/
|
|
|
|
// Standard C/C++ Libraries
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
// redA Libraries
|
|
#include "ApplicationCore.h"
|
|
#include "FileCore.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Global Vars
|
|
extern char * ProcessName;
|
|
//extern CApplication * Application;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Function Constructor
|
|
CFunctionCore * NewFileCore( const char * Name ) {
|
|
return (CFunctionCore*) new CFileCore( Name );
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CFileCore::CFileCore( const char * pName, const char * pType ) : CFunctionCore( pName, pType )
|
|
{
|
|
FirstFile = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CFileCore::~CFileCore()
|
|
{
|
|
TFileHandle * NextFile = NULL;
|
|
|
|
// Destroy file specs
|
|
while (FirstFile)
|
|
{
|
|
// Close file if open
|
|
CloseFile( FirstFile );
|
|
|
|
// Destroy file parameters
|
|
if (FirstFile->Name)
|
|
free( FirstFile->Name );
|
|
if (FirstFile->Path)
|
|
free( FirstFile->Path );
|
|
|
|
// Destroy File
|
|
NextFile = FirstFile->Next;
|
|
delete FirstFile;
|
|
FirstFile = NextFile;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Append, bool CreateChannel )
|
|
{
|
|
TFileHandle ** FileHandle = NULL;
|
|
|
|
// Validate
|
|
if (!Name || !*Name || !Path || !*Path) {
|
|
return NULL;
|
|
}
|
|
|
|
// Find File or End of list
|
|
FileHandle = &FirstFile;
|
|
while (*FileHandle && strcmp( Name, (*FileHandle)->Name )) {
|
|
FileHandle = &((*FileHandle)->Next);
|
|
}
|
|
|
|
// Check if found
|
|
if (!*FileHandle)
|
|
{
|
|
// Create new
|
|
*FileHandle = (TFileHandle*)calloc( 1, sizeof(TFileHandle) );
|
|
|
|
// Set name & Path
|
|
(*FileHandle)->Name = (char*)malloc( strlen(Name)+1 );
|
|
strcpy( (*FileHandle)->Name, Name );
|
|
(*FileHandle)->Path = (char*)malloc( strlen(Path)+1 );
|
|
strcpy( (*FileHandle)->Path, Path );
|
|
}
|
|
|
|
// Create Channel if necessary
|
|
if (CreateChannel) {
|
|
AddChannel( Name );
|
|
}
|
|
|
|
// Set Parameters
|
|
(*FileHandle)->Append = Append;
|
|
(*FileHandle)->FD = NO_FD;
|
|
|
|
// Return File
|
|
return (*FileHandle);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Set parameters
|
|
FileHandle->Persistent = Persistent;
|
|
FileHandle->PersistTimeout = PersistTimeout;
|
|
|
|
// Open persistent file
|
|
if (Persistent && (!PersistTimeout)) {
|
|
OpenFile( FileHandle );
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
}
|
|
// Close non-persistent file
|
|
else if (!Persistent && isOpen(FileHandle)) {
|
|
CloseFile( FileHandle );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::OpenFile( TFileHandle * FileHandle )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Open file if not already open
|
|
if (!isOpen( FileHandle ))
|
|
{
|
|
// GEt file handle
|
|
(FileHandle)->FD = open( FileHandle->Path, O_WRONLY | O_CREAT | ((FileHandle->Append)? O_APPEND : O_TRUNC), 0664 );
|
|
|
|
// Report event
|
|
if (isOpen(FileHandle))
|
|
{
|
|
// Set timer
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
|
|
// Report result
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: File '%s' - Opened",
|
|
ProcessName, Name, FileHandle->Name );
|
|
}
|
|
}
|
|
|
|
// Check if failed
|
|
if (!isOpen(FileHandle))
|
|
{
|
|
// Report result
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: File '%s' - Could not open (%d) %s",
|
|
ProcessName, Name, FileHandle->Name, errno, strerror(errno) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::CloseFile( TFileHandle * FileHandle )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Close file if not already open
|
|
if (isOpen(FileHandle))
|
|
{
|
|
// Close file
|
|
close( FileHandle->FD );
|
|
FileHandle->FD = NO_FD;
|
|
|
|
// Report result
|
|
if (!isOpen(FileHandle)) {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: File '%s' - Closed",
|
|
ProcessName, Name, FileHandle->Name );
|
|
} else {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: File '%s' - Could not close",
|
|
ProcessName, Name, FileHandle->Name );
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFileCore::ReadFromFD( int FD, char * Data, int MaxLen )
|
|
{
|
|
int BytesRead = 0;
|
|
int TotalRead = 0;
|
|
int DataRemain = MaxLen;
|
|
bool Error = false;
|
|
|
|
// Check if buffer created
|
|
if ((FD == -1) || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Read Data into buffer
|
|
while (DataRemain)
|
|
{
|
|
// Read from file descriptor
|
|
BytesRead = read( FD, &Data[TotalRead], DataRemain );
|
|
if (BytesRead <= 0) {
|
|
Error = true;
|
|
errno = (!BytesRead)? 0 : errno; // No error if no bytes written
|
|
break;
|
|
}
|
|
|
|
// Update Data Pointers
|
|
TotalRead += BytesRead;
|
|
DataRemain -= BytesRead;
|
|
|
|
if (DataRemain) {
|
|
usleep( 500 );
|
|
}
|
|
}
|
|
|
|
return (Error)? -TotalRead : TotalRead; // Report negative total on error
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFileCore::WriteToFD( int FD, const char * Data, int Len )
|
|
{
|
|
int BytesWritten = 0;
|
|
int TotalWritten = 0;
|
|
int DataRemain = (Len != -1)? Len : (Data)? strlen(Data) : 0;
|
|
bool Error = false;
|
|
|
|
// Check if buffer created
|
|
if ((FD == -1) || !DataRemain) {
|
|
return 0;
|
|
}
|
|
|
|
// Read Data into buffer
|
|
while (DataRemain)
|
|
{
|
|
// Read from file descriptor
|
|
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
|
|
if ((BytesWritten <= 0) && (errno != EAGAIN)) {
|
|
Error = true;
|
|
errno = (!BytesWritten)? 0 : errno; // No error if no bytes written
|
|
break;
|
|
}
|
|
|
|
// Update Data Pointers
|
|
TotalWritten += BytesWritten;
|
|
DataRemain -= BytesWritten;
|
|
|
|
if (DataRemain) {
|
|
usleep( 500 );
|
|
}
|
|
}
|
|
return (Error)? -TotalWritten : TotalWritten; // Report negative total on error
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Manual Data Input/Output
|
|
int CFileCore::Input( const char * ChannelName, const char * Data, int Len )
|
|
{
|
|
TFileHandle * FileHandle = NULL;
|
|
int BytesWritten = 0;
|
|
|
|
// Validate
|
|
if (!ChannelName || !Data) {
|
|
return 0;
|
|
}
|
|
else if (Len == -1) {
|
|
Len = strlen( Data );
|
|
};
|
|
|
|
// Get Channel
|
|
if (!(FileHandle = GetFile( ChannelName )))
|
|
{
|
|
// Log event
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s/%s: Channel '%s' - Input rejected, Channel not found",
|
|
ProcessName, Name, ChannelName );
|
|
return 0;
|
|
}
|
|
|
|
// Log event
|
|
if (Log) Log->Output( LogLevel, dlHigh, LogOutput, Data, Len, "%s/%s: Channel '%s' - IN:",
|
|
ProcessName, Name, ChannelName );
|
|
|
|
// Open file
|
|
if (!OpenFile( FileHandle )) {
|
|
return 0;
|
|
}
|
|
|
|
// Handle Incoming data
|
|
BytesWritten = WriteToFD( FileHandle->FD, Data, Len );
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
|
|
// Return processed bytes
|
|
return BytesWritten;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::Process()
|
|
{
|
|
TFileHandle * FileHandle;
|
|
|
|
// Close Persistent files not used
|
|
FileHandle = FirstFile;
|
|
while (FileHandle)
|
|
{
|
|
if (isOpen(FileHandle) &&
|
|
(!FileHandle->Persistent ||
|
|
(FileHandle->PersistTimeout && Timeout( FileHandle->PersistTime, FileHandle->PersistTimeout )))) {
|
|
CloseFile( FileHandle );
|
|
}
|
|
|
|
// Next
|
|
FileHandle = FileHandle->Next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|