Sockets, Obsidian and IPC
Introduction
After looking into I/O solutions for Obsidian, sockets seemed like the good next thing to try.
Prototype
In Obsidian
const net = require("net");
const fs = require("fs");
class SocketServerPlugin {
constructor() {
this.server = null;
this.socketPath = "/tmp/obsidian-socket";
}
start() {
// Remove existing socket file if it exists
if (fs.existsSync(this.socketPath)) {
fs.unlinkSync(this.socketPath);
}
this.server = net.createServer((socket) => {
console.log("Client connected");
socket.on("data", (data) => {
const message = data.toString().trim();
console.log("Received:", message);
if (message === "get_active_file") {
const activeFile = app.workspace.getActiveFile();
socket.write(activeFile ? activeFile.path : "No active file");
} else {
socket.write("Unknown command");
}
});
socket.on("end", () => {
console.log("Client disconnected");
});
});
this.server.listen(this.socketPath, () => {
console.log("Server listening on", this.socketPath);
});
}
stop() {
if (this.server) {
this.server.close();
}
if (fs.existsSync(this.socketPath)) {
fs.unlinkSync(this.socketPath);
}
}
}
// Create and start the server
const socketServer = new SocketServerPlugin();
socketServer.start();
// `socketServer.stop()` to stop the server
Anywhere else
(abstracted)
SOCKET_PATH="/tmp/obsidian-socket"
echo -n "get_active_file" | nc -U $SOCKET_PATH
Or
socket_path = "/tmp/obsidian-socket"
client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client_socket.connect(socket_path)
client_socket.sendall(b"get_active_file")
response = client_socket.recv(1024)
print("Received:", response.decode())
Conclusion
Some thoughts need to be put in before designing but this may be the long term solution.
We were also left with 2 problems.
- the inability to get return values
- the inability to reliably build layers of macros and functions across files.
The 2 could probably be fixed with the same plugin where Obsidian reads/write to a socket (allowing for return values)
And where the sockets listens for both:
- raw Javascript code to execute, essentially opening a REPL in IPC
- specific commands and functions called defined in a folder in the vault that plugin monitors