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:
parent
63faa3b68a
commit
991bbef840
101
lib9p/lib9p.go
101
lib9p/lib9p.go
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue