Skip to content

communication: migrate to Conductor to unlock classroom networking activities (currently JS-only) #878

Description

@martin-henz

Context

communication (src/bundles/communication/) is a small MQTT pub/sub + RPC bundle: initCommunications(address, port, user, password) connects to a broker over secure WebSocket, expose/callFunction provide RPC between peers, and updateGlobalState/getGlobalState provide a shared JSON-patched state tree. Any two (or more) students who agree on a broker address/port/credentials can coordinate directly - the module places no gatekeeping on who can connect.

It's a fun, under-used building block for in-class activities, but it's still on the legacy pre-Conductor module system (Communications.ts imports context from js-slang/context, not @sourceacademy/conductor - unlike already-migrated bundles such as sound, repl, rune). Based on investigation in this repo (no code here shows py-slang loading a legacy context.moduleContexts-based bundle, and no manifest field marks bundles as Python-capable), this strongly suggests communication is currently only usable from the JS-based Source language, not from Source Python. The definitive answer lives in py-slang/the frontend, outside this repo, but everything observable here is consistent with "JS only, today."

This issue is to track migrating communication to Conductor, primarily so these activities can run for Python (py-slang) classes too, not just JS ones - and secondarily to bring it in line with the rest of the module ecosystem's migration.

Why this is worth doing: candidate classroom activities

The module's shape (JSON-only payloads, no functions/closures can cross a channel - see below) makes it a good fit for small multiplayer/distributed activities. Some candidates, using either of its two primitives:

Shared state (updateGlobalState/getGlobalState) - everyone sees the same board

  • Distributed Game of Life / shared canvas - each student "owns" a region of a grid; everyone renders the merged grid locally. Concurrent writes to the same cell become a discussion point (race conditions), not a bug to hide.
  • Collaborative story or drawing - append-only array (story/parts, canvas/strokes); each program contributes a shape/sentence. Turn-taking logic (state.length % numPlayers == myTurn) is a nice small design problem.
  • Live poll/leaderboard - students' programs push a vote or score; one "dashboard" program aggregates and displays it live.
  • Simulated sensor network - each program publishes fake readings; one "monitor" program aggregates and raises alerts. Doubles as a real-world MQTT/IoT analogy, since that's literally what the protocol is for.

RPC (expose/callFunction) - request/response between specific peers

  • Turn-based multiplayer games (Tic-Tac-Toe, Battleship, rock-paper-scissors tournament) with one program acting as referee.
  • Auction/marketplace simulation - programs bid via RPC to an "auctioneer" program; explore strategy and fairness under concurrent bids.
  • Echo bots/auto-responders - simplest starting exercise to sanity-check connectivity before building something bigger.
  • Chain/relay message game ("whisper down the lane") - each program mutates a message and calls the next peer; explores message loss/ordering, since MQTT gives no ordering/delivery guarantees by default.

Structural constraint worth teaching, not hiding

Confirmed by code (not inferred): every payload is JSON.stringify'd/JSON.parse'd on the wire (RpcController.ts, GlobalStateController.ts), so only JSON-serializable data crosses a channel - never a function/closure. A function passed as an RPC argument or stashed in shared state silently becomes null on the other end; nothing in the code or docs currently says this. Whatever activity gets built on top of this should probably make that constraint an explicit design point for students ("how do I encode behavior as data?") rather than something they discover by a silent null.

Practical note for running any of this in class

Whichever broker is used, activities should namespace topics per class/section (e.g. prefix everything with a class/section ID) - a shared public test broker means any other user of that broker can see the same topics, and public test brokers aren't rate-limit-friendly for a whole class connecting at once.

Scope

  • Migrate communication to Conductor (mirroring the pattern used by sound/repl/rune etc.)
  • Confirm/verify Python (py-slang) compatibility once migrated
  • Pick and build out one of the above as a concrete starter activity/exercise once migration lands

Metadata

Metadata

Assignees

No one assigned

    Labels

    Enhancement[Category] New feature requestproposalTentative suggestion inviting discussion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions