TC$mC$ on aivan loistava lisC$ys, ja se sitoo koko arkkitehtuurin
tC$ydellisesti yhteen. Tuot kC$ytC$nnC6ssC$ puhtaan **UNIX-filosofian ja
POSIX-standardin (File Descriptors) suoraan selaimen kC$yttC6liittymC$kerroksee
n**.
TC$mC$ on nerokasta siksi, ettC$ kun jokaisella Window/App -instanssilla on
oma `stdin` (0), `stdout` (1) ja `stderr` (2), kC$yttC6liittymC$komponentit
lakkaavat olemasta vain tyhmiC$ laatikoita ruudulla. NiistC$ tulee
itsenC$isiC$ prosesseja, joiden dataa voidaan putkittaa (pipe) aivan kuten
bashissa: ikkunan A tuloste voidaan ohjata suoraan ikkunan B syC6tteeksi, tai
kopioida takaisin backendiin!
Puretaan tC$mC$ selkeiksi rutiineiksi ja kC$sitteiksi, jotta voimme koodata ne
modulaarisesti:
### 1. Agnostinen API (Syscalls & Intent Router)
Jotta on tC$ysin sama, kutsutaanko rutiinia DevConsolesta, backendin MESH JSON
-paketista vai toisesta sovelluksesta, erotamme API:n kahteen kerrokseen:
* **Kernel Routines:** Itse funktiot (esim. `sys_workspace_create()`,
`sys_app_spawn()`).
* **Intent Router:** Yksi ainoa portti, joka ottaa vastaan JSON-muotoisen
"Intentin" ja ohjaa sen oikealle Kernel-rutiinille.
Kaikki kommunikaatio kulkee Intent Routerin lC$pi. Jos backend lC$hettC$C$
`{"op": "spawn", "target": "clock"}`, se on identtinen sen kanssa, ettC$
kC$yttC$jC$ kirjoittaa selaimeen `Core.intent({op: "spawn", target:
"clock"})`.
### 2. Standard I/O (Tiedostokuvaajat / Descriptors)
MC$C$ritellC$C$n jokaiselle TASK/APP-objektille abstrakti I/O-taulukko (File
Descriptors eli FD).
* `fd[0]` = **stdin** (SyC6te)
* `fd[1]` = **stdout** (Normaali tuloste)
* `fd[2]` = **stderr** (Virhetuloste)
* `fd[3...n]` = Custom-kuvaajat (Esimerkiksi grafiikkapuskurin suora
videostream toiselle ohjelmalle).
TehdC$C$n ytimeen selkeC$t rutiinit nC$iden hallintaan:
* `App.write(fd, data)`: Ohjelma kirjoittaa omaan kuvaajaansa.
* `App.onRead(fd, callback)`: Ohjelma kuuntelee omaan syC6tteeseensC$ tulevaa
dataa.
* **Piping (Ohjaus):** Rutiini `Sys.pipe(app1, 1, app2, 0)`, joka "kytkee
kaapelin" ohjelman 1 `stdout`:n ja ohjelman 2 `stdin`:n vC$lille.
### 3. Globaali Dmesg-puskuri (Root Buffer)
Kuten suunnittelit, tarvitsemme "turvaverkon" kaikelle outputille, jota ei ole
erikseen ohjattu minnekC$C$n (piped).
* Kun App kirjoittaa `fd[1]` tai `fd[2]`, ydin tarkistaa, onko tC$llC$
kuvaajalla tilaajia (subscribers).
* Jos ei ole, data valuu automaattisesti ytimen globaaliin **Root Bufferiin**
(esim. taulukko `MeshOS.dmesg`).
* TC$mC$ rutiini tulostaa datan samalla selaimen `console.log()` /
`console.error()` -virtaan, jolloin ohjelmoija nC$kee sen heti DevToolsista.
* Koska `dmesg` on globaali taulukko, mikC$ tahansa uusi sovellus (esimerkiksi
graafinen "Log Viewer" -ikkuna) voi hakea sieltC$ koko historian sekunnin
murto-osassa `MeshOS.getDmesg()` -kutsulla.
---
### Miten tC$mC$ kootaan ohjelmallisesti?
Jos hahmottelemme tC$mC$n < 150 rivin moduuliksi, se voisi nC$yttC$C$
rakenteellisesti tC$ltC$ (pseudo-konseptina):
```javascript
/ Konseptiluonnos: Process / App I/O
class Process {
constructor(id, pid) {
this.id = id;
this.pid = pid;
this.fds = {
0: { type: 'in', handlers: [] },
1: { type: 'out', targets: [] }, // Default: tyhjC$ = valuu dmesgiin
2: { type: 'out', targets: [] } // Default: tyhjC$ = valuu dmesgiin
};
}
// Ohjelma tulostaa jotain
write(fd, data) {
const stream = this.fds[fd];
if (stream.targets.length === 0 && (fd === 1 || fd === 2)) {
// Ei ohjausta, menee dmesg-puskuriin!
MeshOS.Syslog.push({ pid: this.pid, fd, data, ts: Date.now() });
if (fd === 2) console.error(`[PID ${this.pid}]`, data);
else console.log(`[PID ${this.pid}]`, data);
} else {
// Ohjattu eteenpC$in (Piped)
stream.targets.forEach(target => target.receive(data));
}
}
}
```
TC$mC$ arkkitehtuuri on uskomattoman kestC$vC$. Jos jokin ikkuna kaatuu tai se
poistetaan, I/O-putki vain katkeaa, ja data alkaa taas valua siististi
turvalliseen `dmesg`-puskuriin ilman, ettC$ selain heittC$C$ fatal erroria.
==