Integrate BACKBEAT SDK and resolve KACHING license validation

Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

9
vendor/github.com/jbenet/goprocess/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,9 @@
sudo: false
language: go
go:
- 1.12
script:
- go test -race -v ./...

21
vendor/github.com/jbenet/goprocess/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

132
vendor/github.com/jbenet/goprocess/README.md generated vendored Normal file
View File

@@ -0,0 +1,132 @@
# goprocess - lifecycles in go
[![travisbadge](https://travis-ci.org/jbenet/goprocess.svg)](https://travis-ci.org/jbenet/goprocess)
(Based on https://github.com/jbenet/go-ctxgroup)
- Godoc: https://godoc.org/github.com/jbenet/goprocess
`goprocess` introduces a way to manage process lifecycles in go. It is
much like [go.net/context](https://godoc.org/code.google.com/p/go.net/context)
(it actually uses a Context), but it is more like a Context-WaitGroup hybrid.
`goprocess` is about being able to start and stop units of work, which may
receive `Close` signals from many clients. Think of it like a UNIX process
tree, but inside go.
`goprocess` seeks to minimally affect your objects, so you can use it
with both embedding or composition. At the heart of `goprocess` is the
`Process` interface:
```Go
// Process is the basic unit of work in goprocess. It defines a computation
// with a lifecycle:
// - running (before calling Close),
// - closing (after calling Close at least once),
// - closed (after Close returns, and all teardown has _completed_).
//
// More specifically, it fits this:
//
// p := WithTeardown(tf) // new process is created, it is now running.
// p.AddChild(q) // can register children **before** Closing.
// go p.Close() // blocks until done running teardown func.
// <-p.Closing() // would now return true.
// <-p.childrenDone() // wait on all children to be done
// p.teardown() // runs the user's teardown function tf.
// p.Close() // now returns, with error teardown returned.
// <-p.Closed() // would now return true.
//
// Processes can be arranged in a process "tree", where children are
// automatically Closed if their parents are closed. (Note, it is actually
// a Process DAG, children may have multiple parents). A process may also
// optionally wait for another to fully Close before beginning to Close.
// This makes it easy to ensure order of operations and proper sequential
// teardown of resurces. For example:
//
// p1 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 1")
// })
// p2 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 2")
// })
// p3 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 3")
// })
//
// p1.AddChild(p2)
// p2.AddChild(p3)
//
//
// go p1.Close()
// go p2.Close()
// go p3.Close()
//
// // Output:
// // closing 3
// // closing 2
// // closing 1
//
// Process is modelled after the UNIX processes group idea, and heavily
// informed by sync.WaitGroup and go.net/context.Context.
//
// In the function documentation of this interface, `p` always refers to
// the self Process.
type Process interface {
// WaitFor makes p wait for q before exiting. Thus, p will _always_ close
// _after_ q. Note well: a waiting cycle is deadlock.
//
// If q is already Closed, WaitFor calls p.Close()
// If p is already Closing or Closed, WaitFor panics. This is the same thing
// as calling Add(1) _after_ calling Done() on a wait group. Calling WaitFor
// on an already-closed process is a programming error likely due to bad
// synchronization
WaitFor(q Process)
// AddChildNoWait registers child as a "child" of Process. As in UNIX,
// when parent is Closed, child is Closed -- child may Close beforehand.
// This is the equivalent of calling:
//
// go func(parent, child Process) {
// <-parent.Closing()
// child.Close()
// }(p, q)
//
// Note: the naming of functions is `AddChildNoWait` and `AddChild` (instead
// of `AddChild` and `AddChildWaitFor`) because:
// - it is the more common operation,
// - explicitness is helpful in the less common case (no waiting), and
// - usual "child" semantics imply parent Processes should wait for children.
AddChildNoWait(q Process)
// AddChild is the equivalent of calling:
// parent.AddChildNoWait(q)
// parent.WaitFor(q)
AddChild(q Process)
// Go creates a new process, adds it as a child, and spawns the ProcessFunc f
// in its own goroutine. It is equivalent to:
//
// GoChild(p, f)
//
// It is useful to construct simple asynchronous workers, children of p.
Go(f ProcessFunc) Process
// Close ends the process. Close blocks until the process has completely
// shut down, and any teardown has run _exactly once_. The returned error
// is available indefinitely: calling Close twice returns the same error.
// If the process has already been closed, Close returns immediately.
Close() error
// Closing is a signal to wait upon. The returned channel is closed
// _after_ Close has been called at least once, but teardown may or may
// not be done yet. The primary use case of Closing is for children who
// need to know when a parent is shutting down, and therefore also shut
// down.
Closing() <-chan struct{}
// Closed is a signal to wait upon. The returned channel is closed
// _after_ Close has completed; teardown has finished. The primary use case
// of Closed is waiting for a Process to Close without _causing_ the Close.
Closed() <-chan struct{}
}
```

33
vendor/github.com/jbenet/goprocess/background.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
package goprocess
// Background returns the "bgProcess" Process: a statically allocated
// process that can _never_ close. It also never enters Closing() state.
// Calling Background().Close() will hang indefinitely.
func Background() Process {
return background
}
var background = new(bgProcess)
type bgProcess struct{}
func (*bgProcess) WaitFor(q Process) {}
func (*bgProcess) AddChildNoWait(q Process) {}
func (*bgProcess) AddChild(q Process) {}
func (*bgProcess) Close() error { select {} }
func (*bgProcess) CloseAfterChildren() error { select {} }
func (*bgProcess) Closing() <-chan struct{} { return nil }
func (*bgProcess) Closed() <-chan struct{} { return nil }
func (*bgProcess) Err() error { select {} }
func (*bgProcess) SetTeardown(tf TeardownFunc) {
panic("can't set teardown on bgProcess process")
}
func (*bgProcess) Go(f ProcessFunc) Process {
child := newProcess(nil)
go func() {
f(child)
child.Close()
}()
return child
}

263
vendor/github.com/jbenet/goprocess/goprocess.go generated vendored Normal file
View File

@@ -0,0 +1,263 @@
// Package goprocess introduces a Process abstraction that allows simple
// organization, and orchestration of work. It is much like a WaitGroup,
// and much like a context.Context, but also ensures safe **exactly-once**,
// and well-ordered teardown semantics.
package goprocess
import (
"os"
"os/signal"
)
// Process is the basic unit of work in goprocess. It defines a computation
// with a lifecycle:
// - running (before calling Close),
// - closing (after calling Close at least once),
// - closed (after Close returns, and all teardown has _completed_).
//
// More specifically, it fits this:
//
// p := WithTeardown(tf) // new process is created, it is now running.
// p.AddChild(q) // can register children **before** Closed().
// go p.Close() // blocks until done running teardown func.
// <-p.Closing() // would now return true.
// <-p.childrenDone() // wait on all children to be done
// p.teardown() // runs the user's teardown function tf.
// p.Close() // now returns, with error teardown returned.
// <-p.Closed() // would now return true.
//
// Processes can be arranged in a process "tree", where children are
// automatically Closed if their parents are closed. (Note, it is actually
// a Process DAG, children may have multiple parents). A process may also
// optionally wait for another to fully Close before beginning to Close.
// This makes it easy to ensure order of operations and proper sequential
// teardown of resurces. For example:
//
// p1 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 1")
// })
// p2 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 2")
// })
// p3 := goprocess.WithTeardown(func() error {
// fmt.Println("closing 3")
// })
//
// p1.AddChild(p2)
// p2.AddChild(p3)
//
//
// go p1.Close()
// go p2.Close()
// go p3.Close()
//
// // Output:
// // closing 3
// // closing 2
// // closing 1
//
// Process is modelled after the UNIX processes group idea, and heavily
// informed by sync.WaitGroup and go.net/context.Context.
//
// In the function documentation of this interface, `p` always refers to
// the self Process.
type Process interface {
// WaitFor makes p wait for q before exiting. Thus, p will _always_ close
// _after_ q. Note well: a waiting cycle is deadlock.
//
// If p is already Closed, WaitFor panics. This is the same thing as
// calling Add(1) _after_ calling Done() on a wait group. Calling
// WaitFor on an already-closed process is a programming error likely
// due to bad synchronization
WaitFor(q Process)
// AddChildNoWait registers child as a "child" of Process. As in UNIX,
// when parent is Closed, child is Closed -- child may Close beforehand.
// This is the equivalent of calling:
//
// go func(parent, child Process) {
// <-parent.Closing()
// child.Close()
// }(p, q)
//
// Note: the naming of functions is `AddChildNoWait` and `AddChild` (instead
// of `AddChild` and `AddChildWaitFor`) because:
// - it is the more common operation,
// - explicitness is helpful in the less common case (no waiting), and
// - usual "child" semantics imply parent Processes should wait for children.
AddChildNoWait(q Process)
// AddChild is the equivalent of calling:
// parent.AddChildNoWait(q)
// parent.WaitFor(q)
//
// It will _panic_ if the parent is already closed.
AddChild(q Process)
// Go is much like `go`, as it runs a function in a newly spawned goroutine.
// The neat part of Process.Go is that the Process object you call it on will:
// * construct a child Process, and call AddChild(child) on it
// * spawn a goroutine, and call the given function
// * Close the child when the function exits.
// This way, you can rest assured each goroutine you spawn has its very own
// Process context, and that it will be closed when the function exits.
// It is the function's responsibility to respect the Closing of its Process,
// namely it should exit (return) when <-Closing() is ready. It is basically:
//
// func (p Process) Go(f ProcessFunc) Process {
// child := WithParent(p)
// go func () {
// f(child)
// child.Close()
// }()
// }
//
// It is useful to construct simple asynchronous workers, children of p.
Go(f ProcessFunc) Process
// SetTeardown sets the process's teardown to tf.
SetTeardown(tf TeardownFunc)
// Close ends the process. Close blocks until the process has completely
// shut down, and any teardown has run _exactly once_. The returned error
// is available indefinitely: calling Close twice returns the same error.
// If the process has already been closed, Close returns immediately.
Close() error
// CloseAfterChildren calls Close _after_ its children have Closed
// normally (i.e. it _does not_ attempt to close them).
CloseAfterChildren() error
// Closing is a signal to wait upon. The returned channel is closed
// _after_ Close has been called at least once, but teardown may or may
// not be done yet. The primary use case of Closing is for children who
// need to know when a parent is shutting down, and therefore also shut
// down.
Closing() <-chan struct{}
// Closed is a signal to wait upon. The returned channel is closed
// _after_ Close has completed; teardown has finished. The primary use case
// of Closed is waiting for a Process to Close without _causing_ the Close.
Closed() <-chan struct{}
// Err waits until the process is closed, and then returns any error that
// occurred during shutdown.
Err() error
}
// TeardownFunc is a function used to cleanup state at the end of the
// lifecycle of a Process.
type TeardownFunc func() error
// ProcessFunc is a function that takes a process. Its main use case is goprocess.Go,
// which spawns a ProcessFunc in its own goroutine, and returns a corresponding
// Process object.
type ProcessFunc func(proc Process)
var nilProcessFunc = func(Process) {}
// Go is much like `go`: it runs a function in a newly spawned goroutine. The neat
// part of Go is that it provides Process object to communicate between the
// function and the outside world. Thus, callers can easily WaitFor, or Close the
// function. It is the function's responsibility to respect the Closing of its Process,
// namely it should exit (return) when <-Closing() is ready. It is simply:
//
// func Go(f ProcessFunc) Process {
// p := WithParent(Background())
// p.Go(f)
// return p
// }
//
// Note that a naive implementation of Go like the following would not work:
//
// func Go(f ProcessFunc) Process {
// return Background().Go(f)
// }
//
// This is because having the process you
func Go(f ProcessFunc) Process {
// return GoChild(Background(), f)
// we use two processes, one for communication, and
// one for ensuring we wait on the function (unclosable from the outside).
p := newProcess(nil)
waitFor := newProcess(nil)
p.WaitFor(waitFor) // prevent p from closing
go func() {
f(p)
waitFor.Close() // allow p to close.
p.Close() // ensure p closes.
}()
return p
}
// GoChild is like Go, but it registers the returned Process as a child of parent,
// **before** spawning the goroutine, which ensures proper synchronization with parent.
// It is somewhat like
//
// func GoChild(parent Process, f ProcessFunc) Process {
// p := WithParent(parent)
// p.Go(f)
// return p
// }
//
// And it is similar to the classic WaitGroup use case:
//
// func WaitGroupGo(wg sync.WaitGroup, child func()) {
// wg.Add(1)
// go func() {
// child()
// wg.Done()
// }()
// }
//
func GoChild(parent Process, f ProcessFunc) Process {
p := WithParent(parent)
p.Go(f)
return p
}
// Spawn is an alias of `Go`. In many contexts, Spawn is a
// well-known Process launching word, which fits our use case.
var Spawn = Go
// SpawnChild is an alias of `GoChild`. In many contexts, Spawn is a
// well-known Process launching word, which fits our use case.
var SpawnChild = GoChild
// WithTeardown constructs and returns a Process with a TeardownFunc.
// TeardownFunc tf will be called **exactly-once** when Process is
// Closing, after all Children have fully closed, and before p is Closed.
// In fact, Process p will not be Closed until tf runs and exits.
// See lifecycle in Process doc.
func WithTeardown(tf TeardownFunc) Process {
if tf == nil {
panic("nil tf TeardownFunc")
}
return newProcess(tf)
}
// WithParent constructs and returns a Process with a given parent.
func WithParent(parent Process) Process {
if parent == nil {
panic("nil parent Process")
}
q := newProcess(nil)
parent.AddChild(q)
return q
}
// WithSignals returns a Process that will Close() when any given signal fires.
// This is useful to bind Process trees to syscall.SIGTERM, SIGKILL, etc.
func WithSignals(sig ...os.Signal) Process {
p := WithParent(Background())
c := make(chan os.Signal, 1)
signal.Notify(c, sig...)
go func() {
<-c
signal.Stop(c)
p.Close()
}()
return p
}

299
vendor/github.com/jbenet/goprocess/impl-mutex.go generated vendored Normal file
View File

@@ -0,0 +1,299 @@
package goprocess
import (
"sync"
)
// process implements Process
type process struct {
children map[*processLink]struct{} // process to close with us
waitfors map[*processLink]struct{} // process to only wait for
waiters []*processLink // processes that wait for us. for gc.
teardown TeardownFunc // called to run the teardown logic.
closing chan struct{} // closed once close starts.
closed chan struct{} // closed once close is done.
closeErr error // error to return to clients of Close()
sync.Mutex
}
// newProcess constructs and returns a Process.
// It will call tf TeardownFunc exactly once:
// **after** all children have fully Closed,
// **after** entering <-Closing(), and
// **before** <-Closed().
func newProcess(tf TeardownFunc) *process {
return &process{
teardown: tf,
closed: make(chan struct{}),
closing: make(chan struct{}),
waitfors: make(map[*processLink]struct{}),
children: make(map[*processLink]struct{}),
}
}
func (p *process) WaitFor(q Process) {
if q == nil {
panic("waiting for nil process")
}
p.Lock()
defer p.Unlock()
select {
case <-p.Closed():
panic("Process cannot wait after being closed")
default:
}
pl := newProcessLink(p, q)
if p.waitfors == nil {
// This may be nil when we're closing. In close, we'll keep
// reading this map till it stays nil.
p.waitfors = make(map[*processLink]struct{}, 1)
}
p.waitfors[pl] = struct{}{}
go pl.AddToChild()
}
func (p *process) AddChildNoWait(child Process) {
if child == nil {
panic("adding nil child process")
}
p.Lock()
defer p.Unlock()
select {
case <-p.Closing():
// Either closed or closing, close child immediately. This is
// correct because we aren't asked to _wait_ on this child.
go child.Close()
// Wait for the child to start closing so the child is in the
// "correct" state after this function finishes (see #17).
<-child.Closing()
return
default:
}
pl := newProcessLink(p, child)
p.children[pl] = struct{}{}
go pl.AddToChild()
}
func (p *process) AddChild(child Process) {
if child == nil {
panic("adding nil child process")
}
p.Lock()
defer p.Unlock()
pl := newProcessLink(p, child)
select {
case <-p.Closed():
// AddChild must not be called on a dead process. Maybe that's
// too strict?
panic("Process cannot add children after being closed")
default:
}
select {
case <-p.Closing():
// Already closing, close child in background.
go child.Close()
// Wait for the child to start closing so the child is in the
// "correct" state after this function finishes (see #17).
<-child.Closing()
default:
// Only add the child when not closing. When closing, just add
// it to the "waitfors" list.
p.children[pl] = struct{}{}
}
if p.waitfors == nil {
// This may be be nil when we're closing. In close, we'll keep
// reading this map till it stays nil.
p.waitfors = make(map[*processLink]struct{}, 1)
}
p.waitfors[pl] = struct{}{}
go pl.AddToChild()
}
func (p *process) Go(f ProcessFunc) Process {
child := newProcess(nil)
waitFor := newProcess(nil)
child.WaitFor(waitFor) // prevent child from closing
// add child last, to prevent a closing parent from
// closing all of them prematurely, before running the func.
p.AddChild(child)
go func() {
f(child)
waitFor.Close() // allow child to close.
child.CloseAfterChildren() // close to tear down.
}()
return child
}
// SetTeardown to assign a teardown function
func (p *process) SetTeardown(tf TeardownFunc) {
if tf == nil {
panic("cannot set nil TeardownFunc")
}
p.Lock()
if p.teardown != nil {
panic("cannot SetTeardown twice")
}
p.teardown = tf
select {
case <-p.Closed():
// Call the teardown function, but don't set the error. We can't
// change that after we shut down.
tf()
default:
}
p.Unlock()
}
// Close is the external close function.
// it's a wrapper around internalClose that waits on Closed()
func (p *process) Close() error {
p.Lock()
// if already closing, or closed, get out. (but wait!)
select {
case <-p.Closing():
p.Unlock()
<-p.Closed()
return p.closeErr
default:
}
p.doClose()
p.Unlock()
return p.closeErr
}
func (p *process) Closing() <-chan struct{} {
return p.closing
}
func (p *process) Closed() <-chan struct{} {
return p.closed
}
func (p *process) Err() error {
<-p.Closed()
return p.closeErr
}
// the _actual_ close process.
func (p *process) doClose() {
// this function is only be called once (protected by p.Lock()).
// and it will panic (on closing channels) otherwise.
close(p.closing) // signal that we're shutting down (Closing)
// We won't add any children after we start closing so we can do this
// once.
for plc, _ := range p.children {
child := plc.Child()
if child != nil { // check because child may already have been removed.
go child.Close() // force all children to shut down
}
// safe to call multiple times per link
plc.ParentClear()
}
p.children = nil // clear them. release memory.
// We may repeatedly continue to add waiters while we wait to close so
// we have to do this in a loop.
for len(p.waitfors) > 0 {
// we must be careful not to iterate over waitfors directly, as it may
// change under our feet.
wf := p.waitfors
p.waitfors = nil // clear them. release memory.
for w, _ := range wf {
// Here, we wait UNLOCKED, so that waitfors who are in the middle of
// adding a child to us can finish. we will immediately close the child.
p.Unlock()
<-w.ChildClosed() // wait till all waitfors are fully closed (before teardown)
p.Lock()
// safe to call multiple times per link
w.ParentClear()
}
}
if p.teardown != nil {
p.closeErr = p.teardown() // actually run the close logic (ok safe to teardown)
}
close(p.closed) // signal that we're shut down (Closed)
// go remove all the parents from the process links. optimization.
go func(waiters []*processLink) {
for _, pl := range waiters {
pl.ClearChild()
pr, ok := pl.Parent().(*process)
if !ok {
// parent has already been called to close
continue
}
pr.Lock()
delete(pr.waitfors, pl)
delete(pr.children, pl)
pr.Unlock()
}
}(p.waiters) // pass in so
p.waiters = nil // clear them. release memory.
}
// We will only wait on the children we have now.
// We will not wait on children added subsequently.
// this may change in the future.
func (p *process) CloseAfterChildren() error {
p.Lock()
select {
case <-p.Closed():
p.Unlock()
return p.Close() // get error. safe, after p.Closed()
default:
}
p.Unlock()
// here only from one goroutine.
nextToWaitFor := func() Process {
p.Lock()
defer p.Unlock()
for e, _ := range p.waitfors {
c := e.Child()
if c == nil {
continue
}
select {
case <-c.Closed():
default:
return c
}
}
return nil
}
// wait for all processes we're waiting for are closed.
// the semantics here are simple: we will _only_ close
// if there are no processes currently waiting for.
for next := nextToWaitFor(); next != nil; next = nextToWaitFor() {
<-next.Closed()
}
// YAY! we're done. close
return p.Close()
}

128
vendor/github.com/jbenet/goprocess/link.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
package goprocess
import (
"sync"
)
// closedCh is an alread-closed channel. used to return
// in cases where we already know a channel is closed.
var closedCh chan struct{}
func init() {
closedCh = make(chan struct{})
close(closedCh)
}
// a processLink is an internal bookkeeping datastructure.
// it's used to form a relationship between two processes.
// It is mostly for keeping memory usage down (letting
// children close and be garbage-collected).
type processLink struct {
// guards all fields.
// DO NOT HOLD while holding process locks.
// it may be slow, and could deadlock if not careful.
sync.Mutex
parent Process
child Process
}
func newProcessLink(p, c Process) *processLink {
return &processLink{
parent: p,
child: c,
}
}
// Closing returns whether the child is closing
func (pl *processLink) ChildClosing() <-chan struct{} {
// grab a hold of it, and unlock, as .Closing may block.
pl.Lock()
child := pl.child
pl.Unlock()
if child == nil { // already closed? memory optimization.
return closedCh
}
return child.Closing()
}
func (pl *processLink) ChildClosed() <-chan struct{} {
// grab a hold of it, and unlock, as .Closed may block.
pl.Lock()
child := pl.child
pl.Unlock()
if child == nil { // already closed? memory optimization.
return closedCh
}
return child.Closed()
}
func (pl *processLink) ChildClose() {
// grab a hold of it, and unlock, as .Closed may block.
pl.Lock()
child := pl.child
pl.Unlock()
if child != nil { // already closed? memory optimization.
child.Close()
}
}
func (pl *processLink) ClearChild() {
pl.Lock()
pl.child = nil
pl.Unlock()
}
func (pl *processLink) ParentClear() {
pl.Lock()
pl.parent = nil
pl.Unlock()
}
func (pl *processLink) Child() Process {
pl.Lock()
defer pl.Unlock()
return pl.child
}
func (pl *processLink) Parent() Process {
pl.Lock()
defer pl.Unlock()
return pl.parent
}
func (pl *processLink) AddToChild() {
cp := pl.Child()
// is it a *process ? if not... panic.
var c *process
switch cp := cp.(type) {
case *process:
c = cp
case *bgProcess:
// Background process never closes so we don't need to do
// anything.
return
default:
panic("goprocess does not yet support other process impls.")
}
// first, is it Closed?
c.Lock()
select {
case <-c.Closed():
c.Unlock()
// already closed. must not add.
// we must clear it, though. do so without the lock.
pl.ClearChild()
return
default:
// put the process link into q's waiters
c.waiters = append(c.waiters, pl)
c.Unlock()
}
}

14
vendor/github.com/jbenet/goprocess/package.json generated vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"author": "whyrusleeping",
"bugs": {
"url": "https://github.com/jbenet/goprocess"
},
"gx": {
"dvcsimport": "github.com/jbenet/goprocess"
},
"gxVersion": "0.8.0",
"language": "go",
"license": "",
"name": "goprocess",
"version": "1.0.0"
}