{"id":29572680,"url":"https://github.com/accelbyte/extend-event-handler-python","last_synced_at":"2025-07-19T05:10:51.880Z","repository":{"id":208908931,"uuid":"675486232","full_name":"AccelByte/extend-event-handler-python","owner":"AccelByte","description":"A sample Extend Event Handler app written in Python","archived":false,"fork":false,"pushed_at":"2025-06-10T22:53:41.000Z","size":623,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-06-10T23:34:21.419Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AccelByte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-08-07T03:25:23.000Z","updated_at":"2025-06-10T22:53:45.000Z","dependencies_parsed_at":"2024-02-13T05:23:31.123Z","dependency_job_id":"93de366d-6457-4e33-bcb7-297b16e475fc","html_url":"https://github.com/AccelByte/extend-event-handler-python","commit_stats":null,"previous_names":["accelbyte/extend-event-handler-python"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AccelByte/extend-event-handler-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AccelByte%2Fextend-event-handler-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AccelByte%2Fextend-event-handler-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AccelByte%2Fextend-event-handler-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AccelByte%2Fextend-event-handler-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AccelByte","download_url":"https://codeload.github.com/AccelByte/extend-event-handler-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AccelByte%2Fextend-event-handler-python/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265892509,"owners_count":23845032,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-19T05:10:51.235Z","updated_at":"2025-07-19T05:10:51.867Z","avatar_url":"https://github.com/AccelByte.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# extend-event-handler-python \r\n\r\n```mermaid\r\nflowchart LR\r\n   subgraph AccelByte Gaming Services\r\n   KF[Kafka]\r\n   KB[Kafka Connect]\r\n   end\r\n   subgraph Extend Event Handler App\r\n   SV[\"gRPC Server\"]   \r\n   KB --- SV\r\n   KF --- KB\r\n   end   \r\n```\r\n\r\n`AccelByte Gaming Services` (AGS) capabilities can be enhanced using \r\n`Extend Event Handler` apps. An `Extend Event Handler` app is a `gRPC server` \r\nthat receives AGS events through `Kafka Connect` and performs actions based on \r\ncustom logic.\r\n\r\n## Overview\r\n\r\nThis repository provides a project template for an `Extend Event Handler` \r\napp written in `Python`. It includes an example to handle AGS `userLoggedIn` event \r\nand grant an item to the user. Additionally, it comes with built-in \r\ninstrumentation for observability, ensuring that metrics, traces, and logs are \r\navailable upon deployment.\r\n\r\nYou can clone this repository to begin developing your own `Extend Event Handler`\r\napp. Simply modify this project by including the AGS event spec files\r\nyou need and implement custom logic to handle those events.\r\n\r\n## Project Structure\r\n\r\nHere are some important folders you need to know to be able to start modifying\r\nthis project.\r\n\r\n```text\r\n...\r\n├── src\r\n│  └── app\r\n│    ├── proto                   # AGS event spec files (*.proto) and code generated from them\r\n│    └── services\r\n│      ├── __init__.py\r\n│      └── login_handler.py      # Logic to handle AGS event is implemented here\r\n...\r\n```\r\n\r\n\u003e :exclamation: In the example included in this project, we focus solely on the\r\n`userLoggedIn` event. Therefore, only the AGS event spec files \r\nfor IAM are included. For other events, the AGS event spec files are available\r\n[here](https://github.com/AccelByte/accelbyte-api-proto/tree/main/asyncapi/accelbyte). \r\n\r\n## Prerequisites\r\n\r\nBefore starting, you will need the following.\r\n\r\n1. Windows 11 WSL2 or Linux Ubuntu 22.04 or macOS 14+ with the following tools installed:\r\n\r\n   a. Bash\r\n\r\n      - On Windows WSL2 or Linux Ubuntu:\r\n\r\n         ```\r\n         bash --version\r\n\r\n         GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)\r\n         ...\r\n         ```\r\n\r\n      - On macOS:\r\n\r\n         ```\r\n         bash --version\r\n\r\n         GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23)\r\n         ...\r\n         ```\r\n\r\n   b. Make\r\n\r\n      - On Windows WSL2 or Linux Ubuntu:\r\n\r\n         To install from the Ubuntu repository, run `sudo apt update \u0026\u0026 sudo apt install make`.\r\n\r\n         ```\r\n         make --version\r\n\r\n         GNU Make 4.3\r\n         ...\r\n         ```\r\n\r\n      - On macOS:\r\n\r\n         ```\r\n         make --version\r\n\r\n         GNU Make 3.81\r\n         ...\r\n         ```\r\n\r\n   c. Docker (Docker Desktop 4.30+/Docker Engine v23.0+)\r\n   \r\n      - On Linux Ubuntu:\r\n\r\n         1. To install from the Ubuntu repository, run `sudo apt update \u0026\u0026 sudo apt install docker.io docker-buildx docker-compose-v2`.\r\n         2. Add your user to the `docker` group: `sudo usermod -aG docker $USER`.\r\n         3. Log out and log back in to allow the changes to take effect.\r\n\r\n      - On Windows or macOS:\r\n\r\n         Follow Docker's documentation on installing the Docker Desktop on [Windows](https://docs.docker.com/desktop/install/windows-install/) or [macOS](https://docs.docker.com/desktop/install/mac-install/).\r\n\r\n         ```\r\n         docker version\r\n\r\n         ...\r\n         Server: Docker Desktop\r\n            Engine:\r\n            Version:          24.0.5\r\n         ...\r\n         ```\r\n\r\n   d. Python 3.10\r\n\r\n      - On Linux Ubuntu:\r\n\r\n         To install from the Ubuntu repository, run `sudo apt update \u0026\u0026 sudo apt install python3 python3-venv`.\r\n\r\n      - On Windows or macOS:\r\n\r\n         Use the available installer [here](https://www.python.org/downloads/).\r\n\r\n         ```\r\n         python3 --version\r\n\r\n         Python 3.10.12\r\n         ```\r\n\r\n   e. [Postman](https://www.postman.com/)\r\n\r\n      - Use binary available [here](https://www.postman.com/downloads/)\r\n\r\n   f. [extend-helper-cli](https://github.com/AccelByte/extend-helper-cli)\r\n\r\n      - Use the available binary from [extend-helper-cli](https://github.com/AccelByte/extend-helper-cli/releases).\r\n\r\n   \u003e :exclamation: In macOS, you may use [Homebrew](https://brew.sh/) to easily install some of the tools above.\r\n\r\n2. Access to `AccelByte Gaming Services` environment.\r\n\r\n   a. Base URL:\r\n\r\n      - For `Starter` tier e.g.  https://spaceshooter.prod.gamingservices.accelbyte.io\r\n      - For `Premium` tier e.g.  https://dev.accelbyte.io\r\n\r\n   b. [Create a Game Namespace](https://docs.accelbyte.io/gaming-services/services/access/reference/namespaces/manage-your-namespaces/) if you don't have one yet. Keep the `Namespace ID`.\r\n\r\n\r\n   c. [Create an OAuth Client](https://docs.accelbyte.io/gaming-services/services/access/authorization/manage-access-control-for-applications/#create-an-iam-client) with confidential client type with the following permissions. Keep the `Client ID` and `Client Secret`.\r\n   \r\n   - For AGS Premium customers:\r\n      - `ADMIN:NAMESPACE:{namespace}:USER:*:FULFILLMENT [CREATE]`\r\n   - For AGS Starter customers:\r\n      - Platform Store -\u003e Fulfillment (Create)\r\n\r\n3. A published `AGS` Store. Take a note of the `item id` which is to be granted after a user in a certain namespace successfully logged in.\r\n\r\n## Setup\r\n\r\nTo be able to run this app, you will need to follow these setup steps.\r\n\r\n1. Create a docker compose `.env` file by copying the content of \r\n   [.env.template](.env.template) file.\r\n\r\n   \u003e :warning: **The host OS environment variables have higher precedence \r\n   compared to `.env` file variables**: If the variables in `.env` file do not \r\n   seem to take effect properly, check if there are host OS environment \r\n   variables with the same name.  See documentation about \r\n   [docker compose environment variables precedence](https://docs.docker.com/compose/how-tos/environment-variables/envvars-precedence/) \r\n   for more details.\r\n\r\n2. Fill in the required environment variables in `.env` file as shown below.\r\n\r\n   ```\r\n   AB_BASE_URL=https://demo.accelbyte.io     # Base URL of AccelByte Gaming Services demo environment\r\n   AB_CLIENT_ID='xxxxxxxxxx'                 # Client ID from the Prerequisites section\r\n   AB_CLIENT_SECRET='xxxxxxxxxx'             # Client Secret from the Prerequisites section\r\n   AB_NAMESPACE='xxxxxxxxxx'                 # Namespace ID from the Prerequisites section\r\n   ITEM_ID_TO_GRANT='xxxxxxxxxx'             # Item id from a published store we noted previously\r\n   ```\r\n\r\n## Building\r\n\r\nTo build this app, use the following command.\r\n\r\n```\r\nmake build\r\n```\r\n\r\n## Running\r\n\r\nTo (build and) run this app in a container, use the following command.\r\n\r\n```\r\ndocker compose up --build\r\n```\r\n\r\n## Testing\r\n\r\n### Test in Local Development Environment\r\n\r\nThis app can be tested locally using [Postman](https://www.postman.com/).\r\n\r\n1. Run this app by using the command below.\r\n\r\n   ```shell\r\n   docker compose up --build\r\n   ```\r\n\r\n2. Open `Postman`, create a new `gRPC request`, and enter `localhost:6565` as the URL.\r\n\r\n   ![Postman new grpc request](./docs/postman-new-grpc-request.png)\r\n\r\n   \u003e :warning: **If you are running [grpc-plugin-dependencies](https://github.com/AccelByte/grpc-plugin-dependencies) stack alongside this project as mentioned in [Test Observability](#test-observability)**: Use `localhost:10000` instead of `localhost:6565`. This way, the `gRPC server` will be called via `Envoy` service within `grpc-plugin-dependencies` stack instead of directly.\r\n\r\n3. Since we are interested in `userLoggedIn` event, select `UserAuthenticationUserLoggedInService/OnMessage` method. \r\n\r\n   ![Postman new grpc request](./docs/postman-select-grpc-method.png)\r\n\r\n4. Send a `userLoggedIn` event to the gRPC server by copying and pasting the sample Kafka event JSON below, then click `Invoke`. For the sample provided in this Extend app template, ensure that you provide valid values for at least `namespace` and `userId`.\r\n\r\n   ```json\r\n   {\r\n     \"payload\": {\r\n        \"userAccount\": {\r\n           \"userId\": \"string\",\r\n           \"emailAddress\": \"string\",\r\n           \"country\": \"string\",\r\n           \"namespace\": \"string\"\r\n        },\r\n        \"userAuthentication\": {\r\n           \"platformId\": \"string\",\r\n           \"refresh\": true\r\n        }\r\n     },\r\n     \"id\": \"string\",\r\n     \"version\": 0,\r\n     \"name\": \"string\",\r\n     \"namespace\": \"string\",\r\n     \"parentNamespace\": \"string\",\r\n     \"timestamp\": \"2019-08-24T14:15:22Z\",\r\n     \"clientId\": \"string\",\r\n     \"userId\": \"string\",\r\n     \"traceId\": \"string\",\r\n     \"sessionId\": \"string\"\r\n   }\r\n   ```\r\n\r\n   \u003e :exclamation: **For other AGS events:** You can find the information and the corresponding sample Kafka event JSON\r\n   [here](https://docs.accelbyte.io/gaming-services/knowledge-base/api-events/achievement/).\r\n \r\n5. If successful, the response will appear as shown below, and you will also be able to see the item granted to the user you are using for this test.\r\n\r\n   ![Postman new grpc request](./docs/postman-grpc-response.png)\r\n\r\n   ![Granted entitlement](./docs/granted-entitlement.png)\r\n\r\n### Test Observability\r\n\r\nTo be able to see the how the observability works in this app locally, there are few things that need be setup before performing tests.\r\n\r\n1. Uncomment loki logging driver in [docker-compose.yaml](docker-compose.yaml)\r\n\r\n   ```\r\n    # logging:\r\n    #   driver: loki\r\n    #   options:\r\n    #     loki-url: http://host.docker.internal:3100/loki/api/v1/push\r\n    #     mode: non-blocking\r\n    #     max-buffer-size: 4m\r\n    #     loki-retries: \"3\"\r\n   ```\r\n\r\n   \u003e :warning: **Make sure to install docker loki plugin beforehand**: Otherwise,\r\n   this project will not be able to run. This is required so that container logs\r\n   can flow to the `loki` service within `grpc-plugin-dependencies` stack. \r\n   Use this command to install docker loki plugin: `docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions`.\r\n\r\n2. Clone and run [grpc-plugin-dependencies](https://github.com/AccelByte/grpc-plugin-dependencies) stack alongside this project. After this, Grafana \r\nwill be accessible at http://localhost:3000.\r\n\r\n   ```\r\n   git clone https://github.com/AccelByte/grpc-plugin-dependencies.git\r\n   cd grpc-plugin-dependencies\r\n   docker compose up\r\n   ```\r\n\r\n   \u003e :exclamation: More information about [grpc-plugin-dependencies](https://github.com/AccelByte/grpc-plugin-dependencies) is available [here](https://github.com/AccelByte/grpc-plugin-dependencies/blob/main/README.md).\r\n\r\n3. Perform testing. For example, by following [Test in Local Development Environment](#test-in-local-development-environment).\r\n\r\n## Deploying\r\n\r\nAfter completing testing, the next step is to deploy your app to `AccelByte Gaming Services`.\r\n\r\n1. **Create an Extend Event Handler app**\r\n\r\n   If you do not already have one, create a new [Extend Event Handler App](https://docs.accelbyte.io/gaming-services/services/extend/event-handler/getting-started-event-handler/#create-the-extend-app).\r\n\r\n   On the **App Detail** page, take note of the following values.\r\n   - `Namespace`\r\n   - `App Name`\r\n\r\n2. **Build and Push the Container Image**\r\n\r\n   Use [extend-helper-cli](https://github.com/AccelByte/extend-helper-cli) to build and upload the container image.\r\n\r\n   ```\r\n   extend-helper-cli image-upload --login --namespace \u003cnamespace\u003e --app \u003capp-name\u003e --image-tag v0.0.1\r\n   ```\r\n\r\n   \u003e :warning: Run this command from your project directory. If you are in a different directory, add the `--work-dir \u003cproject-dir\u003e` option to specify the correct path.\r\n\r\n3. **Deploy the Image**\r\n   \r\n   On the **App Detail** page:\r\n   - Click **Image Version History**\r\n   - Select the image you just pushed\r\n   - Click **Deploy Image**\r\n\r\n## Next Step\r\n\r\nProceed by modifying this `Extend Event Handler` app template to implement your own custom logic. For more details, see [here](https://docs.accelbyte.io/gaming-services/services/extend/event-handler/how-to-listen-and-handle-different-ags-events/).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faccelbyte%2Fextend-event-handler-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faccelbyte%2Fextend-event-handler-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faccelbyte%2Fextend-event-handler-python/lists"}