🍰
Grasshopper ES por BetweenRealities
  • Using and Generating Documentation
    • GitHub
    • Discord
      • Speckle Webhooks
    • Speckle Client
  • Potencial technological implementations
  • 🧞Compute
    • Introducción a Grasshopper
      • Customizar Entorno
        • VSCode
      • Rhinoceros 3d
      • Hops
      • Galapagos
    • Modelos Informados
      • Comportamiento Estructural
        • Automatizar cálculo Python
      • OOP
      • Rhino Inside Revit
        • Revit
          • Modelado 3d en Revit
          • Certificación profesional Revit
      • Energía
    • Procesos Urbanos
      • Automatizar Qgis
      • Librerías Python
      • Librerías Grasshopper
      • Stable Diffusion
    • Programación
      • RhinoPython
        • Anatomía del script
        • Python básico
        • Tuples, listas y diccionarios
        • Operadores y funciones
        • Ejecución condicional
        • Geometría
        • Clases
      • Multithread
  • 🪅Database
    • Lenguaje Python
      • Types and operations
      • Statements and syntax
      • Function and generators
      • Modules and packages
      • Classes and OPP
      • Exception and tools
      • Advance topics
    • Análisis de la Información
      • Comparison with SQL
      • Comparison with R / R libraries
      • Pandas
    • Abrir Acceso
      • Rest API Abierta
    • Blockchain Descentralización
  • 🕸️COLLECT
    • Captura de Datos
      • Raspberry Pi
        • Encendido y apagado automático
      • Arduino
      • UAS
      • Fotogrametría
        • Crashes
    • Técnicas Machine Learning
      • Clasificación
      • Computer Vision
    • Computación en la Nube
      • Contenedores
      • Azure
      • Ubuntu Server Deploy
      • PostgreSQL Server
      • Rhino Compute Deploy
  • 🍭INTERACT
    • Introducción a Unreal Engine
      • Ejecutar Python
      • Datasmith
      • Materiales
        • Crear PBR
        • Materiales Introducción
      • Iluminación
        • Iluminación Introducción
        • Raytraced Iluminación Cinemática
      • Assets Management
    • Interacción Inmersiva
      • Blueprints
        • Blueprints estandar
        • Blueprints Introducción
        • Diseño Nivel
      • Packaging
      • Performance
    • Interfaces Bidimensionales
Con tecnología de GitBook
En esta página

¿Te fue útil?

  1. Using and Generating Documentation
  2. Discord

Speckle Webhooks

Build a simple Discord integration that will send notifications when stream events occur on your Speckle Server - and learn how to use Speckle's webhooks in the process!

a WebhookServer that will listen for webhook requests from your stream a webhook_called function that will verify that the signature of incoming requests a Discord message template an on_stream_update function which populates your Discord message template with data from your webhook payload an add_author function which handles the author's info and avatar (whether it's a URL or a base64 image that needs to be decoded and attached) a send_to_discord method which puts together and sends a POST request to Discord to send your message

import cherrypy
import requests
import base64
import json
import hmac


# It's not a good practice to hardcode the secret or the URL. It's best to get it from an environment variable.
# See the finished project for an example.
SECRET = ""
DISCORD_URL = "https://discord.com/api/webhooks/1023657743040659466/oyr5N5hhxRScNcqI4ISPNnRd8RFzbOC4bX9dCCkv0z-kfVJAtHKtSoRg5Cja0oPn3mqz"


def get_message_template():
    return {
        "username": "Speckle",
        "avatar_url": "https://avatars.githubusercontent.com/u/65039012?s=200&v=4",
        "embeds": [
            {
                "author": {
                    "name": "speckle user",
                    "url": "",
                    "icon_url": "https://avatars.githubusercontent.com/u/65039012?s=200&v=4",
                },
                "title": "",
                "url": "",
                "description": "",
                "color": 295163,
                "image": {"url": None},
            }
        ],
        "files": [],
    }


