github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/tequilapi/endpoints/config.go (about) 1 /* 2 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package endpoints 19 20 import ( 21 "encoding/json" 22 "reflect" 23 24 "github.com/gin-gonic/gin" 25 "github.com/mysteriumnetwork/go-rest/apierror" 26 "github.com/mysteriumnetwork/node/tequilapi/contract" 27 28 "github.com/mysteriumnetwork/node/config" 29 "github.com/mysteriumnetwork/node/tequilapi/utils" 30 "github.com/rs/zerolog/log" 31 ) 32 33 type configProvider interface { 34 GetConfig() map[string]interface{} 35 GetDefaultConfig() map[string]interface{} 36 GetUserConfig() map[string]interface{} 37 SetUser(key string, value interface{}) 38 RemoveUser(key string) 39 SaveUserConfig() error 40 } 41 42 // swagger:model configPayload 43 type configPayload struct { 44 // example: {"data":{"access-policy":{"list":"mysterium"},"openvpn":{"port":5522}}} 45 Data map[string]interface{} `json:"data"` 46 } 47 48 type configAPI struct { 49 config configProvider 50 } 51 52 func newConfigAPI(config configProvider) *configAPI { 53 return &configAPI{config: config} 54 } 55 56 // GetConfig returns current configuration 57 // swagger:operation GET /config Configuration getConfig 58 // 59 // --- 60 // summary: Returns current configuration values 61 // description: Returns default configuration 62 // responses: 63 // 200: 64 // description: Currently active configuration 65 // schema: 66 // "$ref": "#/definitions/configPayload" 67 func (api *configAPI) GetConfig(c *gin.Context) { 68 res := configPayload{Data: api.config.GetConfig()} 69 utils.WriteAsJSON(res, c.Writer) 70 } 71 72 // GetDefaultConfig returns default configuration 73 // swagger:operation GET /config/default Configuration getDefaultConfig 74 // 75 // --- 76 // summary: Returns default configuration 77 // description: Returns default configuration 78 // responses: 79 // 200: 80 // description: Default configuration values 81 // schema: 82 // "$ref": "#/definitions/configPayload" 83 func (api *configAPI) GetDefaultConfig(c *gin.Context) { 84 res := configPayload{Data: api.config.GetDefaultConfig()} 85 utils.WriteAsJSON(res, c.Writer) 86 } 87 88 // GetUiFeatures returns config.ui.features value 89 // swagger:operation GET /config/ui/features 90 // 91 // --- 92 // summary: Returns returns config.ui.features value 93 // description: Returns returns config.ui.features value 94 // responses: 95 // 200: 96 // description: Default configuration values 97 // schema: 98 // type: string 99 func (api *configAPI) GetUiFeatures(c *gin.Context) { 100 res := "" 101 cfg := api.config.GetConfig() 102 ui, ok := cfg["ui"].((map[string]interface{})) 103 if ok { 104 res_, ok := ui["features"] 105 if ok { 106 res = res_.(string) 107 } 108 } 109 c.Writer.Write([]byte(res)) 110 } 111 112 // GetUserConfig returns current user configuration 113 // swagger:operation GET /config/user Configuration getUserConfig 114 // 115 // --- 116 // summary: Returns current user configuration 117 // description: Returns current user configuration 118 // responses: 119 // 200: 120 // description: User set configuration values 121 // schema: 122 // "$ref": "#/definitions/configPayload" 123 func (api *configAPI) GetUserConfig(c *gin.Context) { 124 res := configPayload{Data: api.config.GetUserConfig()} 125 utils.WriteAsJSON(res, c.Writer) 126 } 127 128 // SetUserConfig sets and returns current configuration 129 // swagger:operation POST /config/user Configuration serUserConfig 130 // 131 // --- 132 // summary: Sets and returns user configuration 133 // description: For keys present in the payload, it will set or remove the user config values (if the key is null). Changes are persisted to the config file. 134 // parameters: 135 // - in: body 136 // name: body 137 // description: configuration keys/values 138 // schema: 139 // $ref: "#/definitions/configPayload" 140 // responses: 141 // 200: 142 // description: User configuration 143 // schema: 144 // "$ref": "#/definitions/configPayload" 145 // 400: 146 // description: Failed to parse or request validation failed 147 // schema: 148 // "$ref": "#/definitions/APIError" 149 // 500: 150 // description: Internal server error 151 // schema: 152 // "$ref": "#/definitions/APIError" 153 func (api *configAPI) SetUserConfig(c *gin.Context) { 154 var req configPayload 155 err := json.NewDecoder(c.Request.Body).Decode(&req) 156 if err != nil { 157 c.Error(apierror.ParseFailed()) 158 return 159 } 160 for k, v := range req.Data { 161 if isNil(v) { 162 log.Debug().Msgf("Clearing user config value: %q", v) 163 api.config.RemoveUser(k) 164 } else { 165 log.Debug().Msgf("Setting user config value: %q = %q", k, v) 166 api.config.SetUser(k, v) 167 } 168 } 169 err = api.config.SaveUserConfig() 170 if err != nil { 171 c.Error(apierror.Internal("Failed to save config", contract.ErrCodeConfigSave)) 172 return 173 } 174 api.GetUserConfig(c) 175 } 176 177 func isNil(val interface{}) bool { 178 if val == nil { 179 return true 180 } 181 v := reflect.ValueOf(val) 182 if v.Kind() == reflect.Ptr && v.IsNil() { 183 return true 184 } 185 return false 186 } 187 188 // AddRoutesForConfig registers /config endpoints in Tequilapi 189 func AddRoutesForConfig( 190 e *gin.Engine, 191 ) error { 192 api := newConfigAPI(config.Current) 193 g := e.Group("/config") 194 { 195 g.GET("", api.GetConfig) 196 g.GET("/default", api.GetDefaultConfig) 197 g.GET("/user", api.GetUserConfig) 198 g.POST("/user", api.SetUserConfig) 199 g.GET("/ui/features", api.GetUiFeatures) 200 } 201 return nil 202 }