common.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package main
  2. import "surdeus.su/core/cli/mtool"
  3. import "surdeus.su/core/amo"
  4. import "sync"
  5. import "os"
  6. import "strconv"
  7. import "log"
  8. import "bufio"
  9. import "math"
  10. type DefaultFlags struct {
  11. SecretPath string
  12. Threads int
  13. Verbose bool
  14. MRPS int
  15. MEPR int
  16. All bool
  17. StartPage int
  18. EndPage int
  19. Indent bool
  20. }
  21. func MakeDefaultFlags(opts *DefaultFlags, flags *mtool.Flags) {
  22. flags.StringVar(
  23. &opts.SecretPath,
  24. "secret",
  25. "secret.json",
  26. "path to JSON file with AMO CRM secrets",
  27. "AMO_SECRET",
  28. )
  29. flags.IntVar(
  30. &opts.MRPS,
  31. "mrps",
  32. 9,
  33. "maximum requests per second",
  34. )
  35. flags.IntVar(
  36. &opts.Threads,
  37. "threads",
  38. 5,
  39. "amount of threads to run the requests",
  40. )
  41. flags.BoolVar(
  42. &opts.Verbose,
  43. "no-verbose",
  44. true,
  45. "disable verbose mode",
  46. )
  47. flags.IntVar(
  48. &opts.MEPR,
  49. "mepr",
  50. amo.MEPR,
  51. "max entities per request",
  52. )
  53. }
  54. func MakeGetterFlags(
  55. opts *DefaultFlags,
  56. flags *mtool.Flags,
  57. ) {
  58. flags.BoolVar(
  59. &opts.All,
  60. "all",
  61. false,
  62. "get all entities",
  63. )
  64. flags.IntVar(
  65. &opts.StartPage,
  66. "startpage",
  67. 1,
  68. "the page to start at (works only with -all)",
  69. )
  70. flags.IntVar(
  71. &opts.EndPage,
  72. "endpage",
  73. math.MaxInt,
  74. "the page to end the requests",
  75. )
  76. flags.BoolVar(
  77. &opts.Indent,
  78. "no-indent",
  79. true,
  80. "disable indenting for JSON output",
  81. )
  82. }
  83. // Run function for slice's parts in different threads.
  84. // Returns a channel that ticks that the threads finished.
  85. func RunForSliceInThreads[V any](
  86. threadN, mepr int, // Thread amount and MERP.
  87. slice []V,
  88. // The function that takes
  89. // the thread number and the slice of slice.
  90. fn func(int, []V),
  91. ) (chan struct{}) {
  92. ret := make(chan struct{})
  93. // No need for threads if
  94. // there are so few entities.
  95. if len(slice) <= mepr {
  96. go func() {
  97. fn(1, slice)
  98. ret <- struct{}{}
  99. }()
  100. return ret
  101. }
  102. var wg sync.WaitGroup
  103. runFn :=func(thread int, s []V) {
  104. defer wg.Done()
  105. iterN := (len(s) / mepr) + 1
  106. for j := 0 ; j<iterN ; j++ {
  107. start := j*mepr
  108. end := start + mepr
  109. if end > len(s) {
  110. end = len(s)
  111. }
  112. if len(s[start:end]) == 0 {
  113. continue
  114. }
  115. fn(thread, s[start:end])
  116. }
  117. }
  118. // Maximizing speed on small data.
  119. //threadSize := len(slice) / threadN
  120. threadMeprRest := len(slice) % mepr
  121. //threadSize := (len(slice)-threadMeprRest)/threadN
  122. preThreadSize :=
  123. ((len(slice)-threadMeprRest)/threadN)
  124. threadSize := (preThreadSize/mepr+1)*mepr
  125. if threadSize < mepr {
  126. threadSize = mepr
  127. threadN = len(slice) / mepr
  128. runFn = func(thread int, s []V) {
  129. defer wg.Done()
  130. fn(thread, s)
  131. }
  132. }
  133. for i := 0 ; i<threadN ; i++ {
  134. first := i * threadSize
  135. last := first + threadSize
  136. if last > len(slice) {
  137. last = len(slice)
  138. }
  139. // Got an empty slice.
  140. if len(slice[first:last]) == 0 {
  141. break
  142. }
  143. wg.Add(1)
  144. go runFn(i+1, slice[first:last])
  145. }
  146. go func() {
  147. wg.Wait()
  148. ret <- struct{}{}
  149. }()
  150. return ret
  151. }
  152. func ReadIDs(idStrs []string) []int {
  153. var ids []int
  154. if len(idStrs) > 0 {
  155. ids = make([]int, 0, len(idStrs))
  156. for _, idStr := range idStrs {
  157. id, err := strconv.Atoi(idStr)
  158. if err != nil {
  159. log.Printf("Error: Atoi(%q): %s\n", err)
  160. continue
  161. }
  162. ids = append(ids, id)
  163. }
  164. } else {
  165. ids = make([]int, 0)
  166. scanner := bufio.NewScanner(os.Stdin)
  167. for scanner.Scan() {
  168. txt := scanner.Text()
  169. id, err := strconv.Atoi(txt)
  170. if err != nil {
  171. log.Printf(
  172. "strconv.Atoi(%q): %s\n",
  173. txt, err,
  174. )
  175. continue
  176. }
  177. ids = append(ids, id)
  178. }
  179. }
  180. return ids
  181. }