cinera.c: Gracefully handle database non-creation
This commit is contained in:
parent
b3470e0f48
commit
6eeb588adf
208
cinera/cinera.c
208
cinera/cinera.c
|
@ -23,7 +23,7 @@ typedef struct
|
|||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 7,
|
||||
.Patch = 17
|
||||
.Patch = 18
|
||||
};
|
||||
|
||||
#include <stdarg.h> // NOTE(matt): varargs
|
||||
|
@ -4735,7 +4735,6 @@ void *
|
|||
LocateBlock(block_id BlockID)
|
||||
{
|
||||
void *Result = 0;
|
||||
|
||||
db_header *Header = (db_header *)DB.Metadata.File.Buffer.Location;
|
||||
char *Ptr = (char *)Header;
|
||||
Ptr += sizeof(db_header);
|
||||
|
@ -14133,9 +14132,10 @@ WriteEntireDatabase()
|
|||
fclose(DB.Metadata.File.Handle);
|
||||
}
|
||||
|
||||
int
|
||||
rc
|
||||
InitDB(void)
|
||||
{
|
||||
rc Result = RC_SUCCESS;
|
||||
// TODO(matt): InitDB() is called once on startup. This is correct for the .metadata file, because we only want one of
|
||||
// those to house the info for all projects. However, we will want to create a .index file for each project, so
|
||||
// need a separate InitIndex() function that we can call when looping over the projects after ParseConfig()
|
||||
|
@ -14261,7 +14261,7 @@ InitDB(void)
|
|||
LogError(LOG_ERROR, "Unable to create directory %.*s: %s", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
||||
fprintf(stderr, "Unable to create directory %.*s: %s\n", (int)Config->DatabaseLocation.Length, Config->DatabaseLocation.Base, strerror(errno));
|
||||
Free(DatabaseLocation0);
|
||||
return RC_ERROR_DIRECTORY;
|
||||
Result = RC_ERROR_DIRECTORY;
|
||||
};
|
||||
}
|
||||
else
|
||||
|
@ -14271,39 +14271,43 @@ InitDB(void)
|
|||
}
|
||||
Free(DatabaseLocation0);
|
||||
|
||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
||||
if(DB.Metadata.File.Handle)
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
||||
|
||||
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||
fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle);
|
||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
||||
if(DB.Metadata.File.Handle)
|
||||
{
|
||||
fwrite(&DB.Header, sizeof(DB.Header), 1, DB.Metadata.File.Handle);
|
||||
|
||||
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
||||
DB.Metadata.Signposts.ProjectsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||
fwrite(&DB.ProjectsBlock, sizeof(DB.ProjectsBlock), 1, DB.Metadata.File.Handle);
|
||||
|
||||
fclose(DB.Metadata.File.Handle);
|
||||
ReadFileIntoBuffer(&DB.Metadata.File);
|
||||
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
||||
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO(matt): Handle unopenable database files
|
||||
PrintC(CS_RED, "Could not open database file: ");
|
||||
PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path);
|
||||
fprintf(stderr, "\n");
|
||||
_exit(0);
|
||||
}
|
||||
DB.Metadata.Signposts.AssetsBlock.Byte = ftell(DB.Metadata.File.Handle);
|
||||
fwrite(&DB.AssetsBlock, sizeof(DB.AssetsBlock), 1, DB.Metadata.File.Handle);
|
||||
|
||||
fclose(DB.Metadata.File.Handle);
|
||||
ReadFileIntoBuffer(&DB.Metadata.File);
|
||||
DB.Metadata.Signposts.ProjectsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.ProjectsBlock.Byte;
|
||||
DB.Metadata.Signposts.AssetsBlock.Ptr = DB.Metadata.File.Buffer.Location + DB.Metadata.Signposts.AssetsBlock.Byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO(matt): Handle unopenable database files
|
||||
PrintC(CS_RED, "Could not open database file: ");
|
||||
PrintC(CS_MAGENTA_BOLD, DB.Metadata.File.Path);
|
||||
fprintf(stderr, "\n");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
DB.File.Handle = fopen(DB.File.Path, "w");
|
||||
fprintf(DB.File.Handle, "---\n");
|
||||
fclose(DB.File.Handle);
|
||||
ReadFileIntoBuffer(&DB.File);
|
||||
DB.File.Handle = fopen(DB.File.Path, "w");
|
||||
fprintf(DB.File.Handle, "---\n");
|
||||
fclose(DB.File.Handle);
|
||||
ReadFileIntoBuffer(&DB.File);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return RC_SUCCESS;
|
||||
return Result;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -15340,58 +15344,63 @@ PrintEvent(struct inotify_event *Event, int EventIndex, int Indentation)
|
|||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
rc
|
||||
InitAll(neighbourhood *Neighbourhood, buffers *CollationBuffers, template *BespokeTemplate)
|
||||
{
|
||||
rc Result = RC_SUCCESS;
|
||||
MEM_TEST_TOP("InitAll()");
|
||||
RewindCollationBuffers(CollationBuffers);
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
/* +MEM */ InitDB();
|
||||
/* +MEM */ Result = InitDB();
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
|
||||
// TODO(matt): Straight up remove these PrintAssetsBlock() calls
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
SyncDB(Config);
|
||||
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
|
||||
printf("\n╾─ Hashing assets ─╼\n");
|
||||
// NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must
|
||||
// ensure that the builtin assets get placed correctly
|
||||
InitAssets();
|
||||
PushConfiguredAssets();
|
||||
//
|
||||
////
|
||||
|
||||
PackTemplates(Neighbourhood);
|
||||
|
||||
bool TitledSync = FALSE;
|
||||
for(int i = 0; i < Config->Project.ItemCount; ++i)
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
/* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync);
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
// TODO(matt): Straight up remove these PrintAssetsBlock() calls
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
SyncDB(Config);
|
||||
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
|
||||
printf("\n╾─ Hashing assets ─╼\n");
|
||||
// NOTE(matt): This had to happen before PackTemplate() because those guys may need to do PushAsset() and we must
|
||||
// ensure that the builtin assets get placed correctly
|
||||
InitAssets();
|
||||
PushConfiguredAssets();
|
||||
//
|
||||
////
|
||||
|
||||
PackTemplates(Neighbourhood);
|
||||
|
||||
bool TitledSync = FALSE;
|
||||
for(int i = 0; i < Config->Project.ItemCount; ++i)
|
||||
{
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
/* +MEM */ SyncProject(GetPlaceInBook(&Config->Project, i), Neighbourhood, CollationBuffers, BespokeTemplate, &TitledSync);
|
||||
/* */ MEM_TEST_MID("InitAll()");
|
||||
}
|
||||
|
||||
SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers);
|
||||
|
||||
for(int i = 0; i < Assets.ItemCount; ++i)
|
||||
{
|
||||
UpdateAssetInDB(GetPlaceInBook(&Assets, i));
|
||||
}
|
||||
DeleteStaleAssets();
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
MEM_TEST_END("InitAll()");
|
||||
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n",
|
||||
ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END],
|
||||
ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END],
|
||||
ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]);
|
||||
}
|
||||
|
||||
SyncGlobalPagesWithInput(Neighbourhood, CollationBuffers);
|
||||
|
||||
for(int i = 0; i < Assets.ItemCount; ++i)
|
||||
{
|
||||
UpdateAssetInDB(GetPlaceInBook(&Assets, i));
|
||||
}
|
||||
DeleteStaleAssets();
|
||||
//PrintAssetsBlock(0);
|
||||
|
||||
MEM_TEST_END("InitAll()");
|
||||
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"╾─ Monitoring file system for %snew%s, %sedited%s and %sdeleted%s .hmml and asset files ─╼\n",
|
||||
ColourStrings[EditTypes[EDIT_ADDITION].Colour], ColourStrings[CS_END],
|
||||
ColourStrings[EditTypes[EDIT_REINSERTION].Colour], ColourStrings[CS_END],
|
||||
ColourStrings[EditTypes[EDIT_DELETION].Colour], ColourStrings[CS_END]);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -15672,6 +15681,7 @@ void
|
|||
Exit(void)
|
||||
{
|
||||
Free(MemoryArena.Location);
|
||||
fprintf(stderr, "Exiting\n");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
|
@ -15812,6 +15822,7 @@ main(int ArgC, char **Args)
|
|||
PushWatchHandle(ConfigPathL, EXT_NULL, WT_CONFIG, 0, 0);
|
||||
|
||||
Config = ParseConfig(ConfigPathL, &TokensList);
|
||||
rc Succeeding = RC_SUCCESS;
|
||||
if(Config)
|
||||
{
|
||||
if(Mode & MODE_EXAMINE)
|
||||
|
@ -15828,7 +15839,7 @@ main(int ArgC, char **Args)
|
|||
else
|
||||
{
|
||||
/* */ MEM_TEST_MID("main()");
|
||||
/* +MEM */ InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||
/* +MEM */ Succeeding = InitAll(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||
/* */ MEM_TEST_MID("main()");
|
||||
}
|
||||
}
|
||||
|
@ -15844,36 +15855,39 @@ main(int ArgC, char **Args)
|
|||
}
|
||||
}
|
||||
|
||||
if(inotifyInstance)
|
||||
if(Succeeding == RC_SUCCESS)
|
||||
{
|
||||
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
||||
if(inotifyInstance)
|
||||
{
|
||||
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
||||
//
|
||||
// Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know
|
||||
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
|
||||
// postpone this for now, but we will certainly need this to happen
|
||||
//
|
||||
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
||||
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
||||
// the player page(s) accordingly.
|
||||
//
|
||||
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
||||
while(MonitorFilesystem(&Neighbourhood, &CollationBuffers, &BespokeTemplate, ConfigPathL, &TokensList) != RC_ARENA_FULL)
|
||||
{
|
||||
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||
// TODO(matt): Refetch the quotes and rebuild player pages if needed
|
||||
//
|
||||
// Every sixty mins, redownload the quotes and, I suppose, SyncDBWithInput(). But here we still don't even know
|
||||
// who the speaker is. To know, we'll probably have to store all quoted speakers in the project's .metadata. Maybe
|
||||
// postpone this for now, but we will certainly need this to happen
|
||||
//
|
||||
// The most ideal solution is possibly that we store quote numbers in the Metadata->Entry, listen for and handle a
|
||||
// REST PUT request from insobot when a quote changes (unless we're supposed to poll insobot for them?), and rebuild
|
||||
// the player page(s) accordingly.
|
||||
//
|
||||
if(!(Mode & MODE_DRYRUN) && Config && Config->RespectingPrivacy && time(0) - LastPrivacyCheck > Config->PrivacyCheckInterval)
|
||||
{
|
||||
RecheckPrivacy(&Neighbourhood, &CollationBuffers, &BespokeTemplate);
|
||||
}
|
||||
sleep(GLOBAL_UPDATE_INTERVAL);
|
||||
}
|
||||
sleep(GLOBAL_UPDATE_INTERVAL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n"
|
||||
" %s\n", strerror(inotifyError));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Quitting because inotify initialisation failed with message\n"
|
||||
" %s\n", strerror(inotifyError));
|
||||
}
|
||||
|
||||
DiscardAllAndFreeConfig();
|
||||
RemoveAndFreeWatchHandles(&WatchHandles);
|
||||
MEM_TEST_END("main()");
|
||||
DiscardAllAndFreeConfig();
|
||||
RemoveAndFreeWatchHandles(&WatchHandles);
|
||||
MEM_TEST_END("main()");
|
||||
}
|
||||
}
|
||||
Exit();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue