mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-01 09:19:23 +01:00
docs: add part of hooks-reference, mention topics and modes in protocol module spec, some more changes
ref: #113.
This commit is contained in:
parent
11b8821228
commit
e4815a72e1
@ -1,23 +1,24 @@
|
|||||||
## PyLink Developer Documentation
|
# PyLink Developer Documentation
|
||||||
|
|
||||||
Please note that as PyLink is still in its development phase, the API is subject to change.
|
Please note that as PyLink is still in its development phase, the API is subject to change.
|
||||||
Any documentation here is provided for reference only.
|
Any documentation here is provided for reference only.
|
||||||
|
|
||||||
It is also really incomplete (contributors welcome!)
|
It is also really incomplete (contributors welcome!)
|
||||||
|
|
||||||
### Introduction
|
## Introduction
|
||||||
|
|
||||||
PyLink is an a modular, plugin-based IRC PseudoService framework. It uses swappable protocol modules and a hook-based system for calling plugins, allowing them to function regardless of the IRCd used.
|
PyLink is an a modular, plugin-based IRC PseudoService framework. It uses swappable protocol modules and a hook-based system for calling plugins, allowing them to function regardless of the IRCd used.
|
||||||
|
|
||||||
<img src="core-structure.png" width="50%" height="50%">
|
<img src="core-structure.png" width="50%" height="50%">
|
||||||
|
|
||||||
### Contents
|
## Contents
|
||||||
|
|
||||||
- [Writing plugins for PyLink](writing-plugins.md)
|
- [Writing plugins for PyLink](writing-plugins.md)
|
||||||
- [PyLink protocol module specification](pmodule-spec.md)
|
- [PyLink protocol module specification](pmodule-spec.md)
|
||||||
|
|
||||||
#### Future topics (not yet available)
|
|
||||||
|
|
||||||
- [Using PyLink's utils module](using-utils.md)
|
- [Using PyLink's utils module](using-utils.md)
|
||||||
|
|
||||||
|
### WIP topics
|
||||||
- [PyLink hooks reference](hooks-reference.md)
|
- [PyLink hooks reference](hooks-reference.md)
|
||||||
|
|
||||||
|
### Future topics (not yet available)
|
||||||
- [Writing tests for PyLink modules](writing-tests.md)
|
- [Writing tests for PyLink modules](writing-tests.md)
|
||||||
|
63
docs/technical/hooks-reference.md
Normal file
63
docs/technical/hooks-reference.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# PyLink hooks reference
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
In PyLink, protocol modules communicate with plugins through a system of hooks. This has the benefit of being IRCd-independent, allowing most plugins to function regardless of the IRCd being used.
|
||||||
|
Each hook payload is formatted as a Python `list`, with three arguments `(numeric, command, args)`:
|
||||||
|
|
||||||
|
1) **numeric**: The sender of the message (UID).
|
||||||
|
|
||||||
|
2) **command**: The command name (hook name) of the payload. These are *always* UPPERCASE, and those starting with "PYLINK_" indicate hooks sent out by IRC objects themselves, that don't require protocol modules to send.
|
||||||
|
|
||||||
|
3) **args**: The hook data (args), a Python `dict`, with different data keys depending on the command given.
|
||||||
|
|
||||||
|
Note that the `ts` key is *automatically added* (using the current time) to all hook data dicts that don't include it - such a key should only be provided if the command the uplink IRCd send has a TS value itself.
|
||||||
|
|
||||||
|
### Example syntax
|
||||||
|
|
||||||
|
The command `:42XAAAAAB PRIVMSG #endlessvoid :test` would result in the following raw hook data:
|
||||||
|
|
||||||
|
- `['42XAAAAAB', 'PRIVMSG', {'target': '#endlessvoid', 'text': 'test', 'ts': 1451174041}]`
|
||||||
|
|
||||||
|
On UnrealIRCd, because SETHOST is mapped to CHGHOST, `:GL SETHOST blah` would return the raw hook data of this (with the nick converted into UID by the UnrealIRCd protocol module):
|
||||||
|
|
||||||
|
- `['001ZJZW01', 'CHGHOST', {'ts': 1451174512, 'target': '001ZJZW01', 'newhost': 'blah'}]`
|
||||||
|
|
||||||
|
Some hooks, like MODE, are more complex and can include the entire state of a channel! This will be further described later. `:GL MODE #chat +o PyLink-devel` is converted into (pretty-printed for readability):
|
||||||
|
|
||||||
|
- ```
|
||||||
|
['001ZJZW01',
|
||||||
|
'MODE',
|
||||||
|
{'modes': [('+o', '38QAAAAAA')],
|
||||||
|
'oldchan': {'modes': set(),
|
||||||
|
'prefixmodes': {'admins': set(),
|
||||||
|
'halfops': set(),
|
||||||
|
'ops': set(),
|
||||||
|
'owners': set(),
|
||||||
|
'voices': set()},
|
||||||
|
'topic': '',
|
||||||
|
'topicset': False,
|
||||||
|
'ts': 1451169448,
|
||||||
|
'users': {'38QAAAAAA', '001ZJZW01'}},
|
||||||
|
'target': '#chat',
|
||||||
|
'ts': 1451174702}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core hooks
|
||||||
|
|
||||||
|
The following hooks are required for PyLink's basic functioning.
|
||||||
|
|
||||||
|
- **ENDBURST**: `{}` - Although the hook data is empty, this should be sent whenever a server finishes its burst. The sender should be the server that finishes bursting.
|
||||||
|
<br>
|
||||||
|
Plugins like Relay need this to know that the uplink has finished bursting all its users!
|
||||||
|
|
||||||
|
- **PYLINK_DISCONNECT**: `{}` - This is sent to plugins by the IRC objects when their network has disconnected. The sender (numeric) is **None** in this case.
|
||||||
|
|
||||||
|
- **PYLINK_SPAWNMAIN**: `{'olduser': olduserobj}` - This is sent whenever `Irc.spawnMain()` is called to (re)spawn the main PyLink client, for example to rejoin it from a KILL. It basically tells plugins that the UID of the main PyLink client has changed, while giving them the old data too.
|
||||||
|
|
||||||
|
## IRC command hooks
|
||||||
|
|
||||||
|
The following hooks represent regular IRC commands sent between servers.
|
||||||
|
|
||||||
|
<br><br><br>
|
||||||
|
(under construction)
|
@ -90,10 +90,54 @@ optional, and defaults to the one we've stored in the channel state if not given
|
|||||||
- **`updateClient`**`(self, source, field, text)` - Updates the ident, host, or realname of a PyLink client. `field` should be either "IDENT", "HOST", "GECOS", or
|
- **`updateClient`**`(self, source, field, text)` - Updates the ident, host, or realname of a PyLink client. `field` should be either "IDENT", "HOST", "GECOS", or
|
||||||
"REALNAME". If changing the field given on the IRCd isn't supported, `NotImplementedError` should be raised.
|
"REALNAME". If changing the field given on the IRCd isn't supported, `NotImplementedError` should be raised.
|
||||||
|
|
||||||
## Special variables
|
## Things to note
|
||||||
|
|
||||||
|
### Special variables
|
||||||
|
|
||||||
A protocol module should also set the following variables in their protocol class:
|
A protocol module should also set the following variables in their protocol class:
|
||||||
|
|
||||||
- `self.casemapping`: set this to `rfc1459` (default) or `ascii` to determine which case mapping the IRCd uses.
|
- `self.casemapping`: set this to `rfc1459` (default) or `ascii` to determine which case mapping the IRCd uses.
|
||||||
- `self.hook_map`: this is a `dict`, which maps non-standard command names sent by the IRCd to those that PyLink plugins use internally.
|
- `self.hook_map`: this is a `dict`, which maps non-standard command names sent by the IRCd to those that PyLink plugins use internally.
|
||||||
- Examples exist in the [UnrealIRCd](https://github.com/GLolol/PyLink/blob/0.5-dev/protocols/unreal.py#L22) and [InspIRCd](https://github.com/GLolol/PyLink/blob/0.5-dev/protocols/inspircd.py#L24) modules.
|
- Examples exist in the [UnrealIRCd](https://github.com/GLolol/PyLink/blob/0.5-dev/protocols/unreal.py#L22) and [InspIRCd](https://github.com/GLolol/PyLink/blob/0.5-dev/protocols/inspircd.py#L24) modules.
|
||||||
|
|
||||||
|
### Topics
|
||||||
|
|
||||||
|
When receiving or sending topics, there is a `topicset` attribute in the IRC channel (IrcChannel) object that should be set **True**. It simply denotes that a topic has been set in the channel at least once.
|
||||||
|
|
||||||
|
(Relay uses this so it doesn't overwrite topics with empty ones during burst, when a relay channel initialize before the uplink has sent the topic for it)
|
||||||
|
|
||||||
|
### Mode formats
|
||||||
|
|
||||||
|
Modes are stored a special format in PyLink, different from raw mode strings in order to make them easier to parse. Mode strings can be turned into mode *lists*, which are used to both represent mode changes in hooks, and when storing them internally.
|
||||||
|
|
||||||
|
`utils.parseModes(irc, target, split_modestring)` is used to convert mode strings to mode lists, where `irc` is the IRC object, `target` is the channel or user the mode is being set on, and `split_modestring` is the string of modes to parse, *split at each space* (really a list).
|
||||||
|
|
||||||
|
- `utils.parseModes(irc, '#chat', ['+tHIs', '*!*@is.sparta'])` would give:
|
||||||
|
- `[('+t', None), ('+H', None), ('+I', '*!*@is.sparta'), ('+s', None)]`
|
||||||
|
|
||||||
|
Also, it will automatically convert prefix mode targets from nicks to UIDs, and drop invalid modes
|
||||||
|
|
||||||
|
- `utils.parseModes(irc, '#chat', ['+ol', 'invalidnick'])`:
|
||||||
|
- `[]`
|
||||||
|
- `utils.parseModes(irc, '#chat', ['+o', 'GLolol'])`:
|
||||||
|
- `[('+o', '001ZJZW01')]`
|
||||||
|
|
||||||
|
Then, the parsed mode lists can be applied to channel using `utils.applyModes(irc, target, parsed_modelist)`.
|
||||||
|
|
||||||
|
Modes are stored in channels and users as sets: `(userobj or chanobj).modes`:
|
||||||
|
|
||||||
|
- ```
|
||||||
|
<+GLolol> PyLink-devel, eval irc.users[source].modes
|
||||||
|
<@PyLink-devel> {('i', None), ('x', None), ('w', None), ('o', None)}
|
||||||
|
<+GLolol> PyLink-devel, eval irc.channels['#chat'].modes
|
||||||
|
<@PyLink-devel> {('n', None), ('t', None)}
|
||||||
|
```
|
||||||
|
|
||||||
|
*With the exception of channel prefix modes* (op, voice, etc.), which are stored as a dict of sets in `chanobj.prefixmodes`:
|
||||||
|
|
||||||
|
- ```
|
||||||
|
<@GLolol> PyLink-devel, eval irc.channels['#chat'].prefixmodes
|
||||||
|
<+PyLink-devel> {'ops': set(), 'halfops': set(), 'voices': {'38QAAAAAA'}, 'owners': set(), 'admins': set()}
|
||||||
|
```
|
||||||
|
|
||||||
|
When a certain mode (e.g. owner) isn't supported on a network, the key still exists in `prefixmodes` but is simply unused.
|
||||||
|
@ -10,7 +10,7 @@ Plugins have three main ways of communicating with IRC: hooks, WHOIS handlers, a
|
|||||||
|
|
||||||
### Hooks
|
### Hooks
|
||||||
|
|
||||||
Hooks are probably the most versatile form of communication. Each hook payload is formatted as a Python `dict`, with different data keys depending on the command.
|
Hooks are probably the most versatile form of communication. The data in each hook payload is formatted as a Python `dict`, with different data keys depending on the command.
|
||||||
For example, a `PRIVMSG` payload would give you the fields `target` and `text`, while a `PART` payload would only give you `channels` and `reason` fields.
|
For example, a `PRIVMSG` payload would give you the fields `target` and `text`, while a `PART` payload would only give you `channels` and `reason` fields.
|
||||||
|
|
||||||
There are many hook types available (one for each supported IRC command), and you can read more about them in the [PyLink hooks reference](hooks-reference.md).
|
There are many hook types available (one for each supported IRC command), and you can read more about them in the [PyLink hooks reference](hooks-reference.md).
|
||||||
|
Loading…
Reference in New Issue
Block a user