| package storage | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "os" | |
| "sync" | |
| "github.com/play-with-docker/play-with-docker/pwd/types" | |
| ) | |
| type storage struct { | |
| rw sync.Mutex | |
| path string | |
| db *DB | |
| } | |
| type DB struct { | |
| Sessions map[string]*types.Session `json:"sessions"` | |
| Instances map[string]*types.Instance `json:"instances"` | |
| Clients map[string]*types.Client `json:"clients"` | |
| WindowsInstances map[string]*types.WindowsInstance `json:"windows_instances"` | |
| LoginRequests map[string]*types.LoginRequest `json:"login_requests"` | |
| Users map[string]*types.User `json:"user"` | |
| Playgrounds map[string]*types.Playground `json:"playgrounds"` | |
| WindowsInstancesBySessionId map[string][]string `json:"windows_instances_by_session_id"` | |
| InstancesBySessionId map[string][]string `json:"instances_by_session_id"` | |
| ClientsBySessionId map[string][]string `json:"clients_by_session_id"` | |
| UsersByProvider map[string]string `json:"users_by_providers"` | |
| } | |
| func (store *storage) SessionGet(id string) (*types.Session, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| s, found := store.db.Sessions[id] | |
| if !found { | |
| return nil, NotFoundError | |
| } | |
| return s, nil | |
| } | |
| func (store *storage) SessionGetAll() ([]*types.Session, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| sessions := make([]*types.Session, len(store.db.Sessions)) | |
| i := 0 | |
| for _, s := range store.db.Sessions { | |
| sessions[i] = s | |
| i++ | |
| } | |
| return sessions, nil | |
| } | |
| func (store *storage) SessionPut(session *types.Session) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| store.db.Sessions[session.Id] = session | |
| return store.save() | |
| } | |
| func (store *storage) SessionDelete(id string) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| _, found := store.db.Sessions[id] | |
| if !found { | |
| return nil | |
| } | |
| for _, i := range store.db.WindowsInstancesBySessionId[id] { | |
| delete(store.db.WindowsInstances, i) | |
| } | |
| store.db.WindowsInstancesBySessionId[id] = []string{} | |
| for _, i := range store.db.InstancesBySessionId[id] { | |
| delete(store.db.Instances, i) | |
| } | |
| store.db.InstancesBySessionId[id] = []string{} | |
| for _, i := range store.db.ClientsBySessionId[id] { | |
| delete(store.db.Clients, i) | |
| } | |
| store.db.ClientsBySessionId[id] = []string{} | |
| delete(store.db.Sessions, id) | |
| return store.save() | |
| } | |
| func (store *storage) SessionCount() (int, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| return len(store.db.Sessions), nil | |
| } | |
| func (store *storage) InstanceGet(name string) (*types.Instance, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| i := store.db.Instances[name] | |
| if i == nil { | |
| return nil, NotFoundError | |
| } | |
| return i, nil | |
| } | |
| func (store *storage) InstancePut(instance *types.Instance) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| _, found := store.db.Sessions[string(instance.SessionId)] | |
| if !found { | |
| return NotFoundError | |
| } | |
| store.db.Instances[instance.Name] = instance | |
| found = false | |
| for _, i := range store.db.InstancesBySessionId[string(instance.SessionId)] { | |
| if i == instance.Name { | |
| found = true | |
| break | |
| } | |
| } | |
| if !found { | |
| store.db.InstancesBySessionId[string(instance.SessionId)] = append(store.db.InstancesBySessionId[string(instance.SessionId)], instance.Name) | |
| } | |
| return store.save() | |
| } | |
| func (store *storage) InstanceDelete(name string) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| instance, found := store.db.Instances[name] | |
| if !found { | |
| return nil | |
| } | |
| instances := store.db.InstancesBySessionId[string(instance.SessionId)] | |
| for n, i := range instances { | |
| if i == name { | |
| instances = append(instances[:n], instances[n+1:]...) | |
| break | |
| } | |
| } | |
| store.db.InstancesBySessionId[string(instance.SessionId)] = instances | |
| delete(store.db.Instances, name) | |
| return store.save() | |
| } | |
| func (store *storage) InstanceCount() (int, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| return len(store.db.Instances), nil | |
| } | |
| func (store *storage) InstanceFindBySessionId(sessionId string) ([]*types.Instance, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| instanceIds := store.db.InstancesBySessionId[sessionId] | |
| instances := make([]*types.Instance, len(instanceIds)) | |
| for i, id := range instanceIds { | |
| instances[i] = store.db.Instances[id] | |
| } | |
| return instances, nil | |
| } | |
| func (store *storage) WindowsInstanceGetAll() ([]*types.WindowsInstance, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| instances := []*types.WindowsInstance{} | |
| for _, s := range store.db.WindowsInstances { | |
| instances = append(instances, s) | |
| } | |
| return instances, nil | |
| } | |
| func (store *storage) WindowsInstancePut(instance *types.WindowsInstance) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| _, found := store.db.Sessions[string(instance.SessionId)] | |
| if !found { | |
| return NotFoundError | |
| } | |
| store.db.WindowsInstances[instance.Id] = instance | |
| found = false | |
| for _, i := range store.db.WindowsInstancesBySessionId[string(instance.SessionId)] { | |
| if i == instance.Id { | |
| found = true | |
| break | |
| } | |
| } | |
| if !found { | |
| store.db.WindowsInstancesBySessionId[string(instance.SessionId)] = append(store.db.WindowsInstancesBySessionId[string(instance.SessionId)], instance.Id) | |
| } | |
| return store.save() | |
| } | |
| func (store *storage) WindowsInstanceDelete(id string) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| instance, found := store.db.WindowsInstances[id] | |
| if !found { | |
| return nil | |
| } | |
| instances := store.db.WindowsInstancesBySessionId[string(instance.SessionId)] | |
| for n, i := range instances { | |
| if i == id { | |
| instances = append(instances[:n], instances[n+1:]...) | |
| break | |
| } | |
| } | |
| store.db.WindowsInstancesBySessionId[string(instance.SessionId)] = instances | |
| delete(store.db.WindowsInstances, id) | |
| return store.save() | |
| } | |
| func (store *storage) ClientGet(id string) (*types.Client, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| i := store.db.Clients[id] | |
| if i == nil { | |
| return nil, NotFoundError | |
| } | |
| return i, nil | |
| } | |
| func (store *storage) ClientPut(client *types.Client) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| _, found := store.db.Sessions[string(client.SessionId)] | |
| if !found { | |
| return NotFoundError | |
| } | |
| store.db.Clients[client.Id] = client | |
| found = false | |
| for _, i := range store.db.ClientsBySessionId[string(client.SessionId)] { | |
| if i == client.Id { | |
| found = true | |
| break | |
| } | |
| } | |
| if !found { | |
| store.db.ClientsBySessionId[string(client.SessionId)] = append(store.db.ClientsBySessionId[string(client.SessionId)], client.Id) | |
| } | |
| return store.save() | |
| } | |
| func (store *storage) ClientDelete(id string) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| client, found := store.db.Clients[id] | |
| if !found { | |
| return nil | |
| } | |
| clients := store.db.ClientsBySessionId[string(client.SessionId)] | |
| for n, i := range clients { | |
| if i == client.Id { | |
| clients = append(clients[:n], clients[n+1:]...) | |
| break | |
| } | |
| } | |
| store.db.ClientsBySessionId[string(client.SessionId)] = clients | |
| delete(store.db.Clients, id) | |
| return store.save() | |
| } | |
| func (store *storage) ClientCount() (int, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| return len(store.db.Clients), nil | |
| } | |
| func (store *storage) ClientFindBySessionId(sessionId string) ([]*types.Client, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| clientIds := store.db.ClientsBySessionId[sessionId] | |
| clients := make([]*types.Client, len(clientIds)) | |
| for i, id := range clientIds { | |
| clients[i] = store.db.Clients[id] | |
| } | |
| return clients, nil | |
| } | |
| func (store *storage) LoginRequestPut(loginRequest *types.LoginRequest) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| store.db.LoginRequests[loginRequest.Id] = loginRequest | |
| return nil | |
| } | |
| func (store *storage) LoginRequestGet(id string) (*types.LoginRequest, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| if lr, found := store.db.LoginRequests[id]; !found { | |
| return nil, NotFoundError | |
| } else { | |
| return lr, nil | |
| } | |
| } | |
| func (store *storage) LoginRequestDelete(id string) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| delete(store.db.LoginRequests, id) | |
| return nil | |
| } | |
| func (store *storage) UserFindByProvider(providerName, providerUserId string) (*types.User, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| if userId, found := store.db.UsersByProvider[fmt.Sprintf("%s_%s", providerName, providerUserId)]; !found { | |
| return nil, NotFoundError | |
| } else { | |
| if user, found := store.db.Users[userId]; !found { | |
| return nil, NotFoundError | |
| } else { | |
| return user, nil | |
| } | |
| } | |
| } | |
| func (store *storage) UserPut(user *types.User) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| store.db.UsersByProvider[fmt.Sprintf("%s_%s", user.Provider, user.ProviderUserId)] = user.Id | |
| store.db.Users[user.Id] = user | |
| return store.save() | |
| } | |
| func (store *storage) UserGet(id string) (*types.User, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| if user, found := store.db.Users[id]; !found { | |
| return nil, NotFoundError | |
| } else { | |
| return user, nil | |
| } | |
| } | |
| func (store *storage) PlaygroundPut(playground *types.Playground) error { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| store.db.Playgrounds[playground.Id] = playground | |
| return store.save() | |
| } | |
| func (store *storage) PlaygroundGet(id string) (*types.Playground, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| playground, found := store.db.Playgrounds[id] | |
| if !found { | |
| return nil, NotFoundError | |
| } | |
| return playground, nil | |
| } | |
| func (store *storage) load() error { | |
| file, err := os.Open(store.path) | |
| if err == nil { | |
| decoder := json.NewDecoder(file) | |
| err = decoder.Decode(&store.db) | |
| if err != nil { | |
| return err | |
| } | |
| } else { | |
| store.db = &DB{ | |
| Sessions: map[string]*types.Session{}, | |
| Instances: map[string]*types.Instance{}, | |
| Clients: map[string]*types.Client{}, | |
| WindowsInstances: map[string]*types.WindowsInstance{}, | |
| LoginRequests: map[string]*types.LoginRequest{}, | |
| Users: map[string]*types.User{}, | |
| Playgrounds: map[string]*types.Playground{}, | |
| WindowsInstancesBySessionId: map[string][]string{}, | |
| InstancesBySessionId: map[string][]string{}, | |
| ClientsBySessionId: map[string][]string{}, | |
| UsersByProvider: map[string]string{}, | |
| } | |
| } | |
| file.Close() | |
| return nil | |
| } | |
| func (store *storage) PlaygroundGetAll() ([]*types.Playground, error) { | |
| store.rw.Lock() | |
| defer store.rw.Unlock() | |
| playgrounds := make([]*types.Playground, len(store.db.Playgrounds)) | |
| i := 0 | |
| for _, p := range store.db.Playgrounds { | |
| playgrounds[i] = p | |
| i++ | |
| } | |
| return playgrounds, nil | |
| } | |
| func (store *storage) save() error { | |
| file, err := os.Create(store.path) | |
| if err != nil { | |
| return err | |
| } | |
| defer file.Close() | |
| encoder := json.NewEncoder(file) | |
| err = encoder.Encode(&store.db) | |
| return err | |
| } | |
| func NewFileStorage(path string) (StorageApi, error) { | |
| s := &storage{path: path} | |
| err := s.load() | |
| if err != nil { | |
| return nil, err | |
| } | |
| return s, nil | |
| } | |