/* * Copyright (C) 2018 "IoT.bzh" * Author Sebastien Douheret * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package xdsserver import ( "fmt" "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1" "github.com/syncthing/syncthing/lib/sync" ) // Terminals Represent a XDS terminals type Terminals struct { *Context terms map[string]*ITERMINAL } // Mutex to make add/delete atomic var tmMutex = sync.NewMutex() // TerminalsConstructor Create a new instance of Model Terminal func TerminalsConstructor(ctx *Context) *Terminals { return &Terminals{ Context: ctx, terms: make(map[string]*ITERMINAL), } } // New Create a new terminal func (t *Terminals) New(cfg xsapiv1.TerminalConfig, targetID string) (*xsapiv1.TerminalConfig, error) { tmMutex.Lock() defer tmMutex.Unlock() var newT ITERMINAL // For now, only SSH term is supported switch cfg.Type { case xsapiv1.TypeTermSSH: newT = NewTermSSH(t.Context, cfg, targetID) default: return nil, fmt.Errorf("terminal type not set") } termCfg := newT.GetConfig() t.terms[termCfg.ID] = &newT termCfg.Status = xsapiv1.StatusTermEnable // Notify terminal add if err := t.events.Emit(xsapiv1.EVTTargetTerminalAdd, &termCfg, ""); err != nil { t.Log.Errorf("WS Emit EVTTargetTerminalAdd : %v", err) } return &termCfg, nil } // Free a specific terminal func (t *Terminals) Free(id string) (*xsapiv1.TerminalConfig, error) { tmMutex.Lock() defer tmMutex.Unlock() tc := t.Get(id) if tc == nil { return nil, fmt.Errorf("Unknown id") } if _, err := (*tc).Close(); err != nil { return nil, err } resTerm := (*tc).GetConfig() delete(t.terms, id) // Notify terminal state change or add if err := t.events.Emit(xsapiv1.EVTTargetTerminalRemove, &resTerm, ""); err != nil { t.Log.Errorf("WS Emit EVTTargetTerminalRemove : %v", err) } return &resTerm, nil } // Get returns the terminal config or nil if not existing func (t *Terminals) Get(id string) *ITERMINAL { if id == "" { return nil } tc, exist := t.terms[id] if !exist { return nil } return tc } // GetConfigArr returns the config of all terminals as an array func (t *Terminals) GetConfigArr() []xsapiv1.TerminalConfig { tmMutex.Lock() defer tmMutex.Unlock() return t.getConfigArrUnsafe() } // getConfigArrUnsafe Same as GetConfigArr without mutex protection func (t *Terminals) getConfigArrUnsafe() []xsapiv1.TerminalConfig { conf := []xsapiv1.TerminalConfig{} for _, v := range t.terms { conf = append(conf, (*v).GetConfig()) } return conf } // Open adds a new terminal func (t *Terminals) Open(id string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) { tc := t.Get(id) if tc == nil { return nil, fmt.Errorf("Unknown id") } if sess.IOSocket == nil { return nil, fmt.Errorf("Websocket not established") } term, err := (*tc).Open(sess.IOSocket, sess.ID) // Notify term state change if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil { t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit) } return term, err } // Close a specific terminal func (t *Terminals) Close(id string, sess *ClientSession) (*xsapiv1.TerminalConfig, error) { tc := t.Get(id) if tc == nil { return nil, fmt.Errorf("Unknown id") } term, err := (*tc).Close() // Notify term state change if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil { t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit) } return term, err } // Resize a specific terminal func (t *Terminals) Resize(id string, cols, rows uint16, sess *ClientSession) (*xsapiv1.TerminalConfig, error) { tmMutex.Lock() defer tmMutex.Unlock() tc := t.Get(id) if tc == nil { return nil, fmt.Errorf("Unknown id") } term, err := (*tc).Resize(cols, rows) // Notify term state change if errEmit := t.events.Emit(xsapiv1.EVTTargetTerminalStateChange, &term, sess.ID); errEmit != nil { t.Log.Errorf("WS Emit EVTTargetTerminalStateChange : %v", errEmit) } return term, err } // Signal Send a Signal a specific terminal func (t *Terminals) Signal(id, sigName string) error { tmMutex.Lock() defer tmMutex.Unlock() tc := t.Get(id) if tc == nil { return fmt.Errorf("Unknown id") } return (*tc).Signal(sigName) }