commit f280a09febb7693e295c83c4f87413d728014cfe Author: Milarin Date: Thu Feb 15 17:09:59 2024 +0100 initial commit diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4bad399 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module git.milar.in/milarin/sock + +go 1.22.0 + +require ( + git.milar.in/milarin/cmap v0.0.2 + git.milar.in/milarin/slices v0.0.8 +) + +require git.milar.in/milarin/gmath v0.0.3 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..8fc108e --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +git.milar.in/milarin/cmap v0.0.2 h1:csO586l0G0+pi+7zR6tpblWEeMA6MDV3ix7B4GWsRiI= +git.milar.in/milarin/cmap v0.0.2/go.mod h1:OFU+P1CVPQqvQ6BC16qb+MK4IBPAdcY+EscNPHQ+n0k= +git.milar.in/milarin/gmath v0.0.3 h1:ii6rKNItS55O/wtIFhD1cTN2BMwDZjTBmiOocKURvxM= +git.milar.in/milarin/gmath v0.0.3/go.mod h1:HDLftG5RLpiNGKiIWh+O2G1PYkNzyLDADO8Cd/1abiE= +git.milar.in/milarin/slices v0.0.8 h1:qN9TE3tkArdTixMKSnwvNPcApwAjxpLVwA5a9k1rm2s= +git.milar.in/milarin/slices v0.0.8/go.mod h1:qMhdtMnfWswc1rHpwgNw33lB84aNEkdBn5BDiYA+G3k= diff --git a/multiwriter.go b/multiwriter.go new file mode 100644 index 0000000..31c2325 --- /dev/null +++ b/multiwriter.go @@ -0,0 +1,31 @@ +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 { + n, err = w.Write(p) + if err != nil || n != len(p) { + continue + } + } + return len(p), nil +} + +func MultiWriter(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} +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..f87b6a3 --- /dev/null +++ b/server.go @@ -0,0 +1,80 @@ +package sock + +import ( + "io" + "net" + "os" + "path/filepath" + + "git.milar.in/milarin/cmap" + "git.milar.in/milarin/slices" +) + +type Server struct { + socketPath string + server net.Listener + clients *cmap.Map[net.Conn, struct{}] +} + +func Listen(socketPath string) (*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{}](), + } + + 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 := MultiWriter(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) + + data := make([]byte, 1024) + for _, err := client.Read(data); err == nil; _, err = client.Read(data) { + + } +} + +func (s *Server) Close() error { + + if err := s.server.Close(); err != nil { + return err + } + + if err := os.Remove(s.socketPath); err != nil { + return err + } + + return nil +}