github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/maps/track.go (about)

     1  package maps
     2  
     3  import (
     4  	"encoding/base64"
     5  	"fmt"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/keybase/client/go/chat/types"
    10  	"github.com/keybase/client/go/protocol/chat1"
    11  	"github.com/keybase/client/go/protocol/gregor1"
    12  )
    13  
    14  type locationTrack struct {
    15  	sync.Mutex
    16  	stopCh   chan struct{}
    17  	updateCh chan chat1.Coordinate
    18  
    19  	convID             chat1.ConversationID
    20  	msgID              chat1.MessageID
    21  	endTime            time.Time
    22  	allCoords          []chat1.Coordinate
    23  	getCurrentPosition bool
    24  	maxCoords          int
    25  	stopped            bool
    26  	perm               chat1.UIWatchPositionPerm
    27  }
    28  
    29  func (t *locationTrack) GetCoords() (res []chat1.Coordinate) {
    30  	t.Lock()
    31  	defer t.Unlock()
    32  	res = make([]chat1.Coordinate, len(t.allCoords))
    33  	copy(res, t.allCoords)
    34  	return res
    35  }
    36  
    37  func (t *locationTrack) capLocked(maxCoords int) {
    38  	if len(t.allCoords) < maxCoords || len(t.allCoords) == 0 {
    39  		return
    40  	}
    41  	newCoords := make([]chat1.Coordinate, maxCoords)
    42  	copy(newCoords, t.allCoords[len(t.allCoords)-maxCoords:len(t.allCoords)])
    43  	newCoords = append([]chat1.Coordinate{t.allCoords[0]}, newCoords...)
    44  	t.allCoords = newCoords
    45  }
    46  
    47  func (t *locationTrack) Drain(coord chat1.Coordinate) (res int) {
    48  	t.Lock()
    49  	defer t.Unlock()
    50  	defer t.capLocked(t.maxCoords)
    51  	if !coord.IsZero() {
    52  		t.allCoords = append(t.allCoords, coord)
    53  		res++
    54  	}
    55  	for {
    56  		select {
    57  		case coord := <-t.updateCh:
    58  			t.allCoords = append(t.allCoords, coord)
    59  			res++
    60  		default:
    61  			return res
    62  		}
    63  	}
    64  }
    65  
    66  func (t *locationTrack) SetCoords(coords []chat1.Coordinate) {
    67  	t.Lock()
    68  	defer t.Unlock()
    69  	t.allCoords = coords
    70  	t.capLocked(t.maxCoords)
    71  }
    72  
    73  func (t *locationTrack) Stop() {
    74  	t.Lock()
    75  	defer t.Unlock()
    76  	if t.stopped {
    77  		return
    78  	}
    79  	t.stopped = true
    80  	close(t.stopCh)
    81  }
    82  
    83  func (t *locationTrack) IsStopped() bool {
    84  	t.Lock()
    85  	defer t.Unlock()
    86  	return t.stopped
    87  }
    88  
    89  func (t *locationTrack) Key() types.LiveLocationKey {
    90  	key := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%d", t.convID, t.msgID)))
    91  	return types.LiveLocationKey(key)
    92  }
    93  
    94  func (t *locationTrack) ToDisk() diskLocationTrack {
    95  	return diskLocationTrack{
    96  		ConvID:             t.convID,
    97  		MsgID:              t.msgID,
    98  		EndTime:            gregor1.ToTime(t.endTime),
    99  		Coords:             t.GetCoords(),
   100  		GetCurrentPosition: t.getCurrentPosition,
   101  		MaxCoords:          t.maxCoords,
   102  		Stopped:            t.stopped,
   103  	}
   104  }
   105  
   106  func newLocationTrack(convID chat1.ConversationID, msgID chat1.MessageID,
   107  	endTime time.Time, getCurrentPosition bool, maxCoords int, stopped bool) *locationTrack {
   108  	perm := chat1.UIWatchPositionPerm_BASE
   109  	if !getCurrentPosition {
   110  		perm = chat1.UIWatchPositionPerm_ALWAYS
   111  	}
   112  	return &locationTrack{
   113  		stopCh:             make(chan struct{}),
   114  		updateCh:           make(chan chat1.Coordinate, 50),
   115  		convID:             convID,
   116  		msgID:              msgID,
   117  		endTime:            endTime,
   118  		getCurrentPosition: getCurrentPosition,
   119  		maxCoords:          maxCoords,
   120  		stopped:            stopped,
   121  		perm:               perm,
   122  	}
   123  }
   124  
   125  func newLocationTrackFromDisk(d diskLocationTrack) *locationTrack {
   126  	t := newLocationTrack(d.ConvID, d.MsgID, gregor1.FromTime(d.EndTime), d.GetCurrentPosition, d.MaxCoords,
   127  		d.Stopped)
   128  	t.allCoords = d.Coords
   129  	return t
   130  }