- FunctionCore/SelectableCore/FileCore/DeviceCore:
- Remove InputChannels
- Only OutputChannels -> LinkedChannels
- Remove PullInput/Output() methods
- Remove StoredOutput
- Add References to channels and linked channels
- Send SourceRef with output
- Receive TargetRef with input
- Filter output channels based on TargetRef
324 lines
8.5 KiB
C++
324 lines
8.5 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 = strdup( Name );
|
|
(*FileHandle)->Path = strdup( 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 * SourceRef, 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;
|
|
}
|
|
//---------------------------------------------------------------------------
|