~aleteoryx/tclircc-docs

bc5b5caa2c8841ed4221b141f982127cbfaabd23 — Aleteoryx a month ago
docs!
5 files changed, 294 insertions(+), 0 deletions(-)

A .gitignore
A LICENSE
A README.md
A index.md
A irc.tcl.md
A  => .gitignore +2 -0
@@ 1,2 @@
*~
*.swp

A  => LICENSE +15 -0
@@ 1,15 @@
This repository is dedicated entirely to the public domain. The creator
waives all intellectual property rights to the work as much as is
possible in the given jurisdiction.

In other words, do whatever.

THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

and these are the docs, so if you hurt yourself that's pretty funny tbh

A  => README.md +3 -0
@@ 1,3 @@
# tclircc docs

View @ [man.amehut.dev](https://man.amehut.dev/~aleteoryx/tclircc).

A  => index.md +10 -0
@@ 1,10 @@
# tclircc

Aleteoryx's Tool Control Language Internet Relay Chat Client, does what it says on the tin.

This documentation is meant to be comprehensive.

## Code

- [irc.tcl](irc.tcl.md)


A  => irc.tcl.md +264 -0
@@ 1,264 @@
# irc.tcl

The core protocol library. `irc.tcl` *exclusively* handles the raw
stream protocol and event dispatch. All other responsibilities are
out-of-scope for it.

It exposes the **`irc`** namespace, which contains the logic for
message-parsing, message validation, channel management, event
dispatch, and various utilities listed below.


## Getting a channel

`irc.tcl` provides 2 ways to connect to an IRC server.


### `irc::connect `*`hostname port ?usetls?`*

Connects to `hostname:port`, and sets up all the necessary state. If
usetls is set to true, the **`tls`** module will be used to connect,
instead of the builtin **`socket`** command. If unset, **`socket`**
will be used.


### `irc::enroll `*`chan ?meta?`*

Sets up the internal state necessary for `chan` to be
used as an IRC socket. It is called internally by **`irc::connect`**. This
command is exposed for the use-case where an IRC channel might have a
more bespoke acquisition process than a simple socket connection.


## Listening to it

`irc.tcl` provides an event dispatch system, via a **`fileevent`**
script registered on the IRC channel. Events are dispatched by matching
their [patterns](#message-pattern-lists) against incoming messages.


### `irc::listen `*`subcommand chan`*

Enable or disable the **`fileevent`** script for the dispatch system.

#### `irc::listen` `on `*`chan`*

Apply the **`fileevent`** wrapper to `chan`. Returns the previous
**`fileevent`** wrapper.

#### `irc::listen` `off `*`chan`*

Remove the **`fileevent`** wrapper from `chan`. Errors if it is not the
irc wrapper.


### `irc::listener `*`subcommand chan ?args ...?`*

Configure listener-type event handlers.

Listener-type handlers are scripts, executed in a sub-interpreter.
The script is executed as part of event handling, and is expected to
return to the main interpreter via **`after`** periodically. For
application responsiveness and stability reasons, it is expected that
listener scripts will not take longer than 100ms to execute, though
this is not enforced. If consistent long-running computations are
required, consider using **`irc::extern`**.

`listener`-type scripts are spawned with the variable `chan` set to the
channel they recieve dispatches over. This will be a **`dict`** with
contents as described in
[Event Dispatch Contents](#event-dispatch-contents).
They are given access to the
[Dispatch-aliased IRC commands](dispatch-aliased-irc-commands).

When a listener is removed, it will recieve a message of just `end`. It
should perform necessary cleanup quickly, and return, as the
application is likely exiting, and it may not be re-executed if it
yields.

#### `irc::listener add `*`chan patlist script`*

Registers `script` as a listener-type handler on `chan`, matching
`patlist` as [described below](#message-pattern-lists). Returns an id
that can be passed to **`irc::listener remove`** or **`irc::patlist`**.

#### `irc::listener remove `*`chan id`*

Unregisters the listener identified by `id` from `chan`.


### `irc::handler `*`subcommand chan ?args ...?`*

Configure handler-type event handlers.

Handler-type event handlers execute a script everytime a message is
matched. For application responsiveness and stability reasons, it is
expected that handler scripts will not take longer than 100ms to
execute, though this is not enforced.

Handlers can be created with or without a stored interpreter. If
created without, they will be spawned with a new interpreter for each
message, and clean scope.

`handler`-type scripts are spawned with the variable `dispatch` set as
described in
[Event Dispatch Contents](#event-dispatch-contents).
They are given access to the
[Dispatch-aliased `irc` commands](dispatch-aliased-codeirccode-commands).

When a handler is removed, if it has a stored interpreter, it will be
deleted. Applications with persistent state should take care to store
it to disk after each command, or use one of the other dispatch types.

#### `irc::handler add `*`chan patlist script ?interp?`*

Registers `script` as a handler-type handler on `chan`, matching
`patlist` as [described below](#message-pattern-lists). Returns an id
that can be passed to **`irc::extern remove`** or **`irc::patlist`**.

If `interp` is supplied, `script` will be added as a stored-interpreter
handler, with `interp` as the stored-interpreter. The same alias setup
performed on internally created interpreters will be performed, once, on
the supplied interpreter, and `dispatch` will be set just before
executing `script`.

#### `irc::extern remove `*`chan id`*

Unregisters the extern handler identified by `id` from `chan`.


### `irc::extern `*`subcommand chan ?args ...?`*

Configure extern-type event handlers.

Extern-type event handlers are backed by a pair of channels. One is for
message dispatch, one is for message replying. Dispatch comes in pairs
of lines, the first being the source channel and the second being the
raw IRC message. Replies are just single IRC messages. Due to this
asymmetry, it is OK to reuse a dispatch channel for multiple `extern`
handlers, but not OK to reuse a reply channel. You will need to make
use of FIFOs or pipes for I/O multiplexing.

When an extern-type handler is removed, the channel id and `end` will
be written to it. The dispatch pipe is never closed by `irc.tcl`. The
reply pipe will be closed immediately. Ensure code that uses multiple
handlers accounts for this.

#### `irc::handler add `*`chan patlist ochan ichan`*

Registers `ochan` and `ichan` as the dispatch and reply pipes of a
extern-type handler on `chan`, matching `patlist` as
[described below](#message-pattern-lists). Returns an id that can
be passed to **`irc::extern remove`** or **`irc::patlist`**.

#### `irc::extern remove `*`chan id`*

Unregisters the extern handler identified by `id` from `chan`.


### `irc::patlist `*`chan id ?patlist?`*

Get or set the [message pattern list](message-pattern-list) for handler
`id` on `chan`. If `patlist` is supplied, it will override the current
one and return `patlist`, otherwise it will return the current pattern
list.


### Message Pattern Lists

Message pattern lists are lists of lists of **`string match`**
patterns. Messages are matched on the command and the first N-1 params,
where N is the length of the message pattern. If the first N segments
all match, the match succeeds. If a message is shorter than a pattern,
the match fails. If any of the message patterns in the message pattern
list for a handler match, the handler is called.

#### Message Pattern List Examples:

```tcl
# pattern:
*

# messages:
PRIVMSG #general :what's up gamers
# matches
PRIVMSG #amehut :bot, do something
# matches
PRIVMSG #bot :do something
# matches
PING foo
# matches


# pattern:
{{}}

# messages:
PRIVMSG #general :what's up gamers
# doesn't match
PRIVMSG #amehut :bot, do something
# doesn't match
PRIVMSG #bot :do something
# doesn't match
PING foo
# doesn't match


# pattern:
{{PRIVMSG * {bot, *}} {PRIVMSG #bot}}

# messages:
PRIVMSG #general :what's up gamers
# doesn't match
PRIVMSG #amehut :bot, do something
# matches
PRIVMSG #bot :do something
# matches
PING foo
# doesn't match


# pattern:
PING

# messages:
PRIVMSG #general :what's up gamers
# doesn't match
PRIVMSG #amehut :bot, do something
# doesn't match
PRIVMSG #bot :do something
# doesn't match
PING foo
# matches
```

### Event Dispatch Contents

The event dispatch dictionary contains the following properties:

- `rawmsg`: the raw IRC message
- `chan`: the source channel
- `tags`: the tags portion of the message
- `src`: the source portion of the message
- `srctype`: the type of message source, either `servername` or `user`
- `srcparts`: the `srcparts` dict, returned from **`irc::src parse`**
- `cmd`: the command of the message
- `params`: the params of the message
- `meta`: channel metadata, such as server hostname

### Dispatch-aliased `irc` Comands

In `listener` and `handlers`, the following commands are aliased:

- `irc::esc`
- `irc::extern`
- `irc::handler`
- `irc::is`
- `irc::listener`
- `irc::msg`
- `irc::patlist`
- `irc::src`
- `irc::tags`
- `irc::unesc`

Additionally, the relevant channel is `share`d.