notesy::ipc
Talking to a program on this computer, through the sockets the plugin names
in [ipc] (plugin.toml). Naming sockets there asks for
the ipc permission; the module is there only once the user grants it.
The plugin owns the connection. It speaks whatever the program on the other end speaks, and notesy stays out of the middle: it never reads what passes, and never writes anything of its own. What notesy keeps is the decision about which sockets may be opened at all, and how much may go through one.
rustuse notesy::{ipc, log};
pub fn ready() {
let got = ipc::connect("run:discord-ipc-0", |event| {
match event.kind {
ipc::Event::Open => event.socket.send("hello"),
ipc::Event::Data => log::info(`${event.bytes.len()} bytes back`),
ipc::Event::Closed => log::warn(`it hung up: ${event.says}`),
_ => {}
}
});
if let Err(why) = got {
log::info(`Discord isn't running: ${why}`);
}
}
#ipc::connect(name, then)
Opens the socket name, one its manifest names. Ok(socket), or Err(why)
when it wouldn't open. then(event) is called on the script's thread for
everything that happens on it, until it closes.
A program that isn't running has no socket, so Err is an ordinary answer
rather than a fault: Discord numbers its own 0 to 9 and a plugin tries
them in turn. Asking for a socket the manifest doesn't name is the plugin's
own mistake, and is raised where it's written.
name is the socket as the manifest writes it (run:discord-ipc-0), never a
path: a path can't be written once for every platform, and one in a prompt
tells the user nothing. A name that isn't one of its own is an error where
connect is called, not in then.
Opening is judged twice. The name has to be one the manifest named, and then whatever answers has to pass: it has to be a socket, and it has to belong to you. A socket answering as the system, as an administrator or as another user is refused as it opens, wherever it sits. Some notesy refuses outright, for every plugin, however they're named and whoever signed them: see plugin.toml.
#The event
| Field | What it is |
|---|---|
kind |
An ipc::Event: Open, Data or Closed. |
socket |
The connection it happened on, to send on or close. |
bytes |
What arrived, for Data; empty otherwise. |
why |
An ipc::Closed, for Closed: why it ended. |
says |
The same in a word, for a log. |
Open comes once, when the connection is through and everything about it
passed. Data comes as bytes arrive, in the order they arrive: a socket is a
stream, so what one send on the other end wrote may come in pieces, and two
may come at once. Whatever framing the program uses is the plugin's to read.
Closed comes once, last, and nothing follows it.
ipc::Closed |
What happened |
|---|---|
Gone |
The program on the other end hung up. Try again if it makes sense. |
Refused |
It couldn't be opened, or what answered wasn't allowed to. Don't try again. |
Stopped |
The user hung it up, or the plugin is being turned off. |
Idle |
Nothing went either way for ten minutes. |
TooMuch |
It went past what one plugin may push through a socket. |
#Socket
| Call | What it does |
|---|---|
socket.send(what) |
Sends bytes, or text as it's written. At most 1 MB at a time. |
socket.close() |
Hangs up. Closed follows, with Stopped. |
socket.name() |
The socket as its manifest names it. |
socket.open() |
Whether it's still open. |
Sending on a closed connection is an error, not a crash: check open(), or
let Closed tell you.
#What it may not do
A plugin holds at most 10 connections at once, so it can try the ten
Discord opens without holding them all. A message is at most 1 MB, and
8 MB a second may go each way; past that the connection closes with
TooMuch. A connection with nothing going either way for ten minutes
closes with Idle.
Turning a plugin off, or reloading it, hangs up everything it has open: a plugin that isn't running is talking to nothing.
A preview never gets a socket, notesy preview --trust or not: a preview is
for looking at, and a socket reaches a program outside notesy altogether.
#What the user sees
The prompt says this first and on its own, above what the plugin would do to their notes, because notesy can't see what passes between a plugin and a program and so can't say where it ends up.
A plugin's page in Settings shows every connection it has open, where each one went, how much has gone each way and how long it's been open, with a way to hang one up. That works whether or not the plugin cooperates: the connection is notesy's to close.
#Where sockets live
run:name is where running programs keep theirs, and own:name is the
plugin's own folder, which nothing else writes to. A name ending in *
covers the names that start that way.
toml[ipc]
sockets = ["run:discord-ipc-*"]
On Windows these are named pipes under \\.\pipe\, and the same plugin works
there unchanged: run:discord-ipc-0 finds the pipe of that name. A pipe
already serving someone else is waited on briefly, since a program that hands
out one connection at a time is busy for a moment rather than for a minute.
Who answered is checked there too, by a different road. Windows has nothing to ask a pipe who is on the other end, so notesy asks the pipe which process serves it and then asks that process whose it is. A pipe that won't say is refused, the same as one belonging to somebody else.
Every page
- Overview
- plugin.toml: Every field of plugin.toml
- Permissions: What a plugin can ask for, when notesy asks, and what changes it
- Scripts: How a script runs: its lifecycle, events, limits and errors
- Packing and installing: Making, checking, signing, packing and installing
- notesy::log: Lines for its log on the Plugins page
- notesy::events: Hearing what happens, and every event
- notesy::commands: Adding commands, and running notesy's
- notesy::store: Keeping its own data
- notesy::settings: Reading its settings
- notesy::secrets: Keys and tokens, in the system keychain
- notesy::notes: Reading and changing the vault's notes
- notesy::editor: The note in front
- notesy::templates: What templates fill in, and functions of its own for them
- notesy::files: A folder of its own
- notesy::links: Opening pages in the browser, naming links after their pages
- notesy::clipboard: Copying and pasting
- notesy::view: What panels, tabs and sections show
- notesy::panels and notesy::views: Adding side panels and tabs
- notesy::sections: Sidebar sections
- notesy::menus: Items in notesy's right-click menus
- notesy::hidden: Hiding notes, files and folders from the tree
- notesy::status: Status bar items
- notesy::notices: Notices
- notesy::dialogs: Asking in a dialog, notesy's kinds or its own
- notesy::wizards: Pages one after another, like a setup
- notesy::cards: Its part of the tree's hover cards
- notesy::boards: Boards' cards and arrows, and kinds of card of its own
- notesy::blocks: Drawing its fenced blocks
- notesy::icons: Drawing its own icons
- notesy::net: Requests to the sites it names
- notesy::ipc: Talking to a program on this computer
- notesy::accounts: Signing in to a service
- notesy::json: Reading and writing JSON
- notesy::toml: Reading and writing TOML
- notesy::yaml: Reading and writing YAML, and a note's front matter
- notesy::time: Now, written in the user's time zone, dates read, how long ago
- notesy::math: Trigonometry and the like, for drawing
- Names: Icon, Color, Tone, Side, Method, Command, Menu, Sidebar, Event: Notesy's names as enums
- notesy::preview: Its own screens for notesy preview
- notesy::perf: Timing its own work
- notesy::tex: Math macros for every note's formulas