Skip to content

Commit cc71499

Browse files
authored
Plugin registry github and Smart contract management (#14)
* Update plugin handling and enhance file input functionality - Added validation for existing plugins during updates to ensure they exist before proceeding, improving error handling and user feedback. - Preserved deployment status when updating plugins to maintain consistency in their configurations. - Introduced a new `FileValue` struct for handling file-based x-source values, including validation and volume mount configurations. - Enhanced the `DeploymentModal` to support file input, allowing users to upload or paste file contents directly, improving usability. - Updated Swagger documentation to reflect changes in API endpoints and request structures. These changes enhance the overall functionality and user experience when managing plugins and file inputs within the application. * Add metrics management commands and enhance API functionality - Introduced new commands for enabling and disabling Prometheus metrics, allowing users to manage metrics deployment directly from the CLI. - Implemented HTTP handlers for the new metrics commands, ensuring proper request handling and response formatting. - Enhanced the metrics service layer to support the new commands, including validation and error handling for metrics operations. - Updated Swagger documentation to reflect the new API endpoints and their functionalities, improving usability for developers. These changes enhance the overall functionality of the application by providing users with better tools for managing metrics and Prometheus integration. * Update Swagger documentation and enhance response models for metrics API - Updated Swagger documentation to reflect new response structures for metrics-related endpoints, ensuring accurate descriptions and references. - Introduced new response models: `MessageResponse`, `LabelValuesResponse`, and `MetricsDataResponse` to standardize API responses across metrics endpoints. - Enhanced error handling and response formatting in the metrics handler methods to utilize the new structured response models, improving consistency and clarity. These changes improve the overall usability and maintainability of the metrics API, providing clearer and more structured responses for users. * Enhance application structure and add smart contract deployment functionality - Updated `.gitignore` to include logs and environment-specific files, improving project cleanliness. - Modified `go.mod` and `go.sum` to add new dependencies for smart contract deployment and plugin management, ensuring compatibility with the latest features. - Implemented a new `chainlaunchdeploy` package for handling smart contract deployments on EVM and Fabric networks, including validation and error handling. - Introduced HTTP handlers for smart contract deployment requests, enhancing the API with new endpoints for Besu and Fabric deployments. - Updated Swagger documentation to reflect the new deployment endpoints and their request/response structures, improving API usability. These changes enhance the overall functionality of the application by providing robust support for smart contract deployments and improving project organization. * Update * Refactor Fabric chaincode routes and enhance peer handling - Updated HTTP routes for Fabric chaincode operations to include peer ID in the URL, improving clarity and specificity in API requests. - Introduced new stub functions for peer lookup and conversion to gateway, laying the groundwork for future implementation. - Enhanced error handling in chaincode installation, approval, and commit methods to ensure robust validation and logging for peer-related operations. These changes improve the overall structure and error management of the Fabric chaincode handling, ensuring better API usability and maintainability. * Update plugin registry configuration and enhance GitHub source handling - Changed the plugin registry source name from "github-public-plugins" to "plugin-hlf-api" for better clarity. - Updated the URL for the GitHub source to point to the correct repository. - Refined the file filtering logic in the GitHub source to only consider "plugin.yaml" or "plugin.yml" files, improving accuracy in plugin metadata retrieval. - Enhanced the PluginMetadata structure to include additional fields such as Tags, Author, License, Hash, Rating, Downloads, Created, Updated, and Labels for better plugin information representation. These changes improve the plugin management functionality and ensure more accurate handling of plugin metadata. * Update API documentation and enhance plugin management functionality - Updated Swagger and YAML documentation to reflect changes in Fabric chaincode operations, including new endpoints for deploying and approving chaincode with peer ID in the URL. - Enhanced the PluginMetadata structure to include a new field for raw YAML, improving the representation of plugin data. - Introduced new API methods for managing available plugins, including installation and refreshing of plugin lists, enhancing user experience in the plugins page. These changes improve the overall usability and maintainability of the API and plugin management features, ensuring better clarity and functionality for users. * Enhance API documentation and introduce new tags for improved clarity - Updated Swagger documentation to include new tags for Audit and Metrics management operations, enhancing the organization and discoverability of API endpoints. - Modified existing handler methods to reflect the new tag names, ensuring consistency across the codebase. - Improved the structure of the Fabric chaincode deployment handler to include a node service, facilitating better peer management during operations. These changes enhance the overall usability and maintainability of the API, providing clearer documentation and improved functionality for users. * Update it * Enhance Fabric chaincode deployment functionality and API documentation - Introduced new endpoints for listing deployed Fabric chaincodes and deploying chaincodes using Docker images, improving the API's capabilities for managing smart contracts. - Updated the HTTP handler to include a new ChaincodeService for better separation of concerns and improved business logic handling. - Enhanced Swagger documentation to reflect the new endpoints and their request/response structures, ensuring clarity and usability for developers. - Implemented database operations for managing Fabric chaincodes, including insertion and updates, to support the new functionalities. These changes significantly improve the overall functionality and maintainability of the application, providing users with better tools for managing Fabric chaincodes. * Update Fabric chaincode API documentation and enhance deployment features - Improved Swagger documentation for Fabric chaincode endpoints, including detailed descriptions and response models for listing and retrieving chaincodes, ensuring clarity for developers. - Enhanced the API to support new functionalities for managing Fabric chaincodes, including detailed runtime information and Docker deployment options. - Updated HTTP handlers to reflect changes in the service layer, ensuring better separation of concerns and improved error handling. - Implemented new database operations for managing chaincode definitions and peer statuses, enhancing the overall functionality of the application. These updates significantly improve the usability and maintainability of the Fabric chaincode management features, providing users with better tools for deployment and monitoring. * Enhance ChaincodeService with logging and new functionalities - Updated ChaincodeService to include a logger for improved debugging and error tracking. - Modified the NewChaincodeService constructor to accept a logger parameter, ensuring better logging practices. - Implemented new methods for generating connection packages and handling code tar.gz files, enhancing the deployment process for chaincodes. - Improved error handling and logging throughout the service methods, ensuring robust operation and easier troubleshooting. These changes significantly enhance the functionality and maintainability of the ChaincodeService, providing better tools for managing chaincode deployments. * Refactor Fabric chaincode management and enhance API functionality - Updated the ChaincodeService to include a nodesService for improved peer management during chaincode operations. - Modified HTTP handlers to reflect changes in the service layer, ensuring better separation of concerns and improved error handling. - Enhanced Swagger documentation for Fabric chaincode endpoints, including updated descriptions and response models for better clarity. - Implemented new database operations for managing chaincode definitions and events, enhancing the overall functionality of the application. These updates significantly improve the usability and maintainability of the Fabric chaincode management features, providing users with better tools for deployment and monitoring. * Refactor FabricChaincodesPage to improve query handling and state management - Removed unused queryClient and replaced it with refetch functions for better control over data fetching. - Updated the useQuery hooks to include refetch capabilities for networks and chaincodes, enhancing the responsiveness of the component. - Improved the success handling of chaincode creation to directly refetch chaincodes instead of invalidating queries, streamlining the data update process. These changes enhance the performance and maintainability of the FabricChaincodesPage, providing a more efficient user experience. * update * Refactor DefinitionTimeline component for improved readability and performance - Simplified the useQuery hook for fetching timeline data by removing unnecessary line breaks. - Streamlined conditional rendering for result icons and button components to enhance code clarity. - Utilized useMemo for filtering available peers, optimizing performance during re-renders. - Consolidated error message rendering for better consistency across the component. These changes enhance the maintainability and performance of the DefinitionTimeline component, providing a more efficient user experience. * Update * Enhance Docker image pull handling in metrics and Besu node management - Updated the Prometheus and Besu Docker handlers to read and log the image pull response, improving visibility during the image pull process. - Implemented error handling for the image pull response reading, ensuring robust operation and easier troubleshooting. These changes enhance the reliability and maintainability of the Docker image management features in the application. * Refactor log handling in Node HTTP and React components - Updated the TailLogs handler to format log messages correctly for SSE by adding "data: " prefix. - Replaced the fetch-based log retrieval in NodeDetailPage and NodesLogsPage with EventSource for real-time log streaming, improving performance and user experience. - Implemented error handling for EventSource connections and ensured proper cleanup on component unmount. These changes enhance the log streaming functionality, providing a more efficient and responsive user experience in the application.
1 parent 9a98269 commit cc71499

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+32289
-7598
lines changed

.gitignore

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,31 @@ certs
1111
test-instance
1212
*.db
1313
decode_extradata
14-
.artifacts
14+
.artifacts
15+
.cursor
16+
17+
# Added by Claude Task Master
18+
# Logs
19+
logs
20+
*.log
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
dev-debug.log
25+
# Dependency directories
26+
node_modules/
27+
# Environment variables
28+
# Editor directories and files
29+
.vscode
30+
*.suo
31+
*.ntvs*
32+
*.njsproj
33+
*.sln
34+
*.sw?
35+
# OS specific
36+
# Task files
37+
tasks.json
38+
tasks/
39+
.roo
40+
.taskmasterconfig
41+
scripts

cmd/common/client.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ func (c *Client) DoRequest(method, path string, body interface{}) (*http.Respons
5555
}
5656
reqBody = bytes.NewBuffer(jsonBody)
5757
}
58-
5958
// Create HTTP request
6059
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", c.baseURL, path), reqBody)
6160
if err != nil {

cmd/common/metrics.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package common
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
8+
metricscommon "github.com/chainlaunch/chainlaunch/pkg/metrics/common"
9+
metricstypes "github.com/chainlaunch/chainlaunch/pkg/metrics/types"
10+
)
11+
12+
// EnableMetrics deploys Prometheus using the provided parameters
13+
func (c *Client) EnableMetrics(req *metricscommon.Config) (map[string]string, error) {
14+
// Convert common.Config to the HTTP request struct expected by the API
15+
httpReq := metricstypes.DeployPrometheusRequest{
16+
PrometheusVersion: req.PrometheusVersion,
17+
PrometheusPort: req.PrometheusPort,
18+
ScrapeInterval: int(req.ScrapeInterval.Seconds()),
19+
}
20+
resp, err := c.Post("/metrics/deploy", httpReq)
21+
if err != nil {
22+
return nil, fmt.Errorf("failed to call /metrics/deploy: %w", err)
23+
}
24+
defer resp.Body.Close()
25+
if resp.StatusCode != http.StatusOK {
26+
var errResp map[string]interface{}
27+
json.NewDecoder(resp.Body).Decode(&errResp)
28+
return nil, fmt.Errorf("unexpected status %d: %v", resp.StatusCode, errResp)
29+
}
30+
var result map[string]string
31+
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
32+
return nil, fmt.Errorf("failed to decode response: %w", err)
33+
}
34+
return result, nil
35+
}
36+
37+
// DisableMetrics undeploys Prometheus
38+
func (c *Client) DisableMetrics() (map[string]string, error) {
39+
resp, err := c.Post("/metrics/undeploy", nil)
40+
if err != nil {
41+
return nil, fmt.Errorf("failed to call /metrics/undeploy: %w", err)
42+
}
43+
defer resp.Body.Close()
44+
if resp.StatusCode != http.StatusOK {
45+
var errResp map[string]interface{}
46+
json.NewDecoder(resp.Body).Decode(&errResp)
47+
return nil, fmt.Errorf("unexpected status %d: %v", resp.StatusCode, errResp)
48+
}
49+
var result map[string]string
50+
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
51+
return nil, fmt.Errorf("failed to decode response: %w", err)
52+
}
53+
return result, nil
54+
}
55+
56+
// GetMetricsStatus returns the current status of the Prometheus instance
57+
func (c *Client) GetMetricsStatus() (*metricscommon.Status, error) {
58+
resp, err := c.Get("/metrics/status")
59+
if err != nil {
60+
return nil, fmt.Errorf("failed to call /metrics/status: %w", err)
61+
}
62+
defer resp.Body.Close()
63+
if resp.StatusCode != http.StatusOK {
64+
var errResp map[string]interface{}
65+
json.NewDecoder(resp.Body).Decode(&errResp)
66+
return nil, fmt.Errorf("unexpected status %d: %v", resp.StatusCode, errResp)
67+
}
68+
var status metricscommon.Status
69+
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
70+
return nil, fmt.Errorf("failed to decode response: %w", err)
71+
}
72+
return &status, nil
73+
}

