session save & load from a file. (#38)

This commit is contained in:
Miroslav Šedivý 2023-03-27 18:33:51 +02:00 committed by GitHub
parent fa69ddd984
commit 09508638ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 0 deletions

View File

@ -40,6 +40,7 @@ docker run --rm -it \
-e "NEKO_WEBRTC_UDPMUX=${NEKO_MUX}" \ -e "NEKO_WEBRTC_UDPMUX=${NEKO_MUX}" \
-e "NEKO_WEBRTC_TCPMUX=${NEKO_MUX}" \ -e "NEKO_WEBRTC_TCPMUX=${NEKO_MUX}" \
-e "NEKO_WEBRTC_NAT1TO1=${NEKO_NAT1TO1}" \ -e "NEKO_WEBRTC_NAT1TO1=${NEKO_NAT1TO1}" \
-e "NEKO_SESSION_FILE=/home/neko/sessions.txt" \
-v "${PWD}/runtime/config.yml:/etc/neko/neko.yml" \ -v "${PWD}/runtime/config.yml:/etc/neko/neko.yml" \
-e "NEKO_DEBUG=1" \ -e "NEKO_DEBUG=1" \
neko_server_app:latest; neko_server_app:latest;

View File

@ -8,6 +8,8 @@ import (
) )
type Session struct { type Session struct {
File string
ImplicitHosting bool ImplicitHosting bool
InactiveCursors bool InactiveCursors bool
MercifulReconnect bool MercifulReconnect bool
@ -20,6 +22,11 @@ type Session struct {
} }
func (Session) Init(cmd *cobra.Command) error { func (Session) Init(cmd *cobra.Command) error {
cmd.PersistentFlags().String("session.file", "", "if sessions should be stored in a file, otherwise they will be stored only in memory")
if err := viper.BindPFlag("session.file", cmd.PersistentFlags().Lookup("session.file")); err != nil {
return err
}
cmd.PersistentFlags().Bool("session.implicit_hosting", true, "allow implicit control switching") cmd.PersistentFlags().Bool("session.implicit_hosting", true, "allow implicit control switching")
if err := viper.BindPFlag("session.implicit_hosting", cmd.PersistentFlags().Lookup("session.implicit_hosting")); err != nil { if err := viper.BindPFlag("session.implicit_hosting", cmd.PersistentFlags().Lookup("session.implicit_hosting")); err != nil {
return err return err
@ -65,6 +72,8 @@ func (Session) Init(cmd *cobra.Command) error {
} }
func (s *Session) Set() { func (s *Session) Set() {
s.File = viper.GetString("session.file")
s.ImplicitHosting = viper.GetBool("session.implicit_hosting") s.ImplicitHosting = viper.GetBool("session.implicit_hosting")
s.InactiveCursors = viper.GetBool("session.inactive_cursors") s.InactiveCursors = viper.GetBool("session.inactive_cursors")
s.MercifulReconnect = viper.GetBool("session.merciful_reconnect") s.MercifulReconnect = viper.GetBool("session.merciful_reconnect")

View File

@ -49,6 +49,9 @@ func New(config *config.Session) *SessionManagerCtx {
} }
} }
// try to load sessions from file
manager.load()
return manager return manager
} }
@ -102,6 +105,8 @@ func (manager *SessionManagerCtx) Create(id string, profile types.MemberProfile)
manager.sessionsMu.Unlock() manager.sessionsMu.Unlock()
manager.emmiter.Emit("created", session) manager.emmiter.Emit("created", session)
manager.save()
return session, token, nil return session, token, nil
} }
@ -118,6 +123,8 @@ func (manager *SessionManagerCtx) Update(id string, profile types.MemberProfile)
manager.sessionsMu.Unlock() manager.sessionsMu.Unlock()
manager.emmiter.Emit("profile_changed", session) manager.emmiter.Emit("profile_changed", session)
manager.save()
session.profileChanged() session.profileChanged()
return nil return nil
} }
@ -143,6 +150,8 @@ func (manager *SessionManagerCtx) Delete(id string) error {
} }
manager.emmiter.Emit("deleted", session) manager.emmiter.Emit("deleted", session)
manager.save()
return nil return nil
} }

View File

@ -0,0 +1,97 @@
package session
import (
"encoding/json"
"errors"
"os"
"github.com/demodesk/neko/pkg/types"
)
func (manager *SessionManagerCtx) save() {
if manager.config.File == "" {
return
}
// serialize sessions
sessions := make([]types.SessionProfile, 0, len(manager.sessions))
for _, session := range manager.sessions {
sessions = append(sessions, types.SessionProfile{
Id: session.id,
Token: session.token,
Profile: session.profile,
})
}
// convert to json
data, err := json.Marshal(sessions)
if err != nil {
manager.logger.Error().Err(err).Msg("failed to marshal sessions")
return
}
// write to file
err = os.WriteFile(manager.config.File, data, 0644)
if err != nil {
manager.logger.Error().Err(err).
Str("file", manager.config.File).
Msg("failed to write sessions to a file")
}
}
func (manager *SessionManagerCtx) load() {
if manager.config.File == "" {
return
}
// read file
data, err := os.ReadFile(manager.config.File)
if err != nil {
// if file does not exist
if errors.Is(err, os.ErrNotExist) {
manager.logger.Info().
Str("file", manager.config.File).
Msg("sessions file does not exist")
return
}
manager.logger.Error().Err(err).
Str("file", manager.config.File).
Msg("failed to read sessions from a file")
return
}
// if file is empty
if len(data) == 0 {
manager.logger.Info().
Str("file", manager.config.File).
Msg("sessions file is empty")
return
}
// deserialize sessions
sessions := make([]types.SessionProfile, 0)
err = json.Unmarshal(data, &sessions)
if err != nil {
manager.logger.Error().Err(err).Msg("failed to unmarshal sessions")
return
}
// create sessions
manager.sessionsMu.Lock()
for _, session := range sessions {
manager.tokens[session.Token] = session.Id
manager.sessions[session.Id] = &SessionCtx{
id: session.Id,
token: session.Token,
manager: manager,
logger: manager.logger.With().Str("session_id", session.Id).Logger(),
profile: session.Profile,
}
}
manager.sessionsMu.Unlock()
manager.logger.Info().
Int("sessions", len(sessions)).
Str("file", manager.config.File).
Msg("loaded sessions from a file")
}

View File

@ -17,6 +17,12 @@ type Cursor struct {
Y int `json:"y"` Y int `json:"y"`
} }
type SessionProfile struct {
Id string
Token string
Profile MemberProfile
}
type SessionState struct { type SessionState struct {
IsConnected bool `json:"is_connected"` IsConnected bool `json:"is_connected"`
IsWatching bool `json:"is_watching"` IsWatching bool `json:"is_watching"`