Updated HTML docs.

This commit is contained in:
Evennia docbuilder action 2022-11-30 23:26:44 +00:00
parent 95fc796b1e
commit e64a9c5a4f
55 changed files with 1432 additions and 162 deletions

View file

@ -86,7 +86,6 @@
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">gettext</span> <span class="k">as</span> <span class="n">_</span>
<span class="kn">from</span> <span class="nn">evennia.accounts.accounts</span> <span class="kn">import</span> <span class="n">DefaultAccount</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.scripts</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span><span class="p">,</span> <span class="n">search</span><span class="p">,</span> <span class="n">utils</span>
@ -644,8 +643,9 @@
<div class="viewcode-block" id="DiscordBot"><a class="viewcode-back" href="../../../api/evennia.accounts.bots.html#evennia.accounts.bots.DiscordBot">[docs]</a><span class="k">class</span> <span class="nc">DiscordBot</span><span class="p">(</span><span class="n">Bot</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Discord bot relay. You will need to set up your own bot (https://discord.com/developers/applications)</span>
<span class="sd"> and add the bot token as `DISCORD_BOT_TOKEN` to `secret_settings.py` to use</span>
<span class="sd"> Discord bot relay. You will need to set up your own bot</span>
<span class="sd"> (https://discord.com/developers/applications) and add the bot token as `DISCORD_BOT_TOKEN` to</span>
<span class="sd"> `secret_settings.py` to use</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">factory_path</span> <span class="o">=</span> <span class="s2">&quot;evennia.server.portal.discord.DiscordWebsocketServerFactory&quot;</span>
@ -653,9 +653,11 @@
<div class="viewcode-block" id="DiscordBot.at_init"><a class="viewcode-back" href="../../../api/evennia.accounts.bots.html#evennia.accounts.bots.DiscordBot.at_init">[docs]</a> <span class="k">def</span> <span class="nf">at_init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Load required channels back into memory</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">channel_links</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">channels</span><span class="p">:</span>
<span class="c1"># this attribute contains a list of evennia&lt;-&gt;discord links in the form of (&quot;evennia_channel&quot;, &quot;discord_chan_id&quot;)</span>
<span class="c1"># this attribute contains a list of evennia&lt;-&gt;discord links in the form</span>
<span class="c1"># of (&quot;evennia_channel&quot;, &quot;discord_chan_id&quot;)</span>
<span class="c1"># grab Evennia channels, cache and connect</span>
<span class="n">channel_set</span> <span class="o">=</span> <span class="p">{</span><span class="n">evchan</span> <span class="k">for</span> <span class="n">evchan</span><span class="p">,</span> <span class="n">dcid</span> <span class="ow">in</span> <span class="n">channel_links</span><span class="p">}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">ev_channels</span> <span class="o">=</span> <span class="p">{}</span>
@ -680,7 +682,8 @@
<span class="n">channel</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">channel_links</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">channels</span><span class="p">:</span>
<span class="c1"># this attribute contains a list of evennia&lt;-&gt;discord links in the form of (&quot;evennia_channel&quot;, &quot;discord_chan_id&quot;)</span>
<span class="c1"># this attribute contains a list of evennia&lt;-&gt;discord links in the form</span>
<span class="c1"># of (&quot;evennia_channel&quot;, &quot;discord_chan_id&quot;)</span>
<span class="c1"># grab Evennia channels, cache and connect</span>
<span class="n">channel_set</span> <span class="o">=</span> <span class="p">{</span><span class="n">evchan</span> <span class="k">for</span> <span class="n">evchan</span><span class="p">,</span> <span class="n">dcid</span> <span class="ow">in</span> <span class="n">channel_links</span><span class="p">}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">ev_channels</span> <span class="o">=</span> <span class="p">{}</span>
@ -705,6 +708,7 @@
<span class="sd"> Called by the Channel just before passing a message into `channel_msg`.</span>
<span class="sd"> We overload this to set the channel tag prefix.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">kwargs</span><span class="p">[</span><span class="s2">&quot;no_prefix&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">tag_channel</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_pre_channel_msg</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">channel</span><span class="p">,</span> <span class="n">senders</span><span class="o">=</span><span class="n">senders</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
@ -741,7 +745,7 @@
<span class="sd"> sender (tuple) - The Discord info for the sender in the form (id, nickname)</span>
<span class="sd"> Keyword args:</span>
<span class="sd"> kwargs (optional) - Unused by default, but can carry additional data from the protocol.</span>
<span class="sd"> **kwargs (optional) - Unused by default, but can carry additional data from the protocol.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span></div>
@ -750,17 +754,20 @@
<span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">to_channel</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">from_channel</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">from_server</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
<span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Formats and sends a Discord -&gt; Evennia message. Called when the Discord bot receives a channel message on Discord.</span>
<span class="sd"> Formats and sends a Discord -&gt; Evennia message. Called when the Discord bot receives a</span>
<span class="sd"> channel message on Discord.</span>
<span class="sd"> Args:</span>
<span class="sd"> message (str) - Incoming text from Discord.</span>
<span class="sd"> to_channel (Channel) - The Evennia channel receiving the message</span>
<span class="sd"> Keyword args:</span>
<span class="sd"> sender (tuple) - The Discord info for the sender in the form (id, nickname)</span>
<span class="sd"> sender (tuple) - The Discord info for the sender in the form `(id, nickname)`</span>
<span class="sd"> from_channel (str) - The Discord channel name</span>
<span class="sd"> from_server (str) - The Discord server name</span>
<span class="sd"> kwargs - Any additional keywords. Unused by default, but available for adding additional flags or parameters.</span>
<span class="sd"> kwargs - Any additional keywords. Unused by default, but available for adding additional</span>
<span class="sd"> flags or parameters.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tag_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

View file

@ -84,6 +84,7 @@
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.paginator</span> <span class="kn">import</span> <span class="n">Paginator</span>
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Max</span><span class="p">,</span> <span class="n">Min</span><span class="p">,</span> <span class="n">Q</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">InterruptCommand</span>
<span class="kn">from</span> <span class="nn">evennia.commands.cmdhandler</span> <span class="kn">import</span> <span class="n">get_and_merge_cmdsets</span>
<span class="kn">from</span> <span class="nn">evennia.locks.lockhandler</span> <span class="kn">import</span> <span class="n">LockException</span>

View file

@ -84,6 +84,7 @@
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Q</span>
<span class="kn">from</span> <span class="nn">django.db.models.fields</span> <span class="kn">import</span> <span class="n">exceptions</span>
<span class="kn">from</span> <span class="nn">evennia.server</span> <span class="kn">import</span> <span class="n">signals</span>
<span class="kn">from</span> <span class="nn">evennia.typeclasses.managers</span> <span class="kn">import</span> <span class="n">TypeclassManager</span><span class="p">,</span> <span class="n">TypedObjectManager</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="p">(</span>

View file

@ -91,6 +91,7 @@
<span class="kn">import</span> <span class="nn">inflect</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">gettext</span> <span class="k">as</span> <span class="n">_</span>
<span class="kn">from</span> <span class="nn">evennia.commands</span> <span class="kn">import</span> <span class="n">cmdset</span>
<span class="kn">from</span> <span class="nn">evennia.commands.cmdsethandler</span> <span class="kn">import</span> <span class="n">CmdSetHandler</span>
<span class="kn">from</span> <span class="nn">evennia.objects.manager</span> <span class="kn">import</span> <span class="n">ObjectManager</span>

View file

@ -0,0 +1,667 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.server.portal.discord &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../../" src="../../../../_static/documentation_options.js"></script>
<script src="../../../../_static/jquery.js"></script>
<script src="../../../../_static/underscore.js"></script>
<script src="../../../../_static/doctools.js"></script>
<script src="../../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../../genindex.html" />
<link rel="search" title="Search" href="../../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.server.portal.discord</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../../index.html">
<img class="logo" src="../../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="discord.html">1.0-dev (develop branch)</a></li>
<ul>
<li><a href="../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.server.portal.discord</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Implements Discord chat channel integration.</span>
<span class="sd">The Discord API uses a mix of websockets and REST API endpoints.</span>
<span class="sd">In order for this integration to work, you need to have your own</span>
<span class="sd">discord bot set up via https://discord.com/developers/applications</span>
<span class="sd">with the MESSAGE CONTENT toggle switched on, and your bot token</span>
<span class="sd">added to `server/conf/secret_settings.py` as your DISCORD_BOT_TOKEN</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">from</span> <span class="nn">io</span> <span class="kn">import</span> <span class="n">BytesIO</span>
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">random</span>
<span class="kn">from</span> <span class="nn">autobahn.twisted.websocket</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">WebSocketClientFactory</span><span class="p">,</span>
<span class="n">WebSocketClientProtocol</span><span class="p">,</span>
<span class="n">connectWS</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">protocol</span><span class="p">,</span> <span class="n">reactor</span><span class="p">,</span> <span class="n">ssl</span><span class="p">,</span> <span class="n">task</span>
<span class="kn">from</span> <span class="nn">twisted.web.client</span> <span class="kn">import</span> <span class="n">Agent</span><span class="p">,</span> <span class="n">FileBodyProducer</span><span class="p">,</span> <span class="n">readBody</span>
<span class="kn">from</span> <span class="nn">twisted.web.http_headers</span> <span class="kn">import</span> <span class="n">Headers</span>
<span class="kn">from</span> <span class="nn">evennia.server.session</span> <span class="kn">import</span> <span class="n">Session</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">class_from_module</span><span class="p">,</span> <span class="n">get_evennia_version</span><span class="p">,</span> <span class="n">logger</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">delay</span>
<span class="n">_AGENT</span> <span class="o">=</span> <span class="n">Agent</span><span class="p">(</span><span class="n">reactor</span><span class="p">)</span>
<span class="n">_BASE_SESSION_CLASS</span> <span class="o">=</span> <span class="n">class_from_module</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">BASE_SESSION_CLASS</span><span class="p">)</span>
<span class="n">DISCORD_API_VERSION</span> <span class="o">=</span> <span class="mi">10</span>
<span class="c1"># include version number to prevent automatically updating to breaking changes</span>
<span class="n">DISCORD_API_BASE_URL</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;https://discord.com/api/v</span><span class="si">{</span><span class="n">DISCORD_API_VERSION</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">DISCORD_USER_AGENT</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;Evennia (https://www.evennia.com, </span><span class="si">{</span><span class="n">get_evennia_version</span><span class="p">(</span><span class="n">mode</span><span class="o">=</span><span class="s1">&#39;short&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="n">DISCORD_BOT_TOKEN</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">DISCORD_BOT_TOKEN</span>
<span class="n">DISCORD_BOT_INTENTS</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">DISCORD_BOT_INTENTS</span>
<span class="c1"># Discord OP codes, alphabetic</span>
<span class="n">OP_DISPATCH</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">OP_HEARTBEAT</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">OP_HEARTBEAT_ACK</span> <span class="o">=</span> <span class="mi">11</span>
<span class="n">OP_HELLO</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">OP_IDENTIFY</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">OP_INVALID_SESSION</span> <span class="o">=</span> <span class="mi">9</span>
<span class="n">OP_RECONNECT</span> <span class="o">=</span> <span class="mi">7</span>
<span class="n">OP_RESUME</span> <span class="o">=</span> <span class="mi">6</span>
<div class="viewcode-block" id="should_retry"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.should_retry">[docs]</a><span class="k">def</span> <span class="nf">should_retry</span><span class="p">(</span><span class="n">status_code</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper function to check if the request should be retried later.</span>
<span class="sd"> Args:</span>
<span class="sd"> status_code (int) - The HTTP status code</span>
<span class="sd"> Returns:</span>
<span class="sd"> retry (bool) - True if request should be retried False otherwise</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">status_code</span> <span class="o">&gt;=</span> <span class="mi">500</span> <span class="ow">and</span> <span class="n">status_code</span> <span class="o">&lt;=</span> <span class="mi">504</span><span class="p">:</span>
<span class="c1"># these are common server error codes when the server is temporarily malfunctioning</span>
<span class="c1"># in these cases, we should retry</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># handle all other cases; this can be expanded later if needed for special cases</span>
<span class="k">return</span> <span class="kc">False</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory">[docs]</a><span class="k">class</span> <span class="nc">DiscordWebsocketServerFactory</span><span class="p">(</span><span class="n">WebSocketClientFactory</span><span class="p">,</span> <span class="n">protocol</span><span class="o">.</span><span class="n">ReconnectingClientFactory</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A variant of the websocket-factory that auto-reconnects.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">initialDelay</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">factor</span> <span class="o">=</span> <span class="mf">1.5</span>
<span class="n">maxDelay</span> <span class="o">=</span> <span class="mi">60</span>
<span class="n">gateway</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">resume_url</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.__init__"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.__init__">[docs]</a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sessionhandler</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">uid</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;uid&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span> <span class="o">=</span> <span class="n">sessionhandler</span>
<span class="bp">self</span><span class="o">.</span><span class="n">port</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">bot</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.get_gateway_url"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.get_gateway_url">[docs]</a> <span class="k">def</span> <span class="nf">get_gateway_url</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># get the websocket gateway URL from Discord</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">_AGENT</span><span class="o">.</span><span class="n">request</span><span class="p">(</span>
<span class="sa">b</span><span class="s2">&quot;GET&quot;</span><span class="p">,</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">DISCORD_API_BASE_URL</span><span class="si">}</span><span class="s2">/gateway&quot;</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">Headers</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;User-Agent&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">DISCORD_USER_AGENT</span><span class="p">],</span>
<span class="s2">&quot;Authorization&quot;</span><span class="p">:</span> <span class="p">[</span><span class="sa">f</span><span class="s2">&quot;Bot </span><span class="si">{</span><span class="n">DISCORD_BOT_TOKEN</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">],</span>
<span class="s2">&quot;Content-Type&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;application/json&quot;</span><span class="p">],</span>
<span class="p">}</span>
<span class="p">),</span>
<span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">cbResponse</span><span class="p">(</span><span class="n">response</span><span class="p">):</span>
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">readBody</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
<span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">websocket_init</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">return</span> <span class="n">d</span>
<span class="k">elif</span> <span class="n">should_retry</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">):</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_gateway_url</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">cbResponse</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.websocket_init"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.websocket_init">[docs]</a> <span class="k">def</span> <span class="nf">websocket_init</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> callback for when the URL is gotten</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="n">url</span> <span class="o">:=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;url&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">gateway</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">url</span><span class="si">}</span><span class="s2">/?v=</span><span class="si">{</span><span class="n">DISCORD_API_VERSION</span><span class="si">}</span><span class="s2">&amp;encoding=json&quot;</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)</span>
<span class="n">useragent</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;useragent&quot;</span><span class="p">,</span> <span class="n">DISCORD_USER_AGENT</span><span class="p">)</span>
<span class="n">headers</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span>
<span class="s2">&quot;headers&quot;</span><span class="p">,</span>
<span class="p">{</span>
<span class="s2">&quot;Authorization&quot;</span><span class="p">:</span> <span class="p">[</span><span class="sa">f</span><span class="s2">&quot;Bot </span><span class="si">{</span><span class="n">DISCORD_BOT_TOKEN</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">],</span>
<span class="s2">&quot;Content-Type&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;application/json&quot;</span><span class="p">],</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="s2">&quot;Connecting to Discord Gateway...&quot;</span><span class="p">)</span>
<span class="n">WebSocketClientFactory</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">useragent</span><span class="o">=</span><span class="n">useragent</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="s2">&quot;Discord did not return a websocket URL; connection cancelled.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.buildProtocol"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.buildProtocol">[docs]</a> <span class="k">def</span> <span class="nf">buildProtocol</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">addr</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Build new instance of protocol</span>
<span class="sd"> Args:</span>
<span class="sd"> addr (str): Not used, using factory/settings data</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s2">&quot;DISCORD_SESSION_CLASS&quot;</span><span class="p">):</span>
<span class="n">protocol_class</span> <span class="o">=</span> <span class="n">class_from_module</span><span class="p">(</span>
<span class="n">settings</span><span class="o">.</span><span class="n">DISCORD_SESSION_CLASS</span><span class="p">,</span> <span class="n">fallback</span><span class="o">=</span><span class="n">DiscordClient</span>
<span class="p">)</span>
<span class="n">protocol</span> <span class="o">=</span> <span class="n">protocol_class</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">protocol</span> <span class="o">=</span> <span class="n">DiscordClient</span><span class="p">()</span>
<span class="n">protocol</span><span class="o">.</span><span class="n">factory</span> <span class="o">=</span> <span class="bp">self</span>
<span class="n">protocol</span><span class="o">.</span><span class="n">sessionhandler</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span>
<span class="k">return</span> <span class="n">protocol</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.startedConnecting"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.startedConnecting">[docs]</a> <span class="k">def</span> <span class="nf">startedConnecting</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">connector</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Tracks reconnections for debugging.</span>
<span class="sd"> Args:</span>
<span class="sd"> connector (Connector): Represents the connection.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="s2">&quot;Attempting connection to Discord...&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.clientConnectionFailed"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.clientConnectionFailed">[docs]</a> <span class="k">def</span> <span class="nf">clientConnectionFailed</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">connector</span><span class="p">,</span> <span class="n">reason</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when Client failed to connect.</span>
<span class="sd"> Args:</span>
<span class="sd"> connector (Connection): Represents the connection.</span>
<span class="sd"> reason (str): The reason for the failure.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">protocol</span><span class="o">.</span><span class="n">ReconnectingClientFactory</span><span class="o">.</span><span class="n">clientConnectionLost</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">connector</span><span class="p">,</span> <span class="n">reason</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.clientConnectionLost"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.clientConnectionLost">[docs]</a> <span class="k">def</span> <span class="nf">clientConnectionLost</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">connector</span><span class="p">,</span> <span class="n">reason</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when Client loses connection.</span>
<span class="sd"> Args:</span>
<span class="sd"> connector (Connection): Represents the connection.</span>
<span class="sd"> reason (str): The reason for the failure.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_retry</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">bot</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">retry</span><span class="p">(</span><span class="n">connector</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.reconnect"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.reconnect">[docs]</a> <span class="k">def</span> <span class="nf">reconnect</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Force a reconnection of the bot protocol. This requires</span>
<span class="sd"> de-registering the session and then reattaching a new one.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">bot</span><span class="o">.</span><span class="n">transport</span><span class="o">.</span><span class="n">loseConnection</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">server_disconnect</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">bot</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">resume_url</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">resume_url</span>
<span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">gateway</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">gateway</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># we don&#39;t know where to reconnect to! start from the beginning</span>
<span class="bp">self</span><span class="o">.</span><span class="n">get_gateway_url</span><span class="p">()</span>
<span class="k">return</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></div>
<div class="viewcode-block" id="DiscordWebsocketServerFactory.start"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordWebsocketServerFactory.start">[docs]</a> <span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;Connect protocol to remote server&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">gateway</span><span class="p">:</span>
<span class="c1"># we can&#39;t actually start yet</span>
<span class="c1"># get the gateway URL from Discord</span>
<span class="bp">self</span><span class="o">.</span><span class="n">get_gateway_url</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">connectWS</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></div></div>
<div class="viewcode-block" id="DiscordClient"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient">[docs]</a><span class="k">class</span> <span class="nc">DiscordClient</span><span class="p">(</span><span class="n">WebSocketClientProtocol</span><span class="p">,</span> <span class="n">_BASE_SESSION_CLASS</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Implements the grapevine client</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">nextHeartbeatCall</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">pending_heartbeat</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">heartbeat_interval</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">last_sequence</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">session_id</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">discord_id</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="DiscordClient.__init__"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.__init__">[docs]</a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">WebSocketClientProtocol</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="n">_BASE_SESSION_CLASS</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">restart_downtime</span> <span class="o">=</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="DiscordClient.at_login"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.at_login">[docs]</a> <span class="k">def</span> <span class="nf">at_login</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="DiscordClient.onOpen"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.onOpen">[docs]</a> <span class="k">def</span> <span class="nf">onOpen</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called when connection is established.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">restart_downtime</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">restart_task</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">bot</span> <span class="o">=</span> <span class="bp">self</span>
<span class="bp">self</span><span class="o">.</span><span class="n">init_session</span><span class="p">(</span><span class="s2">&quot;discord&quot;</span><span class="p">,</span> <span class="s2">&quot;discord.gg&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">sessionhandler</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">uid</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">uid</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">logged_in</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.onMessage"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.onMessage">[docs]</a> <span class="k">def</span> <span class="nf">onMessage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">isBinary</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Callback fired when a complete WebSocket message was received.</span>
<span class="sd"> Args:</span>
<span class="sd"> payload (bytes): The WebSocket message received.</span>
<span class="sd"> isBinary (bool): Flag indicating whether payload is binary or</span>
<span class="sd"> UTF-8 encoded text.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">isBinary</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="s2">&quot;DISCORD: got a binary payload for some reason&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="k">if</span> <span class="n">seqid</span> <span class="o">:=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;s&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_sequence</span> <span class="o">=</span> <span class="n">seqid</span>
<span class="c1"># not sure if that error json format is for websockets</span>
<span class="c1"># check for it just in case</span>
<span class="k">if</span> <span class="s2">&quot;errors&quot;</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handle_error</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># check for discord gateway API op codes first</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_HELLO</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">][</span><span class="s2">&quot;heartbeat_interval&quot;</span><span class="p">]</span> <span class="o">/</span> <span class="mi">1000</span> <span class="c1"># convert millisec to seconds</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">_batched_timer</span><span class="o">.</span><span class="n">call_later</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">*</span> <span class="n">random</span><span class="p">(),</span>
<span class="bp">self</span><span class="o">.</span><span class="n">doHeartbeat</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_id</span><span class="p">:</span>
<span class="c1"># we already have a session; try to resume instead</span>
<span class="bp">self</span><span class="o">.</span><span class="n">resume</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">identify</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_HEARTBEAT_ACK</span><span class="p">:</span>
<span class="c1"># our last heartbeat was acknowledged, so reset the &quot;pending&quot; flag</span>
<span class="bp">self</span><span class="o">.</span><span class="n">pending_heartbeat</span> <span class="o">=</span> <span class="kc">False</span>
<span class="k">elif</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_HEARTBEAT</span><span class="p">:</span>
<span class="c1"># Discord wants us to send a heartbeat immediately</span>
<span class="bp">self</span><span class="o">.</span><span class="n">doHeartbeat</span><span class="p">(</span><span class="n">force</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_INVALID_SESSION</span><span class="p">:</span>
<span class="c1"># Discord doesn&#39;t like our current session; reconnect for a new one</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_msg</span><span class="p">(</span><span class="s2">&quot;Discord: received &#39;Invalid Session&#39; opcode. Reconnecting.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="kc">False</span><span class="p">:</span>
<span class="c1"># can&#39;t resume, clear existing resume data</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_id</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">resume_url</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">reconnect</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_RECONNECT</span><span class="p">:</span>
<span class="c1"># reconnect as requested; Discord does this regularly for server load balancing</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_msg</span><span class="p">(</span><span class="s2">&quot;Discord: received &#39;Reconnect&#39; opcode. Reconnecting.&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">reconnect</span><span class="p">()</span>
<span class="k">elif</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;op&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">OP_DISPATCH</span><span class="p">:</span>
<span class="c1"># handle the general dispatch opcode events by type</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;t&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;READY&quot;</span><span class="p">:</span>
<span class="c1"># our recent identification is valid; process new session info</span>
<span class="bp">self</span><span class="o">.</span><span class="n">connection_ready</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># general message, pass on to data_in</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data_in</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.onClose"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.onClose">[docs]</a> <span class="k">def</span> <span class="nf">onClose</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">wasClean</span><span class="p">,</span> <span class="n">code</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is executed when the connection is lost for whatever</span>
<span class="sd"> reason. it can also be called directly, from the disconnect</span>
<span class="sd"> method.</span>
<span class="sd"> Args:</span>
<span class="sd"> wasClean (bool): ``True`` if the WebSocket was closed cleanly.</span>
<span class="sd"> code (int or None): Close status as sent by the WebSocket peer.</span>
<span class="sd"> reason (str or None): Close reason as sent by the WebSocket peer.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">disconnect</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
<span class="k">if</span> <span class="n">code</span> <span class="o">&gt;=</span> <span class="mi">4000</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Discord connection closed: </span><span class="si">{</span><span class="n">reason</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Discord disconnected: </span><span class="si">{</span><span class="n">reason</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
<span class="k">def</span> <span class="nf">_send_json</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Post JSON data to the websocket</span>
<span class="sd"> Args:</span>
<span class="sd"> data (dict): content to send.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">sendMessage</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">_post_json</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Post JSON data to a REST API endpoint</span>
<span class="sd"> Args:</span>
<span class="sd"> url (str) - The API path which is being posted to</span>
<span class="sd"> data (dict) - Content to be sent</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">DISCORD_API_BASE_URL</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">url</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="n">body</span> <span class="o">=</span> <span class="n">FileBodyProducer</span><span class="p">(</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">)))</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">_AGENT</span><span class="o">.</span><span class="n">request</span><span class="p">(</span>
<span class="sa">b</span><span class="s2">&quot;POST&quot;</span><span class="p">,</span>
<span class="n">url</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">),</span>
<span class="n">Headers</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;User-Agent&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">DISCORD_USER_AGENT</span><span class="p">],</span>
<span class="s2">&quot;Authorization&quot;</span><span class="p">:</span> <span class="p">[</span><span class="sa">f</span><span class="s2">&quot;Bot </span><span class="si">{</span><span class="n">DISCORD_BOT_TOKEN</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">],</span>
<span class="s2">&quot;Content-Type&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&quot;application/json&quot;</span><span class="p">],</span>
<span class="p">}</span>
<span class="p">),</span>
<span class="n">body</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">cbResponse</span><span class="p">(</span><span class="n">response</span><span class="p">):</span>
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">readBody</span><span class="p">(</span><span class="n">response</span><span class="p">)</span>
<span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">post_response</span><span class="p">)</span>
<span class="k">return</span> <span class="n">d</span>
<span class="k">elif</span> <span class="n">should_retry</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">code</span><span class="p">):</span>
<span class="n">delay</span><span class="p">(</span><span class="mi">300</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_post_json</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="n">d</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">cbResponse</span><span class="p">)</span>
<div class="viewcode-block" id="DiscordClient.post_response"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.post_response">[docs]</a> <span class="k">def</span> <span class="nf">post_response</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">body</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Process the response from sending a POST request</span>
<span class="sd"> Args:</span>
<span class="sd"> body (bytes) - The post response body</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>
<span class="k">if</span> <span class="s2">&quot;errors&quot;</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">handle_error</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.handle_error"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.handle_error">[docs]</a> <span class="k">def</span> <span class="nf">handle_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> General hook for processing errors.</span>
<span class="sd"> Args:</span>
<span class="sd"> data (dict) - The received error data</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="p">))</span></div>
<div class="viewcode-block" id="DiscordClient.resume"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.resume">[docs]</a> <span class="k">def</span> <span class="nf">resume</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called after a reconnection to re-identify and replay missed events</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_sequence</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_id</span><span class="p">:</span>
<span class="c1"># we have no known state to resume from, identify normally</span>
<span class="bp">self</span><span class="o">.</span><span class="n">identify</span><span class="p">()</span>
<span class="c1"># build a RESUME request for Discord and send it</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;op&quot;</span><span class="p">:</span> <span class="n">OP_RESUME</span><span class="p">,</span>
<span class="s2">&quot;d&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;token&quot;</span><span class="p">:</span> <span class="n">DISCORD_BOT_TOKEN</span><span class="p">,</span>
<span class="s2">&quot;session_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_id</span><span class="p">,</span>
<span class="s2">&quot;s&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">sequence_id</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_send_json</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.disconnect"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.disconnect">[docs]</a> <span class="k">def</span> <span class="nf">disconnect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">reason</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Generic hook for the engine to call in order to</span>
<span class="sd"> disconnect this protocol.</span>
<span class="sd"> Args:</span>
<span class="sd"> reason (str or None): Motivation for the disconnection.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">disconnect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sendClose</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">CLOSE_STATUS_CODE_NORMAL</span><span class="p">,</span> <span class="n">reason</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.identify"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.identify">[docs]</a> <span class="k">def</span> <span class="nf">identify</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send Discord authentication. This should be sent once heartbeats begin.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;op&quot;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
<span class="s2">&quot;d&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;token&quot;</span><span class="p">:</span> <span class="n">DISCORD_BOT_TOKEN</span><span class="p">,</span>
<span class="s2">&quot;intents&quot;</span><span class="p">:</span> <span class="n">DISCORD_BOT_INTENTS</span><span class="p">,</span>
<span class="s2">&quot;properties&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;os&quot;</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
<span class="s2">&quot;browser&quot;</span><span class="p">:</span> <span class="n">DISCORD_USER_AGENT</span><span class="p">,</span>
<span class="s2">&quot;device&quot;</span><span class="p">:</span> <span class="n">DISCORD_USER_AGENT</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_send_json</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.connection_ready"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.connection_ready">[docs]</a> <span class="k">def</span> <span class="nf">connection_ready</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Process READY data for relevant bot info.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">resume_url</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;resume_gateway_url&quot;</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">session_id</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;session_id&quot;</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">discord_id</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;user&quot;</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span></div>
<div class="viewcode-block" id="DiscordClient.doHeartbeat"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.doHeartbeat">[docs]</a> <span class="k">def</span> <span class="nf">doHeartbeat</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send heartbeat to Discord.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_heartbeat</span> <span class="ow">or</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;force&quot;</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
<span class="c1"># send the heartbeat</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;op&quot;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="s2">&quot;d&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_sequence</span><span class="p">}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_send_json</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1"># track that we sent a heartbeat, in case we don&#39;t receive an ACK</span>
<span class="bp">self</span><span class="o">.</span><span class="n">pending_heartbeat</span> <span class="o">=</span> <span class="kc">True</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nextHeartbeatCall</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">_batched_timer</span><span class="o">.</span><span class="n">call_later</span><span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">doHeartbeat</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># we didn&#39;t get a response since the last heartbeat; reconnect</span>
<span class="bp">self</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">reconnect</span><span class="p">()</span></div>
<div class="viewcode-block" id="DiscordClient.send_channel"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.send_channel">[docs]</a> <span class="k">def</span> <span class="nf">send_channel</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">channel_id</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Send a message from an Evennia channel to a Discord channel.</span>
<span class="sd"> Use with session.msg(channel=(message, channel, sender))</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="n">text</span><span class="p">}</span>
<span class="n">data</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">kwargs</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_post_json</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;channels/</span><span class="si">{</span><span class="n">channel_id</span><span class="si">}</span><span class="s2">/messages&quot;</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span></div>
<div class="viewcode-block" id="DiscordClient.send_default"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.send_default">[docs]</a> <span class="k">def</span> <span class="nf">send_default</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Ignore other outputfuncs</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span></div>
<div class="viewcode-block" id="DiscordClient.data_in"><a class="viewcode-back" href="../../../../api/evennia.server.portal.discord.html#evennia.server.portal.discord.DiscordClient.data_in">[docs]</a> <span class="k">def</span> <span class="nf">data_in</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Process incoming data from Discord and sent to the Evennia server</span>
<span class="sd"> Args:</span>
<span class="sd"> data (dict): Converted json data.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">action_type</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;t&quot;</span><span class="p">,</span> <span class="s2">&quot;UNKNOWN&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">action_type</span> <span class="o">==</span> <span class="s2">&quot;MESSAGE_CREATE&quot;</span><span class="p">:</span>
<span class="c1"># someone posted a message on Discord that the bot can see</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">]</span>
<span class="k">if</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;author&quot;</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">discord_id</span><span class="p">:</span>
<span class="c1"># it&#39;s by the bot itself! disregard</span>
<span class="k">return</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;content&quot;</span><span class="p">]</span>
<span class="n">channel_id</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;channel_id&quot;</span><span class="p">]</span>
<span class="n">keywords</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;channel_id&quot;</span><span class="p">:</span> <span class="n">channel_id</span><span class="p">}</span>
<span class="k">if</span> <span class="s2">&quot;guild_id&quot;</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="c1"># message received to a Discord channel</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;channel&quot;</span>
<span class="n">author</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;member&quot;</span><span class="p">][</span><span class="s2">&quot;nick&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;author&quot;</span><span class="p">][</span><span class="s2">&quot;username&quot;</span><span class="p">]</span>
<span class="n">author_id</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;author&quot;</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">author_id</span><span class="p">,</span> <span class="n">author</span><span class="p">)</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;guild_id&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;guild_id&quot;</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># message sent directly to the bot account via DM</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;direct&quot;</span>
<span class="n">author</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;author&quot;</span><span class="p">][</span><span class="s2">&quot;username&quot;</span><span class="p">]</span>
<span class="n">author_id</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;author&quot;</span><span class="p">][</span><span class="s2">&quot;id&quot;</span><span class="p">]</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;sender&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">author_id</span><span class="p">,</span> <span class="n">author</span><span class="p">)</span>
<span class="c1"># pass the processed data to the server</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bot_data_in</span><span class="o">=</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">keywords</span><span class="p">))</span>
<span class="k">elif</span> <span class="n">action_type</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;GUILD_CREATE&quot;</span><span class="p">,</span> <span class="s2">&quot;GUILD_UPDATE&quot;</span><span class="p">):</span>
<span class="c1"># we received the current status of a guild the bot is on; process relevant info</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">]</span>
<span class="n">keywords</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;guild&quot;</span><span class="p">,</span> <span class="s2">&quot;guild_id&quot;</span><span class="p">:</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">],</span> <span class="s2">&quot;guild_name&quot;</span><span class="p">:</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]}</span>
<span class="n">keywords</span><span class="p">[</span><span class="s2">&quot;channels&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">chan</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]:</span> <span class="p">{</span><span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">chan</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span> <span class="s2">&quot;guild&quot;</span><span class="p">:</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]}</span>
<span class="k">for</span> <span class="n">chan</span> <span class="ow">in</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;channels&quot;</span><span class="p">]</span>
<span class="k">if</span> <span class="n">chan</span><span class="p">[</span><span class="s2">&quot;type&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span>
<span class="p">}</span>
<span class="c1"># send the possibly-updated guild and channel data to the server</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bot_data_in</span><span class="o">=</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">keywords</span><span class="p">))</span>
<span class="k">elif</span> <span class="s2">&quot;DELETE&quot;</span> <span class="ow">in</span> <span class="n">action_type</span><span class="p">:</span>
<span class="c1"># deletes should possibly be handled separately to check for channel removal</span>
<span class="c1"># for now, just ignore</span>
<span class="k">pass</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># send the data for any other action types on to the bot as-is for optional server-side handling</span>
<span class="n">keywords</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="n">action_type</span><span class="p">}</span>
<span class="n">keywords</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">&quot;d&quot;</span><span class="p">])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">bot_data_in</span><span class="o">=</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">keywords</span><span class="p">))</span></div></div>
</pre></div>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.server.portal.discord</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2022, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -86,6 +86,7 @@
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">Count</span><span class="p">,</span> <span class="n">ExpressionWrapper</span><span class="p">,</span> <span class="n">F</span><span class="p">,</span> <span class="n">FloatField</span><span class="p">,</span> <span class="n">Q</span>
<span class="kn">from</span> <span class="nn">django.db.models.functions</span> <span class="kn">import</span> <span class="n">Cast</span>
<span class="kn">from</span> <span class="nn">evennia.typeclasses.attributes</span> <span class="kn">import</span> <span class="n">Attribute</span>
<span class="kn">from</span> <span class="nn">evennia.typeclasses.tags</span> <span class="kn">import</span> <span class="n">Tag</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">idmapper</span>

View file

@ -275,6 +275,7 @@
<li><a href="evennia/server/models.html">evennia.server.models</a></li>
<li><a href="evennia/server/portal/amp.html">evennia.server.portal.amp</a></li>
<li><a href="evennia/server/portal/amp_server.html">evennia.server.portal.amp_server</a></li>
<li><a href="evennia/server/portal/discord.html">evennia.server.portal.discord</a></li>
<li><a href="evennia/server/portal/grapevine.html">evennia.server.portal.grapevine</a></li>
<li><a href="evennia/server/portal/irc.html">evennia.server.portal.irc</a></li>
<li><a href="evennia/server/portal/mccp.html">evennia.server.portal.mccp</a></li>