cmd/metrics/disable.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package metrics
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/chainlaunch/chainlaunch/cmd/common"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// DisableMetricsRunner encapsulates the logic for disabling metrics
11+
type DisableMetricsRunner struct{}
12+
13+
func (r *DisableMetricsRunner) Run() error {
14+
client, err := common.NewClientFromEnv()
15+
if err != nil {
16+
return err
17+
}
18+
status, err := client.GetMetricsStatus()
19+
if err != nil {
20+
return fmt.Errorf("could not get metrics status: %w", err)
21+
}
22+
if status.Status != "running" {
23+
return fmt.Errorf("Prometheus is not running (status: %s)", status.Status)
24+
}
25+
resp, err := client.DisableMetrics()
26+
if err != nil {
27+
return err
28+
}
29+
fmt.Printf("Prometheus undeployed: %v\n", resp)
30+
return nil
31+
}
32+
33+
func NewDisableCmd() *cobra.Command {
34+
runner := &DisableMetricsRunner{}
35+
cmd := &cobra.Command{
36+
Use: "disable",
37+
Short: "Disable metrics by undeploying Prometheus",
38+
RunE: func(cmd *cobra.Command, args []string) error {
39+
return runner.Run()
40+
},
41+
}
42+
return cmd
43+
}

cmd/metrics/enable.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Package metrics provides the 'metrics enable' command to deploy Prometheus for metrics collection.
2+
package metrics
3+
4+
import (
5+
"fmt"
6+
"time"
7+
8+
"github.com/chainlaunch/chainlaunch/cmd/common"
9+
metricscommon "github.com/chainlaunch/chainlaunch/pkg/metrics/common"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
// EnableMetricsConfig holds the parameters for enabling metrics
14+
type EnableMetricsConfig struct {
15+
PrometheusVersion string
16+
PrometheusPort int
17+
ScrapeInterval int
18+
}
19+
20+
// EnableMetricsRunner encapsulates the config and logic for running and validating the enable metrics command
21+
type EnableMetricsRunner struct {
22+
Config EnableMetricsConfig
23+
}
24+
25+
// Validate checks the configuration for required fields
26+
func (r *EnableMetricsRunner) Validate() error {
27+
if r.Config.PrometheusVersion == "" {
28+
return fmt.Errorf("--version is required")
29+
}
30+
if r.Config.PrometheusPort <= 0 {
31+
return fmt.Errorf("--port must be greater than 0")
32+
}
33+
if r.Config.ScrapeInterval <= 0 {
34+
return fmt.Errorf("--scrape-interval must be greater than 0")
35+
}
36+
return nil
37+
}
38+
39+
// Run executes the enable metrics logic
40+
func (r *EnableMetricsRunner) Run() error {
41+
if err := r.Validate(); err != nil {
42+
return err
43+
}
44+
client, err := common.NewClientFromEnv()
45+
if err != nil {
46+
return err
47+
}
48+
status, err := client.GetMetricsStatus()
49+
if err == nil && status.Status == "running" {
50+
return fmt.Errorf("Prometheus is already deployed (status: running)")
51+
}
52+
cfg := &metricscommon.Config{
53+
PrometheusVersion: r.Config.PrometheusVersion,
54+
PrometheusPort: r.Config.PrometheusPort,
55+
ScrapeInterval: time.Duration(r.Config.ScrapeInterval) * time.Second,
56+
}
57+
resp, err := client.EnableMetrics(cfg)
58+
if err != nil {
59+
return err
60+
}
61+
fmt.Printf("Prometheus deployed: %v\n", resp)
62+
return nil
63+
}
64+
65+
func NewEnableCmd() *cobra.Command {
66+
runner := &EnableMetricsRunner{
67+
Config: EnableMetricsConfig{
68+
PrometheusVersion: "v3.4.0",
69+
PrometheusPort: 9090,
70+
ScrapeInterval: 15,
71+
},
72+
}
73+
74+
cmd := &cobra.Command{
75+
Use: "enable",
76+
Short: "Enable metrics by deploying Prometheus",
77+
RunE: func(cmd *cobra.Command, args []string) error {
78+
return runner.Run()
79+
},
80+
}
81+
82+
cmd.Flags().StringVar(&runner.Config.PrometheusVersion, "version", "v3.3.1", "Prometheus version")
83+
cmd.Flags().IntVar(&runner.Config.PrometheusPort, "port", 9090, "Prometheus port")
84+
cmd.Flags().IntVar(&runner.Config.ScrapeInterval, "scrape-interval", 15, "Scrape interval in seconds")
85+
86+
return cmd
87+
}

cmd/metrics/metrics.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package metrics
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
)
6+
7+
// NewMetricsCmd creates the 'metrics' parent command
8+
func NewMetricsCmd() *cobra.Command {
9+
cmd := &cobra.Command{
10+
Use: "metrics",
11+
Short: "Manage metrics and Prometheus integration",
12+
}
13+
cmd.AddCommand(NewEnableCmd())
14+
cmd.AddCommand(NewDisableCmd())
15+
return cmd
16+
}

