26
26
ErrStreamAlreadyExist = errors .New ("stream already exist" )
27
27
// ErrTooManyStreams is the error that the number of streams is exceeded the capacity
28
28
ErrTooManyStreams = errors .New ("too many streams" )
29
+ // ErrStreamRemovalNotExpired is the error that the stream was removed before and can't be added yet
30
+ ErrStreamRemovalNotExpired = errors .New ("stream removal not expired yet" )
29
31
)
30
32
31
33
// streamManager is the implementation of StreamManager. It manages streams on
@@ -44,6 +46,8 @@ type streamManager struct {
44
46
// Note that it could happen that remote node does not share exactly the same
45
47
// protocol ID (e.g. different version)
46
48
streams * streamSet
49
+ // tracks removed streams with cooldown
50
+ removedStreams * sttypes.SafeMap [sttypes.StreamID , * RemovalInfo ]
47
51
// reserved streams
48
52
reservedStreams * streamSet
49
53
// libp2p utilities
@@ -66,6 +70,35 @@ type streamManager struct {
66
70
cancel func ()
67
71
}
68
72
73
+ type RemovalInfo struct {
74
+ count uint64
75
+ removedAt time.Time
76
+ expireAt time.Time
77
+ }
78
+
79
+ // MarkAsRemoved resets the removal time and increments the removal count.
80
+ func (rm * RemovalInfo ) MarkAsRemoved () {
81
+ now := time .Now ()
82
+ rm .removedAt = now
83
+ rm .expireAt = now .Add (RemovalCooldownDuration * time .Minute )
84
+ rm .count ++
85
+ }
86
+
87
+ // RemovedAt returns the timestamp when the stream was removed.
88
+ func (rm * RemovalInfo ) RemovedAt () time.Time {
89
+ return rm .removedAt
90
+ }
91
+
92
+ // HasExpired checks if the cooldown period has passed, allowing the stream to reconnect.
93
+ func (rm * RemovalInfo ) HasExpired () bool {
94
+ return time .Now ().After (rm .expireAt )
95
+ }
96
+
97
+ // IncrementRemovalCount increases the removal count.
98
+ func (rm * RemovalInfo ) IncrementRemovalCount () {
99
+ rm .count ++
100
+ }
101
+
69
102
// NewStreamManager creates a new stream manager for the given proto ID
70
103
func NewStreamManager (pid sttypes.ProtoID , host host , pf peerFinder , handleStream func (network.Stream ), c Config ) StreamManager {
71
104
return newStreamManager (pid , host , pf , handleStream , c )
@@ -92,6 +125,7 @@ func newStreamManager(pid sttypes.ProtoID, host host, pf peerFinder, handleStrea
92
125
config : c ,
93
126
streams : newStreamSet (),
94
127
reservedStreams : newStreamSet (),
128
+ removedStreams : sttypes .NewSafeMap [sttypes.StreamID , * RemovalInfo ](),
95
129
host : host ,
96
130
pf : pf ,
97
131
handleStream : handleStream ,
@@ -272,6 +306,12 @@ func (sm *streamManager) handleAddStream(st sttypes.Stream) error {
272
306
if _ , ok := sm .streams .get (id ); ok {
273
307
return ErrStreamAlreadyExist
274
308
}
309
+ // Check if stream was recently removed
310
+ if removalInfo , exists := sm .removedStreams .Get (id ); exists {
311
+ if ! removalInfo .HasExpired () {
312
+ return ErrStreamRemovalNotExpired
313
+ }
314
+ }
275
315
276
316
// If the stream list has sufficient capacity, the stream can be added to the reserved list
277
317
if sm .streams .size () >= sm .config .HiCap {
@@ -322,9 +362,17 @@ func (sm *streamManager) handleRemoveStream(id sttypes.StreamID) error {
322
362
if ! ok {
323
363
return ErrStreamAlreadyRemoved
324
364
}
325
-
326
365
sm .streams .deleteStream (st )
327
366
367
+ info , exist := sm .removedStreams .Get (id )
368
+ if ! exist {
369
+ info = & RemovalInfo {
370
+ count : 0 ,
371
+ }
372
+ sm .removedStreams .Set (id , info )
373
+ }
374
+ info .MarkAsRemoved ()
375
+
328
376
// try to replace removed streams from reserved list
329
377
requiredStreams := sm .hardRequiredStreams ()
330
378
if added , err := sm .addStreamFromReserved (requiredStreams ); added > 0 {
0 commit comments