pnyx/channel.go

166 lines
4.7 KiB
Go

package pnyx
import (
"fmt"
2024-04-16 15:06:53 -06:00
"slices"
"sync/atomic"
"github.com/google/uuid"
)
2024-04-12 18:06:57 -06:00
type ChannelID byte
const (
2024-04-16 15:06:53 -06:00
MODE_CHANNEL ModeID = iota
MODE_RAW
2024-04-12 18:06:57 -06:00
MODE_AUDIO
2024-04-12 18:06:57 -06:00
AUDIO_SET_SAMPLE_RATE = iota
AUDIO_GET_SAMPLE_RATE
2024-04-16 15:06:53 -06:00
CHANNEL_COMMAND_BUFFER_SIZE int = 2048
)
type ModeID uint8
type CommandID uint8
type Permission string
type Channel struct {
2024-04-16 15:06:53 -06:00
Commands chan SessionChannelCommand
Modes map[ModeID]*atomic.Value
Members atomic.Value
}
2024-04-16 15:06:53 -06:00
func(channel *Channel) update_state() {
for true {
incoming := <-channel.Commands
if incoming.Packet == nil {
break
}
command := incoming.Packet
if command.Mode == MODE_CHANNEL {
switch command.Command {
case CHANNEL_COMMAND_JOIN:
members := channel.Members.Load().([]*ServerSession)
if slices.Contains(members, incoming.Session) == false {
new_members := make([]*ServerSession, len(members) + 1)
copy(new_members, members)
new_members[len(members)] = incoming.Session
channel.Members.Store(new_members)
fmt.Printf("New Members: %+v\n", channel.Members.Load())
}
case CHANNEL_COMMAND_LEAVE:
members := channel.Members.Load().([]*ServerSession)
idx := slices.Index(members, incoming.Session)
if idx != -1 {
new_members := make([]*ServerSession, len(members) - 1)
copy(new_members, members[:idx])
copy(new_members[idx:], members[idx+1:])
channel.Members.Store(new_members)
fmt.Printf("New Members: %+v\n", channel.Members.Load())
}
}
} else {
mode, has_mode := channel.Modes[command.Mode]
if has_mode {
members := channel.Members.Load().([]*ServerSession)
mode_val := mode.Load().(Mode)
new_mode := mode_val.Command(incoming.Session, command.Command, command.ReqID, command.Channel, members, command.Data)
mode.CompareAndSwap(mode_val, new_mode)
}
}
}
}
2024-04-16 15:06:53 -06:00
func NewChannel(modes map[ModeID]Mode) (*Channel, error) {
initial_modes := map[ModeID]*atomic.Value{}
for mode_id, mode := range(modes) {
if mode_id == MODE_CHANNEL {
return nil, fmt.Errorf("Cannot create a channel with MODE_CHANNEL(0x%02x) mode", MODE_CHANNEL)
}
initial_modes[mode_id] = new(atomic.Value)
initial_modes[mode_id].Store(mode)
}
2024-04-16 15:06:53 -06:00
channel := &Channel{
Commands: make(chan SessionChannelCommand, CHANNEL_COMMAND_BUFFER_SIZE),
Modes: initial_modes,
}
channel.Members.Store([]*ServerSession{})
2024-04-16 15:06:53 -06:00
go channel.update_state()
2024-04-16 15:06:53 -06:00
return channel, nil
}
type Mode interface {
2024-04-16 15:06:53 -06:00
Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) Mode
Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte)
}
func multiplex_without_sender(origin SessionID, packet *Packet, sessions []*ServerSession) {
for _, session := range(sessions) {
if session.ID == origin {
continue
}
session.OutgoingPackets <- packet
2024-04-12 18:06:57 -06:00
}
}
func multiplex(packet *Packet, sessions []*ServerSession) {
for _, session := range(sessions) {
session.OutgoingPackets <- packet
}
}
type RawMode struct {
}
2024-04-16 15:06:53 -06:00
func(mode RawMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) Mode {
return mode
}
2024-04-08 17:23:55 -06:00
2024-04-16 15:06:53 -06:00
func(mode RawMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) {
new_packet := NewPeerPacket(session.Peer, channel_id, MODE_RAW, data)
multiplex_without_sender(session.ID, new_packet, members)
}
2024-04-12 18:06:57 -06:00
type SampleRate byte
const (
SAMPLE_RATE_UNSET SampleRate = 0xFF
SAMPLE_RATE_24KHZ = 0x01
SAMPLE_RATE_48KHZ = 0x02
)
type AudioMode struct {
SampleRate SampleRate
}
2024-04-16 15:06:53 -06:00
func(mode AudioMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) Mode {
switch command {
2024-04-12 18:06:57 -06:00
case AUDIO_SET_SAMPLE_RATE:
if len(data) == 1 {
switch SampleRate(data[0]) {
2024-04-12 18:06:57 -06:00
case SAMPLE_RATE_24KHZ:
fallthrough
case SAMPLE_RATE_48KHZ:
mode.SampleRate = SampleRate(data[0])
update_packet := NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, data)
multiplex(update_packet, members)
2024-04-12 18:06:57 -06:00
}
}
case AUDIO_GET_SAMPLE_RATE:
session.OutgoingPackets <- NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, []byte{byte(mode.SampleRate)})
2024-04-12 18:06:57 -06:00
}
2024-04-16 15:06:53 -06:00
return mode
2024-04-12 18:06:57 -06:00
}
2024-04-16 15:06:53 -06:00
func(mode AudioMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) {
new_packet := NewPeerPacket(session.Peer, channel_id, MODE_AUDIO, data)
multiplex_without_sender(session.ID, new_packet, members)
}