Esempio n. 1
0
    class CONFIG_CLASS(BaseWorker.CONFIG_CLASS):
        worker_name = ConfigText(
            'Name of the this message store resource worker',
            required=True,
            static=True)
        twisted_endpoint = ConfigServerEndpoint(
            'Twisted endpoint to listen on.',
            required=True,
            static=True,
            fallbacks=[ServerEndpointFallback()])
        web_path = ConfigText('The path to serve this resource on.',
                              required=True,
                              static=True)
        health_path = ConfigText('The path to serve the health resource on.',
                                 default='/health/',
                                 static=True)
        riak_manager = ConfigDict('Riak client configuration.',
                                  default={},
                                  static=True)
        redis_manager = ConfigDict('Redis client configuration.',
                                   default={},
                                   static=True)

        # TODO: Deprecate these fields when confmodel#5 is done.
        host = ConfigText(
            "*DEPRECATED* 'host' and 'port' fields may be used in place of"
            " the 'twisted_endpoint' field.",
            static=True)
        port = ConfigInt(
            "*DEPRECATED* 'host' and 'port' fields may be used in place of"
            " the 'twisted_endpoint' field.",
            static=True)
Esempio n. 2
0
 class CONFIG_CLASS(BaseWorker.CONFIG_CLASS):
     deadline = ConfigInt(
         "Check-in deadline for participating workers",
         required=True, static=True)
     redis_manager = ConfigDict(
         "Redis client configuration.",
         required=True, static=True)
     monitored_systems = ConfigDict(
         "Tree of systems and workers.",
         required=True, static=True)
Esempio n. 3
0
 class CONFIG_CLASS(BaseWorker.CONFIG_CLASS):
     worker_name = ConfigText(
         "Name of this Go API worker.", required=True, static=True)
     twisted_endpoint = ConfigServerEndpoint(
         "Twisted endpoint to listen on.", required=True, static=True)
     web_path = ConfigText(
         "The path to serve this resource on.", required=True, static=True)
     health_path = ConfigText(
         "The path to server the health resource on.", default='/health/',
         static=True)
     redis_manager = ConfigDict(
         "Redis client configuration.", default={}, static=True)
     riak_manager = ConfigDict(
         "Riak client configuration.", default={}, static=True)
Esempio n. 4
0
class ConversationApiWorkerConfig(BaseWorker.CONFIG_CLASS):
    worker_name = ConfigText(
        "Name of this tagpool API worker.", required=True, static=True)
    web_path = ConfigText(
        "The path to serve this resource on.", required=True, static=True)
    web_port = ConfigInt(
        "The port to server this resource on.", required=True, static=True)
    health_path = ConfigText(
        "The path to server the health resource on.", default='/health/',
        static=True)
    redis_manager = ConfigDict(
        "Redis client configuration.", default={}, static=True)
    riak_manager = ConfigDict(
        "Riak client configuration.", default={}, static=True)
Esempio n. 5
0
class JsBoxConfig(JsSandbox.CONFIG_CLASS, GoApplicationConfigMixin):
    jsbox_app_config = ConfigDict(
        "Custom configuration passed to the javascript code.", default={})
    jsbox = ConfigDict(
        "Must have 'javascript' field containing JavaScript code to run.")

    @property
    def javascript(self):
        if not self.jsbox:
            return None
        return self.jsbox['javascript']

    @property
    def sandbox_id(self):
        return self.conversation.user_account.key
Esempio n. 6
0
class MxitTransportConfig(HttpRpcTransport.CONFIG_CLASS):

    client_id = ConfigText('The OAuth2 ClientID assigned to this transport.',
                           required=True,
                           static=True)
    client_secret = ConfigText(
        'The OAuth2 ClientSecret assigned to this transport.',
        required=True,
        static=True)
    timeout = ConfigInt('Timeout for outbound Mxit HTTP API calls.',
                        required=False,
                        default=30,
                        static=True)
    redis_manager = ConfigDict('How to connect to Redis',
                               required=True,
                               static=True)
    api_send_url = ConfigText('The URL for the Mxit message sending API.',
                              required=False,
                              default="https://api.mxit.com/message/send/",
                              static=True)
    api_auth_url = ConfigText('The URL for the Mxit authentication API.',
                              required=False,
                              default='https://auth.mxit.com',
                              static=True)
    api_auth_scopes = ConfigList('The list of scopes to request access to.',
                                 required=False,
                                 static=True,
                                 default=['message/send'])
