diff --git a/internal/webservice/plugins.go b/internal/webservice/plugins.go new file mode 100755 index 0000000..2085792 --- /dev/null +++ b/internal/webservice/plugins.go @@ -0,0 +1,87 @@ +/* + Copyright (c) 2020 AT&T. All Rights Reserved. + + 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 + + https://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 webservice + +import ( + "encoding/json" + "io/ioutil" + "log" + "os" + "path/filepath" + "time" +) + +// basic structure for a given external dashboard +// TODO: solidify the struct requirements for the input +type extPlugins struct { + ExtDashboard []interface{} `json:"external_dashboards"` +} + +// cache the file so we don't have to reread every execution +var pluginCache map[string]interface{} + +// getPlugins updates the pluginCache from file if needed +func getPlugins() map[string]interface{} { + if pluginCache == nil { + err := getPluginsFromFile() + if err != nil { + log.Printf("Error attempting to get plugins from file: %s\n", err) + } + } + return pluginCache +} + +// TODO: add watcher to the json file to reload conf on change +// Get dashboard links for Plugins if present in $HOME/.airshipui/plugins.json +func getPluginsFromFile() error { + var fileName string + home, err := os.UserHomeDir() + if err != nil { + log.Printf("Error determining the home directory %s\n", err) + } + + fileName = filepath.FromSlash(home + "/.airship/plugins.json") + + jsonFile, err := os.Open(fileName) + if err != nil { + return err + } + + defer jsonFile.Close() + + byteValue, err := ioutil.ReadAll(jsonFile) + + if err != nil { + return err + } + + var plugins extPlugins + err = json.Unmarshal(byteValue, &plugins) + + if err != nil { + return err + } + + log.Printf("Plugins found: %v\n", plugins) + + pluginCache = map[string]interface{}{ + "type": "plugins", + "component": "dropdown", + "timestamp": time.Now().UnixNano() / 1000000, + "plugins": plugins, + } + return err +} diff --git a/internal/webservice/server.go b/internal/webservice/server.go index 8c1cd0c..5f8e46e 100755 --- a/internal/webservice/server.go +++ b/internal/webservice/server.go @@ -19,23 +19,17 @@ import ( "fmt" "log" "net/http" + "time" "github.com/gorilla/websocket" ) // just a base structure to return from the web service -type Message struct { - ID int `json:"id,omitempty"` - Sender string `json:"sender"` - Message string `json:"message"` -} - type wsRequest struct { - ID string `json:"id,omitempty"` - Type string `json:"type,omitempty"` - Component string `json:"component,omitempty"` - Error string `json:"error"` - Data []map[string]string `json:"data"` + Type string `json:"type,omitempty"` + Component string `json:"component,omitempty"` + Error string `json:"error"` + Data map[string]interface{} `json:"data"` } // gorilla ws specific HTTP upgrade to WebSockets @@ -47,10 +41,13 @@ var upgrader = websocket.Upgrader{ // this is a way to allow for arbitrary messages to be processed by the backend // most likely we will need to have sub components register with the system // TODO: make this a dynamic registration of components -var functionMap = map[string]map[string]func() []map[string]string{ +var functionMap = map[string]map[string]func() map[string]interface{}{ "electron": { - "keepalive": basicReply, - "getID": basicReply, + "keepalive": keepaliveReply, + "getID": keepaliveReply, + }, + "initialize": { + "getAll": getPlugins, }, } @@ -92,8 +89,7 @@ func onMessage() { if reqType, ok := functionMap[request.Type]; ok { // the function map may have a component (function) to process the request if component, ok := reqType[request.Component]; ok { - request.Data = component() - if err = ws.WriteJSON(request); err != nil { + if err = ws.WriteJSON(component()); err != nil { onError(err) break } @@ -116,14 +112,14 @@ func onMessage() { } } -func basicReply() []map[string]string { - m := make([]map[string]string, 0) - m = append(m, map[string]string{ - "ID": "foo", - "type": "bar", - "component": "glitch", - }) - return m +// The keepalive response including a timestamp from the server +// The electron / web app will occasionally ping the server due to the websocket default timeout +func keepaliveReply() map[string]interface{} { + return map[string]interface{}{ + "type": "electron", + "component": "keepalive", + "timestamp": time.Now().UnixNano() / 1000000, + } } // common websocket close with logging diff --git a/web/index.html b/web/index.html index 6d1960b..97a0081 100755 --- a/web/index.html +++ b/web/index.html @@ -10,7 +10,6 @@ -
@@ -18,15 +17,14 @@ Airship UI