mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-19 09:40:12 +00:00
75 lines
2.6 KiB
Go
75 lines
2.6 KiB
Go
//go:build agentcompat
|
|
|
|
package rpc
|
|
|
|
import "context"
|
|
|
|
func (s *NezhaHandler) BindAgentCompatIOStreamCapability(binding AgentCompatCapabilityBinding) error {
|
|
s.ioStreamMutex.Lock()
|
|
defer s.ioStreamMutex.Unlock()
|
|
registration, allowed := s.agentCompatRegistrationLocked(binding.AgentCompatCapabilityAccess)
|
|
if !allowed || registration.phase != agentCompatCapabilityRegistered || registration.registration.Purpose == AgentCompatCapabilityNAT {
|
|
return ErrAgentCompatCapabilityHidden
|
|
}
|
|
stream, exists := s.ioStreams[binding.StreamID]
|
|
stored := registration.registration
|
|
if !exists || binding.StreamID == "" || stream.creatorUserID != stored.Owner.UserID ||
|
|
stream.targetServerID != stored.TargetServerID || stream.purpose != stored.Purpose.streamPurpose() {
|
|
return ErrAgentCompatCapabilityHidden
|
|
}
|
|
if registration.stream != nil {
|
|
if registration.stream == stream && registration.streamID == binding.StreamID {
|
|
return nil
|
|
}
|
|
return ErrAgentCompatCapabilityConflict
|
|
}
|
|
registration.streamID = binding.StreamID
|
|
registration.stream = stream
|
|
registration.publishLocked()
|
|
return nil
|
|
}
|
|
|
|
func (s *NezhaHandler) WaitAgentCompatIOStreamCapability(ctx context.Context, access AgentCompatCapabilityAccess) (string, error) {
|
|
for {
|
|
s.ioStreamMutex.RLock()
|
|
registration, allowed := s.agentCompatRegistrationLocked(access)
|
|
if !allowed {
|
|
s.ioStreamMutex.RUnlock()
|
|
return "", ErrAgentCompatCapabilityHidden
|
|
}
|
|
if registration.streamID != "" {
|
|
streamID := registration.streamID
|
|
stream := registration.stream
|
|
stored := registration.registration
|
|
current, live := s.ioStreams[streamID]
|
|
if stored.Purpose == AgentCompatCapabilityNAT && registration.phase == agentCompatCapabilityPublished && stream != nil {
|
|
s.ioStreamMutex.RUnlock()
|
|
return streamID, nil
|
|
}
|
|
// A reused StreamID must not turn a retained capability into authority over a replacement stream.
|
|
creatorMatches := stream != nil && stream.creatorUserID == stored.Owner.UserID
|
|
if stored.Purpose == AgentCompatCapabilityNAT {
|
|
creatorMatches = stream != nil && stream.creatorUserID == 0
|
|
}
|
|
valid := live && current == stream && creatorMatches &&
|
|
stream.targetServerID == stored.TargetServerID && stream.purpose == stored.Purpose.streamPurpose()
|
|
s.ioStreamMutex.RUnlock()
|
|
if !valid {
|
|
return "", ErrAgentCompatCapabilityHidden
|
|
}
|
|
return streamID, nil
|
|
}
|
|
notify := registration.notify
|
|
observer := s.agentCompatCapabilities.waitObserver
|
|
s.ioStreamMutex.RUnlock()
|
|
if observer != nil {
|
|
observer()
|
|
}
|
|
select {
|
|
case <-ctx.Done():
|
|
return "", ctx.Err()
|
|
case <-notify:
|
|
}
|
|
}
|
|
}
|