Esempio n. 7
0
class MessageForwardingConfig(ApplicationConfig):
    '''Config for MessageForwardingWorker application worker'''

    mo_message_url = ConfigText(
        "The URL to send HTTP POST requests to for MO messages",
        default=None,
        static=True)

    message_queue = ConfigText("The AMQP queue to forward messages on",
                               default=None,
                               static=True)

    redis_manager = ConfigDict("Redis config.", required=True, static=True)

    inbound_ttl = ConfigInt(
        "Maximum time (in seconds) allowed to reply to messages",
        required=True,
        static=True)

    outbound_ttl = ConfigInt(
        "Maximum time (in seconds) allowed for events to arrive for messages",
        required=True,
        static=True)

    metric_window = ConfigFloat(
        "Size of the buckets to use (in seconds) for metrics",
        required=True,
        static=True)
Esempio n. 8
0
class TruteqTransportConfig(Transport.CONFIG_CLASS):
    username = ConfigText(
        'Username of the TruTeq account to connect to.', static=True)
    password = ConfigText(
        'Password for the TruTeq account.', static=True)
    twisted_endpoint = ConfigClientEndpoint(
        'The endpoint to connect to.',
        default='tcp:host=sms.truteq.com:port=50008', static=True,
        fallbacks=[ClientEndpointFallback()])
    link_check_period = ConfigInt(
        'Number of seconds between link checks sent to the server.',
        default=60, static=True)
    ussd_session_lifetime = ConfigInt(
        'Maximum number of seconds to retain USSD session information.',
        default=300, static=True)
    debug = ConfigBool(
        'Print verbose log output.', default=False, static=True)
    redis_manager = ConfigDict(
        'How to connect to Redis.', default={}, static=True)

    # TODO: Deprecate these fields when confmodel#5 is done.
    host = ConfigText(
        "*DEPRECATED* 'host' and 'port' fields may be used in place of the"
        " 'twisted_endpoint' field.", static=True)
    port = ConfigInt(
        "*DEPRECATED* 'host' and 'port' fields may be used in place of the"
        " 'twisted_endpoint' field.", static=True)
Esempio n. 9
0
class SequentialSendConfig(GoApplicationWorker.CONFIG_CLASS):
    poll_interval = ConfigInt(
        "Interval between polling watched conversations for scheduled events.",
        default=60,
        static=True)

    schedule = ConfigDict("Scheduler config.")
    messages = ConfigList("List of messages to send in sequence")
Esempio n. 10
0
class HttpApiConfig(HttpRpcTransport.CONFIG_CLASS):
    "HTTP API configuration."
    reply_expected = ConfigBool(
        "True if a reply message is expected.", default=False, static=True)
    allowed_fields = ConfigList(
        "The list of fields a request is allowed to contain. Defaults to the"
        " DEFAULT_ALLOWED_FIELDS class attribute.", static=True)
    field_defaults = ConfigDict(
        "Default values for fields not sent by the client.",
        default={}, static=True)
Esempio n. 11
0
class DeliverShortMessageProcessorConfig(Config):
    data_coding_overrides = ConfigDict(
        "Overrides for data_coding character set mapping. This is useful for "
        "setting the default encoding (0), adding additional undefined "
        "encodings (such as 4 or 8) or overriding encodings in cases where "
        "the SMSC is violating the spec (which happens a lot). Keys should "
        "be integers, values should be strings containing valid Python "
        "character encoding names.",
        default={},
        static=True)
Esempio n. 12
0
class HangmanConfig(ApplicationWorker.CONFIG_CLASS):
    "Hangman worker config."
    worker_name = ConfigText("Name of this hangman worker.",
                             required=True,
                             static=True)
    redis_manager = ConfigDict("Redis client configuration.",
                               default={},
                               static=True)

    random_word_url = ConfigText("URL to GET a random word from.",
                                 required=True)
