cleanup
This commit is contained in:
parent
d5126bfb71
commit
2ff289becf
122
pubsub/pt.go
122
pubsub/pt.go
@ -13,10 +13,10 @@ const (
|
|||||||
Done
|
Done
|
||||||
)
|
)
|
||||||
|
|
||||||
type state struct {
|
type subscriberState struct {
|
||||||
step Step
|
step Step
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
scs []chan<- string
|
subChans []chan<- string
|
||||||
}
|
}
|
||||||
|
|
||||||
type InvalidState struct{ Step Step }
|
type InvalidState struct{ Step Step }
|
||||||
@ -39,115 +39,105 @@ type ProgressTracker interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type progressTracker struct {
|
type progressTracker struct {
|
||||||
subscribers map[string]*state
|
subscribers map[string]*subscriberState
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProgressTracker() ProgressTracker {
|
func NewProgressTracker() ProgressTracker {
|
||||||
return &progressTracker{
|
return &progressTracker{
|
||||||
subscribers: map[string]*state{},
|
subscribers: map[string]*subscriberState{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *progressTracker) Publish(id string) (chan<- string, error) {
|
func (pt *progressTracker) Publish(id string) (chan<- string, error) {
|
||||||
var ste *state
|
var state *subscriberState
|
||||||
func() {
|
func() {
|
||||||
pt.m.Lock()
|
pt.m.Lock()
|
||||||
defer pt.m.Unlock()
|
defer pt.m.Unlock()
|
||||||
ste = pt.subscribers[id]
|
state = pt.subscribers[id]
|
||||||
if ste == nil {
|
if state == nil {
|
||||||
fmt.Println("new pub")
|
state = &subscriberState{step: NotStarted}
|
||||||
ste = &state{step: NotStarted}
|
pt.subscribers[id] = state
|
||||||
pt.subscribers[id] = ste
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err := func() error {
|
err := func() error {
|
||||||
ste.m.Lock()
|
state.m.Lock()
|
||||||
defer ste.m.Unlock()
|
defer state.m.Unlock()
|
||||||
if ste.step != NotStarted {
|
if state.step != NotStarted {
|
||||||
return InvalidState{ste.step}
|
return InvalidState{state.step}
|
||||||
}
|
}
|
||||||
ste.step = Publishing
|
state.step = Publishing
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("About to start loop")
|
prodChan := make(chan string, 100)
|
||||||
pc := make(chan string, 100)
|
|
||||||
go func() {
|
go func() {
|
||||||
var upd string
|
var update string
|
||||||
ok := true
|
prodChanOpen := true
|
||||||
for {
|
for {
|
||||||
fmt.Println("In producer loop")
|
for prodChanOpen {
|
||||||
done := false
|
update, prodChanOpen = <-prodChan
|
||||||
for !done && ok {
|
if !prodChanOpen {
|
||||||
// upd, ok = <-pc
|
break
|
||||||
// fmt.Println("got msg", upd, ok)
|
}
|
||||||
select {
|
select {
|
||||||
case upd, ok = <-pc:
|
case update, prodChanOpen = <-prodChan:
|
||||||
fmt.Println("got msg in select", upd, ok)
|
default:
|
||||||
default:
|
break
|
||||||
fmt.Println("in default")
|
|
||||||
done = true
|
|
||||||
}
|
}
|
||||||
fmt.Println(done, ok)
|
|
||||||
}
|
}
|
||||||
fmt.Println("About to send to subscribers")
|
|
||||||
var scs []chan<- string
|
var scs []chan<- string
|
||||||
func() {
|
func() {
|
||||||
ste.m.Lock()
|
state.m.Lock()
|
||||||
defer ste.m.Unlock()
|
defer state.m.Unlock()
|
||||||
fmt.Println("Inside lock")
|
scs = state.subChans
|
||||||
scs = ste.scs
|
if !prodChanOpen {
|
||||||
if !ok {
|
for _, subChan := range scs {
|
||||||
for _, sc := range scs {
|
close(subChan)
|
||||||
fmt.Println("Closing subs channel")
|
|
||||||
fmt.Printf("From code: chan is %+v and %#v\n", sc, sc)
|
|
||||||
close(sc)
|
|
||||||
}
|
}
|
||||||
ste.step = Done
|
state.step = Done
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
fmt.Println("Len of subs", len(scs))
|
if !prodChanOpen {
|
||||||
if !ok {
|
|
||||||
fmt.Println("channel closed, good bye")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, sc := range scs {
|
for _, subChan := range scs {
|
||||||
select {
|
select {
|
||||||
case sc <- upd:
|
case subChan <- update:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return pc, nil
|
return prodChan, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *progressTracker) Subscribe(id string) <-chan string {
|
func (pt *progressTracker) Subscribe(id string) <-chan string {
|
||||||
c := make(chan string)
|
c := make(chan string, 1)
|
||||||
pt.m.Lock()
|
var state *subscriberState
|
||||||
ste := pt.subscribers[id]
|
func() {
|
||||||
if ste == nil {
|
pt.m.Lock()
|
||||||
fmt.Println("new sub")
|
defer pt.m.Unlock()
|
||||||
pt.subscribers[id] = &state{
|
state = pt.subscribers[id]
|
||||||
step: NotStarted,
|
if state == nil {
|
||||||
scs: []chan<- string{c},
|
pt.subscribers[id] = &subscriberState{
|
||||||
|
step: NotStarted,
|
||||||
|
subChans: []chan<- string{c},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}()
|
||||||
pt.m.Unlock()
|
if state == nil {
|
||||||
if ste == nil {
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
ste.m.Lock()
|
state.m.Lock()
|
||||||
defer ste.m.Unlock()
|
defer state.m.Unlock()
|
||||||
if ste.step == Done {
|
if state.step == Done {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fmt.Println("appending to scs")
|
state.subChans = append(state.subChans, c)
|
||||||
ste.scs = append(ste.scs, c)
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package pubsub
|
package pubsub
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDupePublisher(t *testing.T) {
|
func TestDupePublisher(t *testing.T) {
|
||||||
@ -15,6 +15,8 @@ func TestDupePublisher(t *testing.T) {
|
|||||||
|
|
||||||
if _, err := pt.Publish("foo"); err == nil {
|
if _, err := pt.Publish("foo"); err == nil {
|
||||||
t.Fatal("Dupe publisher should give error but got nil")
|
t.Fatal("Dupe publisher should give error but got nil")
|
||||||
|
} else {
|
||||||
|
t.Logf("Got err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := pt.Publish("bar"); err != nil {
|
if _, err := pt.Publish("bar"); err != nil {
|
||||||
@ -26,8 +28,6 @@ func TestSubSub(t *testing.T) {
|
|||||||
pt := NewProgressTracker()
|
pt := NewProgressTracker()
|
||||||
c1 := pt.Subscribe("foo")
|
c1 := pt.Subscribe("foo")
|
||||||
select {
|
select {
|
||||||
//Not Working: expected 1 expression
|
|
||||||
//case _, ok <- c1:
|
|
||||||
case <-c1:
|
case <-c1:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
@ -42,39 +42,34 @@ func TestSubSub(t *testing.T) {
|
|||||||
|
|
||||||
func TestPubSub(t *testing.T) {
|
func TestPubSub(t *testing.T) {
|
||||||
pt := NewProgressTracker()
|
pt := NewProgressTracker()
|
||||||
pc, _ := pt.Publish("foo")
|
pc, err := pt.Publish("foo")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
|
}
|
||||||
if pc == nil {
|
if pc == nil {
|
||||||
t.Fatal("Should not get nil channel")
|
t.Fatal("Should not get nil channel")
|
||||||
}
|
}
|
||||||
sc := pt.Subscribe("foo")
|
sc := pt.Subscribe("foo")
|
||||||
fmt.Printf("From test: chan is %+v and %#v\n", sc, sc)
|
|
||||||
if sc == nil {
|
if sc == nil {
|
||||||
t.Fatal("Should not get nil channel")
|
t.Fatal("Should not get nil channel")
|
||||||
}
|
}
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
fmt.Println("Subscriber start")
|
|
||||||
c := 0
|
|
||||||
for range sc {
|
for range sc {
|
||||||
fmt.Println("Subscriber got msg")
|
|
||||||
c++
|
|
||||||
}
|
|
||||||
fmt.Println("Subscriber received close")
|
|
||||||
if c == 0 {
|
|
||||||
fmt.Println("Should have gotten update")
|
|
||||||
}
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
fmt.Println("Subscriber Done")
|
|
||||||
}()
|
}()
|
||||||
fmt.Println("Producer Start")
|
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
fmt.Println("Producer Sent")
|
|
||||||
pc <- "blah"
|
pc <- "blah"
|
||||||
|
if i == 4 || i == 5 {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
close(pc)
|
close(pc)
|
||||||
fmt.Println("Producer close")
|
|
||||||
t.Log("Now waiting")
|
|
||||||
fmt.Println("Now waiting")
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
sc2 := pt.Subscribe("foo")
|
||||||
|
if sc2 != nil {
|
||||||
|
t.Fatal("Subscriber after publisher done should return nil")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitlab.com/balki/ytui/pubsub"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("vim-go")
|
|
||||||
foo()
|
|
||||||
// bar()
|
|
||||||
}
|
|
||||||
|
|
||||||
func foo() {
|
|
||||||
pt := pubsub.NewProgressTracker()
|
|
||||||
pc, err := pt.Publish("id1")
|
|
||||||
sc := pt.Subscribe("id1")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
fmt.Println("subscriber loop")
|
|
||||||
for msg := range sc {
|
|
||||||
fmt.Println("received", msg)
|
|
||||||
}
|
|
||||||
fmt.Println("subscriber loop done")
|
|
||||||
wg.Done()
|
|
||||||
}()
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
msg := fmt.Sprint("msg_", i)
|
|
||||||
// fmt.Println("sending: ", msg)
|
|
||||||
pc <- msg
|
|
||||||
}
|
|
||||||
close(pc)
|
|
||||||
wg.Wait()
|
|
||||||
fmt.Println("sleeping")
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bar() {
|
|
||||||
c := make(chan int, 100)
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
c <- i
|
|
||||||
}
|
|
||||||
close(c)
|
|
||||||
|
|
||||||
ok := true
|
|
||||||
var v int
|
|
||||||
for ok {
|
|
||||||
select {
|
|
||||||
case v, ok = <-c:
|
|
||||||
fmt.Println(v, ok)
|
|
||||||
default:
|
|
||||||
fmt.Println("in default")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Println("done")
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user