From 01675fb4dfd25222b9bbc02d62e35bb3e8ce078e Mon Sep 17 00:00:00 2001 From: CoprDistGit Date: Mon, 15 May 2023 08:18:08 +0000 Subject: automatic import of python-asynction --- .gitignore | 1 + python-asynction.spec | 1149 +++++++++++++++++++++++++++++++++++++++++++++++++ sources | 1 + 3 files changed, 1151 insertions(+) create mode 100644 python-asynction.spec create mode 100644 sources diff --git a/.gitignore b/.gitignore index e69de29..d50b613 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/asynction-0.8.3.tar.gz diff --git a/python-asynction.spec b/python-asynction.spec new file mode 100644 index 0000000..365476a --- /dev/null +++ b/python-asynction.spec @@ -0,0 +1,1149 @@ +%global _empty_manifest_terminate_build 0 +Name: python-asynction +Version: 0.8.3 +Release: 1 +Summary: SocketIO framework driven by the AsyncAPI specification. Built on top of Flask-SocketIO. Inspired by Connexion. +License: MIT +URL: https://github.com/dedoussis/asynction +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/a4/e8/e29d4ffca4c98a28e1b36bcb728d22efeb6b72394aacf46ca88744596a3e/asynction-0.8.3.tar.gz +BuildArch: noarch + +Requires: python3-Flask-SocketIO +Requires: python3-Flask +Requires: python3-jsonschema +Requires: python3-PyYAML +Requires: python3-svarog +Requires: python3-typing-extensions +Requires: python3-Faker +Requires: python3-hypothesis-jsonschema +Requires: python3-importlib-metadata +Requires: python3-simple-websocket +Requires: python3-Faker +Requires: python3-hypothesis-jsonschema + +%description +# Asynction + +[![Tests Status](https://github.com/dedoussis/asynction/workflows/tests/badge.svg)](https://github.com/dedoussis/asynction/actions/workflows/tests.yml) [![codecov](https://codecov.io/gh/dedoussis/asynction/branch/main/graph/badge.svg?token=3720QP2994)](https://codecov.io/gh/dedoussis/asynction) [![PyPI version](https://img.shields.io/pypi/v/asynction)](https://pypi.org/project/asynction/) + +SocketIO python framework driven by the [AsyncAPI](https://www.asyncapi.com/) specification. Built on top of [Flask-SocketIO](https://github.com/miguelgrinberg/Flask-SocketIO). Inspired by [Connexion](https://github.com/zalando/connexion). + +The purpose of Asynction is to empower a specification first approach when developing [SocketIO](https://socket.io/) APIs in Python. It guarantees that your API will work in accordance with its documentation. + +_Disclaimer: Asynction is still at a beta stage. Extensive testing is recommended when using this library in production._ + +## Features + +- Registers all event and error handlers that are referenced within the API specification. +- Provides out of the box validation on every Socket.IO interraction. In particular: + - Event validation (for both ingress and egress events), based on the specified message schemata + - HTTP request validation, upon connection, based on the channel binding schemata of each namespace + - Callback validation, upon the ACK of a message, based on the message `x-ack` schemata +- [Security](#security-authentication-and-authorization) à la [Connexion](https://connexion.readthedocs.io/en/latest/security.html). Handles OAuth2 and HTTP based authentication. +- Generates HTML rendered docs, similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). The docs get served through the `GET {base_path}/docs` route of the app. +- [Mock server support](#mock-server) +- [CLI](#cli) + +A complete example can be found [here](example/) (includes examples of both normal and mock server implementations). + +## Prerequisites + +- Python 3.7 (or higher) + +## Install + +```console +$ pip install asynction +``` + +With mock server support: + +```console +$ pip install asynction[mock] +``` + +With CLI support: + +```console +$ pip install asynction[cli] +``` + +The CLI can also be installed via Homebrew: + +```console +$ brew tap dedoussis/tap +$ brew install asynction +``` + +## Usage (basic example) + +Example event and error handler callables located at `./my_api/handlers.py`: + +```python +# /user namespace + +def user_sign_up(data): + logger.info("Signing up user...") + emit("metrics", "signup", namespace="/admin", broadcast=True, callback=cb) + +def user_log_in(data): + logger.info("Logging in user...") + emit("metrics", "login", namespace="/admin", broadcast=True, callback=cb) + return True # Ack + +def user_error(e): + logger.error("Error: %s", e) + + +# /admin namespace + +def authenticated_connect(): + token = request.args["token"] + +def admin_error(e): + logger.error("Admin error: %s", e) +``` + +Example specification located at `./docs/asyncapi.yaml`: + +```yaml +asyncapi: 2.3.0 + +info: + title: User Account Service + version: 1.0.0 + description: This service is in charge of processing user accounts + +servers: + production: + url: my-company.com/api/socket.io # Customizes the `path` kwarg that is fed into the `SocketIO` constructor + protocol: wss + +channels: + /user: # A channel is essentially a SocketIO namespace + publish: + message: + oneOf: # The oneOf Messages relationship expresses the supported events that a client may emit under the `/user` namespace + - $ref: "#/components/messages/UserSignUp" + - $ref: "#/components/messages/UserLogIn" + x-handlers: # Default namespace handlers (such as connect, disconnect and error) + error: my_api.handlers.user_error # Equivelant of: `@socketio.on_error("/user")` + /admin: + subscribe: + message: + oneOf: + - "#/components/messages/Metrics" + x-handlers: + connect: my_api.handlers.authenticated_connect # Equivelant of: `@socketio.on("connect", namespace="/admin")` + error: my_api.handlers.admin_error + bindings: # Bindings are used to validate the HTTP request upon connection + $ref: "#/components/channelBindings/AuthenticatedWsBindings" + +components: + messages: + UserSignUp: + name: sign up # The SocketIO event name. Use `message` or `json` for unnamed events. + payload: # Asynction uses payload JSON Schemata for message validation + type: object + x-handler: my_api.handlers.user_sign_up # The handler that is to be registered. Equivelant of: `@socketio.on("sign up", namespace="/user")` + UserLogIn: + name: log in + payload: + type: object + x-handler: my_api.handlers.user_log_in + x-ack: # Specifies the structure of the ACK data that the client should expect + args: + type: boolean + Metrics: + name: metrics + payload: + type: string + enum: [signup, login] + x-ack: # Specifies the structure of the ACK data that the server expects + args: + type: string + + channelBindings: + AuthenticatedWsBindings: + ws: + query: + type: object + properties: + token: + type: string + required: [token] +``` + +Bootstrap the AsynctionSocketIO server: + +```python +from asynction import AsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +asio = AsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, + message_queue="redis://localhost:6379", + # or any other kwarg that the flask_socketio.SocketIO constructor accepts +) + +if __name__ == "__main__": + asio.run(app=flask_app) +``` + +The `AsynctionSocketIO` class extends the `SocketIO` class of the Flask-SocketIO library. +The above `asio` server object has all the event and error handlers registered, and is ready to run. +Validation of the message payloads, the channel bindings and the ack callbacks is also enabled by default. +Without Asynction, one would need to add additional boilerplate to register the handlers (as shown [here](https://flask-socketio.readthedocs.io/en/latest/#error-handling)) and implement the respective validators. + +## Security (Authentication and Authorization) + +Asynction supports authentication of incoming connections through the security mechanisms specified in the AsyncAPI spec of an application. See [this guide](https://www.asyncapi.com/docs/getting-started/security) on how to add security as part of an API specification. To take advantage of this feature, a security handler callable should be attached to each security scheme definition under the [components](https://www.asyncapi.com/docs/specifications/v2.3.0#componentsObjectSecuritySchemes) section. To attach a security handler(s), see the [security specification extention](#security-handers) section below. + +The security handler callable(s) will be called upon every new client connection and MUST return a [`SecurityInfo`](https://asynction.dedouss.is/#asynction.SecurityInfo) typed dictionary (which allows extra keys). Asynction then validates this returned dictionary, refusing the connection to any unauthenticated/unauthorised requests. Finally, the validated `SecurityInfo` dictionary is passed to the connection handler as an extra `token_info` kwarg, to allow further/custom processing if needed. + +## Docs + +API documentation is autogenerated by Asynction and served through the following routes of the app: + +- `{base_path}/docs`: Rendered HTML docs similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). +- `{base_path}/docs/asyncapi.json`: The raw specification data exposed for programmatic retrieval. + +The `base_path` is determined automagically through the Socket.IO path argument. It essentially is the parent of that path. For example: + +| Socket.IO path | Base path | Docs path | +| --------------------- | --------- | -------------- | +| `socket.io` (default) | `/` | `/docs` | +| `events/socket.io` | `/events` | `/events/docs` | + +Docs can be disabled by toggling the `docs` kwarg of the `AsynctionSocketIO.from_spec` factory method. + +## Emitting from an external process + +All validation features of Asynction can be used when emitting/sending events from an external process. See the [relevant Flask-SocketIO documentation](https://flask-socketio.readthedocs.io/en/latest/deployment.html#emitting-from-an-external-process). Note that the SocketIO instance of the external process needs to be constructed using the same `AsynctionSocketIO.from_spec` factory. + +##  Mock server + +Asynction can also create a fake "mock" based off an AsyncAPI document. This enables the consumers of a SocketIO API to interract with the API before it's even built. + +```python +from asynction import MockAsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +mock_asio = MockAsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, +) + +if __name__ == "__main__": + mock_asio.run(app=flask_app) +``` + +The mock server: + +1. Listens for all events defined in the given spec, returning fake acknowledgements where applicable. +1. Periodically emits events containing payloads of fake data, for the clients to listen on. + +The fake data generation is fueled by [Faker](https://faker.readthedocs.io/en/master/) and [Hypothesis](https://hypothesis.readthedocs.io/en/latest/), hence the use of the mock server functionality requires the installation of extra dependecies: `pip install asynction[mock]` + +To make the fake generated data more realistic, one may attach faker providers to the string schemata of their spec using the [format](https://json-schema.org/understanding-json-schema/reference/string.html#format) keyword of JSON Schema: + +```yaml +# example of a Message object +NewMessageReceived: + name: new message + payload: + type: object + properties: + username: + type: string + format: first_name + message: + type: string + format: sentence + required: [username, message] +``` + +The formats supported are essentially all the [faker providers](https://faker.readthedocs.io/en/master/providers.html) that yield a string value. + +## CLI + +For convenience, Asynction provides a command-line interface (CLI) that aims to be a toolbox of useful utilities for the development, testing and mocking of Asynction apps (ie any Socket.IO app driven by an AsyncAPI doc). For example, it allows one to run a "mock" instance of their Socket.IO server, only by passing the AsyncAPI YAML file, without even having to start the development of the server itself. + +All commands support the `–-help` (or `-h`) argument to display additional information. + +### Available commands + +- `mock run` + + ```console + $ asynction --spec ./docs/asyncapi.yml mock run --port 5001 --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 + (71320) wsgi starting up on http://0.0.0.0:5001 + ... + ``` + +- `scaffold` _(coming soon)_ + + ```console + $ asynction --spec ./docs/asyncapi.yml scaffold + ✨ Successfully generated app.py + ``` + +### Dockerised + +The CLI can be installed via pip or Homebrew (see the [install section](#install)) but is also available through docker, negating the need for a local python environment: + +```console +$ docker run -v ${PWD}/docs/asyncapi.yml:/opt/asynction/asyncapi.yml dedoussis/asynction mock run --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 +(71320) wsgi starting up on http://0.0.0.0:5000 +... +``` + +## Further resources + +- [API reference](https://asynction.dedouss.is) +- [Complete example](example/) + +## Specification Extentions + +Asynction has extended the AsyncAPI 2.x.x specification to provide support for coupling SocketIO semantical entities (such as namespaces, events and acks) to python objects (such as handler callabes or other `flask_socketio.SocketIO` methods). Some of the extentions below are necessary to express the Socket.IO protocol semantics, while others are solely needed for the programmatic purposes of Asynction. The extentions introduced adhere to the [Specification Extention guidelines](https://www.asyncapi.com/docs/specifications/2.0.0#specificationExtensions) of the AsyncAPI spec. + +For further guidance on how to generally express a SocketIO API using AsyncAPI, refer to this article: + +### Event handler + +The `x-handler` field MAY be defined as an additional property of the [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject). The value of this field MUST be of `string` type, expressing a dot joint path to a python callable (the event handler). + +Message Objects listed under a `subscribe` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) MUST include the `x-handler` field. +Message Objects listed under a `publish` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) SHOULD NOT include the `x-handler` field. + +### Default namespace handlers + +The `x-handlers` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/2.0.0#channelItemObject). The value of this field SHOULD be a [Channel Handlers Object](#channel-handlers-object). + +#### Channel Handlers Object + +| Field Name | Type | Description | +| ---------- | -------- | -------------------------------------------------------- | +| connect | `string` | Dot joint path to the python connect handler callable | +| disconnect | `string` | Dot joint path to the python disconnect handler callable | +| error | `string` | Dot joint path to the python error handler callable | + +### ACK packet + +The basic unit of information in the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol) is the packet. There are 7 distinct [packet types](https://github.com/socketio/socket.io-protocol#packet-types). The `publish` and `subscribe` [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s expressed in the A2S YAML above correspond to the [EVENT](https://github.com/socketio/socket.io-protocol#2---event) and [BINARY_EVENT](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. These are essentially the packets that are transmitted when the Socket.IO sender invokes the `emit` or `send` API functions of the Socket.IO library (regardless of implementation). In turn, the Socket.IO event receiver handles the received event using the `on` API function of the Socket.IO library. As part of the `on` handler, the receiver may choose to return an acknowledgement of the received message. This acknowledgement is conveyed back to the transmitter via the [ACK](https://github.com/socketio/socket.io-protocol#3---ack) and [BINARY_ACK](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. This ack data is passed as input into the callback that the message transmitter has provided through the `emit`/`send` invocation. + +In order to express the above acknowledgement semantics, the A2S specification needs to be extended as follows: + +- [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s MAY include the `x-ack` field. The value of this field SHOULD be a [Message Ack Object](#message-ack-object). +- [Components Object](https://www.asyncapi.com/docs/specifications/2.0.0#componentsObject) MAY include the `x-messageAcks` field. The value of this field should be of type: `Map[string, Message Ack Object | Reference Object]` + +Although Asynction uses these fields to validate the input args of the callback functions, these ACK extentions are necessary to express semantics of the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol), regardless of any tooling used for automation / code generation. + +#### Message Ack Object + +| Field Name | Type | Description | +| ---------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| args | [Schema Object](https://www.asyncapi.com/docs/specifications/2.0.0#schemaObject) | Schema of the arguments that are passed as input to the acknowledgement callback function. In the case of multiple arguments, use the `array` type to express the tuple. | + +In the future, the Message Ack Object may be extended with extra fields to enable additional documentation of the callback. + +### Security handers + +In order to support the [AuthN/AuthZ functionality](#security-authentication-and-authorization) of asynction, the [Security Scheme Object](https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject) needs to be extended as follows: + +- A Security Scheme Object of `oauth2` type MUST include the `x-tokenInfoFunc` field. +- A Security Scheme Object of `oauth2` type MAY include the `x-scopeValidateFunc` field. +- A Security Scheme Object of basic `http` type MUST include the `x-basicInfoFunc` field. +- A Security Scheme Object of bearer `http` type MUST include the `x-basicBearerInfoFunc` field. +- A Security Scheme Object of bearer `apiKey` type MUST include the `x-apiKeyInfoFunc` field. + +The value of all these fields MUST be of `string` type, expressing a dot joint path to a python callable (the security handler). + +### Per Namespace Security + +The `x-security` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/v2.0.0#channelItemObject). +The value of this field MUST be an `array` of [Security Requirement Objects](https://www.asyncapi.com/docs/specifications/v2.0.0#securityRequirementObject) which is the same format used to specify [Server Security Requirements](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). +If a namespace specifies `x-security` the security requirements specified for that namespace will overwrite any security requirements specified in the [Server Object](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). + + + + +%package -n python3-asynction +Summary: SocketIO framework driven by the AsyncAPI specification. Built on top of Flask-SocketIO. Inspired by Connexion. +Provides: python-asynction +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-asynction +# Asynction + +[![Tests Status](https://github.com/dedoussis/asynction/workflows/tests/badge.svg)](https://github.com/dedoussis/asynction/actions/workflows/tests.yml) [![codecov](https://codecov.io/gh/dedoussis/asynction/branch/main/graph/badge.svg?token=3720QP2994)](https://codecov.io/gh/dedoussis/asynction) [![PyPI version](https://img.shields.io/pypi/v/asynction)](https://pypi.org/project/asynction/) + +SocketIO python framework driven by the [AsyncAPI](https://www.asyncapi.com/) specification. Built on top of [Flask-SocketIO](https://github.com/miguelgrinberg/Flask-SocketIO). Inspired by [Connexion](https://github.com/zalando/connexion). + +The purpose of Asynction is to empower a specification first approach when developing [SocketIO](https://socket.io/) APIs in Python. It guarantees that your API will work in accordance with its documentation. + +_Disclaimer: Asynction is still at a beta stage. Extensive testing is recommended when using this library in production._ + +## Features + +- Registers all event and error handlers that are referenced within the API specification. +- Provides out of the box validation on every Socket.IO interraction. In particular: + - Event validation (for both ingress and egress events), based on the specified message schemata + - HTTP request validation, upon connection, based on the channel binding schemata of each namespace + - Callback validation, upon the ACK of a message, based on the message `x-ack` schemata +- [Security](#security-authentication-and-authorization) à la [Connexion](https://connexion.readthedocs.io/en/latest/security.html). Handles OAuth2 and HTTP based authentication. +- Generates HTML rendered docs, similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). The docs get served through the `GET {base_path}/docs` route of the app. +- [Mock server support](#mock-server) +- [CLI](#cli) + +A complete example can be found [here](example/) (includes examples of both normal and mock server implementations). + +## Prerequisites + +- Python 3.7 (or higher) + +## Install + +```console +$ pip install asynction +``` + +With mock server support: + +```console +$ pip install asynction[mock] +``` + +With CLI support: + +```console +$ pip install asynction[cli] +``` + +The CLI can also be installed via Homebrew: + +```console +$ brew tap dedoussis/tap +$ brew install asynction +``` + +## Usage (basic example) + +Example event and error handler callables located at `./my_api/handlers.py`: + +```python +# /user namespace + +def user_sign_up(data): + logger.info("Signing up user...") + emit("metrics", "signup", namespace="/admin", broadcast=True, callback=cb) + +def user_log_in(data): + logger.info("Logging in user...") + emit("metrics", "login", namespace="/admin", broadcast=True, callback=cb) + return True # Ack + +def user_error(e): + logger.error("Error: %s", e) + + +# /admin namespace + +def authenticated_connect(): + token = request.args["token"] + +def admin_error(e): + logger.error("Admin error: %s", e) +``` + +Example specification located at `./docs/asyncapi.yaml`: + +```yaml +asyncapi: 2.3.0 + +info: + title: User Account Service + version: 1.0.0 + description: This service is in charge of processing user accounts + +servers: + production: + url: my-company.com/api/socket.io # Customizes the `path` kwarg that is fed into the `SocketIO` constructor + protocol: wss + +channels: + /user: # A channel is essentially a SocketIO namespace + publish: + message: + oneOf: # The oneOf Messages relationship expresses the supported events that a client may emit under the `/user` namespace + - $ref: "#/components/messages/UserSignUp" + - $ref: "#/components/messages/UserLogIn" + x-handlers: # Default namespace handlers (such as connect, disconnect and error) + error: my_api.handlers.user_error # Equivelant of: `@socketio.on_error("/user")` + /admin: + subscribe: + message: + oneOf: + - "#/components/messages/Metrics" + x-handlers: + connect: my_api.handlers.authenticated_connect # Equivelant of: `@socketio.on("connect", namespace="/admin")` + error: my_api.handlers.admin_error + bindings: # Bindings are used to validate the HTTP request upon connection + $ref: "#/components/channelBindings/AuthenticatedWsBindings" + +components: + messages: + UserSignUp: + name: sign up # The SocketIO event name. Use `message` or `json` for unnamed events. + payload: # Asynction uses payload JSON Schemata for message validation + type: object + x-handler: my_api.handlers.user_sign_up # The handler that is to be registered. Equivelant of: `@socketio.on("sign up", namespace="/user")` + UserLogIn: + name: log in + payload: + type: object + x-handler: my_api.handlers.user_log_in + x-ack: # Specifies the structure of the ACK data that the client should expect + args: + type: boolean + Metrics: + name: metrics + payload: + type: string + enum: [signup, login] + x-ack: # Specifies the structure of the ACK data that the server expects + args: + type: string + + channelBindings: + AuthenticatedWsBindings: + ws: + query: + type: object + properties: + token: + type: string + required: [token] +``` + +Bootstrap the AsynctionSocketIO server: + +```python +from asynction import AsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +asio = AsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, + message_queue="redis://localhost:6379", + # or any other kwarg that the flask_socketio.SocketIO constructor accepts +) + +if __name__ == "__main__": + asio.run(app=flask_app) +``` + +The `AsynctionSocketIO` class extends the `SocketIO` class of the Flask-SocketIO library. +The above `asio` server object has all the event and error handlers registered, and is ready to run. +Validation of the message payloads, the channel bindings and the ack callbacks is also enabled by default. +Without Asynction, one would need to add additional boilerplate to register the handlers (as shown [here](https://flask-socketio.readthedocs.io/en/latest/#error-handling)) and implement the respective validators. + +## Security (Authentication and Authorization) + +Asynction supports authentication of incoming connections through the security mechanisms specified in the AsyncAPI spec of an application. See [this guide](https://www.asyncapi.com/docs/getting-started/security) on how to add security as part of an API specification. To take advantage of this feature, a security handler callable should be attached to each security scheme definition under the [components](https://www.asyncapi.com/docs/specifications/v2.3.0#componentsObjectSecuritySchemes) section. To attach a security handler(s), see the [security specification extention](#security-handers) section below. + +The security handler callable(s) will be called upon every new client connection and MUST return a [`SecurityInfo`](https://asynction.dedouss.is/#asynction.SecurityInfo) typed dictionary (which allows extra keys). Asynction then validates this returned dictionary, refusing the connection to any unauthenticated/unauthorised requests. Finally, the validated `SecurityInfo` dictionary is passed to the connection handler as an extra `token_info` kwarg, to allow further/custom processing if needed. + +## Docs + +API documentation is autogenerated by Asynction and served through the following routes of the app: + +- `{base_path}/docs`: Rendered HTML docs similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). +- `{base_path}/docs/asyncapi.json`: The raw specification data exposed for programmatic retrieval. + +The `base_path` is determined automagically through the Socket.IO path argument. It essentially is the parent of that path. For example: + +| Socket.IO path | Base path | Docs path | +| --------------------- | --------- | -------------- | +| `socket.io` (default) | `/` | `/docs` | +| `events/socket.io` | `/events` | `/events/docs` | + +Docs can be disabled by toggling the `docs` kwarg of the `AsynctionSocketIO.from_spec` factory method. + +## Emitting from an external process + +All validation features of Asynction can be used when emitting/sending events from an external process. See the [relevant Flask-SocketIO documentation](https://flask-socketio.readthedocs.io/en/latest/deployment.html#emitting-from-an-external-process). Note that the SocketIO instance of the external process needs to be constructed using the same `AsynctionSocketIO.from_spec` factory. + +##  Mock server + +Asynction can also create a fake "mock" based off an AsyncAPI document. This enables the consumers of a SocketIO API to interract with the API before it's even built. + +```python +from asynction import MockAsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +mock_asio = MockAsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, +) + +if __name__ == "__main__": + mock_asio.run(app=flask_app) +``` + +The mock server: + +1. Listens for all events defined in the given spec, returning fake acknowledgements where applicable. +1. Periodically emits events containing payloads of fake data, for the clients to listen on. + +The fake data generation is fueled by [Faker](https://faker.readthedocs.io/en/master/) and [Hypothesis](https://hypothesis.readthedocs.io/en/latest/), hence the use of the mock server functionality requires the installation of extra dependecies: `pip install asynction[mock]` + +To make the fake generated data more realistic, one may attach faker providers to the string schemata of their spec using the [format](https://json-schema.org/understanding-json-schema/reference/string.html#format) keyword of JSON Schema: + +```yaml +# example of a Message object +NewMessageReceived: + name: new message + payload: + type: object + properties: + username: + type: string + format: first_name + message: + type: string + format: sentence + required: [username, message] +``` + +The formats supported are essentially all the [faker providers](https://faker.readthedocs.io/en/master/providers.html) that yield a string value. + +## CLI + +For convenience, Asynction provides a command-line interface (CLI) that aims to be a toolbox of useful utilities for the development, testing and mocking of Asynction apps (ie any Socket.IO app driven by an AsyncAPI doc). For example, it allows one to run a "mock" instance of their Socket.IO server, only by passing the AsyncAPI YAML file, without even having to start the development of the server itself. + +All commands support the `–-help` (or `-h`) argument to display additional information. + +### Available commands + +- `mock run` + + ```console + $ asynction --spec ./docs/asyncapi.yml mock run --port 5001 --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 + (71320) wsgi starting up on http://0.0.0.0:5001 + ... + ``` + +- `scaffold` _(coming soon)_ + + ```console + $ asynction --spec ./docs/asyncapi.yml scaffold + ✨ Successfully generated app.py + ``` + +### Dockerised + +The CLI can be installed via pip or Homebrew (see the [install section](#install)) but is also available through docker, negating the need for a local python environment: + +```console +$ docker run -v ${PWD}/docs/asyncapi.yml:/opt/asynction/asyncapi.yml dedoussis/asynction mock run --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 +(71320) wsgi starting up on http://0.0.0.0:5000 +... +``` + +## Further resources + +- [API reference](https://asynction.dedouss.is) +- [Complete example](example/) + +## Specification Extentions + +Asynction has extended the AsyncAPI 2.x.x specification to provide support for coupling SocketIO semantical entities (such as namespaces, events and acks) to python objects (such as handler callabes or other `flask_socketio.SocketIO` methods). Some of the extentions below are necessary to express the Socket.IO protocol semantics, while others are solely needed for the programmatic purposes of Asynction. The extentions introduced adhere to the [Specification Extention guidelines](https://www.asyncapi.com/docs/specifications/2.0.0#specificationExtensions) of the AsyncAPI spec. + +For further guidance on how to generally express a SocketIO API using AsyncAPI, refer to this article: + +### Event handler + +The `x-handler` field MAY be defined as an additional property of the [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject). The value of this field MUST be of `string` type, expressing a dot joint path to a python callable (the event handler). + +Message Objects listed under a `subscribe` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) MUST include the `x-handler` field. +Message Objects listed under a `publish` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) SHOULD NOT include the `x-handler` field. + +### Default namespace handlers + +The `x-handlers` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/2.0.0#channelItemObject). The value of this field SHOULD be a [Channel Handlers Object](#channel-handlers-object). + +#### Channel Handlers Object + +| Field Name | Type | Description | +| ---------- | -------- | -------------------------------------------------------- | +| connect | `string` | Dot joint path to the python connect handler callable | +| disconnect | `string` | Dot joint path to the python disconnect handler callable | +| error | `string` | Dot joint path to the python error handler callable | + +### ACK packet + +The basic unit of information in the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol) is the packet. There are 7 distinct [packet types](https://github.com/socketio/socket.io-protocol#packet-types). The `publish` and `subscribe` [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s expressed in the A2S YAML above correspond to the [EVENT](https://github.com/socketio/socket.io-protocol#2---event) and [BINARY_EVENT](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. These are essentially the packets that are transmitted when the Socket.IO sender invokes the `emit` or `send` API functions of the Socket.IO library (regardless of implementation). In turn, the Socket.IO event receiver handles the received event using the `on` API function of the Socket.IO library. As part of the `on` handler, the receiver may choose to return an acknowledgement of the received message. This acknowledgement is conveyed back to the transmitter via the [ACK](https://github.com/socketio/socket.io-protocol#3---ack) and [BINARY_ACK](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. This ack data is passed as input into the callback that the message transmitter has provided through the `emit`/`send` invocation. + +In order to express the above acknowledgement semantics, the A2S specification needs to be extended as follows: + +- [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s MAY include the `x-ack` field. The value of this field SHOULD be a [Message Ack Object](#message-ack-object). +- [Components Object](https://www.asyncapi.com/docs/specifications/2.0.0#componentsObject) MAY include the `x-messageAcks` field. The value of this field should be of type: `Map[string, Message Ack Object | Reference Object]` + +Although Asynction uses these fields to validate the input args of the callback functions, these ACK extentions are necessary to express semantics of the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol), regardless of any tooling used for automation / code generation. + +#### Message Ack Object + +| Field Name | Type | Description | +| ---------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| args | [Schema Object](https://www.asyncapi.com/docs/specifications/2.0.0#schemaObject) | Schema of the arguments that are passed as input to the acknowledgement callback function. In the case of multiple arguments, use the `array` type to express the tuple. | + +In the future, the Message Ack Object may be extended with extra fields to enable additional documentation of the callback. + +### Security handers + +In order to support the [AuthN/AuthZ functionality](#security-authentication-and-authorization) of asynction, the [Security Scheme Object](https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject) needs to be extended as follows: + +- A Security Scheme Object of `oauth2` type MUST include the `x-tokenInfoFunc` field. +- A Security Scheme Object of `oauth2` type MAY include the `x-scopeValidateFunc` field. +- A Security Scheme Object of basic `http` type MUST include the `x-basicInfoFunc` field. +- A Security Scheme Object of bearer `http` type MUST include the `x-basicBearerInfoFunc` field. +- A Security Scheme Object of bearer `apiKey` type MUST include the `x-apiKeyInfoFunc` field. + +The value of all these fields MUST be of `string` type, expressing a dot joint path to a python callable (the security handler). + +### Per Namespace Security + +The `x-security` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/v2.0.0#channelItemObject). +The value of this field MUST be an `array` of [Security Requirement Objects](https://www.asyncapi.com/docs/specifications/v2.0.0#securityRequirementObject) which is the same format used to specify [Server Security Requirements](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). +If a namespace specifies `x-security` the security requirements specified for that namespace will overwrite any security requirements specified in the [Server Object](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). + + + + +%package help +Summary: Development documents and examples for asynction +Provides: python3-asynction-doc +%description help +# Asynction + +[![Tests Status](https://github.com/dedoussis/asynction/workflows/tests/badge.svg)](https://github.com/dedoussis/asynction/actions/workflows/tests.yml) [![codecov](https://codecov.io/gh/dedoussis/asynction/branch/main/graph/badge.svg?token=3720QP2994)](https://codecov.io/gh/dedoussis/asynction) [![PyPI version](https://img.shields.io/pypi/v/asynction)](https://pypi.org/project/asynction/) + +SocketIO python framework driven by the [AsyncAPI](https://www.asyncapi.com/) specification. Built on top of [Flask-SocketIO](https://github.com/miguelgrinberg/Flask-SocketIO). Inspired by [Connexion](https://github.com/zalando/connexion). + +The purpose of Asynction is to empower a specification first approach when developing [SocketIO](https://socket.io/) APIs in Python. It guarantees that your API will work in accordance with its documentation. + +_Disclaimer: Asynction is still at a beta stage. Extensive testing is recommended when using this library in production._ + +## Features + +- Registers all event and error handlers that are referenced within the API specification. +- Provides out of the box validation on every Socket.IO interraction. In particular: + - Event validation (for both ingress and egress events), based on the specified message schemata + - HTTP request validation, upon connection, based on the channel binding schemata of each namespace + - Callback validation, upon the ACK of a message, based on the message `x-ack` schemata +- [Security](#security-authentication-and-authorization) à la [Connexion](https://connexion.readthedocs.io/en/latest/security.html). Handles OAuth2 and HTTP based authentication. +- Generates HTML rendered docs, similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). The docs get served through the `GET {base_path}/docs` route of the app. +- [Mock server support](#mock-server) +- [CLI](#cli) + +A complete example can be found [here](example/) (includes examples of both normal and mock server implementations). + +## Prerequisites + +- Python 3.7 (or higher) + +## Install + +```console +$ pip install asynction +``` + +With mock server support: + +```console +$ pip install asynction[mock] +``` + +With CLI support: + +```console +$ pip install asynction[cli] +``` + +The CLI can also be installed via Homebrew: + +```console +$ brew tap dedoussis/tap +$ brew install asynction +``` + +## Usage (basic example) + +Example event and error handler callables located at `./my_api/handlers.py`: + +```python +# /user namespace + +def user_sign_up(data): + logger.info("Signing up user...") + emit("metrics", "signup", namespace="/admin", broadcast=True, callback=cb) + +def user_log_in(data): + logger.info("Logging in user...") + emit("metrics", "login", namespace="/admin", broadcast=True, callback=cb) + return True # Ack + +def user_error(e): + logger.error("Error: %s", e) + + +# /admin namespace + +def authenticated_connect(): + token = request.args["token"] + +def admin_error(e): + logger.error("Admin error: %s", e) +``` + +Example specification located at `./docs/asyncapi.yaml`: + +```yaml +asyncapi: 2.3.0 + +info: + title: User Account Service + version: 1.0.0 + description: This service is in charge of processing user accounts + +servers: + production: + url: my-company.com/api/socket.io # Customizes the `path` kwarg that is fed into the `SocketIO` constructor + protocol: wss + +channels: + /user: # A channel is essentially a SocketIO namespace + publish: + message: + oneOf: # The oneOf Messages relationship expresses the supported events that a client may emit under the `/user` namespace + - $ref: "#/components/messages/UserSignUp" + - $ref: "#/components/messages/UserLogIn" + x-handlers: # Default namespace handlers (such as connect, disconnect and error) + error: my_api.handlers.user_error # Equivelant of: `@socketio.on_error("/user")` + /admin: + subscribe: + message: + oneOf: + - "#/components/messages/Metrics" + x-handlers: + connect: my_api.handlers.authenticated_connect # Equivelant of: `@socketio.on("connect", namespace="/admin")` + error: my_api.handlers.admin_error + bindings: # Bindings are used to validate the HTTP request upon connection + $ref: "#/components/channelBindings/AuthenticatedWsBindings" + +components: + messages: + UserSignUp: + name: sign up # The SocketIO event name. Use `message` or `json` for unnamed events. + payload: # Asynction uses payload JSON Schemata for message validation + type: object + x-handler: my_api.handlers.user_sign_up # The handler that is to be registered. Equivelant of: `@socketio.on("sign up", namespace="/user")` + UserLogIn: + name: log in + payload: + type: object + x-handler: my_api.handlers.user_log_in + x-ack: # Specifies the structure of the ACK data that the client should expect + args: + type: boolean + Metrics: + name: metrics + payload: + type: string + enum: [signup, login] + x-ack: # Specifies the structure of the ACK data that the server expects + args: + type: string + + channelBindings: + AuthenticatedWsBindings: + ws: + query: + type: object + properties: + token: + type: string + required: [token] +``` + +Bootstrap the AsynctionSocketIO server: + +```python +from asynction import AsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +asio = AsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, + message_queue="redis://localhost:6379", + # or any other kwarg that the flask_socketio.SocketIO constructor accepts +) + +if __name__ == "__main__": + asio.run(app=flask_app) +``` + +The `AsynctionSocketIO` class extends the `SocketIO` class of the Flask-SocketIO library. +The above `asio` server object has all the event and error handlers registered, and is ready to run. +Validation of the message payloads, the channel bindings and the ack callbacks is also enabled by default. +Without Asynction, one would need to add additional boilerplate to register the handlers (as shown [here](https://flask-socketio.readthedocs.io/en/latest/#error-handling)) and implement the respective validators. + +## Security (Authentication and Authorization) + +Asynction supports authentication of incoming connections through the security mechanisms specified in the AsyncAPI spec of an application. See [this guide](https://www.asyncapi.com/docs/getting-started/security) on how to add security as part of an API specification. To take advantage of this feature, a security handler callable should be attached to each security scheme definition under the [components](https://www.asyncapi.com/docs/specifications/v2.3.0#componentsObjectSecuritySchemes) section. To attach a security handler(s), see the [security specification extention](#security-handers) section below. + +The security handler callable(s) will be called upon every new client connection and MUST return a [`SecurityInfo`](https://asynction.dedouss.is/#asynction.SecurityInfo) typed dictionary (which allows extra keys). Asynction then validates this returned dictionary, refusing the connection to any unauthenticated/unauthorised requests. Finally, the validated `SecurityInfo` dictionary is passed to the connection handler as an extra `token_info` kwarg, to allow further/custom processing if needed. + +## Docs + +API documentation is autogenerated by Asynction and served through the following routes of the app: + +- `{base_path}/docs`: Rendered HTML docs similar to the AsyncAPI [playground](https://playground.asyncapi.io/?load=https://raw.githubusercontent.com/asyncapi/asyncapi/master/examples/2.0.0/simple.yml). +- `{base_path}/docs/asyncapi.json`: The raw specification data exposed for programmatic retrieval. + +The `base_path` is determined automagically through the Socket.IO path argument. It essentially is the parent of that path. For example: + +| Socket.IO path | Base path | Docs path | +| --------------------- | --------- | -------------- | +| `socket.io` (default) | `/` | `/docs` | +| `events/socket.io` | `/events` | `/events/docs` | + +Docs can be disabled by toggling the `docs` kwarg of the `AsynctionSocketIO.from_spec` factory method. + +## Emitting from an external process + +All validation features of Asynction can be used when emitting/sending events from an external process. See the [relevant Flask-SocketIO documentation](https://flask-socketio.readthedocs.io/en/latest/deployment.html#emitting-from-an-external-process). Note that the SocketIO instance of the external process needs to be constructed using the same `AsynctionSocketIO.from_spec` factory. + +##  Mock server + +Asynction can also create a fake "mock" based off an AsyncAPI document. This enables the consumers of a SocketIO API to interract with the API before it's even built. + +```python +from asynction import MockAsynctionSocketIO +from flask import Flask + +flask_app = Flask(__name__) + +mock_asio = MockAsynctionSocketIO.from_spec( + spec_path="./docs/asyncapi.yaml", + app=flask_app, +) + +if __name__ == "__main__": + mock_asio.run(app=flask_app) +``` + +The mock server: + +1. Listens for all events defined in the given spec, returning fake acknowledgements where applicable. +1. Periodically emits events containing payloads of fake data, for the clients to listen on. + +The fake data generation is fueled by [Faker](https://faker.readthedocs.io/en/master/) and [Hypothesis](https://hypothesis.readthedocs.io/en/latest/), hence the use of the mock server functionality requires the installation of extra dependecies: `pip install asynction[mock]` + +To make the fake generated data more realistic, one may attach faker providers to the string schemata of their spec using the [format](https://json-schema.org/understanding-json-schema/reference/string.html#format) keyword of JSON Schema: + +```yaml +# example of a Message object +NewMessageReceived: + name: new message + payload: + type: object + properties: + username: + type: string + format: first_name + message: + type: string + format: sentence + required: [username, message] +``` + +The formats supported are essentially all the [faker providers](https://faker.readthedocs.io/en/master/providers.html) that yield a string value. + +## CLI + +For convenience, Asynction provides a command-line interface (CLI) that aims to be a toolbox of useful utilities for the development, testing and mocking of Asynction apps (ie any Socket.IO app driven by an AsyncAPI doc). For example, it allows one to run a "mock" instance of their Socket.IO server, only by passing the AsyncAPI YAML file, without even having to start the development of the server itself. + +All commands support the `–-help` (or `-h`) argument to display additional information. + +### Available commands + +- `mock run` + + ```console + $ asynction --spec ./docs/asyncapi.yml mock run --port 5001 --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 + (71320) wsgi starting up on http://0.0.0.0:5001 + ... + ``` + +- `scaffold` _(coming soon)_ + + ```console + $ asynction --spec ./docs/asyncapi.yml scaffold + ✨ Successfully generated app.py + ``` + +### Dockerised + +The CLI can be installed via pip or Homebrew (see the [install section](#install)) but is also available through docker, negating the need for a local python environment: + +```console +$ docker run -v ${PWD}/docs/asyncapi.yml:/opt/asynction/asyncapi.yml dedoussis/asynction mock run --debugger + * Restarting with stat + * Debugger is active! + * Debugger PIN: 339-844-897 +(71320) wsgi starting up on http://0.0.0.0:5000 +... +``` + +## Further resources + +- [API reference](https://asynction.dedouss.is) +- [Complete example](example/) + +## Specification Extentions + +Asynction has extended the AsyncAPI 2.x.x specification to provide support for coupling SocketIO semantical entities (such as namespaces, events and acks) to python objects (such as handler callabes or other `flask_socketio.SocketIO` methods). Some of the extentions below are necessary to express the Socket.IO protocol semantics, while others are solely needed for the programmatic purposes of Asynction. The extentions introduced adhere to the [Specification Extention guidelines](https://www.asyncapi.com/docs/specifications/2.0.0#specificationExtensions) of the AsyncAPI spec. + +For further guidance on how to generally express a SocketIO API using AsyncAPI, refer to this article: + +### Event handler + +The `x-handler` field MAY be defined as an additional property of the [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject). The value of this field MUST be of `string` type, expressing a dot joint path to a python callable (the event handler). + +Message Objects listed under a `subscribe` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) MUST include the `x-handler` field. +Message Objects listed under a `publish` [operation](https://www.asyncapi.com/docs/specifications/2.0.0#operationObject) SHOULD NOT include the `x-handler` field. + +### Default namespace handlers + +The `x-handlers` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/2.0.0#channelItemObject). The value of this field SHOULD be a [Channel Handlers Object](#channel-handlers-object). + +#### Channel Handlers Object + +| Field Name | Type | Description | +| ---------- | -------- | -------------------------------------------------------- | +| connect | `string` | Dot joint path to the python connect handler callable | +| disconnect | `string` | Dot joint path to the python disconnect handler callable | +| error | `string` | Dot joint path to the python error handler callable | + +### ACK packet + +The basic unit of information in the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol) is the packet. There are 7 distinct [packet types](https://github.com/socketio/socket.io-protocol#packet-types). The `publish` and `subscribe` [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s expressed in the A2S YAML above correspond to the [EVENT](https://github.com/socketio/socket.io-protocol#2---event) and [BINARY_EVENT](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. These are essentially the packets that are transmitted when the Socket.IO sender invokes the `emit` or `send` API functions of the Socket.IO library (regardless of implementation). In turn, the Socket.IO event receiver handles the received event using the `on` API function of the Socket.IO library. As part of the `on` handler, the receiver may choose to return an acknowledgement of the received message. This acknowledgement is conveyed back to the transmitter via the [ACK](https://github.com/socketio/socket.io-protocol#3---ack) and [BINARY_ACK](https://github.com/socketio/socket.io-protocol#5---binary_event) packet types. This ack data is passed as input into the callback that the message transmitter has provided through the `emit`/`send` invocation. + +In order to express the above acknowledgement semantics, the A2S specification needs to be extended as follows: + +- [Message Object](https://www.asyncapi.com/docs/specifications/2.0.0#messageObject)s MAY include the `x-ack` field. The value of this field SHOULD be a [Message Ack Object](#message-ack-object). +- [Components Object](https://www.asyncapi.com/docs/specifications/2.0.0#componentsObject) MAY include the `x-messageAcks` field. The value of this field should be of type: `Map[string, Message Ack Object | Reference Object]` + +Although Asynction uses these fields to validate the input args of the callback functions, these ACK extentions are necessary to express semantics of the [Socket.IO protocol](https://github.com/socketio/socket.io-protocol), regardless of any tooling used for automation / code generation. + +#### Message Ack Object + +| Field Name | Type | Description | +| ---------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| args | [Schema Object](https://www.asyncapi.com/docs/specifications/2.0.0#schemaObject) | Schema of the arguments that are passed as input to the acknowledgement callback function. In the case of multiple arguments, use the `array` type to express the tuple. | + +In the future, the Message Ack Object may be extended with extra fields to enable additional documentation of the callback. + +### Security handers + +In order to support the [AuthN/AuthZ functionality](#security-authentication-and-authorization) of asynction, the [Security Scheme Object](https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject) needs to be extended as follows: + +- A Security Scheme Object of `oauth2` type MUST include the `x-tokenInfoFunc` field. +- A Security Scheme Object of `oauth2` type MAY include the `x-scopeValidateFunc` field. +- A Security Scheme Object of basic `http` type MUST include the `x-basicInfoFunc` field. +- A Security Scheme Object of bearer `http` type MUST include the `x-basicBearerInfoFunc` field. +- A Security Scheme Object of bearer `apiKey` type MUST include the `x-apiKeyInfoFunc` field. + +The value of all these fields MUST be of `string` type, expressing a dot joint path to a python callable (the security handler). + +### Per Namespace Security + +The `x-security` field MAY be defined as an additional property of the [Channel Item Object](https://www.asyncapi.com/docs/specifications/v2.0.0#channelItemObject). +The value of this field MUST be an `array` of [Security Requirement Objects](https://www.asyncapi.com/docs/specifications/v2.0.0#securityRequirementObject) which is the same format used to specify [Server Security Requirements](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). +If a namespace specifies `x-security` the security requirements specified for that namespace will overwrite any security requirements specified in the [Server Object](https://www.asyncapi.com/docs/specifications/v2.0.0#serverObject). + + + + +%prep +%autosetup -n asynction-0.8.3 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-asynction -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Mon May 15 2023 Python_Bot - 0.8.3-1 +- Package Spec generated diff --git a/sources b/sources new file mode 100644 index 0000000..c2f0710 --- /dev/null +++ b/sources @@ -0,0 +1 @@ +ea2d43ecbdca3c74f59dee6447447885 asynction-0.8.3.tar.gz -- cgit v1.2.3