package tokenboard import ( "encoding/json" "git.openprivacy.ca/cwtch.im/tapir" "git.openprivacy.ca/cwtch.im/tapir/applications" "git.openprivacy.ca/cwtch.im/tapir/primitives/auditable" "git.openprivacy.ca/cwtch.im/tapir/primitives/privacypass" "git.openprivacy.ca/openprivacy/log" ) // NewTokenBoardClient generates a new Client for Token Board func NewTokenBoardClient(store *auditable.Store, handler AppHandler, paymentHandler privacypass.TokenPaymentHandler) tapir.Application { tba := new(Client) tba.AuditableStore = store tba.handler = handler tba.paymentHandler = paymentHandler return tba } // Client defines a client for the TokenBoard server type Client struct { applications.AuthApp connection tapir.Connection AuditableStore *auditable.Store paymentHandler privacypass.TokenPaymentHandler handler AppHandler } // NewInstance Client a new TokenBoardApp func (ta *Client) NewInstance() tapir.Application { tba := new(Client) tba.AuditableStore = ta.AuditableStore tba.handler = ta.handler tba.paymentHandler = ta.paymentHandler return tba } // Init initializes the cryptographic TokenBoardApp func (ta *Client) Init(connection tapir.Connection) { ta.AuthApp.Init(connection) if connection.HasCapability(applications.AuthCapability) { ta.connection = connection go ta.Listen() return } connection.Close() } // Listen processes the messages for this application func (ta *Client) Listen() { for { log.Debugf("Client waiting...") data := ta.connection.Expect() if len(data) == 0 { log.Debugf("Server closed the connection...") return // connection is closed } var message Message json.Unmarshal(data, &message) switch message.MessageType { case postResultMessage: log.Debugf("Post result: %x", message.PostResult.Proof) case replayResultMessage: var state auditable.State log.Debugf("Replaying %v Messages...", message.ReplayResult.NumMessages) lastCommit := ta.AuditableStore.LatestCommit for i := 0; i < message.ReplayResult.NumMessages; i++ { message := ta.connection.Expect() state.Messages = append(state.Messages, message) } data := ta.connection.Expect() var signedProof auditable.SignedProof json.Unmarshal(data, &signedProof) state.SignedProof = signedProof err := ta.AuditableStore.AppendState(state) if err == nil { log.Debugf("Successfully updated Auditable Store %v", ta.AuditableStore.LatestCommit) ta.handler.HandleNewMessages(lastCommit) } else { log.Debugf("Error updating Auditable Store %v", err) } } } } // Replay posts a Replay Message to the server. func (ta *Client) Replay() { log.Debugf("Sending replay request for %v", ta.AuditableStore.LatestCommit) data, _ := json.Marshal(Message{MessageType: replayRequestMessage, ReplayRequest: replayRequest{LastCommit: ta.AuditableStore.LatestCommit}}) ta.connection.Send(data) } // PurchaseTokens purchases the given number of tokens from the server (using the provided payment handler) func (ta *Client) PurchaseTokens() { ta.paymentHandler.MakePayment() } // Post sends a Post Request to the server func (ta *Client) Post(message auditable.Message) bool { token, err := ta.paymentHandler.NextToken(message, ta.connection.Hostname()) if err == nil { data, _ := json.Marshal(Message{MessageType: postRequestMessage, PostRequest: postRequest{Token: token, Message: message}}) ta.connection.Send(data) return true } log.Debugf("No Valid Tokens: %v", err) return false }