Skip to content

Commit

Permalink
feat: add service locator
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzianis Dashkevich committed Sep 24, 2024
1 parent 4558ca0 commit fe583cd
Show file tree
Hide file tree
Showing 11 changed files with 161 additions and 109 deletions.
39 changes: 0 additions & 39 deletions packages/playback/index.html

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { PlayerConfiguration } from '../types/configuration.declarations';
import PlayerConfigurationImpl from './configurationNodes/playerConfigurationNode';
import { Store } from '../utils/store';

export default class ConfigurationManager extends Store<PlayerConfiguration> {
export class ConfigurationManager extends Store<PlayerConfiguration> {
public constructor() {
super(() => PlayerConfigurationImpl.default());
}
Expand Down
2 changes: 1 addition & 1 deletion packages/playback/src/lib/network/networkManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { PlayerNetworkConfiguration } from '../types/configuration.declarat
import type { IEventEmitter } from '../types/eventEmitter.declarations';
import type { NetworkEventMap } from '../types/eventTypeToEventMap.declarations';

interface NetworkManagerDependencies {
export interface NetworkManagerDependencies {
logger: ILogger;
networkInterceptorsProvider: INetworkInterceptorsProvider;
eventEmitter: IEventEmitter<NetworkEventMap>;
Expand Down
57 changes: 23 additions & 34 deletions packages/playback/src/lib/player.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import type { ILogger } from './types/logger.declarations';
import Logger from './utils/logger';
import { LoggerLevel } from './consts/loggerLevel';
import type { PlayerConfiguration } from './types/configuration.declarations';
import type { IStore } from './types/store.declarations';
import ConfigurationManager from './configuration/configurationManager';
import type { DeepPartial } from './types/utility.declarations';
import type { EventListener, IEventEmitter } from './types/eventEmitter.declarations';
import type { EventTypeToEventMap } from './types/eventTypeToEventMap.declarations';
import EventEmitter from './utils/eventEmitter';
import { PlayerEventType } from './consts/events';
import {
ConfigurationChangedEvent,
Expand All @@ -17,7 +14,6 @@ import {
VolumeChangedEvent,
} from './events/playerEvents';
import type { CapabilitiesProbeResult, IEnvCapabilitiesProvider } from './types/envCapabilities.declarations';
import EnvCapabilitiesProvider from './utils/envCapabilities';
import type { ILoadLocalSource, ILoadRemoteSource, ISourceModel } from './types/source.declarations';
import type { IPipeline, IPipelineFactory } from './types/pipeline.declarations';
import type PlayerTimeRange from './utils/timeRanges';
Expand All @@ -27,17 +23,16 @@ import type { IAudioTrack } from './types/tracks.declarations';
import { NoSupportedPipelineError } from './errors/pipelineErrors';
import { Source } from './utils/source';
import type { INetworkManager } from './types/network.declarations';
import { NetworkManager } from './network/networkManager';
import { InterceptorsStorage } from './utils/interceptorsStorage';
import { InterceptorType } from './consts/interceptorType';
import type { InterceptorTypeToInterceptorMap } from './types/interceptorTypeToInterceptorMap.declarations';
import type { IInterceptorsStorage } from './types/interceptors.declarations';
import { ServiceLocator } from './serviceLocator';

interface PlayerDependencies {
logger?: ILogger;
configurationManager?: IStore<PlayerConfiguration>;
eventEmitter?: IEventEmitter<EventTypeToEventMap>;
envCapabilitiesProvider?: IEnvCapabilitiesProvider;
networkManager?: INetworkManager;
readonly logger: ILogger;
readonly interceptorsStorage: IInterceptorsStorage;
readonly configurationManager: IStore<PlayerConfiguration>;
readonly eventEmitter: IEventEmitter<EventTypeToEventMap>;
readonly envCapabilitiesProvider: IEnvCapabilitiesProvider;
readonly networkManager: INetworkManager;
}

interface VersionInfo {
Expand All @@ -58,6 +53,10 @@ export class Player {
public static LoggerLevel = LoggerLevel;
public static Event = PlayerEventType;

public static create(): Player {
return new Player(new ServiceLocator());
}

/**
* MARK: Private Properties
*/
Expand All @@ -77,30 +76,20 @@ export class Player {
private readonly eventEmitter_: IEventEmitter<EventTypeToEventMap>;
private readonly envCapabilitiesProvider_: IEnvCapabilitiesProvider;
private readonly networkManager_: INetworkManager;
private readonly interceptorsStorage_: InterceptorsStorage;
private readonly interceptorsStorage_: IInterceptorsStorage;

/**
* You can pass your own implementations via dependencies.
* - Pass your own logger, you have to implement ILogger interface.
* @param dependencies - optional dependencies
*/
public constructor(dependencies: PlayerDependencies = {}) {
this.interceptorsStorage_ = new InterceptorsStorage();
this.logger_ = dependencies.logger ?? new Logger(console, 'Player');
this.configurationManager_ = dependencies.configurationManager ?? new ConfigurationManager();
this.eventEmitter_ = dependencies.eventEmitter ?? new EventEmitter<EventTypeToEventMap>();
this.envCapabilitiesProvider_ = dependencies.envCapabilitiesProvider ?? new EnvCapabilitiesProvider();
this.networkManager_ =
dependencies.networkManager ??
new NetworkManager({
logger: this.logger_.createSubLogger('NetworkManager'),
eventEmitter: this.eventEmitter_,
configuration: this.configurationManager_.getSnapshot().network,
networkInterceptorsProvider: {
getNetworkRequestInterceptors: (): Set<InterceptorTypeToInterceptorMap[InterceptorType.NetworkRequest]> =>
this.interceptorsStorage_.getInterceptorsSet(InterceptorType.NetworkRequest),
},
});
* @param dependencies - player dependencies
*/
public constructor(dependencies: PlayerDependencies) {
this.interceptorsStorage_ = dependencies.interceptorsStorage;
this.logger_ = dependencies.logger;
this.configurationManager_ = dependencies.configurationManager;
this.eventEmitter_ = dependencies.eventEmitter;
this.envCapabilitiesProvider_ = dependencies.envCapabilitiesProvider;
this.networkManager_ = dependencies.networkManager;
}

/**
Expand All @@ -110,7 +99,7 @@ export class Player {
/**
* interceptors storage getter
*/
public getInterceptorsStorage(): InterceptorsStorage {
public getInterceptorsStorage(): IInterceptorsStorage {
return this.interceptorsStorage_;
}

Expand Down
77 changes: 77 additions & 0 deletions packages/playback/src/lib/serviceLocator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Interfaces:
import type { ILogger } from './types/logger.declarations';
import type { LoggerDependencies } from './utils/logger';
import type { IInterceptorsStorage } from './types/interceptors.declarations';
import type { PlayerConfiguration } from './types/configuration.declarations';
import type { IStore } from './types/store.declarations';
import type { IEventEmitter } from './types/eventEmitter.declarations';
import type { EventTypeToEventMap } from './types/eventTypeToEventMap.declarations';
import type { IEnvCapabilitiesProvider } from './types/envCapabilities.declarations';
import type { INetworkManager } from './types/network.declarations';
import type { InterceptorTypeToInterceptorMap } from './types/interceptorTypeToInterceptorMap.declarations';
import type { NetworkManagerDependencies } from './network/networkManager';

// Implementations
import { Logger } from './utils/logger';
import { InterceptorsStorage } from './utils/interceptorsStorage';
import { ConfigurationManager } from './configuration/configurationManager';
import { EventEmitter } from './utils/eventEmitter';
import { EnvCapabilitiesProvider } from './utils/envCapabilities';
import { NetworkManager } from './network/networkManager';
import { InterceptorType } from './consts/interceptorType';

export class ServiceLocator {
public readonly logger: ILogger;
public readonly interceptorsStorage: IInterceptorsStorage;
public readonly configurationManager: IStore<PlayerConfiguration>;
public readonly eventEmitter: IEventEmitter<EventTypeToEventMap>;
public readonly envCapabilitiesProvider: IEnvCapabilitiesProvider;
public readonly networkManager: INetworkManager;

public constructor() {
const { console } = window;

this.configurationManager = this.createConfigurationManager_();

const configuration = this.configurationManager.getSnapshot();

this.logger = this.createLogger_({ console, label: 'Player', delimiter: '>' });

this.interceptorsStorage = this.createInterceptorsStorage_();
this.eventEmitter = this.createEventEmitter_();
this.envCapabilitiesProvider = this.createEnvCapabilitiesProvider_();
this.networkManager = this.createNetworkManager_({
logger: this.logger.createSubLogger('NetworkManager'),
eventEmitter: this.eventEmitter,
configuration: configuration.network,
networkInterceptorsProvider: {
getNetworkRequestInterceptors: (): Set<InterceptorTypeToInterceptorMap[InterceptorType.NetworkRequest]> =>
this.interceptorsStorage.getInterceptorsSet(InterceptorType.NetworkRequest),
},
});
}

protected createLogger_(dependencies: LoggerDependencies): ILogger {
return new Logger(dependencies);
}

protected createInterceptorsStorage_(): IInterceptorsStorage {
return new InterceptorsStorage();
}

protected createConfigurationManager_(): IStore<PlayerConfiguration> {
return new ConfigurationManager();
}

protected createEventEmitter_(): IEventEmitter<EventTypeToEventMap> {
return new EventEmitter<EventTypeToEventMap>();
}

protected createEnvCapabilitiesProvider_(): IEnvCapabilitiesProvider {
return new EnvCapabilitiesProvider();
}

protected createNetworkManager_(dependencies: NetworkManagerDependencies): INetworkManager {
return new NetworkManager(dependencies);
}
}
13 changes: 13 additions & 0 deletions packages/playback/src/lib/types/interceptors.declarations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { InterceptorType } from '../consts/interceptorType';
import type { InterceptorTypeToInterceptorMap } from './interceptorTypeToInterceptorMap.declarations';

export interface IInterceptorsStorage {
addInterceptor<K extends InterceptorType>(interceptorType: K, interceptor: InterceptorTypeToInterceptorMap[K]): void;
removeInterceptor<K extends InterceptorType>(
interceptorType: K,
interceptor: InterceptorTypeToInterceptorMap[K]
): void;
getInterceptorsSet<K extends InterceptorType>(interceptorType: K): Set<InterceptorTypeToInterceptorMap[K]>;
removeAllInterceptorsForType<K extends InterceptorType>(interceptorType: K): void;
removeAllInterceptors(): void;
}
2 changes: 1 addition & 1 deletion packages/playback/src/lib/utils/envCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const persistentEmeConfig = {
sessionTypes: ['persistent-license'],
};

export default class EnvCapabilitiesProvider implements IEnvCapabilitiesProvider {
export class EnvCapabilitiesProvider implements IEnvCapabilitiesProvider {
private cache_: CapabilitiesProbeResult | null = null;

public async probe(): Promise<CapabilitiesProbeResult> {
Expand Down
2 changes: 1 addition & 1 deletion packages/playback/src/lib/utils/eventEmitter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { IEventEmitter, EventListener } from '../types/eventEmitter.declarations';

export default class EventEmitter<M> implements IEventEmitter<M> {
export class EventEmitter<M> implements IEventEmitter<M> {
private events_ = new Map<keyof M, Set<EventListener<unknown>>>();

public addEventListener<K extends keyof M>(event: K, eventListener: EventListener<M[K]>): void {
Expand Down
3 changes: 2 additions & 1 deletion packages/playback/src/lib/utils/interceptorsStorage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { InterceptorType } from '../consts/interceptorType';
import type { InterceptorTypeToInterceptorMap } from '../types/interceptorTypeToInterceptorMap.declarations';
import type { IInterceptorsStorage } from '../types/interceptors.declarations';

export class InterceptorsStorage {
export class InterceptorsStorage implements IInterceptorsStorage {
private readonly storage_ = new Map<InterceptorType, Set<InterceptorTypeToInterceptorMap[InterceptorType]>>();

public addInterceptor<K extends InterceptorType>(
Expand Down
22 changes: 17 additions & 5 deletions packages/playback/src/lib/utils/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,31 @@ import type { ILogger } from '../types/logger.declarations';

const style = 'background: #333; padding: 3px; color: #bada55';

export default class Logger implements ILogger {
export interface LoggerDependencies {
console: Console;
label: string;
delimiter: string;
}

export class Logger implements ILogger {
private readonly console_: Console;
private readonly label_: string;
private readonly delimiter_: string;

private level_: LoggerLevel = LoggerLevel.Debug;

public constructor(console: Console, label: string) {
this.console_ = console;
this.label_ = `%c${label}`;
public constructor(dependencies: LoggerDependencies) {
this.console_ = dependencies.console;
this.label_ = `%c${dependencies.label}`;
this.delimiter_ = dependencies.delimiter;
}

public createSubLogger(subLabel: string): Logger {
return new Logger(this.console_, this.label_ + ' > ' + subLabel);
return new Logger({
console: this.console_,
label: `${this.label_} ${this.delimiter_} ${subLabel}`,
delimiter: this.delimiter_,
});
}

public setLoggerLevel(level: LoggerLevel): void {
Expand Down
Loading

0 comments on commit fe583cd

Please sign in to comment.