Skip to content

Commit 83ac74f

Browse files
committed
wip: first draft of diffing
1 parent a605997 commit 83ac74f

File tree

1 file changed

+101
-8
lines changed

1 file changed

+101
-8
lines changed

packages/mos-gateway/src/mosStatusHandler.ts

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IMOSDevice } from '@mos-connection/connector'
1+
import { getMosTypes, IMOSObjectStatus, type IMOSDevice } from '@mos-connection/connector'
22
import type { MosDeviceStatusesConfig } from './generated/devices'
33
import type { CoreMosDeviceHandler } from './CoreMosDeviceHandler'
44
import {
@@ -8,15 +8,22 @@ import {
88
stringifyError,
99
SubscriptionId,
1010
} from '@sofie-automation/server-core-integration'
11-
import type { IngestRundownStatus } from '@sofie-automation/shared-lib/dist/ingest/rundownStatus'
12-
import { RundownId } from '@sofie-automation/shared-lib/dist/core/model/Ids'
11+
import type { IngestPartStatus, IngestRundownStatus } from '@sofie-automation/shared-lib/dist/ingest/rundownStatus'
12+
import type { RundownId } from '@sofie-automation/shared-lib/dist/core/model/Ids'
1313
import type winston = require('winston')
14+
import { Queue } from '@sofie-automation/server-core-integration/dist/lib/queue'
15+
16+
const MOS_STATUS_UNKNOWN = '' as IMOSObjectStatus // nocommit - check this
17+
18+
const mosTypes = getMosTypes(false)
1419

1520
export class MosStatusHandler {
1621
readonly #logger: winston.Logger
1722
readonly #mosDevice: IMOSDevice
1823
readonly #coreMosHandler: CoreMosDeviceHandler
1924

25+
readonly #messageQueue = new Queue()
26+
2027
#subId: SubscriptionId | undefined
2128
#observer: Observer<IngestRundownStatus> | undefined
2229

@@ -72,7 +79,28 @@ export class MosStatusHandler {
7279
const statusDiff = diffStatuses(previousStatuses, newStatuses)
7380
if (statusDiff.length === 0) return
7481

75-
// nocommit - send statuses to MOS device. with a queue?
82+
const diffTime = mosTypes.mosTime.create(Date.now())
83+
84+
// nocommit - should this be done with some concurrency?
85+
for (const status of statusDiff) {
86+
this.#messageQueue
87+
.putOnQueue(async () => {
88+
// Send status
89+
await this.#mosDevice.sendStoryStatus({
90+
RunningOrderId: mosTypes.mosString128.create(status.rundownExternalId),
91+
ID: mosTypes.mosString128.create(status.storyId),
92+
Status: status.mosStatus,
93+
Time: diffTime,
94+
})
95+
})
96+
.catch((e) => {
97+
this.#logger.error(
98+
`Error sending of "${status.rundownExternalId}"-"${
99+
status.storyId
100+
}" status to MOS device: ${stringifyError(e)}`
101+
)
102+
})
103+
}
76104

77105
throw new Error('Method not implemented.')
78106
}
@@ -86,16 +114,81 @@ export class MosStatusHandler {
86114
}
87115

88116
interface StoryStatusItem {
117+
rundownExternalId: string
89118
storyId: string
90-
mosStatus: string
119+
mosStatus: IMOSObjectStatus
91120
}
92121

93122
function diffStatuses(
94123
previousStatuses: IngestRundownStatus | undefined,
95124
newStatuses: IngestRundownStatus | undefined
96125
): StoryStatusItem[] {
97-
if (!previousStatuses && !newStatuses) return []
126+
const rundownExternalId = previousStatuses?.externalId ?? newStatuses?.externalId
127+
128+
if ((!previousStatuses && !newStatuses) || !rundownExternalId) return []
129+
130+
const statuses: StoryStatusItem[] = []
131+
132+
const previousStories = buildStoriesMap(previousStatuses)
133+
const newStories = buildStoriesMap(newStatuses)
98134

99-
// TODO
100-
return []
135+
// Process any removed stories first
136+
for (const storyId of previousStories.keys()) {
137+
if (!newStories.has(storyId)) {
138+
// The story has been removed
139+
statuses.push({
140+
rundownExternalId,
141+
storyId,
142+
mosStatus: MOS_STATUS_UNKNOWN,
143+
})
144+
}
145+
}
146+
147+
// Then any remaining stories in order
148+
for (const [storyId, status] of newStories) {
149+
const previousStatus = previousStories.get(storyId)
150+
151+
const newMosStatus = buildMosStatus(status)
152+
if (!previousStatus || buildMosStatus(previousStatus) !== newMosStatus) {
153+
statuses.push({
154+
rundownExternalId,
155+
storyId,
156+
mosStatus: newMosStatus,
157+
})
158+
}
159+
}
160+
161+
return statuses
162+
}
163+
164+
function buildStoriesMap(state: IngestRundownStatus | undefined): Map<string, IngestPartStatus> {
165+
const stories = new Map<string, IngestPartStatus>()
166+
167+
if (state) {
168+
for (const segment of state.segments) {
169+
for (const part of segment.parts) {
170+
stories.set(part.externalId, part)
171+
}
172+
}
173+
}
174+
175+
return stories
176+
}
177+
178+
function buildMosStatus(story: IngestPartStatus): IMOSObjectStatus {
179+
switch (story.playbackStatus) {
180+
case 'playing':
181+
return IMOSObjectStatus.PLAY
182+
case 'stopped':
183+
return IMOSObjectStatus.STOP
184+
default:
185+
switch (story.isReady) {
186+
case true:
187+
return IMOSObjectStatus.READY
188+
case false:
189+
return IMOSObjectStatus.NOT_READY
190+
default:
191+
return MOS_STATUS_UNKNOWN
192+
}
193+
}
101194
}

0 commit comments

Comments
 (0)