github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/tequilapi/endpoints/ui.go (about)

     1  /*
     2   * Copyright (C) 2021 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  	"fmt"
    22  	"net/http"
    23  	"strconv"
    24  
    25  	"github.com/gin-gonic/gin"
    26  	"github.com/mysteriumnetwork/go-rest/apierror"
    27  	"github.com/mysteriumnetwork/node/tequilapi/contract"
    28  	"github.com/mysteriumnetwork/node/ui/versionmanager"
    29  )
    30  
    31  // NodeUIEndpoints node ui version management endpoints
    32  type NodeUIEndpoints struct {
    33  	versionManager *versionmanager.VersionManager
    34  }
    35  
    36  // NewNodeUIEndpoints constructor
    37  func NewNodeUIEndpoints(versionManager *versionmanager.VersionManager) *NodeUIEndpoints {
    38  	return &NodeUIEndpoints{
    39  		versionManager: versionManager,
    40  	}
    41  }
    42  
    43  // RemoteVersions list node UI releases from repo
    44  // swagger:operation GET /ui/remote-versions UI uiRemoteVersions
    45  //
    46  //	---
    47  //	summary: List local
    48  //	description: provides a list of node UI releases from github repository
    49  //	responses:
    50  //	  200:
    51  //	    description: Remote version list
    52  //	    schema:
    53  //	      "$ref": "#/definitions/RemoteVersionsResponse"
    54  //	  500:
    55  //	    description: Internal server error
    56  //	    schema:
    57  //	      "$ref": "#/definitions/APIError"
    58  func (n *NodeUIEndpoints) RemoteVersions(c *gin.Context) {
    59  	r := versionmanager.RemoteVersionRequest{
    60  		PerPage: 50,
    61  	}
    62  
    63  	if b, err := strconv.ParseBool(c.Query("flush_cache")); err == nil {
    64  		r.FlushCache = b
    65  	}
    66  
    67  	if pp, err := strconv.ParseInt(c.Query("per_page"), 10, 32); err == nil {
    68  		r.PerPage = int(pp)
    69  	}
    70  
    71  	if p, err := strconv.ParseInt(c.Query("page"), 10, 32); err == nil {
    72  		r.Page = int(p)
    73  	}
    74  
    75  	versions, err := n.versionManager.ListRemoteVersions(r)
    76  	if err != nil {
    77  		c.Error(err)
    78  		return
    79  	}
    80  	c.JSON(http.StatusOK, contract.RemoteVersionsResponse{Versions: versions})
    81  }
    82  
    83  // LocalVersions locally available node UI versions
    84  // swagger:operation GET /ui/local-versions UI uiLocalVersions
    85  //
    86  //	---
    87  //	summary: List remote
    88  //	description: provides a list of node UI releases that have been downloaded or bundled with node
    89  //	responses:
    90  //	  200:
    91  //	    description: Local version list
    92  //	    schema:
    93  //	      "$ref": "#/definitions/LocalVersionsResponse"
    94  //	  500:
    95  //	    description: Internal server error
    96  //	    schema:
    97  //	      "$ref": "#/definitions/APIError"
    98  func (n *NodeUIEndpoints) LocalVersions(c *gin.Context) {
    99  	versions, err := n.versionManager.ListLocalVersions()
   100  	if err != nil {
   101  		c.Error(apierror.Internal("Could not list local versions: "+err.Error(), contract.ErrCodeUILocalVersions))
   102  		return
   103  	}
   104  	c.JSON(http.StatusOK, contract.LocalVersionsResponse{Versions: versions})
   105  }
   106  
   107  // SwitchVersion switches node UI version to locally available one
   108  // swagger:operation POST /ui/switch-version UI uiSwitchVersion
   109  //
   110  //	---
   111  //	summary: Switch Version
   112  //	description: switch node UI version to locally available one
   113  //	responses:
   114  //	  200:
   115  //	    description: version switched
   116  //	  400:
   117  //	    description: Failed to parse or request validation failed
   118  //	    schema:
   119  //	      "$ref": "#/definitions/APIError"
   120  //	  422:
   121  //	    description: Unable to process the request at this point
   122  //	    schema:
   123  //	      "$ref": "#/definitions/APIError"
   124  //	  500:
   125  //	    description: Internal server error
   126  //	    schema:
   127  //	      "$ref": "#/definitions/APIError"
   128  func (n *NodeUIEndpoints) SwitchVersion(c *gin.Context) {
   129  	var req contract.SwitchNodeUIRequest
   130  	if err := c.ShouldBindJSON(&req); err != nil {
   131  		c.Error(apierror.ParseFailed())
   132  		return
   133  	}
   134  
   135  	if err := req.Valid(); err != nil {
   136  		c.Error(err)
   137  		return
   138  	}
   139  
   140  	if err := n.versionManager.SwitchTo(req.Version); err != nil {
   141  		c.Error(apierror.Unprocessable(fmt.Sprintf("Could not switch to node UI version: %s", req.Version), contract.ErrCodeUISwitchVersion))
   142  		return
   143  	}
   144  
   145  	c.AbortWithStatus(http.StatusOK)
   146  }
   147  
   148  // Download download a remote node UI release
   149  // swagger:operation POST /ui/download-version UI uiDownload
   150  //
   151  //	---
   152  //	summary: Download
   153  //	description: download a remote node UI release
   154  //	responses:
   155  //	  200:
   156  //	    description: Download in progress
   157  //	  400:
   158  //	    description: Failed to parse or request validation failed
   159  //	    schema:
   160  //	      "$ref": "#/definitions/APIError"
   161  //	  500:
   162  //	    description: Internal server error
   163  //	    schema:
   164  //	      "$ref": "#/definitions/APIError"
   165  func (n *NodeUIEndpoints) Download(c *gin.Context) {
   166  	var req contract.DownloadNodeUIRequest
   167  	if err := c.ShouldBindJSON(&req); err != nil {
   168  		c.Error(apierror.ParseFailed())
   169  		return
   170  	}
   171  
   172  	if err := req.Valid(); err != nil {
   173  		c.Error(err)
   174  		return
   175  	}
   176  
   177  	if err := n.versionManager.Download(req.Version); err != nil {
   178  		c.Error(apierror.Internal(fmt.Sprintf("Could not download node UI version: %s", req.Version), contract.ErrCodeUIDownload))
   179  		return
   180  	}
   181  
   182  	c.AbortWithStatus(http.StatusOK)
   183  }
   184  
   185  // DownloadStatus returns download status
   186  // swagger:operation GET /ui/download-status UI uiDownloadStatus
   187  //
   188  //	---
   189  //	summary: Download status
   190  //	description: DownloadStatus can download one remote release at a time. This endpoint provides status of the download.
   191  //	responses:
   192  //	  200:
   193  //	    description: download status
   194  //	    schema:
   195  //	      "$ref": "#/definitions/DownloadStatus"
   196  //	  500:
   197  //	    description: Internal server error
   198  //	    schema:
   199  //	      "$ref": "#/definitions/APIError"
   200  func (n *NodeUIEndpoints) DownloadStatus(c *gin.Context) {
   201  	c.JSON(http.StatusOK, n.versionManager.DownloadStatus())
   202  }
   203  
   204  // UI returns download status
   205  // swagger:operation GET /ui/info UI ui
   206  //
   207  //	---
   208  //	summary: Node UI information
   209  //	description: Node UI information
   210  //	responses:
   211  //	  200:
   212  //	    description: Node UI information
   213  //	    schema:
   214  //	      "$ref": "#/definitions/UI"
   215  //	  500:
   216  //	    description: Internal server error
   217  //	    schema:
   218  //	      "$ref": "#/definitions/APIError"
   219  func (n *NodeUIEndpoints) UI(c *gin.Context) {
   220  	bundled, err := n.versionManager.BundledVersion()
   221  	if err != nil {
   222  		c.Error(apierror.Internal("Could not resolve bundled version: "+err.Error(), contract.ErrCodeUIBundledVersion))
   223  		return
   224  	}
   225  
   226  	used, err := n.versionManager.UsedVersion()
   227  	if err != nil {
   228  		c.Error(apierror.Internal("Could not resolve used version: "+err.Error(), contract.ErrCodeUIUsedVersion))
   229  		return
   230  	}
   231  	c.JSON(http.StatusOK, contract.UI{
   232  		BundledVersion: bundled.Name,
   233  		UsedVersion:    used.Name,
   234  	})
   235  }
   236  
   237  // AddRoutesForNodeUI provides controls for nodeUI management via tequilapi
   238  func AddRoutesForNodeUI(versionManager *versionmanager.VersionManager) func(*gin.Engine) error {
   239  	endpoints := NewNodeUIEndpoints(versionManager)
   240  
   241  	return func(e *gin.Engine) error {
   242  		v1Group := e.Group("/ui")
   243  		{
   244  			v1Group.GET("/info", endpoints.UI)
   245  			v1Group.GET("/local-versions", endpoints.LocalVersions)
   246  			v1Group.GET("/remote-versions", endpoints.RemoteVersions)
   247  			v1Group.POST("/switch-version", endpoints.SwitchVersion)
   248  			v1Group.POST("/download-version", endpoints.Download)
   249  			v1Group.GET("/download-status", endpoints.DownloadStatus)
   250  		}
   251  		return nil
   252  	}
   253  }