Esempio n. 13
0
class VumiBridgeTransportConfig(Transport.CONFIG_CLASS):
    account_key = ConfigText('The account key to connect with.',
                             static=True,
                             required=True)
    conversation_key = ConfigText('The conversation key to use.',
                                  static=True,
                                  required=True)
    access_token = ConfigText('The access token for the conversation key.',
                              static=True,
                              required=True)
    base_url = ConfigText('The base URL for the API',
                          static=True,
                          default='https://go.vumi.org/api/v1/go/http_api/')
    message_life_time = ConfigInt('How long to keep message_ids around for.',
                                  static=True,
                                  default=48 * 60 * 60)  # default is 48 hours.
    redis_manager = ConfigDict("Redis client configuration.",
                               default={},
                               static=True)
    max_reconnect_delay = ConfigInt(
        'Maximum number of seconds between connection attempts',
        default=3600,
        static=True)
    max_retries = ConfigInt(
        'Maximum number of consecutive unsuccessful connection attempts '
        'after which no further connection attempts will be made. If this is '
        'not explicitly set, no maximum is applied',
        static=True)
    initial_delay = ConfigFloat('Initial delay for first reconnection attempt',
                                default=0.1,
                                static=True)
    factor = ConfigFloat(
        'A multiplicitive factor by which the delay grows',
        # (math.e)
        default=2.7182818284590451,
        static=True)
    jitter = ConfigFloat(
        'Percentage of randomness to introduce into the delay length'
        'to prevent stampeding.',
        # molar Planck constant times c, joule meter/mole
        default=0.11962656472,
        static=True)
    web_port = ConfigInt(
        "The port to listen for requests on, defaults to `0`.",
        default=0,
        static=True)
    web_path = ConfigText("The path to listen for inbound requests on.",
                          required=True,
                          static=True)
    health_path = ConfigText(
        "The path to listen for downstream health checks on"
        " (useful with HAProxy)",
        default='health',
        static=True)
Esempio n. 14
0
class DmarkUssdTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    """Config for Dmark USSD transport."""

    ussd_session_timeout = ConfigInt(
        "Number of seconds before USSD session information stored in Redis"
        " expires.",
        default=600,
        static=True)

    redis_manager = ConfigDict("Redis client configuration.",
                               default={},
                               static=True)
Esempio n. 15
0
class AppositTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    """Apposit transport config."""

    credentials = ConfigDict(
        "A dictionary where the `from_addr` is used for the key lookup and "
        "the returned value should be a dictionary containing the "
        "corresponding username, password and service id.",
        required=True,
        static=True)
    outbound_url = ConfigText("The URL to send outbound messages to.",
                              required=True,
                              static=True)
Esempio n. 16
0
class ChannelStatusConfig(BaseConfig):
    '''Config for the ChannelStatusWorker'''
    redis_manager = ConfigDict("Redis config.", required=True, static=True)

    channel_id = ConfigText(
        "The channel id which this worker is consuming statuses for",
        required=True,
        static=True)

    status_url = ConfigText("Optional url to POST status events to",
                            default=None,
                            static=True)
Esempio n. 17
0
class SandboxConfig(ApplicationWorker.CONFIG_CLASS):

    sandbox = ConfigDict(
        "Dictionary of resources to provide to the sandbox."
        " Keys are the names of resources (as seen inside the sandbox)."
        " Values are dictionaries which must contain a `cls` key that"
        " gives the full name of the class that provides the resource."
        " Other keys are additional configuration for that resource.",
        default={},
        static=True)

    executable = ConfigText(
        "Full path to the executable to run in the sandbox.")
    args = ConfigList(
        "List of arguments to pass to the executable (not including"
        " the path of the executable itself).",
        default=[])
    path = ConfigText("Current working directory to run the executable in.")
    env = ConfigDict("Custom environment variables for the sandboxed process.",
                     default={})
    timeout = ConfigInt(
        "Length of time the subprocess is given to process a message.",
        default=60)
    recv_limit = ConfigInt(
        "Maximum number of bytes that will be read from a sandboxed"
        " process' stdout and stderr combined.",
        default=1024 * 1024)
    rlimits = ConfigDict(
        "Dictionary of resource limits to be applied to sandboxed"
        " processes. Defaults are fairly restricted. Keys maybe"
        " names or values of the RLIMIT constants in"
        " Python `resource` module. Values should be appropriate integers.",
        default={})
    logging_resource = ConfigText(
        "Name of the logging resource to use to report errors detected"
        " in sandboxed code (e.g. lines written to stderr, unexpected"
        " process termination). Set to null to disable and report"
        " these directly using Twisted logging instead.",
        default=None)
    sandbox_id = ConfigText("This is set based on individual messages.")
