Skip to content

Commit

Permalink
feat: store resources on disk
Browse files Browse the repository at this point in the history
instead of in the session
  • Loading branch information
Alex Van Camp committed Apr 25, 2022
1 parent de869a9 commit 65fe60f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 47 deletions.
6 changes: 3 additions & 3 deletions apps/app/src/electron/IPCServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,7 @@ export class IPCServer
if (!timelineObj) throw new Error(`A timelineObj with the ID "${arg.timelineObjId}" could not be found.`)

if (!timelineObj.resourceId) throw new Error(`TimelineObj "${arg.timelineObjId}" lacks a resourceId.`)
const resource = this.session.getResource(timelineObj.resourceId)
const resource = this.storage.getResource(timelineObj.resourceId)
if (!resource) throw new Error(`Resource ${timelineObj.resourceId} not found.`)

const originalLayer = timelineObj.obj.layer
Expand Down Expand Up @@ -1351,7 +1351,7 @@ export class IPCServer
return
}

const resource = this.session.getResource(arg.resourceId)
const resource = this.storage.getResource(arg.resourceId)
if (!resource) throw new Error(`Resource ${arg.resourceId} not found.`)

const obj: TSRTimelineObj = TSRTimelineObjFromResource(resource)
Expand Down Expand Up @@ -1711,7 +1711,7 @@ export class IPCServer
throw new Error(`TimelineObj "${timelineObj.obj.id}" lacks a resourceId.`)

let deviceId: string | undefined
const resource = this.session.getResource(timelineObj.resourceId)
const resource = this.storage.getResource(timelineObj.resourceId)
if (resource) {
deviceId = resource.deviceId
}
Expand Down
18 changes: 9 additions & 9 deletions apps/app/src/electron/TimedPlayerThingy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ export class TimedPlayerThingy {
CURRENT_VERSION
)

