Skip to content

Commit

Permalink
fix: add PromperSettingsService and ViewPortService
Browse files Browse the repository at this point in the history
  • Loading branch information
nytamin committed Dec 6, 2023
1 parent e830031 commit 20b9604
Show file tree
Hide file tree
Showing 46 changed files with 1,014 additions and 231 deletions.
7 changes: 7 additions & 0 deletions packages/apps/backend/src/api-server/ApiServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { PartFeathersService, PartService } from './services/PartService.js'
import { ExampleFeathersService, ExampleService } from './services/ExampleService.js'
import { Store } from '../data-stores/Store.js'
import { SofieCoreConnection } from '../sofie-core-connection/SofieCoreConnection.js'
import { ViewPortFeathersService, ViewPortService } from './services/ViewPortService.js'
import { PrompterSettingsFeathersService, PrompterSettingsService } from './services/PrompterSettingsService.js'

export type ApiServerEvents = {
connection: []
Expand All @@ -25,6 +27,8 @@ export class ApiServer extends EventEmitter<ApiServerEvents> {
public readonly segment: SegmentFeathersService
public readonly part: PartFeathersService
public readonly example: ExampleFeathersService
public readonly viewPort: ViewPortFeathersService
public readonly prompterSettings: PrompterSettingsFeathersService

private log: LoggerInstance
constructor(
Expand Down Expand Up @@ -54,6 +58,9 @@ export class ApiServer extends EventEmitter<ApiServerEvents> {
this.segment = SegmentService.setupService(this.log, this.app, this.store)
this.part = PartService.setupService(this.log, this.app, this.store)

this.viewPort = ViewPortService.setupService(this.log, this.app, this.store)
this.prompterSettings = PrompterSettingsService.setupService(this.log, this.app, this.store)

this.example = ExampleService.setupService(this.app)

this.app.on('connection', (connection: RealTimeConnection) => {
Expand Down
27 changes: 22 additions & 5 deletions packages/apps/backend/src/api-server/PublishChannels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,33 @@ export const PublishChannels = {
return `example-category/${category}`
},

/** List of RundownPlaylists */
AllPlaylists: (): string => {
return `playlists`
},

/** All info inside one playlist */
Playlist: (playlistId: RundownPlaylistId): string => {
return `playlist/${playlistId}`
},

/**
* ALL data inside of a RundownPlaylist
* Such as
* * Rundowns
* * Segments
* * Parts
*/
RundownsInPlaylist: (playlistId: RundownPlaylistId): string => {
return `playlist/${playlistId}/rundowns`
},

/**
* Data for the Controller
*/
Controller: (): string => {
return `controller`
},

/**
* Data for the ViewPort
*/
ViewPort: (): string => {
return `viewport`
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class PartService extends EventEmitter<Definition.Events> implements Defi
}
public async get(id: Id, _params?: Params): Promise<Data> {
const data = this.store.parts.parts.get(id)
if (!data) throw new NotFound(`Rundown "${id}" not found`)
if (!data) throw new NotFound(`Part "${id}" not found`)
return data
}
/** @deprecated not supported */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ export class PlaylistService extends EventEmitter<Definition.Events> implements
service.publish('removed', (_data, _context) => {
return app.channel(PublishChannels.AllPlaylists())
})

service.publish('created', (data, _context) => {
return app.channel(PublishChannels.Playlist(data._id))
})
}

private observers: Lambda[] = []
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import EventEmitter from 'eventemitter3'
import { Application, PaginationParams, Params } from '@feathersjs/feathers'
import {
ServiceTypes,
Services,
PrompterSettingsServiceDefinition as Definition,
} from '@sofie-prompter-editor/shared-model'
export { PlaylistServiceDefinition } from '@sofie-prompter-editor/shared-model'
import { PublishChannels } from '../PublishChannels.js'
import { CustomFeathersService } from './lib.js'
import { Store } from '../../data-stores/Store.js'
import { Lambda, observe } from 'mobx'
import { LoggerInstance } from '../../lib/logger.js'
import { BadRequest, NotFound, NotImplemented } from '@feathersjs/errors'

export type PrompterSettingsFeathersService = CustomFeathersService<Definition.Service, Definition.Events>

/** The methods exposed by this class are exposed in the API */
export class PrompterSettingsService extends EventEmitter<Definition.Events> implements Definition.Service {
static setupService(
log: LoggerInstance,
app: Application<ServiceTypes, any>,
store: Store
): PrompterSettingsFeathersService {
app.use(
Services.PrompterSettings,
new PrompterSettingsService(log.category('PrompterSettingsService'), app, store),
{
methods: Definition.ALL_METHODS,
serviceEvents: Definition.ALL_EVENTS,
}
)
const service = app.service(Services.PrompterSettings) as PrompterSettingsFeathersService
this.setupPublications(app, service)
return service
}
private static setupPublications(app: Application<ServiceTypes, any>, service: PrompterSettingsFeathersService) {
service.publish('created', (_data, _context) => {
return app.channel(PublishChannels.Controller())
})
service.publish('updated', (_data, _context) => {
return app.channel(PublishChannels.Controller())
})
}

private observers: Lambda[] = []
constructor(private log: LoggerInstance, private app: Application<ServiceTypes, any>, private store: Store) {
super()

this.observers.push(
observe(this.store.prompterSettings.prompterSettings, (change) => {
this.log.debug('observed change', change)

if (change.type === 'add') {
this.emit('created', change.newValue)
} else if (change.type === 'update') {
this.emit('updated', change.newValue)
}
})
)
}
destroy() {
// dispose of observers:
for (const obs of this.observers) {
obs()
}
}

public async find(_params?: Params & { paginate?: PaginationParams }): Promise<Data[]> {
return [this.store.prompterSettings.prompterSettings]
}
public async get(id: Id, _params?: Params): Promise<Data> {
const data = this.store.prompterSettings.prompterSettings
if (!data) throw new NotFound(`PrompterSettings "${id}" not found`)
return data
}
public async create(_data: Data, _params?: Params): Promise<Result> {
throw new NotImplemented(`TODO`)
}
public async update(id: NullId, data: Data, _params?: Params): Promise<Result> {
if (id === null) throw new BadRequest(`id must not be null`)

this.store.prompterSettings.update(data)
return this.get('')
}

public async subscribeToController(_: unknown, params: Params): Promise<void> {
if (!params.connection) throw new Error('No connection!')
this.app.channel(PublishChannels.Controller()).join(params.connection)
}
}
type Result = Definition.Result
type Id = Definition.Id
type NullId = Definition.NullId
type Data = Definition.Data
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
RundownServiceDefinition as Definition,
RundownPlaylistId,
} from '@sofie-prompter-editor/shared-model'
export { PlaylistServiceDefinition } from '@sofie-prompter-editor/shared-model'
import { PublishChannels } from '../PublishChannels.js'
import { CustomFeathersService } from './lib.js'
import { Store } from '../../data-stores/Store.js'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import EventEmitter from 'eventemitter3'
import { Application, PaginationParams, Params } from '@feathersjs/feathers'
import { ServiceTypes, Services, SegmentServiceDefinition as Definition } from '@sofie-prompter-editor/shared-model'
export { PlaylistServiceDefinition } from '@sofie-prompter-editor/shared-model'
import { PublishChannels } from '../PublishChannels.js'
import { CustomFeathersService } from './lib.js'
import { Store } from '../../data-stores/Store.js'
Expand Down Expand Up @@ -73,7 +72,7 @@ export class SegmentService extends EventEmitter<Definition.Events> implements D
}
public async get(id: Id, _params?: Params): Promise<Data> {
const data = this.store.segments.segments.get(id)
if (!data) throw new NotFound(`Rundown "${id}" not found`)
if (!data) throw new NotFound(`Segment "${id}" not found`)
return data
}
/** @deprecated not supported */
Expand Down
92 changes: 92 additions & 0 deletions packages/apps/backend/src/api-server/services/ViewPortService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import EventEmitter from 'eventemitter3'
import { Application, PaginationParams, Params } from '@feathersjs/feathers'
import { ServiceTypes, Services, ViewPortServiceDefinition as Definition } from '@sofie-prompter-editor/shared-model'
import { PublishChannels } from '../PublishChannels.js'
import { CustomFeathersService } from './lib.js'
import { Store } from '../../data-stores/Store.js'
import { Lambda, observe } from 'mobx'
import { LoggerInstance } from '../../lib/logger.js'
import { BadRequest, NotFound } from '@feathersjs/errors'

export type ViewPortFeathersService = CustomFeathersService<Definition.Service, Definition.Events>

/** The methods exposed by this class are exposed in the API */
export class ViewPortService extends EventEmitter<Definition.Events> implements Definition.Service {
static setupService(log: LoggerInstance, app: Application<ServiceTypes, any>, store: Store): ViewPortFeathersService {
app.use(Services.ViewPort, new ViewPortService(log.category('ViewPortService'), app, store), {
methods: Definition.ALL_METHODS,
serviceEvents: Definition.ALL_EVENTS,
})
const service = app.service(Services.ViewPort) as ViewPortFeathersService
this.setupPublications(app, service)
return service
}
private static setupPublications(app: Application<ServiceTypes, any>, service: ViewPortFeathersService) {
service.publish('created', (_data, _context) => {
return app.channel(PublishChannels.ViewPort())
})
service.publish('updated', (_data, _context) => {
return app.channel(PublishChannels.ViewPort())
})
service.publish('removed', (_data, _context) => {
return app.channel(PublishChannels.ViewPort())
})
}

private observers: Lambda[] = []
constructor(private log: LoggerInstance, private app: Application<ServiceTypes, any>, private store: Store) {
super()

this.observers.push(
observe(this.store.viewPort.viewPort, (change) => {
this.log.debug('observed change', change)

if (change.type === 'add') {
this.emit('created', change.newValue)
} else if (change.type === 'update') {
this.emit('updated', change.newValue)
} else if (change.type === 'remove') {
this.emit('removed', {
_id: change.oldValue._id,
})
}
})
)
}
destroy() {
// dispose of observers:
for (const obs of this.observers) {
obs()
}
}

public async find(_params?: Params & { paginate?: PaginationParams }): Promise<Data[]> {
return [this.store.viewPort.viewPort]
}
public async get(id: Id, _params?: Params): Promise<Data> {
const data = this.store.viewPort.viewPort
if (!data) throw new NotFound(`ViewPort "${id}" not found`)
return data
}
public async update(id: NullId, data: Data, _params?: Params): Promise<Result> {
if (id === null) throw new BadRequest(`id must not be null`)
if (id !== data._id) throw new BadRequest(`Cannot change id of ViewPort`)

this.store.viewPort.update(data)
return this.get(data._id)
}

public async registerInstance(instanceId: string, _params?: Params): Promise<boolean> {
return this.store.viewPort.registerInstance(instanceId)
}

public async subscribeToViewPort(_: unknown, params: Params): Promise<void> {
if (!params.connection) throw new Error('No connection!')
this.app.channel(PublishChannels.ViewPort()).join(params.connection)
}
}

type Result = Definition.Result
type Id = Definition.Id
type NullId = Definition.NullId
type Data = Definition.Data
1 change: 0 additions & 1 deletion packages/apps/backend/src/data-stores/PartStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import isEqual from 'lodash.isequal'
import { Part, PartId } from 'packages/shared/model/dist'

export class PartStore {
ready: boolean = false
public readonly parts = observable.map<PartId, Part>()

constructor() {
Expand Down
1 change: 0 additions & 1 deletion packages/apps/backend/src/data-stores/PlaylistStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import isEqual from 'lodash.isequal'
import { RundownPlaylist, RundownPlaylistId } from 'packages/shared/model/dist'

export class PlaylistStore {
ready: boolean = false
public readonly playlists = observable.map<RundownPlaylistId, RundownPlaylist>()

constructor() {
Expand Down
39 changes: 39 additions & 0 deletions packages/apps/backend/src/data-stores/PrompterSettingsStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { action, makeAutoObservable, observable } from 'mobx'
import isEqual from 'lodash.isequal'
import { PrompterSettings } from 'packages/shared/model/dist'

export class PrompterSettingsStore {
public prompterSettings = observable<PrompterSettings>({
// TODO: load these from persistent store upon startup?
fontSize: 10,

mirrorHorizontally: false,
mirrorVertically: false,

focusPosition: 'center',
showFocusPosition: false,

marginHorizontal: 5,
marginVertical: 5,
})

constructor() {
makeAutoObservable(this, {
create: action,
update: action,
})
}

create(part: PrompterSettings) {
this._updateIfChanged(part)
}
update(part: PrompterSettings) {
this._updateIfChanged(part)
}

private _updateIfChanged(prompterSettings: PrompterSettings) {
if (!isEqual(this.prompterSettings, prompterSettings)) {
this.prompterSettings = prompterSettings
}
}
}
1 change: 0 additions & 1 deletion packages/apps/backend/src/data-stores/RundownStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import isEqual from 'lodash.isequal'
import { Rundown, RundownId } from 'packages/shared/model/dist'

export class RundownStore {
ready: boolean = false
public readonly rundowns = observable.map<RundownId, Rundown>()

constructor() {
Expand Down
1 change: 0 additions & 1 deletion packages/apps/backend/src/data-stores/SegmentStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import isEqual from 'lodash.isequal'
import { Segment, SegmentId } from 'packages/shared/model/dist'

export class SegmentStore {
ready: boolean = false
public readonly segments = observable.map<SegmentId, Segment>()

constructor() {
Expand Down
4 changes: 4 additions & 0 deletions packages/apps/backend/src/data-stores/Store.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { PartStore } from './PartStore.js'
import { PlaylistStore } from './PlaylistStore.js'
import { PrompterSettingsStore } from './PrompterSettingsStore.js'
import { RundownStore } from './RundownStore.js'
import { SegmentStore } from './SegmentStore.js'
import { ViewPortStore } from './ViewPortStore.js'

export class Store {
public playlists = new PlaylistStore()
public rundowns = new RundownStore()
public segments = new SegmentStore()
public parts = new PartStore()
public viewPort = new ViewPortStore()
public prompterSettings = new PrompterSettingsStore()
}
Loading

0 comments on commit 20b9604

Please sign in to comment.