Esempio n. 18
0
class CellulantSmsTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    """Cellulant transport config.
    """

    credentials = ConfigDict(
        "A dictionary where the `from_addr` is used for the key lookup and the"
        " returned value should be a dictionary containing the username and"
        " password.",
        required=True,
        static=True)
    outbound_url = ConfigText("The URL to send outbound messages to.",
                              required=True,
                              static=True)
Esempio n. 19
0
class ApplicationConfig(BaseWorker.CONFIG_CLASS):
    """Base config definition for applications.

    You should subclass this and add application-specific fields.
    """

    transport_name = ConfigText(
        "The name this application instance will use to create its queues.",
        required=True,
        static=True)
    send_to = ConfigDict("'send_to' configuration dict.",
                         default={},
                         static=True)
Esempio n. 20
0
class AccountRoutingTableDispatcherConfig(RoutingTableDispatcher.CONFIG_CLASS,
                                          GoWorkerConfigMixin):
    application_connector_mapping = ConfigDict(
        "Mapping from conversation_type to connector name.",
        static=True,
        required=True)
    router_inbound_connector_mapping = ConfigDict(
        "Mapping from router_type to connector name to publish inbound"
        " messages on.",
        static=True,
        required=True)
    router_outbound_connector_mapping = ConfigDict(
        "Mapping from router_type to connector name to publish outbound"
        " messages on.",
        static=True,
        required=True)
    opt_out_connector = ConfigText("Connector to publish opt-out messages on.",
                                   static=True,
                                   required=True)
    billing_inbound_connector = ConfigText(
        "Connector to publish inbound messages on.",
        static=True,
        required=False)
    billing_outbound_connector = ConfigText(
        "Connector to publish outbound messages on.",
        static=True,
        required=False)
    user_account_key = ConfigText(
        "Key of the user account the message is from.")
    default_unroutable_inbound_reply = ConfigText(
        "Default text to send in response to unroutable inbound messages"
        " if the tagpool specifies `reply_to_unroutable_inbound` but not"
        " `unroutable_inbound_reply`.",
        default="Vumi Go could not route your message. Please try again soon.",
        static=True,
        required=False)
Esempio n. 21
0
class RapidSMSRelayConfig(ApplicationWorker.CONFIG_CLASS):
    """RapidSMS relay configuration."""

    web_path = ConfigText(
        "Path to listen for outbound messages from RapidSMS on.", static=True)
    web_port = ConfigInt(
        "Port to listen for outbound messages from RapidSMS on.", static=True)
    redis_manager = ConfigDict(
        "Redis manager configuration (only required if"
        " `allow_replies` is true)",
        default={},
        static=True)
    allow_replies = ConfigBool(
        "Whether to support replies via the `in_reply_to` argument"
        " from RapidSMS.",
        default=True,
        static=True)

    vumi_username = ConfigText(
        "Username required when calling `web_path` (default: no"
        " authentication)",
        default=None)
    vumi_password = ConfigText("Password required when calling `web_path`",
                               default=None)
    vumi_auth_method = ConfigText(
        "Authentication method required when calling `web_path`."
        "The 'basic' method is currently the only available method",
        default='basic')
    vumi_reply_timeout = ConfigInt(
        "Number of seconds to keep original messages in redis so that"
        " replies may be sent via `in_reply_to`.",
        default=10 * 60)
    allowed_endpoints = ConfigList('List of allowed endpoints to send from.',
                                   required=True,
                                   default=("default", ))

    rapidsms_url = ConfigUrl("URL of the rapidsms http backend.")
    rapidsms_username = ConfigText(
        "Username to use for the `rapidsms_url` (default: no authentication)",
        default=None)
    rapidsms_password = ConfigText("Password to use for the `rapidsms_url`",
                                   default=None)
    rapidsms_auth_method = ConfigText(
        "Authentication method to use with `rapidsms_url`."
        " The 'basic' method is currently the only available method.",
        default='basic')
    rapidsms_http_method = ConfigText(
        "HTTP request method to use for the `rapidsms_url`", default='POST')
