prevent multiple instances in same namespace

This commit is contained in:
Levi Neely 2025-11-30 12:10:44 +01:00
parent c2f17beff5
commit 77821a7d01
2 changed files with 43 additions and 8 deletions

View File

@ -34,6 +34,7 @@ import (
"denote/internal/disk"
"denote/pkg/encoding/results"
"denote/pkg/metadata"
"errors"
"fmt"
"io"
"net"
@ -41,6 +42,7 @@ import (
"regexp"
"strings"
"sync"
"syscall"
"time"
"9fans.net/go/plan9"
@ -165,14 +167,36 @@ func StartServer(initialData metadata.Results, denoteDir string, callbacks Callb
sockPath := ns + "/denote"
// Remove old socket if it exists
os.Remove(sockPath)
// Try to create Unix domain socket listener
// Use stale socket detection like acme (see /usr/local/plan9/src/lib9/announce.c)
var listener net.Listener
var err error
for attempts := 0; attempts < 2; attempts++ {
listener, err = net.Listen("unix", sockPath)
if err == nil {
break // Successfully bound to socket
}
// Create Unix domain socket listener
listener, err := net.Listen("unix", sockPath)
if err != nil {
// Check if error is "address already in use"
if errors.Is(err, syscall.EADDRINUSE) {
// Try to connect to see if socket is live or stale
conn, dialErr := net.Dial("unix", sockPath)
if dialErr == nil {
// Connection succeeded - another instance is running
conn.Close()
return fmt.Errorf("Denote already running in this namespace")
}
// Connection failed - socket is stale, remove it and retry
os.Remove(sockPath)
continue
}
// Some other error
return fmt.Errorf("failed to listen on socket: %w", err)
}
if err != nil {
return fmt.Errorf("failed to listen on socket after cleanup: %w", err)
}
// Start accepting connections in background
go srv.acceptLoop(listener)

17
main.go
View File

@ -243,14 +243,25 @@ func main() {
// 9p server startup with pre-loaded data and callbacks
if err := p9server.StartServer(notes, denoteDir, callbacks); err != nil {
fmt.Fprintf(os.Stderr, "warning: failed to start fileserver: %v\n", err)
log.Fatal(err)
}
// start acme log watcher
go disk.WatchAcmeLog()
// open window
if w = acme.Show(wname); w == nil {
// open window - look for existing /Denote/ window across all processes
if wins, err := acme.Windows(); err == nil {
for _, winInfo := range wins {
if winInfo.Name == wname {
// Found existing window, open it
if w, err = acme.Open(winInfo.ID, nil); err == nil {
break
}
}
}
}
// If no existing window found, create new one
if w == nil {
if w, err = acme.New(); err != nil {
log.Fatal(err)
}