Started permissions, and moved server goroutine start to server creation

live
noah metz 2024-04-23 18:12:56 -06:00
parent 6b7e166bb8
commit 419e7857f9
4 changed files with 122 additions and 59 deletions

@ -24,18 +24,50 @@ const (
type ModeID uint8 type ModeID uint8
type CommandID uint8 type CommandID uint8
type Permission string
type Channel struct { type Channel struct {
Commands chan SessionChannelCommand Commands chan SessionChannelCommand
ClosedSessions chan *ServerSession ClosedSessions chan *ServerSession
RemovedRoles chan Role
Modes map[ModeID]*atomic.Value Modes map[ModeID]*atomic.Value
Members atomic.Value Members atomic.Value
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
} }
func(channel *Channel) update_state() { func(channel *Channel) update_state() {
for true { for true {
select { select {
case <-channel.RemovedRoles:
case session := <-channel.ClosedSessions: case session := <-channel.ClosedSessions:
members := channel.Members.Load().([]*ServerSession) members := channel.Members.Load().([]*ServerSession)
idx := slices.Index(members, session) idx := slices.Index(members, session)
@ -102,28 +134,6 @@ func(channel *Channel) update_state() {
} }
} }
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),
Modes: initial_modes,
}
channel.Members.Store([]*ServerSession{})
go channel.update_state()
return channel, nil
}
type Mode interface { type Mode interface {
Join(session *ServerSession) Mode Join(session *ServerSession) Mode
Leave(session *ServerSession) Mode Leave(session *ServerSession) Mode

@ -23,18 +23,13 @@ func main() {
panic(err) panic(err)
} }
server, err := pnyx.NewServer(nil, map[pnyx.ChannelID]*pnyx.Channel{ server, err := pnyx.NewServer(os.Args[1], nil, map[pnyx.ChannelID]*pnyx.Channel{
0: channel_0, 0: channel_0,
}) })
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = server.Start(os.Args[1])
if err != nil {
panic(err)
}
<-os_sigs <-os_sigs
err = server.Stop() err = server.Stop()
if err != nil { if err != nil {

@ -0,0 +1,58 @@
package pnyx
type PermissionLevel int
const (
PERMISSION_FALLTHROUGH PermissionLevel = iota
PERMISSION_ALLOW
PERMISSION_DENY
PERMISSION_ALLOW_ALL
PERMISSION_DENY_ALL
)
type Role string
type Action string
type Permissions map[Action]Permission
type Permission struct {
Level PermissionLevel
Next Permissions
}
func(permissions Permissions) Allowed(action []Action, def bool) bool {
if len(action) == 0 {
return def
} else if permissions == nil {
return def
}
perm, exists := permissions[action[0]]
if exists == false {
return def
} else if len(action) == 1 {
return perm.Level == PERMISSION_ALLOW || perm.Level == PERMISSION_ALLOW_ALL
} else {
switch perm.Level {
case PERMISSION_ALLOW_ALL:
return perm.Next.Allowed(action[1:], true)
case PERMISSION_DENY_ALL:
return perm.Next.Allowed(action[1:], false)
default:
return perm.Next.Allowed(action[1:], def)
}
}
}
func(permissions Permissions) Copy() Permissions {
if permissions == nil {
return nil
}
new_permissions := Permissions{}
for action, permission := range(permissions) {
new_permissions[action] = Permission{
Level: permission.Level,
Next: permission.Next.Copy(),
}
}
return new_permissions
}

@ -49,9 +49,13 @@ type Server struct {
channels atomic.Value channels atomic.Value
peers map[PeerID][]RoleID peers map[PeerID][]RoleID
BasePermissions atomic.Value
RolePermissions atomic.Value
UserPermissions atomic.Value
} }
func NewServer(key ed25519.PrivateKey, channels map[ChannelID]*Channel) (*Server, error) { func NewServer(listen string, key ed25519.PrivateKey, channels map[ChannelID]*Channel) (*Server, error) {
if key == nil { if key == nil {
var err error var err error
_, key, err = ed25519.GenerateKey(rand.Reader) _, key, err = ed25519.GenerateKey(rand.Reader)
@ -59,9 +63,21 @@ func NewServer(key ed25519.PrivateKey, channels map[ChannelID]*Channel) (*Server
return nil, err return nil, err
} }
} }
address, err := net.ResolveUDPAddr("udp", listen)
if err != nil {
return nil, err
}
connection, err := net.ListenUDP("udp", address)
if err != nil {
return nil, fmt.Errorf("Failed to create udp server: %w", err)
}
server := &Server{ server := &Server{
key: key, key: key,
connection: nil, connection: connection,
active: atomic.Bool{}, active: atomic.Bool{},
stopped: make(chan error, 0), stopped: make(chan error, 0),
commands: make(chan Payload, SERVER_COMMAND_BUFFER_SIZE), commands: make(chan Payload, SERVER_COMMAND_BUFFER_SIZE),
@ -72,7 +88,16 @@ func NewServer(key ed25519.PrivateKey, channels map[ChannelID]*Channel) (*Server
peers: map[PeerID][]RoleID{}, peers: map[PeerID][]RoleID{},
} }
server.channels.Store(channels) server.channels.Store(channels)
server.active.Store(false)
server.BasePermissions.Store(Permissions{})
server.RolePermissions.Store(map[Role]Permissions{})
server.UserPermissions.Store(map[PeerID]Permissions{})
server.active.Store(true)
go server.listen_udp()
go server.update_state()
return server, nil return server, nil
} }
@ -81,15 +106,14 @@ func(server *Server) Log(format string, fields ...interface{}) {
} }
func(server *Server) Stop() error { func(server *Server) Stop() error {
was_active := server.active.CompareAndSwap(true, false) if server.active.CompareAndSwap(true, false) {
if was_active {
err := server.connection.Close() err := server.connection.Close()
if err != nil { if err != nil {
return err return err
} }
return <-server.stopped return <-server.stopped
} else { } else {
return fmt.Errorf("Called stop func on stopped server") return fmt.Errorf("Called stop on stopped server")
} }
} }
@ -389,27 +413,3 @@ func(server *Server) update_state() {
} }
} }
} }
func(server *Server) Start(listen string) error {
was_inactive := server.active.CompareAndSwap(false, true)
if was_inactive == false {
return fmt.Errorf("Server already active")
}
address, err := net.ResolveUDPAddr("udp", listen)
if err != nil {
server.active.Store(false)
return err
}
server.connection, err = net.ListenUDP("udp", address)
if err != nil {
server.active.Store(false)
return fmt.Errorf("Failed to create udp server: %w", err)
}
go server.listen_udp()
go server.update_state()
return nil
}