func (pr *consulPipeRouter) handlePipeUpdate(key string, cp consulPipe) { // 1. If this pipe is closed, or we're not one of the ends, we // should ensure our local pipe (and bridge) is closed. if !cp.DeletedAt.IsZero() || !cp.eitherEndFor(pr.advertise) { pipe, ok := pr.activePipes[key] delete(pr.activePipes, key) if ok { log.Infof("Deleting pipe %s", key) pipe.Close() } bridge, ok := pr.bridges[key] delete(pr.bridges, key) if ok { bridge.stop() } return } if !cp.eitherEndFor(pr.advertise) { return } // 2. If this pipe if for us, we should have a pipe for it. pipe, ok := pr.activePipes[key] if !ok { log.Infof("Creating pipe %s", key) pipe = xfer.NewPipe() pr.activePipes[key] = pipe for _, pw := range pr.pipeWaiters[key] { pw <- pipe } delete(pr.pipeWaiters, key) } // 3. Ensure there is a bridging connection for this pipe. // Semantics are the owner of the UIEnd connects to the owner of the ProbeEnd shouldBridge := cp.DeletedAt.IsZero() && cp.addrFor(app.UIEnd) != cp.addrFor(app.ProbeEnd) && cp.addrFor(app.UIEnd) == pr.advertise && cp.addrFor(app.ProbeEnd) != "" bridge, ok := pr.bridges[key] // If we shouldn't be bridging but are, or we should be bridging but are pointing // at the wrong place, stop the current bridge. if (!shouldBridge && ok) || (shouldBridge && ok && bridge.addr != cp.addrFor(app.ProbeEnd)) { delete(pr.bridges, key) bridge.stop() ok = false } // If we should be bridging and are not, start a new bridge if shouldBridge && !ok { bridge = newBridgeConnection(key, cp.addrFor(app.ProbeEnd), pipe) pr.bridges[key] = bridge } }
func (pr *localPipeRouter) Get(_ context.Context, id string, e End) (xfer.Pipe, io.ReadWriter, error) { pr.Lock() defer pr.Unlock() p, ok := pr.pipes[id] if !ok { log.Infof("Creating pipe id %s", id) p = &pipe{ ui: end{lastUsedTime: mtime.Now()}, probe: end{lastUsedTime: mtime.Now()}, Pipe: xfer.NewPipe(), } pr.pipes[id] = p } if p.Closed() { return nil, nil, fmt.Errorf("Pipe %s closed", id) } end, endIO := p.end(e) end.refCount++ return p, endIO, nil }
pipeID := fmt.Sprintf("pipe-%d", rand.Int63()) pipe := &pipe{ Pipe: p, appID: appID, id: pipeID, client: c, } if err := c.PipeConnection(appID, pipeID, pipe.Pipe); err != nil { return "", nil, err } return pipeID, pipe, nil } // NewPipe creates a new pipe and connects it to the app. var NewPipe = func(c PipeClient, appID string) (string, xfer.Pipe, error) { return newPipe(xfer.NewPipe(), c, appID) } // NewPipeFromEnds creates a new pipe from its ends and connects it to the app. func NewPipeFromEnds(local, remote io.ReadWriter, c PipeClient, appID string) (string, xfer.Pipe, error) { return newPipe(xfer.NewPipeFromEnds(local, remote), c, appID) } func (p *pipe) Close() error { err1 := p.Pipe.Close() err2 := p.client.PipeClose(p.appID, p.id) if err1 != nil { return err1 } return err2 }