Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PETSGI

PETSGI (PET Server Gateway Interface) is an experimental Perl application framework for networked Commodore PET software using unmodified PETdisk MAX.

The first supported target is deliberately narrow: a 40-column Commodore PET and the stock PETdisk MAX network protocol. PETSGI is PET-first, not PET-locked: application semantics, target rendering, and transport are separated so future third-party targets/transports do not have to weaken the PET implementation.

The idea

PETdisk already turns Commodore disk operations into a small bidirectional HTTP protocol. PETSGI normalizes that protocol into application operations:

PETdisk request PETSGI operation Application meaning
GET ?d=1&p=N DIRECTORY discovery / launcher
GET ?file=X&l=1 STAT materialize and size a response
GET ?file=X&s=A&e=B READ ranged response transport
PUT ?f=X&n=1&b64=1 CREATE first write block
PUT ?f=X&b64=1 APPEND subsequent write block
PUT ?f=X&u=1&s=A&e=B&b64=1 UPDATE random-access update

PRG is intended to become PETSGI's primary executable UX response; SEQ is useful for live/polled state and submissions, while D64 remains the natural choice for mounted storage and software collections.

Full-stack application model

PETSGI treats a dynamically generated PRG as an executable view of server-side application state, not merely downloadable content. A running PRG may then use SEQ resources for lighter-weight updates or submissions without replacing the whole application state.

The first semantic application API is intentionally small:

$app->view(
    name => 'HOME.PRG',
    render => sub {
        my ($ctx) = @_;
        return $ctx->ui
            ->title('PETSGI BBS')
            ->text('WELCOME')
            ->menu(
                { label => 'MESSAGES', route => 'BOARD.PRG' },
                { label => 'CHAT',     route => 'CHAT.PRG'  },
            );
    },
);

$app->resource(
    name => 'STATE.SEQ',
    type => 'SEQ',
    read => sub {
        return "NEW=3\nONLINE=2\n";
    },
);

$app->action(
    name => 'POST.SEQ',
    write => sub {
        my ($ctx, $bytes, $operation) = @_;
        # validate and persist the submitted block
    },
);

PETSGI::Context gives application callbacks a framework-level object rather than a CGI or PETdisk implementation object. The initial PETSGI::UI::Screen builder is a deliberately small intermediate representation for 40-column PET screens. It currently renders to tokenized BASIC; later native/hybrid renderers can implement highlighted menus, scrolling regions, forms, and other local effects without changing application code.

A future template language should compile to the same UI tree rather than become a second runtime model.

Shared-hosting baseline

examples/petsgi.cgi is a CGI::Tiny deployment which behaves like the original petdisk.php for PRG/SEQ/D64, ranged reads, writes, and TIME, while adding safer filename handling and cleaner implementation boundaries.

10,example.com/cgi-bin/petsgi.cgi

Set PETSGI_ROOT to the directory to expose.

examples/fullstack.cgi demonstrates the semantic application API. It exposes a server-rendered HOME.PRG, a polled STATUS.SEQ, and an ACTION.SEQ submission endpoint.

Dynamic PRG materialization

PETdisk requests a dynamic object in at least two HTTP operations: first its length, then one or more ranged reads. Under CGI these are separate Perl processes. PETSGI::Materializer::File therefore freezes the generated bytes between STAT and the subsequent reads so an executable view cannot change in the middle of a load.

LOAD"HOME",10
RUN

The initial BASIC generator targets the PET BASIC program address at $0401 and only claims the 40-column PET target. It is intentionally a foundation for the native local-effects/runtime work, not a complete BASIC compiler.

Testing

PETSGI::Test::PETdiskMax mocks only the part of PETdisk MAX that PETSGI depends on: directory pages, stat-before-read, 512-byte range reads, first/append PUTs, block updates, and base64 write bodies. It deliberately does not emulate IEEE-488, Wi-Fi, LEDs, or unrelated firmware internals.

prove -lr t

The tests also exercise executable views, dynamic SEQ refreshes, action writes, the semantic UI builder, and cross-request materialization. GitHub Actions tests several Perl versions and runs Devel::Cover on the latest.

Sessions and identity

PETSGI::Session::SQLite provides an intentionally modest first session model: a user may claim a name and receive a compact PETSGI token. This is identity, not strong authentication. PETSGI::Application accepts a session_resolver callback so transport-specific token carriage does not leak into application code.

Stock PETdisk write boundary

PETdisk MAX does not send an HTTP close/commit request after a sequence of PUT blocks. An action() callback therefore receives individual CREATE, APPEND, or UPDATE blocks. Applications needing transactional submissions larger than one block must define explicit framing/commit semantics at the PETSGI application layer.

Dependencies

The CGI adapter uses CGI::Tiny; PETSGI operation routing uses Dispatch::Fu; small request/resource/context objects use Util::H2O::More. DBI and DBD::SQLite are recommended for sessions rather than required for simple file service.

Status

This is an initial 0.01 design/prototype. The next major work is the PET-native local-effects renderer: highlighted keyboard menus, forms/input, scrolling regions, navigation, and eventually a small reusable 6502 runtime that can be linked into dynamic PRGs while retaining a BASIC fallback.

About

PET-first network application framework turning PETdisk I/O into dynamic PRGs, application state, services, and native PET UX.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages