UNPKG

@tvkitchen/countertop

Version:

The entry point for developers who want to set up a TV Kitchen.

122 lines (113 loc) 4.49 kB
import CountertopStream from './CountertopStream' import { getCollectiveOutputTypes, getStationsThatConsumeTypes, getLongestStreamLength, filterStreamsContainingStation, generateTributaryMaps, getStreamOutputMap, getSourceStations, identifyObsoleteStreams, pruneStreams, } from '../tools/utils/countertop' /** * CountertopToplogies are a complete set of valid *paths* that data might take across a given * array of CountertopStations. * * The distinction of paths (as opposed to edges / direct steps) is important, as a given payload * will have a source, and only payloads with a common source should be considered together in * the case of dual-input appliances. * * In many data processing pipelines, topologies need to be manually specified by the developer * configuring the system. In this case, the topologies are automatically generated based on which * appliances produce outputs that are valid inputs to others. * * The logic for generating a CountertopTopology starts in the static `generateStreams` method. */ class CountertopTopology { stations = [] streams = [] /** * Create a CountertopTopology. * * @param {CountertopStation[]} stations The stations used to define the topology. */ constructor(stations = []) { this.stations = stations this.streams = CountertopTopology.generateStreams(this.stations) } /** * Extend a set of streams by a single station. * * This will only create streams that pull from the same source. * This will generate and return any valid streams that extend a given stream set. * This will ONLY return new streams, which means if no valid streams extensions exist, it will * return an empty array. * This will not create streams that re-visit a given station (no loops). * * @param {CountertopStream[]} streams The set of streams to be extended. * @param {CountertopStation[]} station The station being used to extend. * @return {CountertopStream[]} The extended streams. */ static extendStreamsByStation = (streams, station) => { const streamOutputMap = getStreamOutputMap( filterStreamsContainingStation(streams), ) const tributaryMaps = generateTributaryMaps( station, streamOutputMap, ) return tributaryMaps.map( (tributaryMap) => new CountertopStream(station, tributaryMap), ) } /** * Fully extends a set of streams to flow through a set of new stations. * * This will only create streams that pull from the same source. * This will not create streams that re-visit a given station (no loops). * This will create distinct streams for incremental steps from a source (e.g. A->B, and A->B->C). * * @param {CountertopStream[]} streams The base set of streams being extended. * @param {CountertopStation[]} stations The stations being used to extend the streams. * @return {CountertopStream[]} The complete set of streams. */ static generateStreams = (stations, streams = []) => { let nextStreams = [] if (streams.length === 0) { nextStreams = CountertopTopology.generateSourceStreams(stations) } else { const extentionLength = 1 + getLongestStreamLength(streams) const outputTypes = getCollectiveOutputTypes(streams) const nextStations = getStationsThatConsumeTypes(stations, outputTypes) nextStreams = nextStations.flatMap( (station) => CountertopTopology.extendStreamsByStation(streams, station), ) // Remove any new streams that aren't long enough .filter((stream) => stream.getLength() === extentionLength) } // Prune any past streams whose tributaries are explicit subsets of new streams const obsoleteStreams = identifyObsoleteStreams(streams, nextStreams) const prunedStreams = pruneStreams(streams, obsoleteStreams) const prunedNextStreams = pruneStreams(nextStreams, obsoleteStreams) // If there were any new streams, iterate again if (prunedNextStreams.length !== 0) { return CountertopTopology.generateStreams( stations, prunedStreams.concat(prunedNextStreams), ) } return prunedStreams } /** * Generates streams that only include source stations. * * These streams will, by defintiion, be of length 1. * * @param {CountertopStations[]} stations The stations to be processed. * @return {CountertopStreams[]} The resulting streams. */ static generateSourceStreams = (stations) => getSourceStations(stations) .map((station) => new CountertopStream(station)) } export default CountertopTopology