lib9p: add streaming API for native reads

Add ollie9p_open, ollie9p_read_fid, ollie9p_close_fid for streaming
file reads. This allows the KDE GUI to read chat/statewait/eventwait
files natively without spawning subprocesses.
This commit is contained in:
Levi Neely 2026-08-07 18:02:24 +02:00
parent 63faa3b68a
commit 991bbef840
1 changed files with 101 additions and 0 deletions

View File

@ -14,6 +14,7 @@ package main
import "C"
import (
"io"
"strings"
"sync"
"unsafe"
@ -27,10 +28,20 @@ type connHandle struct {
fsys *client.Fsys
}
// File handle - for streaming reads
type fidHandle struct {
conn C.int // parent connection handle
reader io.ReadCloser
}
var (
handleMu sync.Mutex
handles = make(map[C.int]*connHandle)
nextHandle C.int = 1
fidMu sync.Mutex
fids = make(map[C.int]*fidHandle)
nextFid C.int = 1
)
func allocHandle(h *connHandle) C.int {
@ -54,6 +65,27 @@ func freeHandle(id C.int) {
delete(handles, id)
}
func allocFid(f *fidHandle) C.int {
fidMu.Lock()
defer fidMu.Unlock()
id := nextFid
nextFid++
fids[id] = f
return id
}
func getFid(id C.int) *fidHandle {
fidMu.Lock()
defer fidMu.Unlock()
return fids[id]
}
func freeFid(id C.int) {
fidMu.Lock()
defer fidMu.Unlock()
delete(fids, id)
}
// Error handling - last error per thread (simplified: global for now)
var lastError string
var lastErrMu sync.Mutex
@ -361,6 +393,75 @@ func ollie9p_rename(handle C.int, oldPath *C.char, newName *C.char) C.int {
return 0
}
// --- Streaming API ---
// ollie9p_open opens a file for streaming reads.
// Returns: fid handle > 0 on success, -1 on error.
// The fid must be closed with ollie9p_close_fid.
//
//export ollie9p_open
func ollie9p_open(handle C.int, path *C.char) C.int {
h := getHandle(handle)
if h == nil {
setError(&errString{"invalid handle"})
return -1
}
reader, err := h.fsys.OpenRead(C.GoString(path))
if err != nil {
setError(err)
return -1
}
fid := &fidHandle{
conn: handle,
reader: reader,
}
setError(nil)
return allocFid(fid)
}
// ollie9p_read_fid reads from an open file into a buffer.
// Returns: bytes read (0 on EOF), -1 on error.
// Blocks until data is available or EOF.
//
//export ollie9p_read_fid
func ollie9p_read_fid(fid C.int, buf *C.char, bufLen C.int) C.int {
f := getFid(fid)
if f == nil {
setError(&errString{"invalid fid"})
return -1
}
goBuf := unsafe.Slice((*byte)(unsafe.Pointer(buf)), int(bufLen))
n, err := f.reader.Read(goBuf)
if err != nil {
if err == io.EOF {
setError(nil)
return 0
}
setError(err)
return -1
}
setError(nil)
return C.int(n)
}
// ollie9p_close_fid closes an open file handle.
//
//export ollie9p_close_fid
func ollie9p_close_fid(fid C.int) {
f := getFid(fid)
if f == nil {
return
}
if f.reader != nil {
f.reader.Close()
}
freeFid(fid)
}
// Helper types
type errString struct{ s string }