ctrlc.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package ctrlc
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "os"
  7. "os/signal"
  8. "syscall"
  9. "time"
  10. )
  11. const C_ICON_START = "🌟"
  12. const C_ICON_WARN = "⚡️"
  13. const C_ICON_HOT = "🔥"
  14. const C_ICON_MAG = "✨"
  15. const C_ICON_SC = "🌳"
  16. type Iface interface {
  17. Shutdown(ctx context.Context) error
  18. }
  19. type CallbackFunc func(ctx context.Context, shutdown context.CancelFunc) *[]Iface
  20. func App(t time.Duration, f CallbackFunc) {
  21. var ParamColor string
  22. flag.StringVar(&ParamColor, "color", "auto", "color output (auto/always/never)")
  23. flag.Parse()
  24. useColors := !IS_WIN_PLATFORM && ParamColor == "always"
  25. stop := make(chan os.Signal)
  26. signal.Notify(stop, syscall.SIGTERM)
  27. signal.Notify(stop, syscall.SIGINT)
  28. fmt.Printf(
  29. icon_start(useColors)+"%s\n",
  30. cly(
  31. useColors,
  32. fmt.Sprintf(
  33. "Application started (%d sec)",
  34. t/time.Second,
  35. ),
  36. ),
  37. )
  38. sctx, shutdown := context.WithCancel(context.Background())
  39. ifaces := f(sctx, shutdown)
  40. select {
  41. case <-sctx.Done():
  42. fmt.Printf(
  43. "\r"+icon_warn(useColors)+"%s\n",
  44. cly(
  45. useColors,
  46. fmt.Sprintf(
  47. "Shutting down (application) (%d sec)",
  48. t/time.Second,
  49. ),
  50. ),
  51. )
  52. case val := <-stop:
  53. switch val {
  54. case syscall.SIGINT:
  55. fmt.Printf(
  56. "\r"+icon_warn(useColors)+"%s\n",
  57. cly(
  58. useColors,
  59. fmt.Sprintf(
  60. "Shutting down (interrupt) (%d sec)",
  61. t/time.Second,
  62. ),
  63. ),
  64. )
  65. case syscall.SIGTERM:
  66. fmt.Printf(
  67. icon_warn(useColors)+"%s\n",
  68. cly(
  69. useColors,
  70. fmt.Sprintf(
  71. "Shutting down (terminate) (%d sec)",
  72. t/time.Second,
  73. ),
  74. ),
  75. )
  76. default:
  77. fmt.Printf(
  78. icon_warn(useColors)+"%s\n",
  79. cly(
  80. useColors,
  81. fmt.Sprintf(
  82. "Shutting down (%d sec)",
  83. t/time.Second,
  84. ),
  85. ),
  86. )
  87. }
  88. }
  89. shutdown()
  90. errors := false
  91. ctx, cancel := context.WithTimeout(context.Background(), t)
  92. for _, iface := range *ifaces {
  93. if err := iface.Shutdown(ctx); err != nil {
  94. errors = true
  95. fmt.Printf(
  96. icon_hot(useColors)+"%s\n",
  97. clr(
  98. useColors,
  99. fmt.Sprintf(
  100. "Shutdown error (%T): %s",
  101. iface,
  102. err.Error(),
  103. ),
  104. ),
  105. )
  106. }
  107. }
  108. cancel()
  109. if errors {
  110. fmt.Printf(
  111. icon_mag(useColors)+"%s\n",
  112. cly(
  113. useColors,
  114. fmt.Sprintf(
  115. "Application exited with errors (%d sec)",
  116. t/time.Second,
  117. ),
  118. ),
  119. )
  120. os.Exit(1)
  121. } else {
  122. fmt.Printf(
  123. icon_sc(useColors)+"%s\n",
  124. clg(
  125. useColors,
  126. fmt.Sprintf(
  127. "Application exited successfully (%d sec)",
  128. t/time.Second,
  129. ),
  130. ),
  131. )
  132. }
  133. }