func (server *Server) Run(ctx context.Context, options ...RunOption) error {
	cctx, cancel := context.WithCancel(ctx)
	defer cancel()

	opts := &RunOptions{gracefulCtx: context.Background()}
	for _, opt := range options {
		opt(opts)
	}

	router := gin.New()
	router.Use(gin.Recovery())
	if gin.Mode() == gin.DebugMode {
		router.Use(gin.Logger())
	}

	base := filepath.Join(server.options.Base)
	api := router.Group(base)

	// Routes
	api.GET("/", server.handleListContainers)
	api.GET("/auth_token.js", server.handleAuthToken)
	api.GET("/config.js", server.handleConfig)

	rewriteH := func(c *gin.Context) {
		if base != "/" {
			c.Request.RequestURI = strings.TrimPrefix(
				c.Request.RequestURI, base,
			)
		}
		asset.Handler(c.Writer, c.Request)
	}
	for _, f := range asset.List() {
		if f.Name() != "/" {
			api.GET(f.Name(), rewriteH)
		}
	}

	// exec
	counter := newCounter(server.options.IdleTime)
	api.GET("/e/:cid/", server.handleExecRedirect) // containerID
	api.GET("/exec/:eid/", server.handleWSIndex)   // execID
	api.GET("/exec/:eid/"+"ws", func(c *gin.Context) { server.handleExec(c, counter) })

	// logs
	api.GET("/logs/:cid/", server.handleWSIndex)
	api.GET("/logs/:cid/"+"ws", func(c *gin.Context) { server.handleLogs(c) })

	ctl := server.options.Control
	if ctl.Enable {
		// container actions: start|stop|restart
		containerG := api.Group("/container")
		if ctl.Start || ctl.All {
			containerG.POST("/start/:id", server.handleStartContainer)
		}
		if ctl.Stop || ctl.All {
			containerG.POST("/stop/:id", server.handleStopContainer)
		}
		if ctl.Restart || ctl.All {
			containerG.POST("/restart/:id", server.handleRestartContainer)
		}
	}

	// pprof
	rootMux := http.NewServeMux()
	if log.GetLevel() == log.DebugLevel {
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/"), pprof.Index)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/cmdline"), pprof.Cmdline)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/profile"), pprof.Profile)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/symbol"), pprof.Symbol)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/trace"), pprof.Trace)
	}
	rootMux.Handle("/", router)

	hostPort := net.JoinHostPort(server.options.Address,
		fmt.Sprint(server.options.Port))
	srv := &http.Server{
		Addr:    hostPort,
		Handler: rootMux,
	}

	srvErr := make(chan error, 1)
	go func() {
		srvErr <- srv.ListenAndServe()
	}()

	go func() {
		select {
		case <-opts.gracefulCtx.Done():
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			if err := srv.Shutdown(ctx); err != nil {
				log.Fatal("Server Shutdown:", err)
			}
		case <-cctx.Done():
		}
	}()

	log.Infof("Server running at http://%s%s", hostPort, base)

	var err error
	select {
	case err = <-srvErr:
		if err == http.ErrServerClosed { // by graceful ctx
			err = nil
		} else {
			cancel()
		}
	case <-cctx.Done():
		srv.Close()
		err = cctx.Err()
	}

	conn := counter.count()
	if conn > 0 {
		log.Printf("Waiting for %d connections to be closed", conn)
		fmt.Println("Ctl-C to force close")
	}
	counter.wait()

	return err
}
// Run starts the main process of the Server.
// The cancelation of ctx will shutdown the server immediately with aborting
// existing connections. Use WithGracefulContext() to support graceful shutdown.
Run starts the main process of the Server.
The cancelation of ctx will shutdown the server immediately with aborting
existing connections. Use WithGracefulContext() to support graceful shutdown.
// Run starts the main process of the Server . // The cancelation of ctx will shutdown the server immediately with aborting // existing connections . Use WithGracefulContext () to support graceful shutdown .
func (server *Server) Run(ctx context.Context, options ...RunOption) error {
	cctx, cancel := context.WithCancel(ctx)
	defer cancel()
	opts := &RunOptions{gracefulCtx: context.Background()}
	for _, opt := range options {
		opt(opts)
	}
	router := gin.New()
	router.Use(gin.Recovery())
	if gin.Mode() == gin.DebugMode {
		router.Use(gin.Logger())
	}
	base := filepath.Join(server.options.Base)
	api := router.Group(base)
	api.GET("/", server.handleListContainers)
	api.GET("/auth_token.js", server.handleAuthToken)
	api.GET("/config.js", server.handleConfig)
	rewriteH := func(c *gin.Context) {
		if base != "/" {
			c.Request.RequestURI = strings.TrimPrefix(
				c.Request.RequestURI, base,
			)
		}
		asset.Handler(c.Writer, c.Request)
	}
	for _, f := range asset.List() {
		if f.Name() != "/" {
			api.GET(f.Name(), rewriteH)
		}
	}
	counter := newCounter(server.options.IdleTime)
	api.GET("/e/:cid/", server.handleExecRedirect) 
	api.GET("/exec/:eid/", server.handleWSIndex)   ID
	api.GET("/exec/:eid/"+"ws", func(c *gin.Context) { server.handleExec(c, counter) })
	api.GET("/logs/:cid/", server.handleWSIndex)
	api.GET("/logs/:cid/"+"ws", func(c *gin.Context) { server.handleLogs(c) })
	ctl := server.options.Control
	if ctl.Enable {
		containerG := api.Group("/container")
		if ctl.Start || ctl.All {
			containerG.POST("/start/:id", server.handleStartContainer)
		}
		if ctl.Stop || ctl.All {
			containerG.POST("/stop/:id", server.handleStopContainer)
		}
		if ctl.Restart || ctl.All {
			containerG.POST("/restart/:id", server.handleRestartContainer)
		}
	}
	rootMux := http.NewServeMux()
	if log.GetLevel() == log.DebugLevel {
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/"), pprof.Index)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/cmdline"), pprof.Cmdline)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/profile"), pprof.Profile)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/symbol"), pprof.Symbol)
		rootMux.HandleFunc(filepath.Join(base, "/debug/pprof/trace"), pprof.Trace)
	}
	rootMux.Handle("/", router)
	hostPort := net.JoinHostPort(server.options.Address,
		fmt.Sprint(server.options.Port))
	srv := &http.Server{
		Addr:    hostPort,
		Handler: rootMux,
	}
	srvErr := make(chan error, 1)
	go func() {
		srvErr <- srv.ListenAndServe()
	}()
	go func() {
		select {
		case <-opts.gracefulCtx.Done():
			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			if err := srv.Shutdown(ctx); err != nil {
				log.Fatal("Server Shutdown:", err)
			}
		case <-cctx.Done():
		}
	}()
	log.Infof("Server running at http://%s%s", hostPort, base)
	var err error
	select {
	case err = <-srvErr:
		if err == http.ErrServerClosed { 
			err = nil
		} else {
			cancel()
		}
	case <-cctx.Done():
		srv.Close()
		err = cctx.Err()
	}
	conn := counter.count()
	if conn > 0 {
		log.Printf("Waiting for %d connections to be closed", conn)
		fmt.Println("Ctl-C to force close")
	}
	counter.wait()
	return err
}
func ( server * Server ) Run ( ctx context . Context , options ... RunOption ) error { cctx , cancel := context . WithCancel ( ctx ) defer cancel ( ) opts := & RunOptions { gracefulCtx : context . Background ( ) } for _ , opt := range options { opt ( opts ) } router := gin . New ( ) router . Use ( gin . Recovery ( ) ) if gin . Mode ( ) == gin . DebugMode { router . Use ( gin . Logger ( ) ) } base := filepath . Join ( server . options . Base ) api := router . Group ( base ) api . GET ( " " , server . handleListContainers ) api . GET ( " " , server . handleAuthToken ) api . GET ( " " , server . handleConfig ) rewriteH := func ( c * gin . Context ) { if base != " " { c . Request . RequestURI = strings . TrimPrefix ( c . Request . RequestURI , base , ) } asset . Handler ( c . Writer , c . Request ) } for _ , f := range asset . List ( ) { if f . Name ( ) != " " { api . GET ( f . Name ( ) , rewriteH ) } } counter := newCounter ( server . options . IdleTime ) api . GET ( " " , server . handleExecRedirect ) api . GET ( " " , server . handleWSIndex ) api . GET ( " " + " " , func ( c * gin . Context ) { server . handleExec ( c , counter ) } ) api . GET ( " " , server . handleWSIndex ) api . GET ( " " + " " , func ( c * gin . Context ) { server . handleLogs ( c ) } ) ctl := server . options . Control if ctl . Enable { containerG := api . Group ( " " ) if ctl . Start || ctl . All { containerG . POST ( " " , server . handleStartContainer ) } if ctl . Stop || ctl . All { containerG . POST ( " " , server . handleStopContainer ) } if ctl . Restart || ctl . All { containerG . POST ( " " , server . handleRestartContainer ) } } rootMux := http . NewServeMux ( ) if log . GetLevel ( ) == log . DebugLevel { rootMux . HandleFunc ( filepath . Join ( base , " " ) , pprof . Index ) rootMux . HandleFunc ( filepath . Join ( base , " " ) , pprof . Cmdline ) rootMux . HandleFunc ( filepath . Join ( base , " " ) , pprof . Profile ) rootMux . HandleFunc ( filepath . Join ( base , " " ) , pprof . Symbol ) rootMux . HandleFunc ( filepath . Join ( base , " " ) , pprof . Trace ) } rootMux . Handle ( " " , router ) hostPort := net . JoinHostPort ( server . options . Address , fmt . Sprint ( server . options . Port ) ) srv := & http . Server { Addr : hostPort , Handler : rootMux , } srvErr := make ( chan error , 1 ) go func ( ) { srvErr <- srv . ListenAndServe ( ) } ( ) go func ( ) { select { case <- opts . gracefulCtx . Done ( ) : ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second ) defer cancel ( ) if err := srv . Shutdown ( ctx ) ; err != nil { log . Fatal ( " " , err ) } case <- cctx . Done ( ) : } } ( ) log . Infof ( " " , hostPort , base ) var err error select { case err = <- srvErr : if err == http . ErrServerClosed { err = nil } else { cancel ( ) } case <- cctx . Done ( ) : srv . Close ( ) err = cctx . Err ( ) } conn := counter . count ( ) if conn > 0 { log . Printf ( " " , conn ) fmt . Println ( " " ) } counter . wait ( ) return err }
Run starts the main process of the Server.
Run starts the main process of the Server .
// Routes // exec // containerID // execID // logs // container actions: start|stop|restart // pprof // by graceful ctx