Example #1
0
//ircManager takes the connection to the IRC server and then coordinates the
//communication between the irc server, and the connected webclients
//It it will block until the connection to the irc server is closed, or Stop() is called
func ircManager(c ircchat) { //ircConn irc.Conn, newClients chan irc.Conn
	fmt.Println("*** Entering ircManager ***")
	defer fmt.Println("*** Leaving ircManager ***")

	fromServer := make(chan irc.Message)
	errChan := make(chan error) //errors from irc server

	//Listen for incoming messages form server
	go serverListener(c.client, fromServer, errChan, c.quit)

	for {
		select {
		case msg := <-fromServer: //Recieved message from irc server
			//Send it to all clients
			c.webClientsLock.RLock()
			for _, client := range c.webclients {
				err := client.Write(msg)
				if err != nil {
					fmt.Printf("***Error sending to websocket for %s.", c.account.Username())
				}
			}
			c.webClientsLock.RUnlock()

		//Received a message from a webclient
		case msg := <-c.toServer:
			err := c.client.Write(msg.Message)
			if err != nil {
				fmt.Printf("Error writing to server: %s", err.Error())
			}

			c.webClientsLock.RLock()
			for k, client := range c.webclients {
				if k != msg.SessionID { //Notify webclients other than the one that sent it
					cerr := client.Write(msg.Message)
					if cerr != nil {
						fmt.Printf("***Error sending to websocket for %s.", c.account.Username())
					}
					if err != nil && cerr == nil { //If no error from client, but an error from server, forward server error
						client.Write(irc.NewMessage("Error sending message: " + err.Error()))
					}
				}
			}
			c.webClientsLock.RUnlock()
		case err := <-errChan:
			log.Printf("Recieved error: %s", err.Error())
			c.Stop()
		case <-c.quit:
			c.client.Write(irc.NewMessage("QUIT"))
			return
		}
	}
}
Example #2
0
/*
The socketHandler for the websocket connection.
Accepts the websocket, hands it off through the socketChan, and
waits until the socket is closed before exiting the function.
//TODO: Actually manage disconnections properly.
*/
func webSocketHandler(ws *websocket.Conn) {
	//Notify the irc manager of a new websocket
	log.Println("socketHandler starting")
	defer log.Println("socketHandler exiting")
	var client ircClient = newWSClient(ws)

	//Authenticate websocket:
	var user *iwcUser = nil

	for user == nil {
		client.SendMessage(irc.NewMessage("Enter a username."))
		msg, err := client.ReceiveMessage()
		if err != nil {
			return
		}
		username := strings.TrimSpace(msg.String())

		client.SendMessage(irc.NewMessage("Enter a password."))
		msg, err = client.ReceiveMessage()
		if err != nil {
			return
		}
		password := strings.TrimSpace(msg.String())
		user = authenticate(username, password)

		if user != nil {
			client.SendMessage("Successfully logged in.")
		} else {
			client.SendMessage(irc.NewMessage("Invalid username/password."))
		}
	}

	newclients := getSessionNotifier(user.username)
	if newclients == nil {
		client.SendMessage("Unable to find session. Closing...")
		log.Printf("Unable to find session for ", user.username)
		return
	}

	//Notify the client what the user's current nick is
	client.SendMessage(irc.NewMessage("NICK " + user.profile.nick.name))
	newclients <- &client

	for {
		if ws.IsServerConn() {
			time.Sleep(100 * time.Millisecond)
		} else {
			log.Println("!!!!socketHandler returning after IsServerConn returned false")
			return
		}
	}
}
Example #3
0
//Join adds a webclient to the list of active clients. It blocks until webclient socket closes or chat ends
func (c ircchat) Join(sessionID string, webclient irc.Conn) error {
	if !c.Active() {
		return errors.New("The chat session is not active or enabled. Check settings")
	}

	webclient.Write(irc.NickMessage(c.settings.Login.Nick))
	//Send open channels to client
	for _, ch := range c.client.ChannelNames() {
		webclient.Write(irc.JoinMessage(ch))

		//Send users in the rooms as a names reply commands (353 to indicate start, 366 to indicate end)
		//Webclient doesn't care about length, but a traditional IRC client will
		//TODO: Indicate if channel is public, private or secret ( "=" / "*" / "@" ), current sends as pub
		//:tepper.freenode.net 353 goirctest @ #gotest :goirctest @Oooska
		//:tepper.freenode.net 366 goirctest #gotest :End of /NAMES list.
		users, _ := c.client.Users(ch)
		namesRepl := fmt.Sprintf("353 %s = %s :%s", c.settings.Login.Nick, ch, strings.Join(users, " "))
		namesEndRepl := fmt.Sprintf("366 %s %s", c.settings.Login.Nick, ch)
		webclient.Write(irc.NewMessage(namesRepl))
		webclient.Write(irc.NewMessage(namesEndRepl))

		messages, err := persistenceInstance.messages(c.account, ch, time.Now(), 200)
		if err != nil {
			log.Printf("Error retrieving message logs: %s", err.Error())
		}
		for _, msg := range messages {
			webclient.Write(msg)
		}

	}

	//Register as a listener
	c.registerClient(sessionID, webclient)
	for {
		select {
		case <-c.quit:
			fmt.Println("Exiting ircClientListener")
			return errors.New("IRC Session has ended")
		default:
			msg, err := webclient.Read()
			if err != nil {
				c.unregisterClient(sessionID)
				return err
			}
			c.toServer <- clientMessage{SessionID: sessionID, Message: msg}
		}
	}

}
Example #4
0
//ircManager takes the connection to the IRC server and then coordinates the
//communication between the irc server, and the active IRCClients
func ircManager(ircConn irc.IRCConn, newClients chan *ircClient) {
	fmt.Println("*** Entering ircManager ***")
	defer fmt.Println("*** Leaving ircManager ***")

	var clients []*ircClient

	fromServer := make(chan irc.Message)
	fromClient := make(chan irc.Message)
	errChan := make(chan error)
	quitChan := make(chan bool)

	//Listen for incoming messages form server
	go ircServerListener(ircConn, fromServer, errChan, quitChan)

	for {
		select {
		case msg := <-fromServer:
			//Log it,
			log.Println(msg)

			//Repsond if it's a ping
			if len(msg) >= 4 && msg[0:4] == "PING" {
				var end string = msg[4:].String()
				ircConn.Write(irc.NewMessage("PONG" + end))
				//break
			}

			//...and send it to all clients
			for k := 0; k < len(clients); k++ {
				client := *clients[k]
				err := client.SendMessage(msg)

				if err != nil {
					stopClientListener(&client)
					client.Close()
					clients = deleteNthItem(clients, k)
					k-- //Account for socket deletion in slice
					fmt.Println("*** Disconnected irc Client. ", len(clients), "remaining.")
				}
			}
		//Received a message from the server
		case msg := <-fromClient:
			err := ircConn.Write(msg)
			if err != nil {
				fmt.Println("Error writing to server: ", err)
			}

		//A new client has connected
		case client := <-newClients:
			clients = append(clients, client)
			startClientListener(client, fromClient)
			fmt.Println("*** Accepted the ", len(clients), " client connection ***")
		}
	}

	quitChan <- true
}
Example #5
0
File: main.go Project: Oooska/irc
//parseLine returns an irc.Message object. If the line starts with a forward
//slash, everything after the '/' is converted directly to a server command
//If there is no slash, the first word is taken to be the channel or user to
//send a PRIVMSG to
func parseLine(line string) (msg irc.Message, err error) {
	if line[0] == '/' {
		msg = irc.NewMessage(line[1:])
	} else {
		splitlines := strings.SplitN(line, " ", 2)
		if len(splitlines) > 1 {
			msg = irc.PrivMessage(splitlines[0], splitlines[1])
		} else {
			err = errors.New("Unable to parse input")
		}
	}
	return
}
Example #6
0
//A basic irc client that communicates over a websocket.
func main() {
	origin := "http://127.0.0.1/"
	url := "ws://127.0.0.1:8080/chat/socket"
	ws, err := websocket.Dial(url, "", origin)
	if err != nil {
		panic(err)
	}
	conn := irc.IRCConnectionWrapper(ws)

	go func() { //Read from stdin
		reader := bufio.NewReader(os.Stdin)
		for {
			line, err := reader.ReadString('\n')
			if err != nil {
				log.Fatalf("Cannot read from stdin: %s", err)
			}

			line = strings.TrimSpace(line)
			if len(line) == 0 {
				continue
			}

			msg, err := parseLine(line)
			if err != nil {
				log.Println("Err: ", err)
			} else {
				log.Println("YOU: ", msg)
				conn.Write(msg)
			}
		}
	}()

	var msg irc.Message

	// handle incomming messages
	for {

		msg, err = conn.Read()
		if err != nil {
			fmt.Printf("ERROR: %s\n", err)
			return
		}

		if len(msg) >= 4 && msg[0:4] == "PING" {
			var end string = msg[4:].String()
			conn.Write(irc.NewMessage("PONG" + end))
		}

		fmt.Println(msg)
	}
}
Example #7
0
func startSession(user iwcUser) error {
	//Start the IRC connection... //TODO: Move this elsewhere.
	conn, err := irc.NewIRCConnection(user.profile.address, false)
	if err != nil {
		return err
	}

	//Channel to accept new http clients logging in
	var newClients chan *ircClient = make(chan *ircClient)

	conn.Write(irc.UserMessage(user.username, "servername", "hostname", user.profile.realname))
	conn.Write(irc.NickMessage(user.profile.nick.name))
	conn.Write(irc.NewMessage("join #gotest"))
	go ircManager(conn, newClients)
	log.Println("Starting session for ", user.username)
	sessionNewClientsMap[user.username] = newClients
	return nil
}
Example #8
0
//Receives a message from the client/user
//TODO: Remove terrible parsing rules in parseLine()
func (wsclient wsClient) ReceiveMessage() (irc.Message, error) {
	msg, err := wsclient.reader.ReadString('\n')
	return irc.NewMessage(msg), err
}