this.session.on('resource', (id: string, resource: ResourceAny | null) => {
// Add the resource to the list of resources to send to the client in batches later:
this.resourceUpdatesToSend.push({ id, resource })
this._triggerBatchSendResources()
})
this.session.on('bridgeStatus', (id: string, status: BridgeStatus | null) => {
this.ipcClient?.updateBridgeStatus(id, status)
})
Expand All @@ -77,6 +72,11 @@ export class TimedPlayerThingy {
this.storage.on('rundown', (fileName: string, rundown: Rundown) => {
this.ipcClient?.updateRundown(fileName, rundown)
})
this.storage.on('resource', (id: string, resource: ResourceAny | null) => {
// Add the resource to the list of resources to send to the client in batches later:
this.resourceUpdatesToSend.push({ id, resource })
this._triggerBatchSendResources()
})
}
private _triggerBatchSendResources() {
// Send updates of resources in batches to the client.
Expand All @@ -101,13 +101,13 @@ export class TimedPlayerThingy {
const newResouceIds = new Set<string>()
for (const resource of resources) {
newResouceIds.add(resource.id)
if (!_.isEqual(this.session.getResource(resource.id), resource)) {
this.session.updateResource(resource.id, resource)
if (!_.isEqual(this.storage.getResource(resource.id), resource)) {
this.storage.updateResource(resource.id, resource)
}
}
// Removed:
for (const id of this.session.getResourceIds(deviceId)) {
if (!newResouceIds.has(id)) this.session.updateResource(id, null)
for (const id of this.storage.getResourceIds(deviceId)) {
if (!newResouceIds.has(id)) this.storage.updateResource(id, null)
}
},
onVersionMismatch: (bridgeId: string, bridgeVersion: string, ourVersion: string): void => {
Expand Down
35 changes: 0 additions & 35 deletions apps/app/src/electron/sessionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import EventEmitter from 'events'
import { ResourceAny } from '@shared/models'
import { BridgeStatus } from '../models/project/Bridge'
import { PeripheralStatus } from '../models/project/Peripheral'
import _ from 'lodash'
Expand All @@ -9,9 +8,6 @@ import { DefiningArea } from '../lib/triggers/keyDisplay'

/** This class handles all non-persistant data */
export class SessionHandler extends EventEmitter {
private resources: { [resourceId: string]: ResourceAny } = {}
private resourcesHasChanged: { [resourceId: string]: true } = {}

private bridgeStatuses: { [bridgeId: string]: BridgeStatus } = {}
private bridgeStatusesHasChanged: { [bridgeId: string]: true } = {}

Expand Down Expand Up @@ -41,19 +37,6 @@ export class SessionHandler extends EventEmitter {
this.triggerUpdate()
}

getResources() {
return this.resources
}
getResource(id: string): ResourceAny | undefined {
return this.resources[id]
}
getResourceIds(deviceId: string): string[] {
const ids: string[] = []
for (const [id, resource] of Object.entries(this.resources)) {
if (resource.deviceId === deviceId) ids.push(id)
}
return ids
}
getDefiningArea(): DefiningArea | null {
return this.definingArea
}
Expand All @@ -62,17 +45,6 @@ export class SessionHandler extends EventEmitter {
this.definingAreaHasChanged = true
this.triggerUpdate()
}
updateResource(id: string, resource: ResourceAny | null) {
if (resource) {
this.resources[id] = resource
this.resourcesHasChanged[id] = true
} else {
delete this.resources[id]
this.resourcesHasChanged[id] = true
}

this.triggerUpdate()
}

getBridgeStatuses() {
return this.bridgeStatuses
Expand Down Expand Up @@ -180,9 +152,6 @@ export class SessionHandler extends EventEmitter {
}
private emitChanges() {
if (this.emitEverything) {
for (const resourceId of Object.keys(this.resources)) {
this.resourcesHasChanged[resourceId] = true
}
for (const bridgeId of Object.keys(this.bridgeStatuses)) {
this.bridgeStatusesHasChanged[bridgeId] = true
}
Expand All @@ -195,10 +164,6 @@ export class SessionHandler extends EventEmitter {
this.emitEverything = false
}

for (const resourceId of Object.keys(this.resourcesHasChanged)) {
this.emit('resource', resourceId, this.resources[resourceId] ?? null)
delete this.resourcesHasChanged[resourceId]
}
for (const bridgeId of Object.keys(this.bridgeStatusesHasChanged)) {
this.emit('bridgeStatus', bridgeId, this.bridgeStatuses[bridgeId] ?? null)
delete this.bridgeStatusesHasChanged[bridgeId]
Expand Down
92 changes: 92 additions & 0 deletions apps/app/src/electron/storageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Rundown } from '../models/rundown/Rundown'
import { AppData, WindowPosition } from '../models/App/AppData'
import { omit } from '@shared/lib'
import { getDefaultProject, getDefaultRundown } from './defaults'
import { ResourceAny } from '@shared/models'

const fsWriteFile = fs.promises.writeFile
const fsRm = fs.promises.rm
Expand Down Expand Up @@ -36,6 +37,10 @@ export class StorageHandler extends EventEmitter {
private rundownsHasChanged: { [fileName: string]: true } = {}
private rundownsNeedsWrite: { [fileName: string]: true } = {}

private resources: { [resourceId: string]: ResourceAny } = {}
private resourcesHasChanged: { [resourceId: string]: true } = {}
private resourcesNeedsWrite = false

private emitEverything = false

private emitTimeout: NodeJS.Timeout | null = null
Expand All @@ -47,6 +52,7 @@ export class StorageHandler extends EventEmitter {

this.project = this.loadProject()
this.rundowns = this.loadRundowns()
this.resources = this.loadResources()
}

init() {
Expand Down Expand Up @@ -321,6 +327,31 @@ export class StorageHandler extends EventEmitter {
return newFileName
}

getResources() {
return this.resources
}
getResource(id: string): ResourceAny | undefined {
return this.resources[id]
}
getResourceIds(deviceId: string): string[] {
const ids: string[] = []
for (const [id, resource] of Object.entries(this.resources)) {
if (resource.deviceId === deviceId) ids.push(id)
}
return ids
}
updateResource(id: string, resource: ResourceAny | null) {
if (resource) {
this.resources[id] = resource
this.resourcesHasChanged[id] = true
} else {
delete this.resources[id]
this.resourcesHasChanged[id] = true
}

this.triggerUpdate({ resources: { [id]: true } })
}

convertToFilename(str: string): string {
return str.toLowerCase().replace(/[^a-z0-9]/g, '-')
}
Expand All @@ -331,6 +362,7 @@ export class StorageHandler extends EventEmitter {
project?: true
rundowns?: { [rundownId: string]: true }
closedRundowns?: true
resources?: { [resourceId: string]: true }
}): void {
if (updates.appData) {
this.appDataHasChanged = true
Expand All @@ -346,6 +378,12 @@ export class StorageHandler extends EventEmitter {
this.rundownsNeedsWrite[rundownId] = true
}
}
if (updates.resources) {
for (const resourceId of Object.keys(updates.resources)) {
this.resourcesHasChanged[resourceId] = true
this.resourcesNeedsWrite = true
}
}

if (!this.emitTimeout) {
this.emitTimeout = setTimeout(() => {
Expand Down Expand Up @@ -543,6 +581,45 @@ export class StorageHandler extends EventEmitter {

return rundown
}
private loadResources(): { [resourceId: string]: ResourceAny } {
let resources: { [resourceId: string]: ResourceAny } | undefined = {}
const resourcesPath = this.resourcesPath(this._projectId)
try {
const read = fs.readFileSync(resourcesPath, 'utf8')
resources = JSON.parse(read)
} catch (error) {
if ((error as any)?.code === 'ENOENT') {
// not found
resources = {}
} else {
throw new Error(`Unable to read Resources file "${resourcesPath}": ${error}`)
}
}

if (!resources) {
// Second try; Check if there is a temporary file, to use instead?
const tmpPath = this.getTmpFilePath(resourcesPath)
try {
const read = fs.readFileSync(tmpPath, 'utf8')
resources = JSON.parse(read)

// If we only have a temporary file, we should write to the real one asap:
this.resourcesNeedsWrite = true
} catch (error) {
if ((error as any)?.code === 'ENOENT') {
// not found
} else {
throw new Error(`Unable to read temp Resources file "${tmpPath}": ${error}`)
}
}
}

if (!resources) {
resources = {}
}

return resources
}

private getDefaultAppData(defaultWindowPosition: WindowPosition, appVersion: string): FileAppData {
return {
Expand Down Expand Up @@ -582,6 +659,9 @@ export class StorageHandler extends EventEmitter {
for (const fileName of Object.keys(this.rundowns)) {
this.rundownsHasChanged[fileName] = true
}
for (const resourceId of Object.keys(this.resources)) {
this.resourcesHasChanged[resourceId] = true
}
this.emitEverything = false
}

Expand All @@ -598,6 +678,10 @@ export class StorageHandler extends EventEmitter {
this.emit('rundown', fileName, this.getRundown(fileName))
delete this.rundownsHasChanged[fileName]
}
for (const resourceId of Object.keys(this.resourcesHasChanged)) {
this.emit('resource', resourceId, this.resources[resourceId] ?? null)
delete this.resourcesHasChanged[resourceId]
}
}
private async writeChanges() {
// Create dir if not exists:
Expand Down Expand Up @@ -634,6 +718,11 @@ export class StorageHandler extends EventEmitter {

delete this.rundownsNeedsWrite[fileName]
}
// Store Resources:
if (this.resourcesNeedsWrite) {
await this.writeFileSafe(this.resourcesPath(this._projectId), JSON.stringify(this.resources))
this.projectNeedsWrite = false
}
}
private getTmpFilePath(filePath: string): string {
return `${filePath}.tmp`
Expand Down Expand Up @@ -683,6 +772,9 @@ export class StorageHandler extends EventEmitter {
private projectPath(projectId: string): string {
return path.join(this.projectDir(projectId), 'project.json')
}
private resourcesPath(projectId: string): string {
return path.join(this.projectDir(projectId), 'resources.json')
}
private get appDataPath(): string {
return path.join(this._baseFolder, 'appData.json')
}
Expand Down

0 comments on commit 65fe60f

Please sign in to comment.