initial commit
This commit is contained in:
12
go.mod
Normal file
12
go.mod
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module git.tordarus.net/tordarus/sock
|
||||||
|
|
||||||
|
go 1.24.1
|
||||||
|
|
||||||
|
toolchain go1.24.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
git.tordarus.net/tordarus/cmap v0.0.5
|
||||||
|
git.tordarus.net/tordarus/slices v0.0.15
|
||||||
|
)
|
||||||
|
|
||||||
|
require git.tordarus.net/tordarus/gmath v0.0.7 // indirect
|
6
go.sum
Normal file
6
go.sum
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
git.tordarus.net/tordarus/cmap v0.0.5 h1:g2STu3iMXCLn96JZ/f0iN5hbzct9cI5B8+V8ATB4ryE=
|
||||||
|
git.tordarus.net/tordarus/cmap v0.0.5/go.mod h1:Wx2snnIzdDrmONR9X5bt5aFq8E8EDCK5Zy50DmRwK1M=
|
||||||
|
git.tordarus.net/tordarus/gmath v0.0.7 h1:tR48idt9AUL0r556ww3ZxByTKJEr6NWCTlhl2ihzYxQ=
|
||||||
|
git.tordarus.net/tordarus/gmath v0.0.7/go.mod h1:mO7aPlvNrGVE9UFXEuuACjZgMDsM63l3OcQy6xSQnoE=
|
||||||
|
git.tordarus.net/tordarus/slices v0.0.15 h1:qxKS+7BCZ/LzQbRCvdDFoLQXaJZ2C0GfVju/kPt1r3g=
|
||||||
|
git.tordarus.net/tordarus/slices v0.0.15/go.mod h1:eJBw6pSDNivPI0l4e0sGKUJzou/lbzHflXdAUzp1g4o=
|
28
multiwriter.go
Normal file
28
multiwriter.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package sock
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
type multiWriter struct {
|
||||||
|
writers []io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ io.Writer = &multiWriter{}
|
||||||
|
|
||||||
|
func (t *multiWriter) Write(p []byte) (n int, err error) {
|
||||||
|
for _, w := range t.writers {
|
||||||
|
w.Write(p)
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMultiWriter(writers ...io.Writer) io.Writer {
|
||||||
|
allWriters := make([]io.Writer, 0, len(writers))
|
||||||
|
for _, w := range writers {
|
||||||
|
if mw, ok := w.(*multiWriter); ok {
|
||||||
|
allWriters = append(allWriters, mw.writers...)
|
||||||
|
} else {
|
||||||
|
allWriters = append(allWriters, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &multiWriter{allWriters}
|
||||||
|
}
|
89
server.go
Normal file
89
server.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package sock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.tordarus.net/tordarus/cmap"
|
||||||
|
"git.tordarus.net/tordarus/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
socketPath string
|
||||||
|
server net.Listener
|
||||||
|
clients *cmap.Map[net.Conn, struct{}]
|
||||||
|
|
||||||
|
onNewClient func(client net.Conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Listen(socketPath string, onNewClient func(client net.Conn)) (*Server, error) {
|
||||||
|
absPath, err := filepath.Abs(socketPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Remove(absPath)
|
||||||
|
server, err := net.Listen("unix", absPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s := &Server{
|
||||||
|
socketPath: absPath,
|
||||||
|
server: server,
|
||||||
|
clients: cmap.New[net.Conn, struct{}](),
|
||||||
|
onNewClient: onNewClient,
|
||||||
|
}
|
||||||
|
|
||||||
|
go s.handleClients()
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Broadcast(r io.Reader) error {
|
||||||
|
clients := slices.Map(s.clients.Keys(), func(c net.Conn) io.Writer { return c })
|
||||||
|
w := newMultiWriter(clients...)
|
||||||
|
|
||||||
|
if _, err := io.Copy(w, r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleClients() {
|
||||||
|
for client, err := s.server.Accept(); err == nil; client, err = s.server.Accept() {
|
||||||
|
go s.handleClient(client)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleClient(client net.Conn) {
|
||||||
|
s.clients.Put(client, struct{}{})
|
||||||
|
defer s.clients.Delete(client)
|
||||||
|
|
||||||
|
if s.onNewClient != nil {
|
||||||
|
s.onNewClient(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
for _, err := client.Read(data); err == nil; _, err = client.Read(data) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Close() error {
|
||||||
|
for client := range s.clients.Iterate() {
|
||||||
|
client.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.server.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Remove(s.socketPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Reference in New Issue
Block a user