github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/synchronization/endpoint/remote/protocol.go (about) 1 package remote 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 const ( 9 // controlStreamBufferSize is the buffer size to use for control stream 10 // buffering. It should be ideally large enough to fill the kernel buffer 11 // for whatever stream is being used as a transport, which in our case is 12 // typically an OS pipe. 13 controlStreamCompressedBufferSize = 64 * 1024 14 // controlStreamCompressorBufferSize is the buffer size to use for 15 // compressor input and decompressor output. 16 controlStreamUncompressedBufferSize = 64 * 1024 17 ) 18 19 // ensureValid ensures that the InitializeSynchronizationRequest's invariants 20 // are respected. 21 func (r *InitializeSynchronizationRequest) ensureValid() error { 22 // A nil initialize request is not valid. 23 if r == nil { 24 return errors.New("nil initialize request") 25 } 26 27 // Ensure that the session identifier is non-empty. 28 if r.Session == "" { 29 return errors.New("empty session identifier") 30 } 31 32 // Ensure that the session version is supported. 33 if !r.Version.Supported() { 34 return errors.New("unsupported session version") 35 } 36 37 // Ensure that the configuration is valid. 38 if err := r.Configuration.EnsureValid(false); err != nil { 39 return fmt.Errorf("invalid configuration: %w", err) 40 } 41 42 // Ensure that the root path is non-empty. 43 if r.Root == "" { 44 return errors.New("empty root path") 45 } 46 47 // There's no need to validate Alpha - either value is correct. 48 49 // Success. 50 return nil 51 } 52 53 // ensureValid ensures that the InitializeSynchronizationResponse's invariants 54 // are respected. 55 func (r *InitializeSynchronizationResponse) ensureValid() error { 56 // A nil initialize response is not valid. 57 if r == nil { 58 return errors.New("nil initialize response") 59 } 60 61 // Success. 62 return nil 63 } 64 65 // ensureValid ensures that the PollRequest's invariants are respected. 66 func (r *PollRequest) ensureValid() error { 67 // A nil poll request is not valid. 68 if r == nil { 69 return errors.New("nil poll request") 70 } 71 72 // Success. 73 return nil 74 } 75 76 // ensureValid ensures that the PollCompletionRequest's invariants are 77 // respected. 78 func (r *PollCompletionRequest) ensureValid() error { 79 // A nil poll completion request is not valid. 80 if r == nil { 81 return errors.New("nil poll completion request") 82 } 83 84 // Success. 85 return nil 86 } 87 88 // ensureValid ensures that the PollResponse's invariants are respected. 89 func (r *PollResponse) ensureValid() error { 90 // A nil poll response is not valid. 91 if r == nil { 92 return errors.New("nil poll response") 93 } 94 95 // Success. 96 return nil 97 } 98 99 // ensureValid ensures that the ScanRequest's invariants are respected. 100 func (r *ScanRequest) ensureValid() error { 101 // A nil scan request is not valid. 102 if r == nil { 103 return errors.New("nil scan request") 104 } 105 106 // Ensure that the baseline snapshot signature is valid. 107 if err := r.BaselineSnapshotSignature.EnsureValid(); err != nil { 108 return fmt.Errorf("invalid baseline snapshot signature: %w", err) 109 } 110 111 // Full is correct regardless of value, so no validation is required. 112 113 // Success. 114 return nil 115 } 116 117 // ensureValid ensures that the ScanCompletionRequest's invariants are 118 // respected. 119 func (r *ScanCompletionRequest) ensureValid() error { 120 // A nil scan completion request is not valid. 121 if r == nil { 122 return errors.New("nil scan completion request") 123 } 124 125 // Success. 126 return nil 127 } 128 129 // ensureValid ensures that the ScanResponse's invariants are respected. 130 func (r *ScanResponse) ensureValid() error { 131 // A nil scan response is not valid. 132 if r == nil { 133 return errors.New("nil scan response") 134 } 135 136 // Ensure that each snapshot delta operation is valid. 137 for _, operation := range r.SnapshotDelta { 138 if err := operation.EnsureValid(); err != nil { 139 return fmt.Errorf("invalid snapshot delta operation: %w", err) 140 } 141 } 142 143 // If an error is set, then make sure that no snapshot delta was provided. 144 if r.Error != "" { 145 if len(r.SnapshotDelta) > 0 { 146 return errors.New("non-empty snapshot delta present on error") 147 } 148 } 149 150 // Success. 151 return nil 152 } 153 154 // ensureValid ensures that the StageRequest's invariants are respected. 155 func (r *StageRequest) ensureValid() error { 156 // A nil stage request is not valid. 157 if r == nil { 158 return errors.New("nil stage request") 159 } 160 161 // Ensure that there are a non-zero number of paths. This isn't an invariant 162 // that we really *need* to enforce, as our logic is capable of handling it, 163 // but it's a useful check to make sure that the client is avoiding 164 // transmission in these cases. 165 if len(r.Paths) == 0 { 166 return errors.New("no paths present") 167 } 168 169 // NOTE: We could perform an additional check that the specified paths are 170 // unique, but this isn't quite so cheap, and it won't break anything if 171 // they're not. 172 173 // HACK: We don't verify that the paths are valid (and we'd have a hard time 174 // doing so in any sense other than syntactically) because we use the 175 // filesystem.Opener infrastructure to properly traverse the synchronization 176 // root. It would also be expensive to verify the correctness of these paths 177 // and it would be of little benefit. I'd class this as a hack because it's 178 // sort of a layering violation (the message shouldn't know about the code 179 // that uses it), but I'm willing to live with it because the message is so 180 // tightly coupled to the endpoint implementation anyway. 181 182 // Ensure that the number of digests matches the number of paths. 183 if len(r.Digests) != len(r.Paths) { 184 return errors.New("digest count does not match path count") 185 } 186 187 // NOTE: We could perform an additional check that the specified digests are 188 // valid, but this isn't really necessary, and we'd have to handle varying 189 // digest lengths. 190 191 // Success. 192 return nil 193 } 194 195 // ensureValid ensures that StageResponse's invariants are respected. 196 func (r *StageResponse) ensureValid(paths []string) error { 197 // A nil stage response is not valid. 198 if r == nil { 199 return errors.New("nil stage response") 200 } 201 202 // Verify that path and signature counts are sane. We have to take into 203 // account the shorthand that's used when all paths are requested. 204 p, s := len(r.Paths), len(r.Signatures) 205 if p == 0 && s > 0 { 206 if s != len(paths) { 207 return errors.New("signature count does not match original path count") 208 } 209 p = s 210 } 211 if p != s { 212 return errors.New("number of paths not equal to number of signatures") 213 } else if p > len(paths) { 214 return errors.New("number of paths requested greater than original path count") 215 } 216 217 // Verify that all signatures are valid. 218 for _, signature := range r.Signatures { 219 if err := signature.EnsureValid(); err != nil { 220 return fmt.Errorf("invalid rsync signature: %w", err) 221 } 222 } 223 224 // Verify that paths and signatures are not present if there's an error. 225 if r.Error != "" { 226 if len(r.Paths) > 0 { 227 return errors.New("paths/signatures present on error") 228 } 229 } 230 231 // Success. 232 return nil 233 } 234 235 // ensureValid ensures that SupplyRequest's invariants are respected. 236 func (r *SupplyRequest) ensureValid() error { 237 // A nil supply request is not valid. 238 if r == nil { 239 return errors.New("nil supply request") 240 } 241 242 // Ensure that the number of paths matches the number of signatures. 243 if len(r.Paths) != len(r.Signatures) { 244 return errors.New("number of paths does not match number of signatures") 245 } 246 247 // Ensure that all signatures are valid. 248 for _, s := range r.Signatures { 249 if err := s.EnsureValid(); err != nil { 250 return fmt.Errorf("invalid base signature detected: %w", err) 251 } 252 } 253 254 // Success. 255 return nil 256 } 257 258 // ensureValid ensures that TransitionRequest's invariants are respected. 259 func (r *TransitionRequest) ensureValid() error { 260 // A nil transition request is not valid. 261 if r == nil { 262 return errors.New("nil transition request") 263 } 264 265 // Ensure that each change is valid. Each should contain only synchronizable 266 // content. 267 for _, change := range r.Transitions { 268 if err := change.EnsureValid(true); err != nil { 269 return fmt.Errorf("invalid transition: %w", err) 270 } 271 } 272 273 // Success. 274 return nil 275 } 276 277 // ensureValid ensures that the TransitionCompletionRequest's invariants are 278 // respected. 279 func (r *TransitionCompletionRequest) ensureValid() error { 280 // A nil transition completion request is not valid. 281 if r == nil { 282 return errors.New("nil transition completion request") 283 } 284 285 // Success. 286 return nil 287 } 288 289 // ensureValid ensures that TransitionResponse's invariants are respected. 290 func (r *TransitionResponse) ensureValid(expectedCount int) error { 291 // A nil transition response is not valid. 292 if r == nil { 293 return errors.New("nil transition response") 294 } 295 296 // Ensure that the number of results matches the number expected. 297 if len(r.Results) != expectedCount { 298 return errors.New("unexpected number of results returned") 299 } 300 301 // Validate that each result is a valid archive. Each should contain only 302 // synchronizable content. 303 for _, result := range r.Results { 304 if err := result.EnsureValid(true); err != nil { 305 return fmt.Errorf("invalid result returned: %w", err) 306 } 307 } 308 309 // Validate that each problem is a valid problem specification. 310 for _, problem := range r.Problems { 311 if err := problem.EnsureValid(); err != nil { 312 return fmt.Errorf("invalid problem returned: %w", err) 313 } 314 } 315 316 // Success. 317 return nil 318 } 319 320 // ensureValid ensures that EndpointRequest's invariants are respected. 321 func (r *EndpointRequest) ensureValid() error { 322 // A nil endpoint request is not valid. 323 if r == nil { 324 return errors.New("nil endpoint request") 325 } 326 327 // Ensure that exactly one field is set. 328 set := 0 329 if r.Poll != nil { 330 set++ 331 } 332 if r.Scan != nil { 333 set++ 334 } 335 if r.Stage != nil { 336 set++ 337 } 338 if r.Supply != nil { 339 set++ 340 } 341 if r.Transition != nil { 342 set++ 343 } 344 if set != 1 { 345 return errors.New("invalid number of fields set") 346 } 347 348 // Success. 349 return nil 350 }