EN /HU | Login

RuBBS

rubbs is our Ruby gem for building telnet bulletin boards: a login dialogue in ten lines, a full-screen board with windows, menus and mouse in a few hundred, and the same board on a Commodore 64 on the same port. All eleven boards of our BBS network run on it. This manual describes rubbs 1.0.0. Every class and method is documented in the source: the API reference (RDoc) is rebuilt from it on every release tag.

What you get

  • Three layers in one call — Flow for line dialogues (login, wizards), Application for a desktop with windows, menus and widgets, and the PETSCII Screen with its Selector cursor menus for a line-by-line board on a Commodore 64 or a modern terminal; a call moves between them freely.
  • Turbo Vision on a telnet line — windows that move, size, zoom and switch, a menubar with hotkeys, a statusbar, forms, master-detail browsers, chat streams, five colour themes and a Markdown renderer, all clickable with the mouse.
  • A Commodore 64 face — session.petscii! turns the line into 40×25 PETSCII while the code keeps writing UTF-8 and ANSI; BBS::Terminal asks each caller which terminal is calling and starts the modern or the C64 face.
  • Doors and gateways — simulated machines (FakeOS), flows and any program as doors, telnet gateways that hand the line on to another board (a C64 can even call an ASCII board), ZMODEM and XMODEM downloads.
  • AI characters — a persona in a YAML file talking through any OpenAI-compatible model, streamed word by word, with canned replies when the model is away.
  • The blocks of a content board — an SQLite file with migrations, bounded HTTP, a cache, rate limits, a paced Wikipedia client, one log format and background work with retry.
  • Made for the real line — telnet negotiation, window size, SGR mouse, idle, session and per-address limits, control-free input, a gateway that calls only public addresses, and a door's crash never ends the call.

The manual

Page What you find there
Minimal project The smallest complete project: a question-and-answer board in four files, Dockerfile, compose, running on Windows, Linux and macOS
Getting started Installation, a first board, BBS.configure and every setting, the server, a real board's project layout, Docker
Flow The line-dialogue DSL step by step: ask, say, menu, confirm, gate, persist, call, screens, banners, sub-flows
Application The desktop: the application DSL, menubar, statusbar, helpers and services, the run loop, events and focus
Windows Windows and the window DSL; Info, Form, MasterDetail, Stream; dialogs; zoom, move, size, switch
Widgets Every widget and container, scenes, and writing your own widget
Drawing Themes and their colour roles, the palette, the FrameBuffer, the renderer, Markdown
Doors Doors, simulated machines (FakeOS), telnet gateways (Gateway), ZMODEM and XMODEM
AI characters Personas, the model client, chat with history and fallbacks, the typewriter
Commodore 64 PETSCII, the terminal question, the PETSCII Screen and Selector, and a board with a modern and a C64 face
Art and graphics screens Drawings as YAML for both faces, the C64 graphics canvas and a cursor menu on it, scenes with live hotspots, seasonal layers, art-preview
Telnet and the store The session: negotiation, keys, mouse, lines, limits; BBS::Store on SQLite
Data and network BBS.log, BBS.background, BBS::SQLite, HTTP, Cache, RateLimit, Wikipedia, Text, Address, and where an error is handled
Changelog What each version brought, and what 1.0 removed

A first board

The gem is called bbs. It listens on a TCP port, negotiates telnet with every caller, gives each one a Session, and runs the flow you configure:

RUBY
require 'bbs'

BBS.configure do |c|
  c.log_tag = 'my-bbs'
  c.flow = BBS::Flow.define do
    big_banner 'My BBS'
    ask :name, prompt: 'Your name'
    say 'Welcome!', style: :success
  end
end

BBS.start

ruby bbs.rb, then telnet localhost 2323. From there, Getting started builds it into a board with windows and a C64 face.

The three layers

