<commit_before>/* @flow */
/* global $PropertyType */
import logger from '../util/logger'
import Registry from '../util/registry'
import EmailProvider from './email'
import PushProvider from './push'
import SmsProvider from './sms'
import WebpushProvider from './webpush'
// Types
import type {ChannelType, OptionsType, ProviderStrategyType} from '../index'

type ChannelOptionsType = $PropertyType<OptionsType, 'channels'>

export interface ProviderType {
  id: string;
  send(Object): Promise<string>;
}

type ContextType = {
  attempt?: number
}

export default class ProviderFactory {
  channels: ChannelOptionsType
  lastIndexUsedByChannel: {[ChannelType]: number} = {}

  constructor (channels: ChannelOptionsType) {
    this.channels = channels
  }

  get (channel: ChannelType, {attempt}: ContextType): ?ProviderType {
    const index = Math.max(0, attempt ? attempt - 1 : 0)
    if (this.channels && this.channels[channel]) {
      const channelConfig = this.channels[channel]
      const providerConfig = channelConfig.providers[index]
      if (this.getMultiProviderStrategy(channel) === 'roundrobin') {
        return this.getUsingRoundRobinStrategy(channel, index, channelConfig.providers.length)
      } else if (providerConfig) {
        return this.getProviderByIndex(channel, index)
      } else if (index === 0) {
        return this.getDefaultProvider(channel)
      } else {
        return null
      }
    } else {
      throw new Error(`Unknown channel "${channel}".`)
    }
  }

  getMultiProviderStrategy (channel: ChannelType): ProviderStrategyType {
    let strategy = 'fallback'
    if (this.channels && this.channels[channel]) {
      if (this.channels[channel].providers.length <= 1) {
        strategy = 'no-fallback'
      } else if (this.channels[channel].multiProviderStrategy !== undefined) {
        strategy = this.channels[channel].multiProviderStrategy
      }
    }
    return strategy
  }

  getUsingRoundRobinStrategy (channel: ChannelType, index: number, channelProviderCount: number) {
    const nextIndex = this.lastIndexUsedByChannel[channel] !== undefined
      ? (this.lastIndexUsedByChannel[channel] + 1) % channelProviderCount
      : index
    this.lastIndexUsedByChannel[channel] = nextIndex
    return this.getProviderByIndex(channel, nextIndex)
  }

  getDefaultProvider (channel: ChannelType) {
    return this.getProviderByIndex(channel, 0, 'logger')
  }

  getProviderByIndex (channel: ChannelType, index: number, forceType?: string): ?ProviderType {
    if (this.channels && this.channels[channel]) {
      const providerConfig = this.channels[channel].providers[index]
      const type = forceType || providerConfig.type
      return Registry.getInstance(`${channel}-${type}-${index}`, () => {
        try {
          switch (channel) {
            case 'email':
              return new EmailProvider(type, providerConfig)
            case 'push':
              return new PushProvider(type, providerConfig)
            case 'sms':
              return new SmsProvider(type, providerConfig)
            case 'webpush':
              return new WebpushProvider(type, providerConfig)
          }
        } catch (error) {
          logger.error(error)
          return null
        }
      })
    }
  }
}
<commit_msg>don't throw exception if no provider<commit_after>/* @flow */
/* global $PropertyType */
import logger from '../util/logger'
import Registry from '../util/registry'
import EmailProvider from './email'
import PushProvider from './push'
import SmsProvider from './sms'
import WebpushProvider from './webpush'
// Types
import type {ChannelType, OptionsType, ProviderStrategyType} from '../index'

type ChannelOptionsType = $PropertyType<OptionsType, 'channels'>

export interface ProviderType {
  id: string;
  send(Object): Promise<string>;
}

type ContextType = {
  attempt?: number
}

export default class ProviderFactory {
  channels: ChannelOptionsType
  lastIndexUsedByChannel: {[ChannelType]: number} = {}

  constructor (channels: ChannelOptionsType) {
    this.channels = channels
  }

  get (channel: ChannelType, {attempt}: ContextType): ?ProviderType {
    const index = Math.max(0, attempt ? attempt - 1 : 0)
    if (this.channels && this.channels[channel]) {
      const channelConfig = this.channels[channel]
      const providerConfig = channelConfig.providers[index]
      if (this.getMultiProviderStrategy(channel) === 'roundrobin') {
        return this.getUsingRoundRobinStrategy(channel, index, channelConfig.providers.length)
      } else if (providerConfig) {
        return this.getProviderByIndex(channel, index)
      } else if (index === 0) {
        return this.getDefaultProvider(channel)
      } else {
        return null
      }
    }
  }

  getMultiProviderStrategy (channel: ChannelType): ProviderStrategyType {
    let strategy = 'fallback'
    if (this.channels && this.channels[channel]) {
      if (this.channels[channel].providers.length <= 1) {
        strategy = 'no-fallback'
      } else if (this.channels[channel].multiProviderStrategy !== undefined) {
        strategy = this.channels[channel].multiProviderStrategy
      }
    }
    return strategy
  }

  getUsingRoundRobinStrategy (channel: ChannelType, index: number, channelProviderCount: number) {
    const nextIndex = this.lastIndexUsedByChannel[channel] !== undefined
      ? (this.lastIndexUsedByChannel[channel] + 1) % channelProviderCount
      : index
    this.lastIndexUsedByChannel[channel] = nextIndex
    return this.getProviderByIndex(channel, nextIndex)
  }

  getDefaultProvider (channel: ChannelType) {
    return this.getProviderByIndex(channel, 0, 'logger')
  }

  getProviderByIndex (channel: ChannelType, index: number, forceType?: string): ?ProviderType {
    if (this.channels && this.channels[channel]) {
      const providerConfig = this.channels[channel].providers[index]
      const type = forceType || providerConfig.type
      return Registry.getInstance(`${channel}-${type}-${index}`, () => {
        try {
          switch (channel) {
            case 'email':
              return new EmailProvider(type, providerConfig)
            case 'push':
              return new PushProvider(type, providerConfig)
            case 'sms':
              return new SmsProvider(type, providerConfig)
            case 'webpush':
              return new WebpushProvider(type, providerConfig)
          }
        } catch (error) {
          logger.error(error)
          return null
        }
      })
    }
  }
}

{'fraction_non_alphanumeric': 0.11179455635860372, 'fraction_numerical': 0.002152852529601722, 'mean_word_length': 3.1772639691714835, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3067603', 'n_tokens_mistral': 1766, 'n_tokens_neox': 1728, 'n_words': 433}