-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathaccounts.go
More file actions
149 lines (116 loc) · 3.63 KB
/
accounts.go
File metadata and controls
149 lines (116 loc) · 3.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"container/ring"
"errors"
"fmt"
"sync"
"time"
"github.com/distributeddesigns/currency"
)
type portfolio map[string]uint64
// Account : State of a particular Account
type account struct {
userID string
balance currency.Currency
portfolio portfolio
pendingBuys txStack
pendingSells txStack
summary *ring.Ring
sync.Mutex
}
const (
summarySize = 20
)
// newAccountForUser creates an empty account for the given user
func newAccountForUser(userID string) *account {
var ac = account{userID: userID}
ac.portfolio = make(portfolio)
ac.summary = ring.New(summarySize)
ac.AddSummaryItem("Created")
return &ac
}
// AddFunds : Increases the balance of the account
func (ac *account) AddFunds(amount currency.Currency) {
consoleLog.Debugf("Old balance for %s is %s", ac.userID, ac.balance)
ac.balance.Add(amount)
ac.AddSummaryItem("Added " + amount.String())
consoleLog.Debugf("New balance for %s is %s", ac.userID, ac.balance)
}
// RemoveFunds : Decrease balance of the account
func (ac *account) RemoveFunds(amount currency.Currency) error {
consoleLog.Debugf("Old balance for %s is %s", ac.userID, ac.balance)
err := ac.balance.Sub(amount)
if err != nil {
ac.AddSummaryItem("Removed " + amount.String())
}
consoleLog.Debugf("New balance for %s is %s", ac.userID, ac.balance)
return err
}
// AddStock grants the user the specified amount of stock in their portfolio
func (ac *account) AddStock(stock string, quantity uint64) {
consoleLog.Debugf("Old portfolio for %s: %d x %s",
ac.userID, ac.portfolio[stock], stock)
ac.portfolio[stock] += quantity
ac.AddSummaryItem(fmt.Sprintf("Added %dx%s", quantity, stock))
consoleLog.Debugf("New portfolio for %s: %d x %s",
ac.userID, ac.portfolio[stock], stock)
}
// RemoveStock surrenders stock from the user's portfolio
func (ac *account) RemoveStock(stock string, quantity uint64) error {
// Check to see if user can surrender that much stock
if ac.portfolio[stock] < quantity {
return errors.New("User does not have enough stock to surrender")
}
consoleLog.Debugf("Old portfolio for %s: %d x %s",
ac.userID, ac.portfolio[stock], stock)
ac.portfolio[stock] -= quantity
ac.AddSummaryItem(fmt.Sprintf("Removed %dx%s", quantity, stock))
consoleLog.Debugf("New portfolio for %s: %d x %s",
ac.userID, ac.portfolio[stock], stock)
return nil
}
// PruneExpiredTxs will remove all pendingTxs that are expired
func (ac *account) PruneExpiredTxs() {
ac.Lock()
ac.AddSummaryItem("Starting expired TX cleanup")
expiredBuys := ac.pendingBuys.SplitExpired()
expiredSells := ac.pendingSells.SplitExpired()
ac.Unlock()
for _, buy := range *expiredBuys {
buy.RollBack()
}
for _, sell := range *expiredSells {
sell.RollBack()
}
ac.AddSummaryItem("Finished expired TX cleanup")
}
type summaryItem struct {
loggedAt time.Time
message string
}
func (ac *account) AddSummaryItem(s string) {
// Since ring.Do() always goes _forward_ we want to make sure the forward
// order of elements is newest -> oldest. This saves us a reverse after
// we convert the ring to a slice.
ac.summary = ac.summary.Prev()
ac.summary.Value = summaryItem{time.Now(), s}
}
// GetSummary returns a list of the user's most recent account activities,
// sorted newest to oldest
func (ac *account) GetSummary() []summaryItem {
s := make([]summaryItem, summarySize)
// Track non-nil items added
var i int
ac.summary.Do(func(node interface{}) {
if node != nil {
s[i] = node.(summaryItem)
i++
}
})
// If we didn't fill the return slice only send back the non-nil items.
// Complaint: shrinking slices in Go is D:
if i < summarySize {
return s[:i]
}
return s
}