2024-04-06 16:38:14 -06:00
|
|
|
package pnyx
|
|
|
|
|
|
|
|
import (
|
2024-04-13 14:00:56 -06:00
|
|
|
"fmt"
|
2024-04-16 15:06:53 -06:00
|
|
|
"slices"
|
|
|
|
"sync/atomic"
|
2024-04-13 14:00:56 -06:00
|
|
|
|
|
|
|
"github.com/google/uuid"
|
2024-04-06 16:38:14 -06:00
|
|
|
)
|
|
|
|
|
2024-04-12 18:06:57 -06:00
|
|
|
type ChannelID byte
|
2024-04-06 16:38:14 -06:00
|
|
|
|
2024-04-08 11:28:52 -06:00
|
|
|
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-08 11:28:52 -06:00
|
|
|
|
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
|
2024-04-18 20:10:01 -06:00
|
|
|
CHANNEL_CLOSE_BUFFER_SIZE int = 100
|
2024-04-08 11:28:52 -06:00
|
|
|
)
|
2024-04-06 16:38:14 -06:00
|
|
|
|
|
|
|
type ModeID uint8
|
|
|
|
type CommandID uint8
|
|
|
|
|
|
|
|
type Channel struct {
|
2024-04-16 15:06:53 -06:00
|
|
|
Commands chan SessionChannelCommand
|
2024-04-18 20:10:01 -06:00
|
|
|
ClosedSessions chan *ServerSession
|
2024-04-23 18:12:56 -06:00
|
|
|
RemovedRoles chan Role
|
2024-04-16 15:06:53 -06:00
|
|
|
Modes map[ModeID]*atomic.Value
|
|
|
|
Members atomic.Value
|
2024-04-23 18:12:56 -06:00
|
|
|
|
|
|
|
BasePermissions atomic.Value
|
|
|
|
RolePermissions atomic.Value
|
|
|
|
UserPermissions atomic.Value
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
channel := &Channel{
|
|
|
|
Commands: make(chan SessionChannelCommand, CHANNEL_COMMAND_BUFFER_SIZE),
|
|
|
|
ClosedSessions: make(chan *ServerSession, CHANNEL_CLOSE_BUFFER_SIZE),
|
|
|
|
RemovedRoles: make(chan Role, CHANNEL_CLOSE_BUFFER_SIZE),
|
|
|
|
Modes: initial_modes,
|
|
|
|
}
|
|
|
|
|
|
|
|
channel.Members.Store([]*ServerSession{})
|
|
|
|
channel.BasePermissions.Store(Permissions{})
|
|
|
|
channel.RolePermissions.Store(map[Role]Permissions{})
|
|
|
|
channel.UserPermissions.Store(map[PeerID]Permissions{})
|
|
|
|
|
|
|
|
go channel.update_state()
|
|
|
|
|
|
|
|
return channel, nil
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func(channel *Channel) update_state() {
|
|
|
|
for true {
|
2024-04-18 20:10:01 -06:00
|
|
|
select {
|
2024-04-23 18:12:56 -06:00
|
|
|
case <-channel.RemovedRoles:
|
2024-04-18 20:10:01 -06:00
|
|
|
case session := <-channel.ClosedSessions:
|
|
|
|
members := channel.Members.Load().([]*ServerSession)
|
|
|
|
idx := slices.Index(members, 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)
|
|
|
|
|
|
|
|
for _, mode_val := range(channel.Modes) {
|
|
|
|
mode := mode_val.Load().(Mode)
|
|
|
|
mode_val.Store(mode.Leave(session))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case incoming := <-channel.Commands:
|
|
|
|
if incoming.Packet == nil {
|
|
|
|
break
|
|
|
|
} else if incoming.Session.active.Load() == false {
|
|
|
|
continue
|
|
|
|
}
|
2024-04-16 15:06:53 -06:00
|
|
|
|
2024-04-18 20:10:01 -06:00
|
|
|
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)
|
|
|
|
|
|
|
|
for _, mode_val := range(channel.Modes) {
|
|
|
|
mode := mode_val.Load().(Mode)
|
|
|
|
mode_val.Store(mode.Join(incoming.Session))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
|
|
|
|
for _, mode_val := range(channel.Modes) {
|
|
|
|
mode := mode_val.Load().(Mode)
|
|
|
|
mode_val.Store(mode.Leave(incoming.Session))
|
|
|
|
}
|
|
|
|
}
|
2024-04-16 15:06:53 -06:00
|
|
|
}
|
2024-04-18 20:10:01 -06:00
|
|
|
} 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.Store(new_mode)
|
2024-04-16 15:06:53 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-06 16:38:14 -06:00
|
|
|
type Mode interface {
|
2024-04-18 20:10:01 -06:00
|
|
|
Join(session *ServerSession) Mode
|
|
|
|
Leave(session *ServerSession) Mode
|
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
|
2024-04-13 14:00:56 -06:00
|
|
|
Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte)
|
2024-04-08 11:28:52 -06:00
|
|
|
}
|
|
|
|
|
2024-04-13 14:00:56 -06:00
|
|
|
func multiplex_without_sender(origin SessionID, packet *Packet, sessions []*ServerSession) {
|
|
|
|
for _, session := range(sessions) {
|
|
|
|
if session.ID == origin {
|
2024-04-08 11:28:52 -06:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:34:53 -06:00
|
|
|
session.Send(packet)
|
2024-04-12 18:06:57 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-13 14:00:56 -06:00
|
|
|
func multiplex(packet *Packet, sessions []*ServerSession) {
|
|
|
|
for _, session := range(sessions) {
|
2024-04-16 15:34:53 -06:00
|
|
|
session.Send(packet)
|
2024-04-08 11:28:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type RawMode struct {
|
|
|
|
}
|
|
|
|
|
2024-04-18 20:10:01 -06:00
|
|
|
func(mode RawMode) Join(session *ServerSession) Mode {
|
|
|
|
return mode
|
|
|
|
}
|
|
|
|
|
|
|
|
func(mode RawMode) Leave(session *ServerSession) Mode {
|
|
|
|
return mode
|
|
|
|
}
|
|
|
|
|
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-09 17:08:46 -06:00
|
|
|
}
|
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)
|
2024-04-13 14:00:56 -06:00
|
|
|
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-18 20:10:01 -06:00
|
|
|
func(mode AudioMode) Join(session *ServerSession) Mode {
|
|
|
|
return mode
|
|
|
|
}
|
|
|
|
|
|
|
|
func(mode AudioMode) Leave(session *ServerSession) Mode {
|
|
|
|
return mode
|
|
|
|
}
|
|
|
|
|
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 {
|
2024-04-13 14:00:56 -06:00
|
|
|
switch command {
|
2024-04-12 18:06:57 -06:00
|
|
|
case AUDIO_SET_SAMPLE_RATE:
|
2024-04-13 14:00:56 -06:00
|
|
|
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:
|
2024-04-13 14:00:56 -06:00
|
|
|
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:
|
2024-04-13 14:00:56 -06:00
|
|
|
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)
|
2024-04-13 14:00:56 -06:00
|
|
|
multiplex_without_sender(session.ID, new_packet, members)
|
|
|
|
}
|