|  |  |  | @ -1,25 +1,19 @@ | 
		
	
		
			
				|  |  |  |  | package pnyx | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | import ( | 
		
	
		
			
				|  |  |  |  | 	"slices" | 
		
	
		
			
				|  |  |  |  | 	"fmt" | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	"github.com/google/uuid" | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type ChannelID byte | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const ( | 
		
	
		
			
				|  |  |  |  |   MODE_CHANNEL ModeID = iota | 
		
	
		
			
				|  |  |  |  |   MODE_RAW | 
		
	
		
			
				|  |  |  |  |   MODE_RAW ModeID = iota | 
		
	
		
			
				|  |  |  |  |   MODE_AUDIO | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   CHANNEL_JOIN byte = iota | 
		
	
		
			
				|  |  |  |  |   CHANNEL_LEAVE | 
		
	
		
			
				|  |  |  |  |   CHANNEL_MEMBERS | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   AUDIO_SET_SAMPLE_RATE = iota | 
		
	
		
			
				|  |  |  |  |   AUDIO_GET_SAMPLE_RATE | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   RAW_DATA = iota | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type ModeID uint8 | 
		
	
	
		
			
				
					|  |  |  | @ -30,103 +24,70 @@ type Channel struct { | 
		
	
		
			
				|  |  |  |  |   id ChannelID | 
		
	
		
			
				|  |  |  |  |   name string | 
		
	
		
			
				|  |  |  |  |   modes map[ModeID]Mode | 
		
	
		
			
				|  |  |  |  |   sessions []SessionID | 
		
	
		
			
				|  |  |  |  |   members []*ServerSession | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Data(session *Session, mode ModeID, data []byte) []SendPacket { | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Data(session *ServerSession, mode ModeID, data []byte) { | 
		
	
		
			
				|  |  |  |  |   m, has_mode := channel.modes[mode] | 
		
	
		
			
				|  |  |  |  |   if has_mode == false { | 
		
	
		
			
				|  |  |  |  |     return nil | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     return m.Data(session, channel, data) | 
		
	
		
			
				|  |  |  |  |   if has_mode { | 
		
	
		
			
				|  |  |  |  |     m.Data(session, channel.id, channel.members, data) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Command(session *Session, packet ChannelCommandPacket) ([]SendPacket, error) { | 
		
	
		
			
				|  |  |  |  |   if packet.Mode == MODE_CHANNEL { | 
		
	
		
			
				|  |  |  |  |     switch packet.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", packet.Command) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     mode, has_mode := channel.modes[packet.Mode] | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Command(session *ServerSession, command byte, request_id uuid.UUID, mode_id ModeID, data []byte) error { | 
		
	
		
			
				|  |  |  |  |   mode, has_mode := channel.modes[mode_id] | 
		
	
		
			
				|  |  |  |  |   if has_mode == false { | 
		
	
		
			
				|  |  |  |  |       return nil, fmt.Errorf("Channel has no mode 0x%02x", mode) | 
		
	
		
			
				|  |  |  |  |     return fmt.Errorf("Channel has no mode 0x%02x", mode) | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |       return mode.Command(session, channel, packet) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return mode.Command(session, command, request_id, channel.id, channel.members, data) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type SendPacket struct { | 
		
	
		
			
				|  |  |  |  |   Packet *Packet | 
		
	
		
			
				|  |  |  |  |   Session SessionID | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Join(client PeerID, session SessionID) { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(channel *Channel) Leave(client PeerID, 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, packet ChannelCommandPacket) ([]SendPacket, error) | 
		
	
		
			
				|  |  |  |  |   Data(session *Session, channel *Channel, data []byte) []SendPacket | 
		
	
		
			
				|  |  |  |  |   Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error | 
		
	
		
			
				|  |  |  |  |   Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Join(client PeerID, session SessionID) | 
		
	
		
			
				|  |  |  |  |   Leave(client PeerID, session SessionID) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func multiplex_without_sender(origin SessionID, packet *Packet, sessions []SessionID) []SendPacket { | 
		
	
		
			
				|  |  |  |  |   send_packets := make([]SendPacket, len(sessions) - 1) | 
		
	
		
			
				|  |  |  |  |   i := 0 | 
		
	
		
			
				|  |  |  |  |   for _, session_id := range(sessions) { | 
		
	
		
			
				|  |  |  |  |     if session_id == origin { | 
		
	
		
			
				|  |  |  |  | func multiplex_without_sender(origin SessionID, packet *Packet, sessions []*ServerSession) { | 
		
	
		
			
				|  |  |  |  |   for _, session := range(sessions) { | 
		
	
		
			
				|  |  |  |  |     if session.ID == origin { | 
		
	
		
			
				|  |  |  |  |       continue | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     send_packets[i] = SendPacket{ | 
		
	
		
			
				|  |  |  |  |       Packet: packet, | 
		
	
		
			
				|  |  |  |  |       Session: session_id, | 
		
	
		
			
				|  |  |  |  |     session.OutgoingPackets <- packet | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |     i += 1 | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return send_packets | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func multiplex(packet *Packet, sessions []SessionID) []SendPacket { | 
		
	
		
			
				|  |  |  |  |   send_packets := make([]SendPacket, len(sessions)) | 
		
	
		
			
				|  |  |  |  |   for i, session_id := range(sessions) { | 
		
	
		
			
				|  |  |  |  |     send_packets[i] = SendPacket{ | 
		
	
		
			
				|  |  |  |  |       Packet: packet, | 
		
	
		
			
				|  |  |  |  |       Session: session_id, | 
		
	
		
			
				|  |  |  |  | func multiplex(packet *Packet, sessions []*ServerSession) { | 
		
	
		
			
				|  |  |  |  |   for _, session := range(sessions) { | 
		
	
		
			
				|  |  |  |  |     session.OutgoingPackets <- packet | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return send_packets | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type RawMode struct { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(mode *RawMode) Command(session *Session, channel *Channel, packet ChannelCommandPacket) ([]SendPacket, error) { | 
		
	
		
			
				|  |  |  |  |   return nil, fmt.Errorf("unknown raw mode command 0x%02x", packet.Command) | 
		
	
		
			
				|  |  |  |  | func(mode *RawMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error { | 
		
	
		
			
				|  |  |  |  |   return 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_without_sender(session.ID, new_packet, channel.sessions) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   return nil | 
		
	
		
			
				|  |  |  |  | func(mode *RawMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) { | 
		
	
		
			
				|  |  |  |  |   new_packet := NewChannelPeerPacket(session.Peer, channel_id, MODE_RAW, data) | 
		
	
		
			
				|  |  |  |  |   multiplex_without_sender(session.ID, new_packet, members) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(mode *RawMode) Join(client PeerID, session SessionID) { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | func(mode *RawMode) Leave(client PeerID, session SessionID) { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | type SampleRate byte | 
		
	
	
		
			
				
					|  |  |  | @ -140,37 +101,38 @@ type AudioMode struct { | 
		
	
		
			
				|  |  |  |  |   SampleRate SampleRate | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Command(session *Session, channel *Channel, packet ChannelCommandPacket) ([]SendPacket, error) { | 
		
	
		
			
				|  |  |  |  |   switch packet.Command { | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Command(session *ServerSession, command byte, request_id uuid.UUID, channel_id ChannelID, members []*ServerSession, data []byte) error { | 
		
	
		
			
				|  |  |  |  |   switch command { | 
		
	
		
			
				|  |  |  |  |   case AUDIO_SET_SAMPLE_RATE: | 
		
	
		
			
				|  |  |  |  |     if len(packet.Data) == 1 { | 
		
	
		
			
				|  |  |  |  |       switch SampleRate(packet.Data[0]) { | 
		
	
		
			
				|  |  |  |  |     if len(data) == 1 { | 
		
	
		
			
				|  |  |  |  |       switch SampleRate(data[0]) { | 
		
	
		
			
				|  |  |  |  |       case SAMPLE_RATE_24KHZ: | 
		
	
		
			
				|  |  |  |  |         fallthrough | 
		
	
		
			
				|  |  |  |  |       case SAMPLE_RATE_48KHZ: | 
		
	
		
			
				|  |  |  |  |         mode.SampleRate = SampleRate(packet.Data[0]) | 
		
	
		
			
				|  |  |  |  |         update_packet := NewChannelCommandPacket(packet.ReqID, channel.id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, packet.Data) | 
		
	
		
			
				|  |  |  |  |         return multiplex(update_packet, channel.sessions), nil | 
		
	
		
			
				|  |  |  |  |         mode.SampleRate = SampleRate(data[0]) | 
		
	
		
			
				|  |  |  |  |         update_packet := NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, data) | 
		
	
		
			
				|  |  |  |  |         multiplex(update_packet, members) | 
		
	
		
			
				|  |  |  |  |         return nil | 
		
	
		
			
				|  |  |  |  |       default: | 
		
	
		
			
				|  |  |  |  |         return nil, fmt.Errorf("Invalid sample rate: %x", packet.Data[0]) | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("Invalid sample rate: %x", data[0]) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |     } else { | 
		
	
		
			
				|  |  |  |  |       return nil, fmt.Errorf("Invalid AUDIO_SET_SAMPLE_RATE payload: %x", packet.Data) | 
		
	
		
			
				|  |  |  |  |       return fmt.Errorf("Invalid AUDIO_SET_SAMPLE_RATE payload: %x", data) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   case AUDIO_GET_SAMPLE_RATE: | 
		
	
		
			
				|  |  |  |  |     return []SendPacket{{ | 
		
	
		
			
				|  |  |  |  |       Packet: NewChannelCommandPacket(packet.ReqID, channel.id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, []byte{byte(mode.SampleRate)}), | 
		
	
		
			
				|  |  |  |  |       Session: session.ID, | 
		
	
		
			
				|  |  |  |  |     }}, nil | 
		
	
		
			
				|  |  |  |  |     session.OutgoingPackets <- NewChannelCommandPacket(request_id, channel_id, MODE_AUDIO, AUDIO_SET_SAMPLE_RATE, []byte{byte(mode.SampleRate)}) | 
		
	
		
			
				|  |  |  |  |     return nil | 
		
	
		
			
				|  |  |  |  |   default: | 
		
	
		
			
				|  |  |  |  |     return nil, fmt.Errorf("unknown audio mode command 0x%02x", packet.Command) | 
		
	
		
			
				|  |  |  |  |     return fmt.Errorf("unknown audio mode command 0x%02x", command) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Data(session *Session, channel *Channel, data []byte) []SendPacket { | 
		
	
		
			
				|  |  |  |  |   if slices.Contains(channel.sessions, session.ID) { | 
		
	
		
			
				|  |  |  |  |     new_packet := NewChannelPeerPacket(session.Peer, channel.id, MODE_AUDIO, data) | 
		
	
		
			
				|  |  |  |  |     return multiplex_without_sender(session.ID, new_packet, channel.sessions) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   return nil | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Data(session *ServerSession, channel_id ChannelID, members []*ServerSession, data []byte) { | 
		
	
		
			
				|  |  |  |  |   new_packet := NewChannelPeerPacket(session.Peer, channel_id, MODE_AUDIO, data) | 
		
	
		
			
				|  |  |  |  |   multiplex_without_sender(session.ID, new_packet, members) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Join(client PeerID, session SessionID) { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | func(mode *AudioMode) Leave(client PeerID, session SessionID) { | 
		
	
		
			
				|  |  |  |  | } | 
		
	
	
		
			
				
					|  |  |  | 
 |