Esempio n. 22
0
class DeliveryReportProcessorConfig(Config):

    DELIVERY_REPORT_REGEX = ('id:(?P<id>[^ ]{,65})'
                             '(?: +sub:(?P<sub>[^ ]+))?'
                             '(?: +dlvrd:(?P<dlvrd>[^ ]+))?'
                             '(?: +submit date:(?P<submit_date>\d*))?'
                             '(?: +done date:(?P<done_date>\d*))?'
                             ' +stat:(?P<stat>[A-Z]{5,7})'
                             '(?: +err:(?P<err>[^ ]+))?'
                             ' +[Tt]ext:(?P<text>.{,20})'
                             '.*')

    DELIVERY_REPORT_STATUS_MAPPING = {
        # Output values should map to themselves:
        'delivered': 'delivered',
        'failed': 'failed',
        'pending': 'pending',
        # SMPP `message_state` values:
        'ENROUTE': 'pending',
        'DELIVERED': 'delivered',
        'EXPIRED': 'failed',
        'DELETED': 'failed',
        'UNDELIVERABLE': 'failed',
        'ACCEPTED': 'delivered',
        'UNKNOWN': 'pending',
        'REJECTED': 'failed',
        # From the most common regex-extracted format:
        'DELIVRD': 'delivered',
        'REJECTD': 'failed',
        'FAILED': 'failed',
        # Currently we will accept this for Yo! TODO: investigate
        '0': 'delivered',
    }

    delivery_report_regex = ConfigRegex(
        'Regex to use for matching delivery reports',
        default=DELIVERY_REPORT_REGEX,
        static=True)
    delivery_report_status_mapping = ConfigDict(
        "Mapping from delivery report message state to"
        " (`delivered`, `failed`, `pending`)",
        default=DELIVERY_REPORT_STATUS_MAPPING,
        static=True)
    delivery_report_use_esm_class = ConfigBool(
        "Use `esm_class` PDU parameter to determine whether a message is a"
        " delivery report.",
        default=True,
        static=True)
Esempio n. 23
0
class DeliverShortMessageProcessorConfig(Config):

    data_coding_overrides = ConfigDict(
        "Overrides for data_coding character set mapping. This is useful for "
        "setting the default encoding (0), adding additional undefined "
        "encodings (such as 4 or 8) or overriding encodings in cases where "
        "the SMSC is violating the spec (which happens a lot). Keys should "
        "be something that can be cast to an integer, values should be strings"
        "containing valid Python character encoding names.",
        default={},
        static=True)

    allow_empty_messages = ConfigBool(
        "If True, send on empty messages as an empty unicode string. "
        "If False, reject empty messages as invalid.",
        default=False,
        static=True)
Esempio n. 24
0
class MessageForwardingConfig(ApplicationConfig):
    '''Config for MessageForwardingWorker application worker'''

    mo_message_url = ConfigUrl(
        "The URL to send HTTP POST requests to for MO messages",
        default=None,
        static=True)

    mo_message_url_auth_token = ConfigText(
        "Authorization Token to use for the mo_message_url",
        default=None,
        static=True)

    mo_message_url_timeout = ConfigInt(
        "Maximum time (in seconds) a mo_message_url is allowed to take "
        "to process a message",
        default=10,
        static=True)

    event_url_timeout = ConfigInt(
        "Maximum time (in seconds) an event_url is allowed to take "
        "to process an event",
        default=10,
        static=True)

    message_queue = ConfigText("The AMQP queue to forward messages on",
                               default=None,
                               static=True)

    redis_manager = ConfigDict("Redis config.", required=True, static=True)

    inbound_ttl = ConfigInt(
        "Maximum time (in seconds) allowed to reply to messages",
        required=True,
        static=True)

    outbound_ttl = ConfigInt(
        "Maximum time (in seconds) allowed for events to arrive for messages",
        required=True,
        static=True)

    metric_window = ConfigFloat(
        "Size of the buckets to use (in seconds) for metrics",
        required=True,
        static=True)
Esempio n. 25
0
class DmarkUssdTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    """Config for Dmark USSD transport."""

    ussd_session_timeout = ConfigInt(
        "Number of seconds before USSD session information stored in Redis"
        " expires.",
        default=600,
        static=True)

    fix_to_addr = ConfigBool(
        "Whether or not to ensure that the to_addr is always starting with a "
        "* and ending with a #",
        default=False,
        static=True)

    redis_manager = ConfigDict("Redis client configuration.",
                               default={},
                               static=True)
Esempio n. 26
0
class ChannelStatusConfig(BaseConfig):
    '''Config for the ChannelStatusWorker'''
    redis_manager = ConfigDict(
        "Redis config.",
        required=True, static=True)

    channel_id = ConfigText(
        "The channel id which this worker is consuming statuses for",
        required=True, static=True)

    status_url = ConfigText(
        "Optional url to POST status events to",
        default=None, static=True)

    status_url_timeout = ConfigInt(
        "Maximum time (in seconds) a status_url is allowed to take "
        "to process a status update",
        default=10, static=True)
