Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

521 wiersze
15 KiB

  1. package redis
  2. import (
  3. "context"
  4. "time"
  5. )
  6. type StreamCmdable interface {
  7. XAdd(ctx context.Context, a *XAddArgs) *StringCmd
  8. XAckDel(ctx context.Context, stream string, group string, mode string, ids ...string) *SliceCmd
  9. XDel(ctx context.Context, stream string, ids ...string) *IntCmd
  10. XDelEx(ctx context.Context, stream string, mode string, ids ...string) *SliceCmd
  11. XLen(ctx context.Context, stream string) *IntCmd
  12. XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
  13. XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
  14. XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
  15. XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
  16. XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
  17. XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
  18. XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
  19. XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
  20. XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
  21. XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
  22. XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
  23. XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
  24. XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
  25. XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
  26. XPending(ctx context.Context, stream, group string) *XPendingCmd
  27. XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
  28. XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
  29. XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
  30. XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd
  31. XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
  32. XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
  33. XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
  34. XTrimMaxLenMode(ctx context.Context, key string, maxLen int64, mode string) *IntCmd
  35. XTrimMaxLenApproxMode(ctx context.Context, key string, maxLen, limit int64, mode string) *IntCmd
  36. XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
  37. XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
  38. XTrimMinIDMode(ctx context.Context, key string, minID string, mode string) *IntCmd
  39. XTrimMinIDApproxMode(ctx context.Context, key string, minID string, limit int64, mode string) *IntCmd
  40. XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
  41. XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
  42. XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
  43. XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd
  44. }
  45. // XAddArgs accepts values in the following formats:
  46. // - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
  47. // - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
  48. // - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
  49. //
  50. // Note that map will not preserve the order of key-value pairs.
  51. // MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used.
  52. type XAddArgs struct {
  53. Stream string
  54. NoMkStream bool
  55. MaxLen int64 // MAXLEN N
  56. MinID string
  57. // Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
  58. Approx bool
  59. Limit int64
  60. Mode string
  61. ID string
  62. Values interface{}
  63. }
  64. func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
  65. args := make([]interface{}, 0, 11)
  66. args = append(args, "xadd", a.Stream)
  67. if a.NoMkStream {
  68. args = append(args, "nomkstream")
  69. }
  70. switch {
  71. case a.MaxLen > 0:
  72. if a.Approx {
  73. args = append(args, "maxlen", "~", a.MaxLen)
  74. } else {
  75. args = append(args, "maxlen", a.MaxLen)
  76. }
  77. case a.MinID != "":
  78. if a.Approx {
  79. args = append(args, "minid", "~", a.MinID)
  80. } else {
  81. args = append(args, "minid", a.MinID)
  82. }
  83. }
  84. if a.Limit > 0 {
  85. args = append(args, "limit", a.Limit)
  86. }
  87. if a.Mode != "" {
  88. args = append(args, a.Mode)
  89. }
  90. if a.ID != "" {
  91. args = append(args, a.ID)
  92. } else {
  93. args = append(args, "*")
  94. }
  95. args = appendArg(args, a.Values)
  96. cmd := NewStringCmd(ctx, args...)
  97. _ = c(ctx, cmd)
  98. return cmd
  99. }
  100. func (c cmdable) XAckDel(ctx context.Context, stream string, group string, mode string, ids ...string) *SliceCmd {
  101. args := []interface{}{"xackdel", stream, group, mode, "ids", len(ids)}
  102. for _, id := range ids {
  103. args = append(args, id)
  104. }
  105. cmd := NewSliceCmd(ctx, args...)
  106. _ = c(ctx, cmd)
  107. return cmd
  108. }
  109. func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
  110. args := []interface{}{"xdel", stream}
  111. for _, id := range ids {
  112. args = append(args, id)
  113. }
  114. cmd := NewIntCmd(ctx, args...)
  115. _ = c(ctx, cmd)
  116. return cmd
  117. }
  118. func (c cmdable) XDelEx(ctx context.Context, stream string, mode string, ids ...string) *SliceCmd {
  119. args := []interface{}{"xdelex", stream, mode, "ids", len(ids)}
  120. for _, id := range ids {
  121. args = append(args, id)
  122. }
  123. cmd := NewSliceCmd(ctx, args...)
  124. _ = c(ctx, cmd)
  125. return cmd
  126. }
  127. func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
  128. cmd := NewIntCmd(ctx, "xlen", stream)
  129. _ = c(ctx, cmd)
  130. return cmd
  131. }
  132. func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
  133. cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
  134. _ = c(ctx, cmd)
  135. return cmd
  136. }
  137. func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
  138. cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
  139. _ = c(ctx, cmd)
  140. return cmd
  141. }
  142. func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
  143. cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
  144. _ = c(ctx, cmd)
  145. return cmd
  146. }
  147. func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
  148. cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
  149. _ = c(ctx, cmd)
  150. return cmd
  151. }
  152. type XReadArgs struct {
  153. Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
  154. Count int64
  155. Block time.Duration
  156. ID string
  157. }
  158. func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
  159. args := make([]interface{}, 0, 2*len(a.Streams)+6)
  160. args = append(args, "xread")
  161. keyPos := int8(1)
  162. if a.Count > 0 {
  163. args = append(args, "count")
  164. args = append(args, a.Count)
  165. keyPos += 2
  166. }
  167. if a.Block >= 0 {
  168. args = append(args, "block")
  169. args = append(args, int64(a.Block/time.Millisecond))
  170. keyPos += 2
  171. }
  172. args = append(args, "streams")
  173. keyPos++
  174. for _, s := range a.Streams {
  175. args = append(args, s)
  176. }
  177. if a.ID != "" {
  178. for range a.Streams {
  179. args = append(args, a.ID)
  180. }
  181. }
  182. cmd := NewXStreamSliceCmd(ctx, args...)
  183. if a.Block >= 0 {
  184. cmd.setReadTimeout(a.Block)
  185. }
  186. cmd.SetFirstKeyPos(keyPos)
  187. _ = c(ctx, cmd)
  188. return cmd
  189. }
  190. func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
  191. return c.XRead(ctx, &XReadArgs{
  192. Streams: streams,
  193. Block: -1,
  194. })
  195. }
  196. func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
  197. cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
  198. cmd.SetFirstKeyPos(2)
  199. _ = c(ctx, cmd)
  200. return cmd
  201. }
  202. func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
  203. cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
  204. cmd.SetFirstKeyPos(2)
  205. _ = c(ctx, cmd)
  206. return cmd
  207. }
  208. func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
  209. cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
  210. cmd.SetFirstKeyPos(2)
  211. _ = c(ctx, cmd)
  212. return cmd
  213. }
  214. func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
  215. cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
  216. cmd.SetFirstKeyPos(2)
  217. _ = c(ctx, cmd)
  218. return cmd
  219. }
  220. func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
  221. cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer)
  222. cmd.SetFirstKeyPos(2)
  223. _ = c(ctx, cmd)
  224. return cmd
  225. }
  226. func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
  227. cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
  228. cmd.SetFirstKeyPos(2)
  229. _ = c(ctx, cmd)
  230. return cmd
  231. }
  232. type XReadGroupArgs struct {
  233. Group string
  234. Consumer string
  235. Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
  236. Count int64
  237. Block time.Duration
  238. NoAck bool
  239. }
  240. func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
  241. args := make([]interface{}, 0, 10+len(a.Streams))
  242. args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
  243. keyPos := int8(4)
  244. if a.Count > 0 {
  245. args = append(args, "count", a.Count)
  246. keyPos += 2
  247. }
  248. if a.Block >= 0 {
  249. args = append(args, "block", int64(a.Block/time.Millisecond))
  250. keyPos += 2
  251. }
  252. if a.NoAck {
  253. args = append(args, "noack")
  254. keyPos++
  255. }
  256. args = append(args, "streams")
  257. keyPos++
  258. for _, s := range a.Streams {
  259. args = append(args, s)
  260. }
  261. cmd := NewXStreamSliceCmd(ctx, args...)
  262. if a.Block >= 0 {
  263. cmd.setReadTimeout(a.Block)
  264. }
  265. cmd.SetFirstKeyPos(keyPos)
  266. _ = c(ctx, cmd)
  267. return cmd
  268. }
  269. func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
  270. args := []interface{}{"xack", stream, group}
  271. for _, id := range ids {
  272. args = append(args, id)
  273. }
  274. cmd := NewIntCmd(ctx, args...)
  275. _ = c(ctx, cmd)
  276. return cmd
  277. }
  278. func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
  279. cmd := NewXPendingCmd(ctx, "xpending", stream, group)
  280. _ = c(ctx, cmd)
  281. return cmd
  282. }
  283. type XPendingExtArgs struct {
  284. Stream string
  285. Group string
  286. Idle time.Duration
  287. Start string
  288. End string
  289. Count int64
  290. Consumer string
  291. }
  292. func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
  293. args := make([]interface{}, 0, 9)
  294. args = append(args, "xpending", a.Stream, a.Group)
  295. if a.Idle != 0 {
  296. args = append(args, "idle", formatMs(ctx, a.Idle))
  297. }
  298. args = append(args, a.Start, a.End, a.Count)
  299. if a.Consumer != "" {
  300. args = append(args, a.Consumer)
  301. }
  302. cmd := NewXPendingExtCmd(ctx, args...)
  303. _ = c(ctx, cmd)
  304. return cmd
  305. }
  306. type XAutoClaimArgs struct {
  307. Stream string
  308. Group string
  309. MinIdle time.Duration
  310. Start string
  311. Count int64
  312. Consumer string
  313. }
  314. func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd {
  315. args := xAutoClaimArgs(ctx, a)
  316. cmd := NewXAutoClaimCmd(ctx, args...)
  317. _ = c(ctx, cmd)
  318. return cmd
  319. }
  320. func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd {
  321. args := xAutoClaimArgs(ctx, a)
  322. args = append(args, "justid")
  323. cmd := NewXAutoClaimJustIDCmd(ctx, args...)
  324. _ = c(ctx, cmd)
  325. return cmd
  326. }
  327. func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} {
  328. args := make([]interface{}, 0, 8)
  329. args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start)
  330. if a.Count > 0 {
  331. args = append(args, "count", a.Count)
  332. }
  333. return args
  334. }
  335. type XClaimArgs struct {
  336. Stream string
  337. Group string
  338. Consumer string
  339. MinIdle time.Duration
  340. Messages []string
  341. }
  342. func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
  343. args := xClaimArgs(a)
  344. cmd := NewXMessageSliceCmd(ctx, args...)
  345. _ = c(ctx, cmd)
  346. return cmd
  347. }
  348. func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
  349. args := xClaimArgs(a)
  350. args = append(args, "justid")
  351. cmd := NewStringSliceCmd(ctx, args...)
  352. _ = c(ctx, cmd)
  353. return cmd
  354. }
  355. func xClaimArgs(a *XClaimArgs) []interface{} {
  356. args := make([]interface{}, 0, 5+len(a.Messages))
  357. args = append(args,
  358. "xclaim",
  359. a.Stream,
  360. a.Group, a.Consumer,
  361. int64(a.MinIdle/time.Millisecond))
  362. for _, id := range a.Messages {
  363. args = append(args, id)
  364. }
  365. return args
  366. }
  367. // TODO: refactor xTrim, xTrimMode and the wrappers over the functions
  368. // xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
  369. // example:
  370. //
  371. // XTRIM key MAXLEN/MINID threshold LIMIT limit.
  372. // XTRIM key MAXLEN/MINID ~ threshold LIMIT limit.
  373. //
  374. // The redis-server version is lower than 6.2, please set limit to 0.
  375. func (c cmdable) xTrim(
  376. ctx context.Context, key, strategy string,
  377. approx bool, threshold interface{}, limit int64,
  378. ) *IntCmd {
  379. args := make([]interface{}, 0, 7)
  380. args = append(args, "xtrim", key, strategy)
  381. if approx {
  382. args = append(args, "~")
  383. }
  384. args = append(args, threshold)
  385. if limit > 0 {
  386. args = append(args, "limit", limit)
  387. }
  388. cmd := NewIntCmd(ctx, args...)
  389. _ = c(ctx, cmd)
  390. return cmd
  391. }
  392. // XTrimMaxLen No `~` rules are used, `limit` cannot be used.
  393. // cmd: XTRIM key MAXLEN maxLen
  394. func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd {
  395. return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
  396. }
  397. func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd {
  398. return c.xTrim(ctx, key, "maxlen", true, maxLen, limit)
  399. }
  400. func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd {
  401. return c.xTrim(ctx, key, "minid", false, minID, 0)
  402. }
  403. func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd {
  404. return c.xTrim(ctx, key, "minid", true, minID, limit)
  405. }
  406. func (c cmdable) xTrimMode(
  407. ctx context.Context, key, strategy string,
  408. approx bool, threshold interface{}, limit int64,
  409. mode string,
  410. ) *IntCmd {
  411. args := make([]interface{}, 0, 7)
  412. args = append(args, "xtrim", key, strategy)
  413. if approx {
  414. args = append(args, "~")
  415. }
  416. args = append(args, threshold)
  417. if limit > 0 {
  418. args = append(args, "limit", limit)
  419. }
  420. args = append(args, mode)
  421. cmd := NewIntCmd(ctx, args...)
  422. _ = c(ctx, cmd)
  423. return cmd
  424. }
  425. func (c cmdable) XTrimMaxLenMode(ctx context.Context, key string, maxLen int64, mode string) *IntCmd {
  426. return c.xTrimMode(ctx, key, "maxlen", false, maxLen, 0, mode)
  427. }
  428. func (c cmdable) XTrimMaxLenApproxMode(ctx context.Context, key string, maxLen, limit int64, mode string) *IntCmd {
  429. return c.xTrimMode(ctx, key, "maxlen", true, maxLen, limit, mode)
  430. }
  431. func (c cmdable) XTrimMinIDMode(ctx context.Context, key string, minID string, mode string) *IntCmd {
  432. return c.xTrimMode(ctx, key, "minid", false, minID, 0, mode)
  433. }
  434. func (c cmdable) XTrimMinIDApproxMode(ctx context.Context, key string, minID string, limit int64, mode string) *IntCmd {
  435. return c.xTrimMode(ctx, key, "minid", true, minID, limit, mode)
  436. }
  437. func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
  438. cmd := NewXInfoConsumersCmd(ctx, key, group)
  439. _ = c(ctx, cmd)
  440. return cmd
  441. }
  442. func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
  443. cmd := NewXInfoGroupsCmd(ctx, key)
  444. _ = c(ctx, cmd)
  445. return cmd
  446. }
  447. func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
  448. cmd := NewXInfoStreamCmd(ctx, key)
  449. _ = c(ctx, cmd)
  450. return cmd
  451. }
  452. // XInfoStreamFull XINFO STREAM FULL [COUNT count]
  453. // redis-server >= 6.0.
  454. func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd {
  455. args := make([]interface{}, 0, 6)
  456. args = append(args, "xinfo", "stream", key, "full")
  457. if count > 0 {
  458. args = append(args, "count", count)
  459. }
  460. cmd := NewXInfoStreamFullCmd(ctx, args...)
  461. _ = c(ctx, cmd)
  462. return cmd
  463. }