cmd/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/chainlaunch/chainlaunch/cmd/besu"
99
"github.com/chainlaunch/chainlaunch/cmd/fabric"
1010
"github.com/chainlaunch/chainlaunch/cmd/keymanagement"
11+
"github.com/chainlaunch/chainlaunch/cmd/metrics"
1112
"github.com/chainlaunch/chainlaunch/cmd/networks"
1213
"github.com/chainlaunch/chainlaunch/cmd/serve"
1314
"github.com/chainlaunch/chainlaunch/cmd/testnet"
@@ -37,6 +38,7 @@ func NewRootCmd(configCMD config.ConfigCMD) *cobra.Command {
3738
rootCmd.AddCommand(networks.NewNetworksCmd(logger))
3839
rootCmd.AddCommand(keymanagement.NewKeyManagementCmd())
3940
rootCmd.AddCommand(testnet.NewTestnetCmd())
41+
rootCmd.AddCommand(metrics.NewMetricsCmd())
4042
// In the function where rootCmd is defined and commands are added:
4143
// rootCmd.AddCommand(testnet.NewTestnetCmd())
4244
return rootCmd

cmd/serve/serve.go

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
nodeTypes "github.com/chainlaunch/chainlaunch/pkg/nodes/types"
3434

3535
"github.com/chainlaunch/chainlaunch/pkg/audit"
36+
"github.com/chainlaunch/chainlaunch/pkg/chainlaunchdeploy"
3637
"github.com/chainlaunch/chainlaunch/pkg/metrics"
3738
networkshttp "github.com/chainlaunch/chainlaunch/pkg/networks/http"
3839
networksservice "github.com/chainlaunch/chainlaunch/pkg/networks/service"
@@ -41,6 +42,7 @@ import (
4142
notificationhttp "github.com/chainlaunch/chainlaunch/pkg/notifications/http"
4243
notificationservice "github.com/chainlaunch/chainlaunch/pkg/notifications/service"
4344
"github.com/chainlaunch/chainlaunch/pkg/plugin"
45+
pluginregistry "github.com/chainlaunch/chainlaunch/pkg/plugin/registry"
4446
settingshttp "github.com/chainlaunch/chainlaunch/pkg/settings/http"
4547
settingsservice "github.com/chainlaunch/chainlaunch/pkg/settings/service"
4648
"github.com/go-chi/chi/v5"
@@ -137,6 +139,9 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
137139
// @in cookie
138140
// @name session_id
139141

142+
// @tag.name Audit
143+
// @tag.description Audit management operations
144+
140145
// @tag.name Authentication
141146
// @tag.description User authentication and authorization operations
142147

@@ -158,6 +163,9 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
158163
// @tag.name Keys
159164
// @tag.description Cryptographic key management operations
160165

166+
// @tag.name Metrics
167+
// @tag.description Metrics management operations
168+
161169
// @tag.name Nodes
162170
// @tag.description Network node management operations
163171

@@ -176,6 +184,9 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
176184
// @tag.name Settings
177185
// @tag.description Settings management operations
178186

187+
// @tag.name SmartContracts
188+
// @tag.description Smart contract management operations
189+
179190
// @tag.name Users
180191
// @tag.description User account management operations
181192

@@ -425,7 +436,45 @@ func setupServer(queries *db.Queries, authService *auth.AuthService, views embed
425436
if err != nil {
426437
log.Fatal("Failed to initialize plugin manager:", err)
427438
}
428-
pluginHandler := plugin.NewHandler(pluginStore, pluginManager, logger)
439+
// --- Registry integration for GitHub plugins ---
440+
// TODO: Load registry config from file or env
441+
regConfig := &pluginregistry.RegistryConfig{
442+
Sources: []pluginregistry.RegistrySource{
443+
{
444+
Name: "plugin-hlf-api",
445+
Type: "github",
446+
URL: "https://github.com/kfsoftware/plugin-hlf-api", // Example public repo
447+
Enabled: true,
448+
},
449+
},
450+
}
451+
reg, err := pluginregistry.NewRegistry(regConfig)
452+
if err != nil {
453+
log.Fatal("Failed to initialize plugin registry:", err)
454+
}
455+
456+
// Create and start available plugins cache
457+
availablePluginsCache := pluginregistry.NewAvailablePluginsCache()
458+
go func() {
459+
for {
460+
plugins, err := reg.ListAvailablePluginsFromGitHub()
461+
if err == nil {
462+
availablePluginsCache.Set(plugins)
463+
} else {
464+
log.Printf("Failed to refresh available plugins from GitHub: %v", err)
465+
}
466+
time.Sleep(5 * time.Minute)
467+
}
468+
}()
469+
470+
registryStore := plugin.NewRegistryStore(pluginStore, reg)
471+
pluginHandler := plugin.NewHandler(registryStore, pluginManager, logger, reg, availablePluginsCache)
472+
473+
// --- Smart contract deployment handler (Fabric & Besu) ---
474+
// Import the EVM deployer constructor
475+
besuDeployer := chainlaunchdeploy.NewDeployerWithAudit(auditService)
476+
chaincodeService := chainlaunchdeploy.NewChaincodeService(queries, logger, nodesService)
477+
scHandler := chainlaunchdeploy.NewHandler(auditService, logger, besuDeployer, nodesService, chaincodeService)
429478

430479
// Initialize handlers
431480
keyManagementHandler := handler.NewKeyManagementHandler(keyManagementService)
@@ -492,6 +541,9 @@ func setupServer(queries *db.Queries, authService *auth.AuthService, views embed
492541

493542
// Mount audit routes
494543
auditHandler.RegisterRoutes(r)
544+
545+
// Register smart contract deployment routes
546+
scHandler.RegisterRoutes(r)
495547
})
496548
})
497549
r.Get("/api/swagger/*", httpSwagger.Handler(

0 commit comments

Comments
 (0)