Major Update:
- Minor fix: Set correct names in comments at top of file - New FileCore Class: - Writing data to output file - BufferCore: - Check for "EAGAIN" on write and retry write - FunctionCore: - Add new Output method that references LocalIO directly - SelectableCore: - New method SetAutomanage to specify auto re-open parameters - Re-open timer implemented to slow re-open events - Only call ProcessBuffer() if data received on socket - Force processing input data when no input marker set - Use new Output method to simplify code - Bug fix: Read correctly from buffer on multiple reads/writes on FD - Check for "EAGAIN" on write to FD and retry write
This commit is contained in:
330
FileCore.cpp
Normal file
330
FileCore.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* FileCore.cpp
|
||||
*
|
||||
* Created on: 1 Jun 2016
|
||||
* Author: wentzelc
|
||||
*/
|
||||
|
||||
// redA Libraries
|
||||
#include "FileCore.h"
|
||||
#include "FunctionCore.h"
|
||||
#include "TimingCore.h"
|
||||
#include "LogCore.h"
|
||||
|
||||
// Standard C/C++ Libraries
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Constants
|
||||
const float PI = 3.1415927;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
CFileCore::CFileCore( const char * Name, EDebugLevel pDebugLevel, int pOuputDisplay ) :
|
||||
CFunctionCore( Name, pDebugLevel, pOuputDisplay )
|
||||
{
|
||||
FirstFile = NULL;
|
||||
|
||||
// temp
|
||||
count = 0;
|
||||
x = 0;
|
||||
// temp
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
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 CreateLocalIO )
|
||||
{
|
||||
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 IO if necessary
|
||||
if (CreateLocalIO) {
|
||||
AddLocalIO( 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 ))
|
||||
{
|
||||
// temp
|
||||
//char FilePath[50];
|
||||
//sprintf( FilePath, "%s%03d", FileHandle->Path, x++ );
|
||||
//LogMessage( DebugLevel, dlNone, "f: %s", FilePath );
|
||||
// temp
|
||||
|
||||
// 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) );
|
||||
|
||||
// temp
|
||||
count = 0;
|
||||
// temp
|
||||
|
||||
// Report result
|
||||
LogMessage( DebugLevel, dlHigh, "%s: File '%s' - Opened", Name, FileHandle->Name );
|
||||
}
|
||||
}
|
||||
|
||||
// Check if failed
|
||||
if (!isOpen(FileHandle))
|
||||
{
|
||||
// Report result
|
||||
LogMessage( DebugLevel, dlHigh, "%s: File '%s' - Could not open (%d) %s", 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)) {
|
||||
LogMessage( DebugLevel, dlHigh, "%s: File '%s' - Closed", Name, FileHandle->Name );
|
||||
} else {
|
||||
LogMessage( DebugLevel, dlHigh, "%s: File '%s' - Could not close", Name, FileHandle->Name );
|
||||
}
|
||||
|
||||
// temp
|
||||
LogMessage( DebugLevel, dlNone, "%s: File '%s' - Bytes written %d (%d)", Name, FileHandle->Name, count, (count-5038848) );
|
||||
// temp
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int CFileCore::ReadFromFD( int FD, char * Data, int MaxLen )
|
||||
{
|
||||
int BytesRead = 0;
|
||||
int TotalRead = 0;
|
||||
int DataRemain = 0;
|
||||
|
||||
// Check if buffer created
|
||||
if ((FD == -1) || !Data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read Data into buffer
|
||||
DataRemain = (MaxLen == -1)? strlen(Data) : MaxLen;
|
||||
while (DataRemain)
|
||||
{
|
||||
// Read from file descriptor
|
||||
BytesRead = read( FD, &Data[TotalRead], DataRemain );
|
||||
if (BytesRead <= 0)
|
||||
break;
|
||||
|
||||
// Update Data Pointers
|
||||
TotalRead += BytesRead;
|
||||
DataRemain -= BytesRead;
|
||||
}
|
||||
|
||||
return TotalRead;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int CFileCore::WriteToFD( int FD, const char * Data, int Len )
|
||||
{
|
||||
int BytesWritten = 0;
|
||||
int TotalWritten = 0;
|
||||
int DataRemain = 0;
|
||||
|
||||
// Check if buffer created
|
||||
if ((FD == -1) || !Data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read Data into buffer
|
||||
DataRemain = (Len == -1)? strlen(Data) : Len;
|
||||
while (DataRemain)
|
||||
{
|
||||
// Read from file descriptor
|
||||
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
|
||||
if ((BytesWritten <= 0) && (errno != EAGAIN))
|
||||
break;
|
||||
|
||||
// Update Data Pointers
|
||||
TotalWritten += BytesWritten;
|
||||
DataRemain -= BytesWritten;
|
||||
}
|
||||
|
||||
return TotalWritten;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
// Manual Data Input/Output
|
||||
int CFileCore::Input( const char * IOName, const char * Data, int MaxLen )
|
||||
{
|
||||
TFileHandle * FileHandle = NULL;
|
||||
int BytesWritten = 0;
|
||||
|
||||
// Validate
|
||||
if (!IOName || !Data) {
|
||||
return 0;
|
||||
}
|
||||
else if (MaxLen == -1) {
|
||||
MaxLen = strlen( Data );
|
||||
};
|
||||
|
||||
// Get IO
|
||||
if (!(FileHandle = GetFile( IOName )))
|
||||
{
|
||||
// Log event
|
||||
LogMessage( DebugLevel, dlHigh, "%s: Local IO '%s' - Input rejected, Local IO not found", Name, IOName );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Log event
|
||||
//ShowOutput( DebugLevel, dlHigh, OutputDisplay, Data, MaxLen, "%s: Local IO '%s' - IN:", Name, IOName );
|
||||
|
||||
// Open file
|
||||
if (!OpenFile( FileHandle )) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle Incoming data
|
||||
BytesWritten = WriteToFD( FileHandle->FD, Data, MaxLen );
|
||||
SetStartTime( &(FileHandle->PersistTime) );
|
||||
|
||||
// temp
|
||||
count += BytesWritten;
|
||||
// temp
|
||||
|
||||
// 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;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user