Implementation 1 of a minimalistic IRC server

This commit is contained in:
2025-09-26 20:36:54 -07:00
commit d340bc49da
18 changed files with 1082 additions and 0 deletions

122
src/irc/world/world.go Normal file
View File

@@ -0,0 +1,122 @@
package world
import (
"fmt"
"log"
"slices"
"git.chromaticdragon.app/pyrex/minimal-irc-server/v2/src/irc/users"
"git.chromaticdragon.app/pyrex/minimal-irc-server/v2/src/transport"
)
type World struct {
Server *transport.Server
UsersSystem *users.UsersSystem
}
type WrappedMessage struct {
World *World
Sender *users.User
Content transport.Content
}
func NewWorld(server *transport.Server) *World {
usersSystem := users.NewUsersSystem()
return &World{
Server: server,
UsersSystem: usersSystem,
}
}
func (world *World) Wrap(msg transport.IncomingMessage) WrappedMessage {
sender := world.UsersSystem.ByClientIdOrCreate(msg.Sender)
return WrappedMessage{
World: world,
Sender: sender,
Content: msg.Content,
}
}
// transmission of messages
func (world *World) RelayToVagueDestination(
msg WrappedMessage,
name string,
exclude []transport.ClientId,
) {
nick, err := users.ValidateNick(name)
if err == nil {
// so it's a nick!
world.RelayToNick(msg, nick, exclude)
return
}
channel, err := users.ValidateChannelName(name)
if err == nil {
// so it's a channel!
world.RelayToChannel(msg, channel, exclude)
return
}
log.Fatalf("not sure how to send to %s", name)
// TODO: Error response: "what is this?"
}
func (world *World) RelayToClient(
msg WrappedMessage,
client transport.ClientId,
exclude []transport.ClientId,
) {
content := createAnnotatedContent(msg)
if slices.Contains(exclude, client) {
return // don't relay
}
world.Server.SendMessage(client, content)
}
func (world *World) RelayToNick(
msg WrappedMessage,
nick users.Nick,
exclude []transport.ClientId,
) {
content := createAnnotatedContent(msg)
user := world.UsersSystem.ByNick(nick)
if user == nil {
// TODO: Send an error reply. The user didn't exist
return
}
if slices.Contains(exclude, user.GetClientId()) {
return // don't relay
}
world.Server.SendMessage(user.GetClientId(), content)
}
func (world *World) RelayToChannel(
msg WrappedMessage,
channelName users.ChannelName,
exclude []transport.ClientId,
) {
content := createAnnotatedContent(msg)
members := world.UsersSystem.ByChannel(channelName)
log.Printf("Members of %s: %v\n", channelName, members)
for member := range members {
if slices.Contains(exclude, member.GetClientId()) {
return // don't relay
}
world.Server.SendMessage(member.GetClientId(), content)
}
}
func createAnnotatedContent(
msg WrappedMessage,
) transport.Content {
content := msg.Content
fullSource := fmt.Sprintf("%s!clients/%d", msg.Sender.GetNick().Value, msg.Sender.GetClientId())
content.Source = &fullSource
return content
}