Asterisk - The Open Source Telephony Project  18.5.0
swagger_model.py
Go to the documentation of this file.
1 
2 # Asterisk -- An open source telephony toolkit.
3 #
4 # Copyright (C) 2013, Digium, Inc.
5 #
6 # David M. Lee, II <[email protected]>
7 #
8 # See http://www.asterisk.org for more information about
9 # the Asterisk project. Please do not directly contact
10 # any of the maintainers of this project for assistance;
11 # the project provides a web site, mailing lists and IRC
12 # channels for your use.
13 #
14 # This program is free software, distributed under the terms of
15 # the GNU General Public License Version 2. See the LICENSE file
16 # at the top of the source tree.
17 #
18 
19 """Swagger data model objects.
20 
21 These objects should map directly to the Swagger api-docs, without a lot of
22 additional fields. In the process of translation, it should also validate the
23 model for consistency against the Swagger spec (i.e., fail if fields are
24 missing, or have incorrect values).
25 
26 See https://github.com/wordnik/swagger-core/wiki/API-Declaration for the spec.
27 """
28 
29 from __future__ import print_function
30 import json
31 import os.path
32 import pprint
33 import re
34 import sys
35 import traceback
36 
37 # We don't fully support Swagger 1.2, but we need it for subtyping
38 SWAGGER_VERSIONS = ["1.1", "1.2"]
39 
40 SWAGGER_PRIMITIVES = [
41  'void',
42  'string',
43  'boolean',
44  'number',
45  'int',
46  'long',
47  'double',
48  'float',
49  'Date',
50 ]
51 
52 
53 class Stringify(object):
54  """Simple mix-in to make the repr of the model classes more meaningful.
55  """
56  def __repr__(self):
57  return "%s(%s)" % (self.__class__, pprint.saferepr(self.__dict__))
58 
59 
60 def compare_versions(lhs, rhs):
61  '''Performs a lexicographical comparison between two version numbers.
62 
63  This properly handles simple major.minor.whatever.sure.why.not version
64  numbers, but fails miserably if there's any letters in there.
65 
66  For reference:
67  1.0 == 1.0
68  1.0 < 1.0.1
69  1.2 < 1.10
70 
71  @param lhs Left hand side of the comparison
72  @param rhs Right hand side of the comparison
73  @return < 0 if lhs < rhs
74  @return == 0 if lhs == rhs
75  @return > 0 if lhs > rhs
76  '''
77  lhs = [int(v) for v in lhs.split('.')]
78  rhs = [int(v) for v in rhs.split('.')]
79  return (lhs > rhs) - (lhs < rhs)
80 
81 
82 class ParsingContext(object):
83  """Context information for parsing.
84 
85  This object is immutable. To change contexts (like adding an item to the
86  stack), use the next() and next_stack() functions to build a new one.
87  """
88 
89  def __init__(self, swagger_version, stack):
90  self.__swagger_version = swagger_version
91  self.__stack = stack
92 
93  def __repr__(self):
94  return "ParsingContext(swagger_version=%s, stack=%s)" % (
95  self.swagger_version, self.stack)
96 
98  return self.__swagger_version
99 
100  def get_stack(self):
101  return self.__stack
102 
103  swagger_version = property(get_swagger_version)
104 
105  stack = property(get_stack)
106 
107  def version_less_than(self, ver):
108  return compare_versions(self.swagger_version, ver) < 0
109 
110  def next_stack(self, json, id_field):
111  """Returns a new item pushed to the stack.
112 
113  @param json: Current JSON object.
114  @param id_field: Field identifying this object.
115  @return New context with additional item in the stack.
116  """
117  if not id_field in json:
118  raise SwaggerError("Missing id_field: %s" % id_field, self)
119  new_stack = self.stack + ['%s=%s' % (id_field, str(json[id_field]))]
120  return ParsingContext(self.swagger_version, new_stack)
121 
122  def next(self, version=None, stack=None):
123  if version is None:
124  version = self.version
125  if stack is None:
126  stack = self.stack
127  return ParsingContext(version, stack)
128 
129 
130 class SwaggerError(Exception):
131  """Raised when an error is encountered mapping the JSON objects into the
132  model.
133  """
134 
135  def __init__(self, msg, context, cause=None):
136  """Ctor.
137 
138  @param msg: String message for the error.
139  @param context: ParsingContext object
140  @param cause: Optional exception that caused this one.
141  """
142  super(Exception, self).__init__(msg, context, cause)
143 
144 
145 class SwaggerPostProcessor(object):
146  """Post processing interface for model objects. This processor can add
147  fields to model objects for additional information to use in the
148  templates.
149  """
150  def process_resource_api(self, resource_api, context):
151  """Post process a ResourceApi object.
152 
153  @param resource_api: ResourceApi object.
154  @param context: Current context in the API.
155  """
156  pass
157 
158  def process_api(self, api, context):
159  """Post process an Api object.
160 
161  @param api: Api object.
162  @param context: Current context in the API.
163  """
164  pass
165 
166  def process_operation(self, operation, context):
167  """Post process a Operation object.
168 
169  @param operation: Operation object.
170  @param context: Current context in the API.
171  """
172  pass
173 
174  def process_parameter(self, parameter, context):
175  """Post process a Parameter object.
176 
177  @param parameter: Parameter object.
178  @param context: Current context in the API.
179  """
180  pass
181 
182  def process_model(self, model, context):
183  """Post process a Model object.
184 
185  @param model: Model object.
186  @param context: Current context in the API.
187  """
188  pass
189 
190  def process_property(self, property, context):
191  """Post process a Property object.
192 
193  @param property: Property object.
194  @param context: Current context in the API.
195  """
196  pass
197 
198  def process_type(self, swagger_type, context):
199  """Post process a SwaggerType object.
200 
201  @param swagger_type: ResourceListing object.
202  @param context: Current context in the API.
203  """
204  pass
205 
206  def process_resource_listing(self, resource_listing, context):
207  """Post process the overall ResourceListing object.
208 
209  @param resource_listing: ResourceListing object.
210  @param context: Current context in the API.
211  """
212  pass
213 
214 
215 class AllowableRange(Stringify):
216  """Model of a allowableValues of type RANGE
217 
218  See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
219  """
220  def __init__(self, min_value, max_value):
221  self.min_value = min_value
222  self.max_value = max_value
223 
224  def to_wiki(self):
225  return "Allowed range: Min: {0}; Max: {1}".format(self.min_value, self.max_value)
226 
227 
229  """Model of a allowableValues of type LIST
230 
231  See https://github.com/wordnik/swagger-core/wiki/datatypes#complex-types
232  """
233  def __init__(self, values):
234  self.values = values
235 
236  def to_wiki(self):
237  return "Allowed values: {0}".format(", ".join(self.values))
238 
239 
240 def load_allowable_values(json, context):
241  """Parse a JSON allowableValues object.
242 
243  This returns None, AllowableList or AllowableRange, depending on the
244  valueType in the JSON. If the valueType is not recognized, a SwaggerError
245  is raised.
246  """
247  if not json:
248  return None
249 
250  if not 'valueType' in json:
251  raise SwaggerError("Missing valueType field", context)
252 
253  value_type = json['valueType']
254 
255  if value_type == 'RANGE':
256  if not 'min' in json and not 'max' in json:
257  raise SwaggerError("Missing fields min/max", context)
258  return AllowableRange(json.get('min'), json.get('max'))
259  if value_type == 'LIST':
260  if not 'values' in json:
261  raise SwaggerError("Missing field values", context)
262  return AllowableList(json['values'])
263  raise SwaggerError("Unkown valueType %s" % value_type, context)
264 
265 
267  """Model of an operation's parameter.
268 
269  See https://github.com/wordnik/swagger-core/wiki/parameters
270  """
271 
272  required_fields = ['name', 'paramType', 'dataType']
273 
274  def __init__(self):
275  self.param_type = None
276  self.name = None
277  self.description = None
278  self.data_type = None
279  self.required = None
280  self.allowable_values = None
281  self.allow_multiple = None
282 
283  def load(self, parameter_json, processor, context):
284  context = context.next_stack(parameter_json, 'name')
285  validate_required_fields(parameter_json, self.required_fields, context)
286  self.name = parameter_json.get('name')
287  self.param_type = parameter_json.get('paramType')
288  self.description = parameter_json.get('description') or ''
289  self.data_type = parameter_json.get('dataType')
290  self.required = parameter_json.get('required') or False
291  self.default_value = parameter_json.get('defaultValue')
293  parameter_json.get('allowableValues'), context)
294  self.allow_multiple = parameter_json.get('allowMultiple') or False
295  processor.process_parameter(self, context)
296  if parameter_json.get('allowedValues'):
297  raise SwaggerError(
298  "Field 'allowedValues' invalid; use 'allowableValues'",
299  context)
300  return self
301 
302  def is_type(self, other_type):
303  return self.param_type == other_type
304 
305 
307  """Model of an error response.
308 
309  See https://github.com/wordnik/swagger-core/wiki/errors
310  """
311 
312  required_fields = ['code', 'reason']
313 
314  def __init__(self):
315  self.code = None
316  self.reason = None
317 
318  def load(self, err_json, processor, context):
319  context = context.next_stack(err_json, 'code')
320  validate_required_fields(err_json, self.required_fields, context)
321  self.code = err_json.get('code')
322  self.reason = err_json.get('reason')
323  return self
324 
325 
327  """Model of a data type.
328  """
329 
330  def __init__(self):
331  self.name = None
332  self.is_discriminator = None
333  self.is_list = None
334  self.singular_name = None
335  self.is_primitive = None
336  self.is_binary = None
337 
338  def load(self, type_name, processor, context):
339  # Some common errors
340  if type_name == 'integer':
341  raise SwaggerError("The type for integer should be 'int'", context)
342 
343  self.name = type_name
344  type_param = get_list_parameter_type(self.name)
345  self.is_list = type_param is not None
346  if self.is_list:
347  self.singular_name = type_param
348  else:
349  self.singular_name = self.name
350  self.is_primitive = self.singular_name in SWAGGER_PRIMITIVES
351  self.is_binary = (self.singular_name == 'binary')
352  processor.process_type(self, context)
353  return self
354 
355 
357  """Model of an operation on an API
358 
359  See https://github.com/wordnik/swagger-core/wiki/API-Declaration#apis
360  """
361 
362  required_fields = ['httpMethod', 'nickname', 'responseClass', 'summary']
363 
364  def __init__(self):
365  self.http_method = None
366  self.nickname = None
367  self.response_class = None
368  self.parameters = []
369  self.summary = None
370  self.notes = None
371  self.error_responses = []
372 
373  def load(self, op_json, processor, context):
374  context = context.next_stack(op_json, 'nickname')
375  validate_required_fields(op_json, self.required_fields, context)
376  self.http_method = op_json.get('httpMethod')
377  self.nickname = op_json.get('nickname')
378  response_class = op_json.get('responseClass')
379  self.response_class = response_class and SwaggerType().load(
380  response_class, processor, context)
381 
382  # Specifying WebSocket URL's is our own extension
383  self.is_websocket = op_json.get('upgrade') == 'websocket'
384  self.is_req = not self.is_websocket
385 
386  if self.is_websocket:
387  self.websocket_protocol = op_json.get('websocketProtocol')
388  if self.http_method != 'GET':
389  raise SwaggerError(
390  "upgrade: websocket is only valid on GET operations",
391  context)
392 
393  params_json = op_json.get('parameters') or []
394  self.parameters = [
395  Parameter().load(j, processor, context) for j in params_json]
397  p for p in self.parameters if p.is_type('query')]
400  p for p in self.parameters if p.is_type('path')]
403  p for p in self.parameters if p.is_type('header')]
407  self.is_binary_response = self.response_class.is_binary
408 
409  # Body param is different, since there's at most one
410  self.body_parameter = [
411  p for p in self.parameters if p.is_type('body')]
412  if len(self.body_parameter) > 1:
413  raise SwaggerError("Cannot have more than one body param", context)
414  self.body_parameter = self.body_parameter and self.body_parameter[0]
415  self.has_body_parameter = self.body_parameter and True
416 
417  self.summary = op_json.get('summary')
418  self.notes = op_json.get('notes')
419  err_json = op_json.get('errorResponses') or []
420  self.error_responses = [
421  ErrorResponse().load(j, processor, context) for j in err_json]
423  processor.process_operation(self, context)
424  return self
425 
426 
427 class Api(Stringify):
428  """Model of a single API in an API declaration.
429 
430  See https://github.com/wordnik/swagger-core/wiki/API-Declaration
431  """
432 
433  required_fields = ['path', 'operations']
434 
435  def __init__(self,):
436  self.path = None
437  self.description = None
438  self.operations = []
439 
440  def load(self, api_json, processor, context):
441  context = context.next_stack(api_json, 'path')
442  validate_required_fields(api_json, self.required_fields, context)
443  self.path = api_json.get('path')
444  self.description = api_json.get('description')
445  op_json = api_json.get('operations')
446  self.operations = [
447  Operation().load(j, processor, context) for j in op_json]
448  self.has_websocket = any(op.is_websocket for op in self.operations)
449  processor.process_api(self, context)
450  return self
451 
452 
453 def get_list_parameter_type(type_string):
454  """Returns the type parameter if the given type_string is List[].
455 
456  @param type_string: Type string to parse
457  @returns Type parameter of the list, or None if not a List.
458  """
459  list_match = re.match('^List\[(.*)\]$', type_string)
460  return list_match and list_match.group(1)
461 
462 
464  """Model of a Swagger property.
465 
466  See https://github.com/wordnik/swagger-core/wiki/datatypes
467  """
468 
469  required_fields = ['type']
470 
471  def __init__(self, name):
472  self.name = name
473  self.type = None
474  self.description = None
475  self.required = None
476 
477  def load(self, property_json, processor, context):
478  validate_required_fields(property_json, self.required_fields, context)
479  # Bit of a hack, but properties do not self-identify
480  context = context.next_stack({'name': self.name}, 'name')
481  self.description = property_json.get('description') or ''
482  self.required = property_json.get('required') or False
483 
484  type = property_json.get('type')
485  self.type = type and SwaggerType().load(type, processor, context)
486 
487  processor.process_property(self, context)
488  return self
489 
490 
492  """Model of a Swagger model.
493 
494  See https://github.com/wordnik/swagger-core/wiki/datatypes
495  """
496 
497  required_fields = ['description', 'properties']
498 
499  def __init__(self):
500  self.id = None
501  self.subtypes = []
502  self.__subtype_types = []
503  self.notes = None
504  self.description = None
505  self.__properties = None
506  self.__discriminator = None
507  self.__extends_type = None
508 
509  def load(self, id, model_json, processor, context):
510  context = context.next_stack(model_json, 'id')
511  validate_required_fields(model_json, self.required_fields, context)
512  # The duplication of the model's id is required by the Swagger spec.
513  self.id = model_json.get('id')
514  if id != self.id:
515  raise SwaggerError("Model id doesn't match name", context)
516  self.subtypes = model_json.get('subTypes') or []
517  if self.subtypes and context.version_less_than("1.2"):
518  raise SwaggerError("Type extension support added in Swagger 1.2",
519  context)
520  self.description = model_json.get('description')
521  props = model_json.get('properties').items() or []
522  self.__properties = [
523  Property(k).load(j, processor, context) for (k, j) in props]
524  self.__properties = sorted(self.__properties, key=lambda p: p.name)
525 
526  discriminator = model_json.get('discriminator')
527 
528  if discriminator:
529  if context.version_less_than("1.2"):
530  raise SwaggerError("Discriminator support added in Swagger 1.2",
531  context)
532 
533  discr_props = [p for p in self.__properties if p.name == discriminator]
534  if not discr_props:
535  raise SwaggerError(
536  "Discriminator '%s' does not name a property of '%s'" % (
537  discriminator, self.id),
538  context)
539 
540  self.__discriminator = discr_props[0]
541 
542  self.model_json = json.dumps(model_json,
543  indent=2, separators=(',', ': '))
544 
545  processor.process_model(self, context)
546  return self
547 
548  def extends(self):
549  return self.__extends_type and self.__extends_type.id
550 
551  def set_extends_type(self, extends_type):
552  self.__extends_type = extends_type
553 
554  def set_subtype_types(self, subtype_types):
555  self.__subtype_types = subtype_types
556 
557  def discriminator(self):
558  """Returns the discriminator, digging through base types if needed.
559  """
560  return self.__discriminator or \
562 
563  def properties(self):
564  base_props = []
565  if self.__extends_type:
566  base_props = self.__extends_type.properties()
567  return base_props + self.__properties
568 
569  def has_properties(self):
570  return len(self.properties()) > 0
571 
572  def all_subtypes(self):
573  """Returns the full list of all subtypes, including sub-subtypes.
574  """
575  res = self.__subtype_types + \
576  [subsubtypes for subtype in self.__subtype_types
577  for subsubtypes in subtype.all_subtypes()]
578  return sorted(res, key=lambda m: m.id)
579 
580  def has_subtypes(self):
581  """Returns True if type has any subtypes.
582  """
583  return len(self.subtypes) > 0
584 
585 
587  """Model class for an API Declaration.
588 
589  See https://github.com/wordnik/swagger-core/wiki/API-Declaration
590  """
591 
592  required_fields = [
593  'swaggerVersion', '_author', '_copyright', 'apiVersion', 'basePath',
594  'resourcePath', 'apis', 'models'
595  ]
596 
597  def __init__(self):
598  self.swagger_version = None
599  self.author = None
600  self.copyright = None
601  self.api_version = None
602  self.base_path = None
603  self.resource_path = None
604  self.apis = []
605  self.models = []
606 
607  def load_file(self, api_declaration_file, processor):
608  context = ParsingContext(None, [api_declaration_file])
609  try:
610  return self.__load_file(api_declaration_file, processor, context)
611  except SwaggerError:
612  raise
613  except Exception as e:
614  print("Error: ", traceback.format_exc(), file=sys.stderr)
615  raise SwaggerError(
616  "Error loading %s" % api_declaration_file, context, e)
617 
618  def __load_file(self, api_declaration_file, processor, context):
619  with open(api_declaration_file) as fp:
620  self.load(json.load(fp), processor, context)
621 
622  expected_resource_path = '/api-docs/' + \
623  os.path.basename(api_declaration_file) \
624  .replace(".json", ".{format}")
625 
626  if self.resource_path != expected_resource_path:
627  print("%s != %s" % (self.resource_path, expected_resource_path),
628  file=sys.stderr)
629  raise SwaggerError("resourcePath has incorrect value", context)
630 
631  return self
632 
633  def load(self, api_decl_json, processor, context):
634  """Loads a resource from a single Swagger resource.json file.
635  """
636  # If the version doesn't match, all bets are off.
637  self.swagger_version = api_decl_json.get('swaggerVersion')
638  context = context.next(version=self.swagger_version)
639  if not self.swagger_version in SWAGGER_VERSIONS:
640  raise SwaggerError(
641  "Unsupported Swagger version %s" % self.swagger_version, context)
642 
643  validate_required_fields(api_decl_json, self.required_fields, context)
644 
645  self.author = api_decl_json.get('_author')
646  self.copyright = api_decl_json.get('_copyright')
647  self.api_version = api_decl_json.get('apiVersion')
648  self.base_path = api_decl_json.get('basePath')
649  self.resource_path = api_decl_json.get('resourcePath')
650  self.requires_modules = api_decl_json.get('requiresModules') or []
651  api_json = api_decl_json.get('apis') or []
652  self.apis = [
653  Api().load(j, processor, context) for j in api_json]
654  paths = set()
655  for api in self.apis:
656  if api.path in paths:
657  raise SwaggerError("API with duplicated path: %s" % api.path, context)
658  paths.add(api.path)
659  self.has_websocket = any(api.has_websocket for api in self.apis)
660  models = api_decl_json.get('models').items() or []
661  self.models = [Model().load(id, json, processor, context)
662  for (id, json) in models]
663  self.models = sorted(self.models, key=lambda m: m.id)
664  # Now link all base/extended types
665  model_dict = dict((m.id, m) for m in self.models)
666  for m in self.models:
667  def link_subtype(name):
668  res = model_dict.get(name)
669  if not res:
670  raise SwaggerError("%s has non-existing subtype %s",
671  m.id, name)
672  res.set_extends_type(m)
673  return res;
674  if m.subtypes:
675  m.set_subtype_types([
676  link_subtype(subtype) for subtype in m.subtypes])
677  return self
678 
679 
681  """Model of an API listing in the resources.json file.
682  """
683 
684  required_fields = ['path', 'description']
685 
686  def __init__(self):
687  self.path = None
688  self.description = None
689  self.api_declaration = None
690 
691  def load(self, api_json, processor, context):
692  context = context.next_stack(api_json, 'path')
693  validate_required_fields(api_json, self.required_fields, context)
694  self.path = api_json['path'].replace('{format}', 'json')
695  self.description = api_json['description']
696 
697  if not self.path or self.path[0] != '/':
698  raise SwaggerError("Path must start with /", context)
699  processor.process_resource_api(self, context)
700  return self
701 
702  def load_api_declaration(self, base_dir, processor):
703  self.file = (base_dir + self.path)
704  self.api_declaration = ApiDeclaration().load_file(self.file, processor)
705  processor.process_resource_api(self, [self.file])
706 
707 
709  """Model of Swagger's resources.json file.
710  """
711 
712  required_fields = ['apiVersion', 'basePath', 'apis']
713 
714  def __init__(self):
715  self.swagger_version = None
716  self.api_version = None
717  self.base_path = None
718  self.apis = None
719 
720  def load_file(self, resource_file, processor):
721  context = ParsingContext(None, [resource_file])
722  try:
723  return self.__load_file(resource_file, processor, context)
724  except SwaggerError:
725  raise
726  except Exception as e:
727  print("Error: ", traceback.format_exc(), file=sys.stderr)
728  raise SwaggerError(
729  "Error loading %s" % resource_file, context, e)
730 
731  def __load_file(self, resource_file, processor, context):
732  with open(resource_file) as fp:
733  return self.load(json.load(fp), processor, context)
734 
735  def load(self, resources_json, processor, context):
736  # If the version doesn't match, all bets are off.
737  self.swagger_version = resources_json.get('swaggerVersion')
738  if not self.swagger_version in SWAGGER_VERSIONS:
739  raise SwaggerError(
740  "Unsupported Swagger version %s" % self.swagger_version, context)
741 
742  validate_required_fields(resources_json, self.required_fields, context)
743  self.api_version = resources_json['apiVersion']
744  self.base_path = resources_json['basePath']
745  apis_json = resources_json['apis']
746  self.apis = [
747  ResourceApi().load(j, processor, context) for j in apis_json]
748  processor.process_resource_listing(self, context)
749  return self
750 
751 
752 def validate_required_fields(json, required_fields, context):
753  """Checks a JSON object for a set of required fields.
754 
755  If any required field is missing, a SwaggerError is raised.
756 
757  @param json: JSON object to check.
758  @param required_fields: List of required fields.
759  @param context: Current context in the API.
760  """
761  missing_fields = [f for f in required_fields if not f in json]
762 
763  if missing_fields:
764  raise SwaggerError(
765  "Missing fields: %s" % ', '.join(missing_fields), context)
def next_stack(self, json, id_field)
def __init__(self, swagger_version, stack)
def __load_file(self, resource_file, processor, context)
def load_allowable_values(json, context)
def load(self, property_json, processor, context)
def __init__(self, values)
def load(self, api_json, processor, context)
def set_subtype_types(self, subtype_types)
def process_model(self, model, context)
const char * str
Definition: app_jack.c:147
def process_api(self, api, context)
def validate_required_fields(json, required_fields, context)
def get_list_parameter_type(type_string)
def is_type(self, other_type)
def load_file(self, resource_file, processor)
def process_operation(self, operation, context)
def load_file(self, api_declaration_file, processor)
def next(self, version=None, stack=None)
def compare_versions(lhs, rhs)
def load(self, resources_json, processor, context)
def load(self, op_json, processor, context)
def has_properties(self)
def load(self, err_json, processor, context)
def process_property(self, property, context)
def process_resource_api(self, resource_api, context)
static int load_file(const char *filename, char **ret)
Read a TEXT file into a string and return the length.
def load_api_declaration(self, base_dir, processor)
def process_type(self, swagger_type, context)
def __init__(self, msg, context, cause=None)
def __load_file(self, api_declaration_file, processor, context)
def __init__(self, min_value, max_value)
def version_less_than(self, ver)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
def load(self, api_json, processor, context)
def load(self, api_decl_json, processor, context)
def process_parameter(self, parameter, context)
def load(self, type_name, processor, context)
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
def load(self, id, model_json, processor, context)
static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_logic.c:206
def set_extends_type(self, extends_type)
def process_resource_listing(self, resource_listing, context)
static snd_pcm_format_t format
Definition: chan_alsa.c:102
def __init__(self, name)
def load(self, parameter_json, processor, context)