Layer What it is Good for
BBS::Flow a line-by-line dialogue, declared step by step logins, registration, wizards, the glue of a call
BBS::Application a desktop: menubar, windows, widgets, mouse a whole board on a modern terminal
BBS::Petscii::Screen + BBS::Selector a line-by-line screen of 40×25 (or a modern terminal's size): titles, pages, cursor menus, prompts, the editor a board's C64 face, or a whole board that reads line by line

A call usually starts in a flow (the terminal question, the login) and continues in an application or on a PETSCII screen; doors and gateways step out of it and come back. Until 1.0 there was a fourth layer, BBS::TUI, for single full-screen pages; no board used it, and 1.0 removed it (see the Changelog).

MERMAID
flowchart LR
  S[TCP server] --> SE[Session: telnet, window size]
  SE --> F[Flow]
  F --> A[Application]
  F --> P[PETSCII Screen + Selector]
  A <--> D[Door: FakeOS, Flow, program]
  A <--> G[Gateway: another board]
  P <--> G
  F --> F2[Sub-flow]

Who uses it

Board What rubbs gives it
Teletype BBS :2323 the whole desktop and its C64 face; SERMO and Chat of Ra are FakeOS doors with AI characters, the C64 and Plus/4 doors FakeOS machines
Impostor BBS :2324 a flow with its own screens, in a gem, so another board can run it as a door too
TTG Wiki BBS :2325 a two-pane wiki browser over the wiki's JSON API
Alexandria BBS :2326 Wikipedia (BBS::Wikipedia) in master-detail windows, and in PETSCII
Feedia BBS :2327 an RSS reader with forms to the admins, and in PETSCII
TTG Blog BBS :2328 a blog on BBS::SQLite, line by line on both faces
WarpEngine BBS :2329 the C64 and Plus/4 shelves, ZMODEM and XMODEM downloads
Scriptorium BBS :2330 Project Gutenberg's books through BBS::HTTP and BBS::Cache
Commodex BBS :2331 C64 games from Wikidata and Wikipedia, tips rate-limited with BBS::RateLimit
Pixelia BBS :2332 an ANSI and PETSCII gallery and a shared canvas (Petscii::Canvas, Art)
TTG Gate BBS one port for the network and a directory of the world's boards, all by BBS::Gateway (translate: for a C64 calling an ASCII board)

Building blocks of a line-by-line board

Since 0.29.0 rubbs carries what every line-by-line board of ours used to write for itself. All of them are in the API reference; the Commodore 64 page shows them at work.

Class What it is
BBS::Petscii::Screen the 40×25 screen of a C64 call: title (reversed bar), say(text, color:), rule(color:), page (20 lines a page, RETURN for more, optional 2/5 page numbers), pick (a numbered BBS::Selector list), menu, actions (a row of keys), choose (one key of a few), ask (BBS::Field), edit (BBS::Editor, nil when the caller quits), pause, key, bell, plain. Subclass it for the board's own methods; cols:/rows: make it serve a modern terminal too
BBS::Selector the one cursor menu: numbered, the cursor keys and the digits light an option, RETURN takes it; a Flow's menu, every menu of a Screen and the canvas menu are all Selectors, coloured by Selector::COLORS
BBS::Petscii::Colors the C64 names of the BBS::Ansi palette: WH YE CY LG GR DG LB BL GN RD PU OR, RV/RO for reverse on/off. Colors.install(self) in a board's namespace module gives every class nested in it the bare names
BBS::BlockFont the 3×5 block font of the logos (A–Z, 0–9, space and a few signs): rows, half_blocks for a modern face, petscii (reversed spaces, a colour a row) for a C64; NARROW_I and WIDE_W are the other letter shapes
BBS::Goodbye the last screen of a call: modern ("Thanks for calling …", NO CARRIER) and petscii (reversed bar, +++, ATH0, NO CARRIER a moment apart)
BBS::DiscordWebhook posts to a Discord webhook in a background thread, mentions off, a relay limit (20 posts in 10 minutes by default), timeouts, errors logged under the board's log tag; loads alone with require 'bbs/discord_webhook', so a board's domain can use it
RUBY
module UI
  module Petscii
    BBS::Petscii::Colors.install(self)

    class Screen < BBS::Petscii::Screen
    end

    LOGO = BBS::BlockFont.petscii('WARP', colors: [LB, LB, CY, CY, WH], indent: 10)
  end
end

screen = UI::Petscii::Screen.new(runner.session)
book   = screen.pick('the shelves', books, &:title)
screen.say('Downloading…', color: YE)
BBS::Goodbye.petscii(screen, title: 'warpengine bbs', color: LB)

Upgrading from 0.x

1.0 is the cleanup release: one way to do each thing. What a board usually has to change:

  • screen.say(text, GN) → screen.say(text, color: GN), screen.rule(DG) → screen.rule(color: DG);
  • screen.editor(max, title) → screen.edit(title: title, max: max).to_s;
  • Petscii::Screen::MENU → BBS::Selector::COLORS (or nothing: it is the default);
  • a gateway to a neighbour board on a private address → public_only: false;
  • BBS::TUI, BBS::Color, ProgressBar, Spinner, HBox, VBox, Panel, AnsiArt, most Flow steps beside call and the colour-named Flow styles are gone.

The Changelog has the list in short; UPGRADING.md in the repository lists every removed or renamed API with its replacement and a grep that finds it.

Installation

RUBY
gem 'bbs', git: 'https://git.teletypegames.org/engines/rubbs.git', tag: 'v1.0.0'

Ruby 3.2 or newer (the socket timeouts need IO#timeout=), with the sqlite3 gem. Boards pin rubbs by tag or by git revision in their Gemfile.lock.

Source layout

File Responsibility
lib/bbs.rb the public surface: BBS.configure, BBS.config, BBS.start, BBS.log, BBS.background
bbs/server.rb, bbs/session.rb, bbs/telnet.rb, bbs/telnet/ accept loop, one thread per caller; telnet (the one IAC Parser), keys, mouse, lines
bbs/petscii.rb, bbs/petscii/, bbs/terminal.rb the C64 line, its one glyph table and encoder, the Screen, the canvas; the modern-or-C64 question
bbs/flow.rb, bbs/flow/, bbs/flow_runner.rb, bbs/banner.rb the Flow DSL, its step objects and their runner; banners
bbs/selector.rb, bbs/selector/ the cursor menu
bbs/application.rb, bbs/menu.rb, bbs/statusbar.rb, bbs/focus_manager.rb, bbs/event.rb the Application layer
bbs/widget.rb, bbs/container.rb, bbs/widgets/ widgets, one a file
bbs/window.rb, bbs/window_spec.rb, bbs/windows/*, bbs/dialogs.rb windows, the window DSL, the ready-made windows, dialogs
bbs/ansi.rb, bbs/theme.rb, bbs/theme/presets.rb, bbs/frame_buffer.rb, bbs/renderer.rb, bbs/markdown.rb the palette and drawing
bbs/art.rb, bbs/season.rb, bin/art-preview drawings for both faces
bbs/door.rb, bbs/fake_os.rb, bbs/gateway.rb, bbs/gateway/, bbs/zmodem.rb, bbs/xmodem.rb doors, simulated machines, gateways, downloads
bbs/ai.rb AI characters
bbs/block_font.rb, bbs/goodbye.rb, bbs/discord_webhook.rb logo font, goodbye, Discord webhook posts
bbs/sqlite.rb, bbs/store.rb, bbs/store/ SQLite with migrations; the upsert store on it
bbs/http.rb, bbs/cache.rb, bbs/rate_limit.rb, bbs/wikipedia.rb, bbs/background.rb, bbs/text.rb, bbs/address.rb the shared blocks of a content board

Repository

engines/rubbs — MIT licensed. Its README.md is the developer reference in one file, UPGRADING.md the way from 0.x to 1.0; this manual is the guided version.