diff --git a/Makefile b/Makefile index fb27478..0d683d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ -GOPATH := $(shell pwd) - default: run -run: src/*.go - go run src/*.go +run: *.go */*.go + go run main.go + +fmt: + go fmt *.go + go fmt sircd/*.go diff --git a/main.go b/main.go index 7300618..b20d777 100644 --- a/main.go +++ b/main.go @@ -1,17 +1,17 @@ package main -import "log" -import "os" -import "sircd" +import "github.com/sirupsen/logrus" +import "github.com/sneak/sircd/sircd" import "time" func main() { - l := log.New(os.Stdout, "", log.Ldate | log.Lmicroseconds | log.Lshortfile) - l.Println("sircd starting up") + var log = logrus.New() + log.SetLevel(log.DebugLevel) + log.Println("sircd starting up") s := sircd.NewSircd() - s.SetLogger(l) + s.SetLogger(log) go s.Start() - for s.Running { - time.Sleep(1 * time.Second) - } + for s.Running { + time.Sleep(1 * time.Second) + } } diff --git a/sircd/client.go b/sircd/client.go index e71aa31..b22e3f4 100644 --- a/sircd/client.go +++ b/sircd/client.go @@ -1,40 +1,54 @@ package sircd import ( - "log" + "bytes" + "github.com/google/uuid" + "github.com/sirupsen/logrus" "net" - "bytes" ) -func newClientIRCConnection(conn net.Conn, log *log.Logger) *clientIRCConnection { - c := new(clientIRCConnection) - c.conn = conn - c.log = log - c.inputBytes = new(bytes.Buffer) - c.outputBytes = new(bytes.Buffer) - c.ReadSocket() - return c +func newIrcClient(conn net.Conn, log *logrus.Logger, mc chan *ircMessage) *ircClient { + c := new(ircClient) + c.Id = uuid.New().String() + c.conn = conn + c.log = log + c.mc = mc + c.inputBytes = new(bytes.Buffer) + c.outputBytes = new(bytes.Buffer) + return c } -type clientIRCConnection struct { - Id uint64 +type ircClient struct { + Id string conn net.Conn - log *log.Logger + log *logrus.Logger + session *ircUserSession inputBytes *bytes.Buffer outputBytes *bytes.Buffer + mc chan *ircMessage } -func (c *clientIRCConnection) ReadSocket() { +type ircMessage struct { + from *ircClient + //received + //command +} + +func (c *ircClient) Close() { + //client cleanup + c.log.Infof("client %d disconnect", c.Id) +} + +func (c *ircClient) AppendInputBuffer(input []byte) { // Read the incoming connection into the buffer. - buf := make([]byte, 1024*1024) - bytesRead, err := c.conn.Read(buf) - c.log.Printf("conn<%d>: read %d bytes from net", c.Id, bytesRead) - if err != nil { - c.log.Println("Error reading:", err.Error()) - } - c.inputBytes.Write(buf) + c.log.Printf("conn<%s>: got %d bytes from net", c.Id, len(input)) + c.inputBytes.Write(input) + c.log.Debugf("conn<%s> buffer now %d bytes total", c.inputBytes.Len()) + c.ParseMessages() } -func (c *clientIRCConnection) ParseMessages() { - c.log.Fatalln("not implemented") +func (c *ircClient) ParseMessages() { + c.log.Debugln("my input buffer is %d", c.inputBytes.Len()) + c.log.Debugln("my input buffer is: '%s'", c.inputBytes.String()) + //c.log.Fatalln("not implemented") } diff --git a/sircd/main.go b/sircd/main.go new file mode 100644 index 0000000..582246a --- /dev/null +++ b/sircd/main.go @@ -0,0 +1,30 @@ +package sircd + +func (s *sircd) processIRCMessage(m *ircMessage) { + s.log.Info("not implemented") + //for client, _ := range s.ircClients { + //} +} + +/* + +import "net" + case publish := <-publishes: + for conn, _ := range conns { + go func(conn net.Conn) { + totalWritten := 0 + for totalWritten < len(publish) { + writtenThisCall, err := conn.Write(publish[totalWritten:]) + if err != nil { + deadConns <- conn + break + } + totalWritten += writtenThisCall + } + }(conn) + } + } + } + listener.Close() +} +*/ diff --git a/sircd/server.go b/sircd/server.go index 283adb3..a129c10 100644 --- a/sircd/server.go +++ b/sircd/server.go @@ -1,20 +1,21 @@ package sircd import ( - "log" + "github.com/sirupsen/logrus" "net" - "os" - "container/list" ) type sircd struct { - Running bool - log *log.Logger - netName string - ircPort uint16 - httpPort uint16 - ircListener net.Listener - ircClients *list.List + Running bool + log *logrus.Logger + netName string + ircPort uint16 + httpPort uint16 + ircListener net.Listener + ircClients map[*ircClient]bool + newClients chan *ircClient + deadClients chan *ircClient + messageQueue chan *ircMessage } const ( @@ -26,55 +27,84 @@ const ( func NewSircd() *sircd { s := new(sircd) s.Running = true - s.ircClients = list.New() + s.ircClients = make(map[*ircClient]bool) return s } -func (s *sircd) SetLogger(l *log.Logger) { +func (s *sircd) SetLogger(l *logrus.Logger) { s.log = l } -func (s *sircd) startIRCServer() { +func (s *sircd) Start() { + + s.newClients = make(chan *ircClient, 128) + s.deadClients = make(chan *ircClient, 128) + s.messageQueue = make(chan *ircMessage, 128) + var err error s.ircListener, err = net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT) if err != nil { - log.Println("Error listening:", err.Error()) - os.Exit(1) + s.log.Fatalln("Error listening:", err.Error()) } - defer s.ircListener.Close() s.log.Println("Listening for irc on " + CONN_HOST + ":" + CONN_PORT) - for { - // Listen for an incoming connection. + go func() { conn, err := s.ircListener.Accept() if err != nil { - s.log.Fatalf("Error accepting: ", err.Error()) + s.log.Panicf("Error accepting: ", err.Error()) + } + s.newClients <- newIrcClient(conn, s.log, s.messageQueue) + }() + + go s.mainloop() +} + +func (s *sircd) mainloop() { + for { + select { + case client := <-s.newClients: + s.ircClients[client] = true + s.log.Println("new irc client: %s", client.Id) + go func() { + buf := make([]byte, 1024*1024) + for { + nbyte, err := client.conn.Read(buf) + if err != nil { + s.deadClients <- client + break + } else { + fragment := make([]byte, nbyte) + copy(fragment, buf[:nbyte]) + // this will populate the message channel + client.AppendInputBuffer(fragment) + } + } + }() + case deadClient := <-s.deadClients: + delete(s.ircClients, deadClient) + deadClient.Close() + case message := <-s.messageQueue: + s.processIRCMessage(message) } - // Handle connections in a new goroutine. - go s.handleIRCConnection(conn) } - } -func (s *sircd) processIRC() { - for { - s.readFromClients() - } -} - -func (s *sircd) readFromClients() { - for e := s.ircClients.Front(); e != nil; e = e.Next() { - client := e.Value.(clientIRCConnection) - client.ReadSocket() - client.ParseMessages() - } -} - -func (s *sircd) Start() { - go s.startIRCServer() -} - -func (s *sircd) handleIRCConnection(conn net.Conn) { - c := newClientIRCConnection(conn, s.log) - s.ircClients.PushBack(c) -} +/* + case publish := <-publishes: + for conn, _ := range conns { + go func(conn net.Conn) { + totalWritten := 0 + for totalWritten < len(publish) { + writtenThisCall, err := conn.Write(publish[totalWritten:]) + if err != nil { + deadConns <- conn + break + } + totalWritten += writtenThisCall + } + }(conn) + } + } + } + listener.Close() +*/ diff --git a/sircd/session.go b/sircd/session.go new file mode 100644 index 0000000..2883bc4 --- /dev/null +++ b/sircd/session.go @@ -0,0 +1,9 @@ +package sircd + +type ircNick string +type ircRealName string + +type ircUserSession struct { + nick ircNick + realname ircRealName +}