def send_to_discord(message: str):
    files = message.pop("files")  # any images we're attaching (user avatar)
    # dump our message to the `payload_json` field
    files.append(("payload_json", (None, json.dumps(message))))
    res = requests.post(DISCORD_URL, files=files)


def add_author(msg, user_info, server_url):
    avatar = user_info["avatar"]  # get the user's avatar
    if avatar and not avatar.startswith("http"):
        type = avatar[5:].split(";")[0]
        filename = f"avatar.{type.split('/')[1]}"
        # decode and prepare it for being uploaded
        msg["files"].append(
            (
                "file",
                (
                    filename,
                    (base64.b64decode(avatar.split(",")[1])),
                    type,
                ),
            )
        )
        avatar = f"attachment://{filename}"  # attachment syntax for files

    msg["embeds"][0]["author"].update(
        {
            "name": user_info["name"],
            "url": f"{server_url}/profile/{user_info['id']}",
            "icon_url": avatar,
        }
    )


def on_stream_update(server_info, user_info, stream_info, webhook_info, event_info):
    server_url = server_info["canonicalUrl"].rstrip("/")
    msg = get_message_template()
    msg["embeds"][0].update(
        {
            "title": f"Stream Updated: [{stream_info['name']}]",
            "url": f"{server_url}/streams/{stream_info['id']}",
            "description": f"{user_info['name']} updated stream `{stream_info['id']}`",
            "fields": [
                {
                    "name": "Old",
                    "value": f"**Name:** {event_info['old']['name']}\n**Description:** {event_info['old']['description'] if len(event_info['old']['description']) < 30 else event_info['old']['description'][:30] + '...'}\n**Is Public:** {event_info['old']['isPublic']}",
                    "inline": True,
                },
                {
                    "name": "Updated",
                    "value": f"**Name:** {event_info['new']['name']}\n**Description:** {event_info['new']['description'] if len(event_info['new']['description']) < 30 else event_info['new']['description'][:30] + '...'}\n**Is Public:** {event_info['new']['isPublic']}",
                    "inline": True,
                },
            ],
            "image": {"url": f"{server_url}/preview/{stream_info['id']}"},
        }
    )
    add_author(msg, user_info, server_url)  # * see next section for more info on this
    send_to_discord(msg)


# Web server:
class WebhookServer(object):
    @cherrypy.expose
    @cherrypy.tools.json_in()
    def webhook(self, *args, **kwargs):
        payload_json = cherrypy.request.json.get("payload", "{}")
        signature = cherrypy.request.headers["X-WEBHOOK-SIGNATURE"]
        self.webhook_called(payload_json, signature)

    # This function will be called each time the webhook endpoint is accessed
    def webhook_called(self, payload_json: str, signature: str):
        # verify the signature
        expected_signature = hmac.new(
            SECRET.encode(), payload_json.encode(), "sha256"
        ).hexdigest()
        if not hmac.compare_digest(expected_signature, signature):
            print("Ignoring request with invalid signature")
            return
        payload = json.loads(payload_json)
        print("Received webhook payload:\n" + json.dumps(payload, indent=4))

        # check the event and invoke the correct response
        event_name = payload.get("event", {}).get("event_name", "UNKNOWN")
        if event_name == "stream_update":
            on_stream_update(
                payload["server"],
                payload["user"],
                payload["stream"],
                payload["webhook"],
                payload["event"].get("data", {}),
            )


cherrypy.config.update(
    {
        # TODO: uncomment the following line after finishing development
        # 'environment': 'production',
        "server.socket_host": "0.0.0.0",
        "server.socket_port": 8003,
    }
)

# start the server
cherrypy.quickstart(WebhookServer())

ngrok server: https://dashboard.ngrok.com/get-started/setup webhook discord-speckle: https://speckle.systems/tutorials/webhooks-discord-tutorial/

AnteriorDiscordSiguienteSpeckle Client

Última actualización hace 2 años

¿Te fue útil?