From a427e2bb47bb04f17d31d711a7d5a57cb41f4d35 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Sat, 7 Apr 2012 11:44:59 -0700 Subject: [PATCH] initial commit --- .gitignore | 3 +++ goircd.go | 11 +++++++++++ src/irc/client.go | 28 +++++++++++++++++++++++++++ src/irc/net.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ src/irc/protocol.go | 43 ++++++++++++++++++++++++++++++++++++++++++ src/irc/server.go | 44 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 175 insertions(+) create mode 100644 .gitignore create mode 100644 goircd.go create mode 100644 src/irc/client.go create mode 100644 src/irc/net.go create mode 100644 src/irc/protocol.go create mode 100644 src/irc/server.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..57cfbcdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +pkg +bin +goircd \ No newline at end of file diff --git a/goircd.go b/goircd.go new file mode 100644 index 00000000..822d34bd --- /dev/null +++ b/goircd.go @@ -0,0 +1,11 @@ +package main +// http://tools.ietf.org/html/rfc1459 + +import ( + "irc" +) + +func main() { + server := irc.NewServer() + server.Listen(":6697") +} diff --git a/src/irc/client.go b/src/irc/client.go new file mode 100644 index 00000000..e5370924 --- /dev/null +++ b/src/irc/client.go @@ -0,0 +1,28 @@ +package irc + +import ( + "net" +) + + +type Client struct { + conn net.Conn + ch chan Message +} + +func NewClient(conn net.Conn) *Client { + return &Client{conn, NewMessageChan(NewStringChan(conn))} +} + +// Write messages from the client to the server. +func (c *Client) Communicate(server chan Message) { + for message := range c.ch { + message.client = c + server <- message + } + c.Close() +} + +func (c *Client) Close() { + c.conn.Close() +} diff --git a/src/irc/net.go b/src/irc/net.go new file mode 100644 index 00000000..fcbfa874 --- /dev/null +++ b/src/irc/net.go @@ -0,0 +1,46 @@ +package irc + +import ( + "bufio" + "log" + "net" +) + +// Adapt `net.Conn` to a `chan string`. +func NewStringChan(conn net.Conn) chan string { + ch := make(chan string) + rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) + + done := make(chan bool) + go func() { + <- done + close(ch) + }() + + // conn -> ch + go func() { + for { + line, err := rw.ReadString('\n') + if err != nil { + log.Print("StringChan[read]: %v", err) + break + } + ch <- line + } + done <- true + }() + + // ch -> conn + go func() { + for str := range ch { + if _, err := rw.WriteString(str + "\r\n"); err != nil { + log.Print("StringChan[write]: %v", err) + break + } + rw.Flush() + } + done <- true + }() + + return ch +} diff --git a/src/irc/protocol.go b/src/irc/protocol.go new file mode 100644 index 00000000..f5699040 --- /dev/null +++ b/src/irc/protocol.go @@ -0,0 +1,43 @@ +package irc + +import ( +) + +type Message struct { + line string + client *Client +} + +func (m *Message) Encode() string { + return m.line +} + + +// Adapt `chan string` to a `chan Message`. +func NewMessageChan(strch chan string) chan Message { + msgch := make(chan Message) + + done := make(chan bool) + go func() { + <- done + close(msgch) + }() + + // str -> msg + go func() { + for str := range strch { + msgch <- Message{str, nil} + } + done <- true + }() + + // msg -> str + go func() { + for message := range msgch { + strch <- message.Encode() + } + done <- true + }() + + return msgch +} diff --git a/src/irc/server.go b/src/irc/server.go new file mode 100644 index 00000000..39ca7bba --- /dev/null +++ b/src/irc/server.go @@ -0,0 +1,44 @@ +package irc + +import ( + "log" + "net" +) + +type Server struct { + ch chan Message +} + +func NewServer() *Server { + server := Server{make(chan Message)} + go server.Receive() + return &server +} + +func (s *Server) Listen(addr string) { + listener, err := net.Listen("tcp", addr) + if err != nil { + log.Fatal("Server.Listen: %v", err) + } + + for { + conn, err := listener.Accept() + if err != nil { + log.Print("Server.Listen: %v", err) + continue + } + client := NewClient(conn) + go client.Communicate(s.ch) + } +} + +func (s *Server) Receive() { + for message := range s.ch { + log.Print("Server.Receive: %v", message.line) + message.client.ch <- Message{"pong: " + message.line, nil} + } +} + +func (s *Server) Close() { + close(s.ch) +}