package irc import ( "bufio" "fmt" "github.com/ergochat/ergo/irc/caps" "io" "net" "os" "strings" ) const LISTEN = "0.0.0.0:22843" type CefConnection struct { connections map[string]net.Conn server *Server } func (instance *CefConnection) CEFMessage(action string, extra ...string) { if instance == nil { return } str := fmt.Sprintf("%s %s\n", action, strings.Join(extra, " ")) for _, conn := range instance.connections { conn.Write([]byte(str)) } } func (instance *CefConnection) KickBroadcast(channel string, user string) { instance.CEFMessage("KICK", channel, user) } func cefConnection(server *Server) *CefConnection { // create a tcp listener on the given port listener, err := net.Listen("tcp", LISTEN) if err != nil { fmt.Println("Unable to open CefConnection listener:", err) os.Exit(1) } fmt.Printf("CefConnection listener on %s active\n", LISTEN) instance := CefConnection{connections: make(map[string]net.Conn), server: server} go cefListener(listener, &instance) return &instance } func cefListener(listener net.Listener, instance *CefConnection) { // listen for new connections for { conn, err := listener.Accept() if err != nil { fmt.Println("failed to accept cef connection, err:", err) continue } instance.connections[conn.RemoteAddr().String()] = conn // pass an accepted connection to a handler goroutine go handleConnection(conn, instance) } } func handleConnection(conn net.Conn, instance *CefConnection) { defer delete(instance.connections, conn.RemoteAddr().String()) reader := bufio.NewReader(conn) println("Connection with CEF service established") for { // read client request data bytes, err := reader.ReadBytes(byte('\n')) if err != nil { if err != io.EOF { fmt.Println("failed to read data, err:", err) } return } convertedLine := string(bytes[:len(bytes)-1]) line := strings.Split(strings.Trim(convertedLine, " \n"), " ") fmt.Printf("cef: %+q\n", line) switch line[0] { case "PART": if len(line) == 1 || len(line[1]) == 0 { println("skipping malformed line") continue } channel := instance.server.channels.Get(line[1]) for _, member := range channel.Members() { for _, session := range member.Sessions() { session.Send(nil, member.server.name, "VOICEPART", line[1], line[2]) } } break case "VOICESTATE": channel := instance.server.channels.Get(line[1]) for _, member := range channel.Members() { for _, session := range member.Sessions() { session.Send(nil, member.server.name, "VOICESTATE", line[1], line[2], line[3], line[4]) } } break case "BROADCASTAS": // TODO: global broadcast user := instance.server.clients.Get(line[1]) if user != nil { // I'm not too sure what the capability bit is, I think it's just ones that match for friend := range user.Friends(caps.ExtendedNames) { friend.Send(nil, user.NickMaskString(), line[2], line[3:]...) } } break case "BROADCASTTO": channel := instance.server.channels.Get(line[1]) if channel != nil { // I'm not too sure what the capability bit is, I think it's just ones that match for _, person := range channel.Members() { person.Send(nil, instance.server.name, line[2], line[3:]...) } } break case "FULLYREMOVE": user := instance.server.clients.Get(line[1]) if user != nil { user.destroy(nil) err := instance.server.accounts.Unregister(user.Account(), true) if err != nil { return } } break default: println("Unknown cef message: ", line[0]) } } }