Esempio n. 27
0
class MessengerTransportConfig(HttpRpcTransport.CONFIG_CLASS):

    access_token = ConfigText(
        "The access_token for the Messenger API",
        required=True)
    page_id = ConfigText(
        "The page id for the Messenger API",
        required=False,
        fallbacks=[SingleFieldFallback("app_id")])
    app_id = ConfigText(
        "DEPRECATED The page app id for the Messenger API",
        required=False)
    welcome_message = ConfigDict(
        ("The payload for setting up a welcome message. "
         "Requires a page_id to be set"),
        required=False)
    retrieve_profile = ConfigBool(
        "Set to true to include the user profile details in "
        "the helper_metadata", required=False, default=False)
Esempio n. 28
0
class TrueAfricanUssdTransportConfig(Transport.CONFIG_CLASS):
    """TrueAfrican USSD transport configuration."""

    port = ConfigInt("Bind to this port", required=True, static=True)
    interface = ConfigText("Bind to this interface", default='', static=True)
    redis_manager = ConfigDict("Parameters to connect to Redis with",
                               default={},
                               static=True)
    session_timeout = ConfigInt(
        "Number of seconds before USSD session information stored in"
        " Redis expires.",
        default=600,
        static=True)
    request_timeout = ConfigInt(
        "How long should we wait for the remote side generating the response"
        " for this synchronous operation to come back. Any connection that has"
        " waited longer than `request_timeout` seconds will manually be"
        " closed.",
        default=(4 * 60),
        static=True)
Esempio n. 29
0
class MtnNigeriaUssdTransportConfig(Transport.CONFIG_CLASS):
    """MTN Nigeria USSD transport configuration."""

    server_hostname = ConfigText(
        "Hostname of the server the transport's client should connect to.",
        required=True,
        static=True)
    server_port = ConfigInt("Port that the server is listening on.",
                            required=True,
                            static=True)
    username = ConfigText("The username for this transport.",
                          required=True,
                          static=True)
    password = ConfigText("The password for this transport.",
                          required=True,
                          static=True)
    application_id = ConfigText(
        "An application ID required by MTN Nigeria for client authentication.",
        required=True,
        static=True)
    enquire_link_interval = ConfigInt(
        "The interval (in seconds) between enquire links sent to the server "
        "to check whether the connection is alive and well.",
        default=30,
        static=True)
    timeout_period = ConfigInt(
        "How long (in seconds) after sending an enquire link request the "
        "client should wait for a response before timing out. NOTE: The "
        "timeout period should not be longer than the enquire link interval",
        default=30,
        static=True)
    user_termination_response = ConfigText(
        "Response given back to the user if the user terminated the session.",
        default='Session Ended',
        static=True)
    redis_manager = ConfigDict("Parameters to connect to Redis with",
                               default={},
                               static=True)
    session_timeout_period = ConfigInt(
        "Max length (in seconds) of a USSD session", default=600, static=True)
Esempio n. 30
0
class AirtelUSSDTransportConfig(HttpRpcTransport.CONFIG_CLASS):
    airtel_username = ConfigText('The username for this transport',
                                 default=None,
                                 static=True)
    airtel_password = ConfigText('The password for this transport',
                                 default=None,
                                 static=True)
    airtel_charge = ConfigBool(
        'Whether or not to charge for the responses sent.',
        required=False,
        default=False,
        static=True)
    airtel_charge_amount = ConfigInt('How much to charge',
                                     default=0,
                                     required=False,
                                     static=True)
    redis_manager = ConfigDict('Parameters to connect to Redis with.',
                               default={},
                               required=False,
                               static=True)
    session_key_prefix = ConfigText(
        'The prefix to use for session key management. Specify this'
        'if you are using more than 1 worker in a load-balanced'
        'fashion.',
        default=None,
        static=True)
    ussd_session_timeout = ConfigInt('Max length of a USSD session',
                                     default=60 * 10,
                                     required=False,
                                     static=True)
    to_addr_pattern = ConfigText(
        'A regular expression that to_addr values in messages that start a'
        ' new USSD session must match. Initial messages with invalid'
        ' to_addr values are rejected.',
        default=None,
        required=False,
        static=True,
    )