package pnyx import ( "slices" "fmt" ) type ChannelID uint32 const ( MODE_CHANNEL ModeID = iota MODE_RAW CHANNEL_JOIN byte = iota CHANNEL_LEAVE CHANNEL_MEMBERS RAW_DATA = iota ) type ModeID uint8 type CommandID uint8 type Permission string type Channel struct { id ChannelID modes map[ModeID]Mode sessions []SessionID } func(channel *Channel) Data(session *Session, mode ModeID, data []byte) []SendPacket { m, has_mode := channel.modes[mode] if has_mode == false { return nil } else { return m.Data(session, channel, data) } } func(channel *Channel) Command(session *Session, mode ModeID, command byte, data []byte) ([]SendPacket, error) { if mode == MODE_CHANNEL { switch command { case CHANNEL_JOIN: if slices.Contains(channel.sessions, session.ID) { return nil, fmt.Errorf("Session %s already in channel %d, can't join", session.ID, channel.id) } else { channel.sessions = append(channel.sessions, session.ID) return nil, nil } case CHANNEL_LEAVE: idx := slices.Index(channel.sessions, session.ID) if idx == -1 { return nil, fmt.Errorf("Session %s not in channel %d, can't leave", session.ID, channel.id) } else { channel.sessions = slices.Delete(channel.sessions, idx, idx+1) return nil, nil } default: return nil, fmt.Errorf("Unknown MODE_CHANNEL command: 0x%02x", command) } } else { mode, has_mode := channel.modes[mode] if has_mode == false { return nil, fmt.Errorf("Channel has no mode 0x%02x", mode) } else { return mode.Command(session, channel, command, data) } } } type SendPacket struct { Packet *Packet Session SessionID } type Mode interface { // Process takes incoming packets from a session and returns a list of packets to send Command(session *Session, channel *Channel, command byte, data []byte) ([]SendPacket, error) Data(session *Session, channel *Channel, data []byte) []SendPacket } func multiplex(session *Session, packet *Packet, sessions []SessionID) []SendPacket { send_packets := make([]SendPacket, len(sessions)) for i, session_id := range(sessions) { if session_id == session.ID { continue } send_packets[i] = SendPacket{ Packet: packet, Session: session_id, } } return send_packets } type RawMode struct { } func(mode *RawMode) Command(session *Session, channel *Channel, command byte, data []byte) ([]SendPacket, error) { return nil, fmt.Errorf("unknown raw mode command 0x%02x", command) } func(mode *RawMode) Data(session *Session, channel *Channel, data []byte) []SendPacket { if slices.Contains(channel.sessions, session.ID) { new_packet := NewChannelPeerPacket(session.Peer, channel.id, MODE_RAW, data) return multiplex(session, new_packet, channel.sessions) } return nil }