Skip to content

Commit

Permalink
feat: add method to list shows in the MSE's directory
Browse files Browse the repository at this point in the history
  • Loading branch information
ianshade committed Nov 15, 2022
1 parent 3243ff0 commit 76b253f
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 23 deletions.
52 changes: 51 additions & 1 deletion src/__tests__/xml.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { flattenEntry, entry2XML, buildXML } from '../xml'
import { flattenEntry, entry2XML, buildXML, toFlatMap } from '../xml'
import * as Xml2JS from 'xml2js'

const testXML = `<entry mode="enabled" status="uninitialized" type="viz" name="Viz A">
Expand Down Expand Up @@ -149,3 +149,53 @@ describe('Transform a non-entry', () => {
expect(flat).toBeTruthy()
})
})

const directoryEntry = `<entry name="shows">
<ref name="some_show.show">/storage/shows/{UUID1}</ref>
<entry name="SOFIE">
<ref name="some_show2.show">/storage/shows/{UUID2}</ref>
<entry name="deep">
<ref name="some show3.show">/storage/shows/{UUID3}</ref>
<ref name="some_show4.show">/storage/shows/{UUID4}</ref>
</entry>
<entry name="deep2">
<ref name="some_show5.show">/storage/shows/{UUID5}</ref>
</entry>
</entry>
<ref name="some_show6.show">/storage/shows/{UUID6}</ref>
</entry>`

const emptyDirectoryEntry = `<entry name="shows" />`

const nestedEmptyDirectoryEntries = `<entry name="shows">
<entry name="SOFIE">
<entry name="deep">
</entry>
</entry>
<ref name="some_show.show">/storage/shows/{UUID1}</ref>
</entry>`

describe('toFlatMap', () => {
test('Builds a flat map', async () => {
const fromXML = await Xml2JS.parseStringPromise(directoryEntry)
const flat = await toFlatMap(fromXML)
expect(flat.size).toBe(6)
expect(flat.get('some_show.show')).toBe('/storage/shows/{UUID1}')
expect(flat.get('SOFIE/some_show2.show')).toBe('/storage/shows/{UUID2}')
expect(flat.get('SOFIE/deep/some show3.show')).toBe('/storage/shows/{UUID3}')
expect(flat.get('SOFIE/deep/some_show4.show')).toBe('/storage/shows/{UUID4}')
expect(flat.get('SOFIE/deep2/some_show5.show')).toBe('/storage/shows/{UUID5}')
expect(flat.get('some_show6.show')).toBe('/storage/shows/{UUID6}')
})
test('Supports empty entry', async () => {
const fromXML = await Xml2JS.parseStringPromise(emptyDirectoryEntry)
const flat = await toFlatMap(fromXML)
expect(flat.size).toBe(0)
})
test('Supports nested empty entries', async () => {
const fromXML = await Xml2JS.parseStringPromise(nestedEmptyDirectoryEntries)
const flat = await toFlatMap(fromXML)
expect(flat.size).toBe(1)
expect(flat.get('some_show.show')).toBe('/storage/shows/{UUID1}')
})
})
43 changes: 21 additions & 22 deletions src/mse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MSE, VizEngine, VPlaylist, VProfile, VRundown, VShow } from './v-connec
import { getPepErrorMessage, LocationType, PepResponse, PepTalkClient, PepTalkJS, startPepTalk } from './peptalk'
import { CommandResult, IHTTPRequestError } from './msehttp'
import { EventEmitter } from 'events'
import { AtomEntry, FlatEntry, flattenEntry } from './xml'
import { AtomEntry, FlatEntry, flattenEntry, toFlatMap } from './xml'
import { Rundown } from './rundown'
import * as uuid from 'uuid'
import { wrapInBracesIfNeeded } from './util'
Expand Down Expand Up @@ -128,6 +128,26 @@ export class MSERep extends EventEmitter implements MSE {
return Object.keys(flatList).filter((x: string) => x !== 'name')
}

async listShowsFromDirectory(): Promise<Map<string, string>> {
await this.checkConnection()
const showList = await this.pep.getJS('/directory/shows')
const flatMap = await toFlatMap(showList.js as AtomEntry)
this.extractShowIdsFromPaths(flatMap)
return flatMap
}

private extractShowIdsFromPaths(flatMap: Map<string, string>) {
for (const [key, value] of flatMap) {
const showId = value.match(/{(.+)}/)
if (!showId) {
// probably some faulty ref
flatMap.delete(key)
} else {
flatMap.set(key, showId[1])
}
}
}

async getShow(showId: string): Promise<VShow> {
showId = wrapInBracesIfNeeded(showId)
if (!UUID_RE.exec(showId)) {
Expand Down Expand Up @@ -292,24 +312,3 @@ export class MSERep extends EventEmitter implements MSE {
export function createMSE(hostname: string, restPort?: number, wsPort?: number, resthost?: string): MSE {
return new MSERep(hostname, restPort, wsPort, resthost)
}

// let sleep = (t: number) => new Promise((resolve, _reject) => {
// setTimeout(resolve, t)
// })
//
// async function run () {
// let mse = createMSE('mse_ws.ngrok.io', 80, 80, 'mse_http.ngrok.io')
// let rundown = await mse.createRundown('66E45216-9476-4BDC-9556-C3DB487ED9DF', 'SOFIE')
// await rundown.createElement(2552305, 'FULL1')
// try { await rundown.activate() } catch (err) { /* */ }
// await sleep(5000)
// console.log('Taking now')
// rundown.take(2552305)
// await rundown.createElement(2565133, 'FULL1')
// await sleep(3000)
// rundown.take(2565133)
// await mse.close()
// // console.log('After close.')
// }
//
// run().catch(console.error)
6 changes: 6 additions & 0 deletions src/v-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,12 @@ export interface MSE extends EventEmitter {
* @returns List of all the shows stored for this MSE.
*/
listShows(): Promise<string[]>
/**
* List the shows in the MSE's directory.
* @returns A map of all the shows in the directory (paths relative to /directory/shows/), and their unique IDs.
* Example entry: ['overlay-shows/sample-show.show', '66E45216-9476-4BDC-9556-C3DB487ED9DF']
*/
listShowsFromDirectory(): Promise<Map<string, string>>
/**
* Retrieve details of a specific show as stored at this MSE.
* @param showId Name of the show to query, a UUID.
Expand Down
25 changes: 25 additions & 0 deletions src/xml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,28 @@ export function buildXML(x: AtomEntry): string {
const builder = new Xml2JS.Builder({ headless: true })
return builder.buildObject({ entry: x })
}

/**
* Build a Map containing paths and their contents
* @param x Source atom pub entry.
* @return a Map where keys are paths, and values are the contents of the entries
*/
export async function toFlatMap(x: AtomEntry): Promise<Map<string, string>> {
const result = new Map<string, string>()
const flatEntry = await flattenEntry(x)
toFlatMapInternal(flatEntry, result, '')
return result
}

function toFlatMapInternal(x: FlatEntry, map: Map<string, string>, path: string) {
for (const key in x) {
if (key === 'name' || x[key] === undefined) continue
if (key === 'value' && typeof x['value'] === 'string') {
map.set(path, x['value'])
return
}
if (typeof x[key] === 'object') {
toFlatMapInternal(x[key] as FlatEntry, map, `${path}${path && '/'}${key}`)
}
}
}

0 comments on commit 76b253f

Please sign in to comment.