Skip to content
Snippets Groups Projects
Commit da1e1a36 authored by Jono Wenger's avatar Jono Wenger
Browse files

Fix ui and add test mode

parent 6b4391d2
No related branches found
No related tags found
No related merge requests found
package main
import (
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/api"
"gitlab.com/elixxir/client/interfaces"
"gitlab.com/elixxir/client/interfaces/contact"
"gitlab.com/elixxir/client/interfaces/params"
"gitlab.com/elixxir/client/single"
"gitlab.com/elixxir/client/stoppable"
"gitlab.com/xx_network/primitives/utils"
"io/ioutil"
"gitlab.com/elixxir/client/single"
"os"
jww "github.com/spf13/jwalterweatherman"
"time"
)
func initClient() (*api.Client, *single.Manager) {
type ClientAPI interface {
StartNetworkFollower() (<-chan interfaces.ClientError, error)
GetHealth() interfaces.HealthTracker
AddService(sp api.ServiceProcess)
GetNodeRegistrationStatus() (int, int, error)
}
type SingleManager interface {
StartProcesses() stoppable.Stoppable
TransmitSingleUse(contact.Contact, []byte, string, uint8, single.ReplyComm,
time.Duration) error
}
type TestClient struct {
}
func (tc TestClient) StartNetworkFollower() (<-chan interfaces.ClientError, error) {
return nil, nil
}
func (tc TestClient) GetHealth() interfaces.HealthTracker {
return nil
}
func (tc TestClient) AddService(api.ServiceProcess) {
}
var NodeRegistrationStatusTrack = 0
func (tc TestClient) GetNodeRegistrationStatus() (int, int, error) {
NodeRegistrationStatusTrack++
return NodeRegistrationStatusTrack, 30, nil
}
type TestSingle struct {
}
func (ts TestSingle) StartProcesses() stoppable.Stoppable {
return nil
}
func (ts TestSingle) TransmitSingleUse(_ contact.Contact, payload []byte,
_ string, _ uint8, callback single.ReplyComm, _ time.Duration) error {
go func() {
time.Sleep(5 * time.Second)
// callback(payload, errors.New("ERROR"))
callback(payload, nil)
}()
// return errors.New("ERROR")
return nil
}
func initClient(test bool) (ClientAPI, SingleManager) {
if test {
time.Sleep(1 * time.Second)
return TestClient{}, TestSingle{}
}
createClient()
pass := password
......@@ -41,12 +104,11 @@ func initClient() (*api.Client, *single.Manager) {
return client, singleMng
}
func createClient() *api.Client {
pass := password
storeDir := session
//create a new client if none exist
// Create a new client if none exist
if _, err := os.Stat(storeDir); os.IsNotExist(err) {
// Load NDF
ndfJSON, err := ioutil.ReadFile(ndfPath)
......@@ -69,7 +131,6 @@ func createClient() *api.Client {
return client
}
func waitUntilConnected(connected chan bool) {
timeoutTimer := time.NewTimer(90 * time.Second)
isConnected := false
......
This diff is collapsed.
......@@ -4,7 +4,14 @@ go 1.13
require (
github.com/dtylman/gowd v0.0.0-20190619113956-15e38debca22
github.com/nyaruka/phonenumbers v1.0.68 // indirect
github.com/spf13/jwalterweatherman v1.1.0
gitlab.com/elixxir/client v1.5.1-0.20210322233828-da6ce1646ade
github.com/stretchr/testify v1.7.0 // indirect
github.com/zeebo/assert v1.3.0 // indirect
gitlab.com/elixxir/client v1.5.1-0.20210323170252-7aa7a34f2682
gitlab.com/xx_network/primitives v0.0.4-0.20210309173740-eb8cd411334a
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
golang.org/x/net v0.0.0-20210323141857-08027d57d8cf // indirect
google.golang.org/genproto v0.0.0-20210323160006-e668133fea6a // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
This diff is collapsed.
img/favicon-16x16.png

1.05 KiB

img/favicon-32x32.png

1.55 KiB

img/favicon.ico

14.7 KiB

img/xx_logo.png

4.02 KiB

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="26" height="29" viewBox="0 0 26 29">
<defs>
<path id="o9gfh6ivaa" d="M0.192 0.041L18.206 0.041 18.206 20.206 0.192 20.206z"/>
</defs>
<g fill="none" fill-rule="evenodd">
<g>
<g>
<path fill="#037281" d="M18.957 6.552c.635 1.395.987 2.925.987 4.53 0 .051.008.1.01.151l5.252-4.666V1l-6.249 5.552z" transform="translate(-35 -42) translate(35 42)"/>
<g transform="translate(-35 -42) translate(35 42) translate(7 .959)">
<mask id="1p1nayj4gb" fill="#fff">
<use xlink:href="#o9gfh6ivaa"/>
</mask>
<path fill="#037281" d="M11.28 10.124C11.28 4.564 6.306.04.192.04v4.162c3.732 0 6.776 2.538 6.914 5.7L4.28 12.415c.752 1.312 1.245 2.768 1.411 4.313l2.522-2.241c1.792 3.38 5.6 5.719 9.994 5.719v-4.161c-3.819 0-6.926-2.656-6.926-5.921" mask="url(#1p1nayj4gb)"/>
</g>
<path fill="#037281" d="M18.015 28.93v-4.162c-3.819 0-6.927-2.656-6.927-5.92 0-5.56-4.974-10.083-11.088-10.083v4.161c3.245 0 5.969 1.92 6.717 4.5l-1.462 1.298-3.028 2.69L0 23.392v5.566l7.572-6.725c1.533 3.898 5.634 6.696 10.443 6.696" transform="translate(-35 -42) translate(35 42)"/>
</g>
</g>
</g>
</svg>
......@@ -7,7 +7,12 @@
<script type="text/javascript" src="js/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"/>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<title>App</title>
<script type="text/javascript" src='js/solitaireVictory.js'></script>
<script type="text/javascript" src="js/code.js"></script>
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png">
<link rel="shortcut icon" type="image/x-icon" href="img/favicon.ico">
<title>xx Coin Game</title>
</head>
<body id="app"></body>
......
var pattern = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'b', 'a'];
var current = 0;
var keyHandler = function (event) {
// If the key isn't in the pattern, or isn't the current key in the pattern, reset
if (pattern.indexOf(event.key) < 0 || event.key !== pattern[current]) {
current = 0;
return;
}
// Update how much of the pattern is complete
current++;
// If complete, alert and reset
if (pattern.length === current) {
current = 0;
//window.alert('You found it!');
$('img').solitaireVictory({fallToLeft: true});
}
};
// Listen for keydown events
document.addEventListener('keydown', keyHandler, false);
\ No newline at end of file
(function( $ ) {
$.fn.solitaireVictory = function(settings) {
settings = settings || {};
var g = settings.g || -3;
var dt = settings.dt || 20;
var bounce = settings.bounce || 0.7;
var endVelocity = settings.endVelocity || 20;
var stagger = settings.stagger || 200;
var relativeToDocument = settings.relativeToDocument || false;
var clear = settings.clear || false;
var fallToLeft = settings.fallToLeft || false;
var body = $('body');
var windowHeight = (relativeToDocument ? $(document).height() : $(window).height());
var fallIteration = function(elem, elemHeight, oldPos, dx, dy) {
var copy = elem.clone();
body.append(copy);
var newTop = Math.min(windowHeight - elemHeight, oldPos.top + dy);
var newPos = {
left: oldPos.left + dx,
top: newTop
};
copy.offset(newPos);
if (Math.abs(newTop - (windowHeight - elemHeight)) < 5) {
if (dy < 0 || dy > endVelocity) {
dy *= -1*bounce;
setTimeout(function() {
fallIteration(copy, elemHeight, newPos, dx, dy);
}, dt);
}
} else {
dy = dy - g;
setTimeout(function() {
fallIteration(copy, elemHeight, newPos, dx, dy);
}, dt);
}
};
var startFall = function(elem, height, stagger) {
var dx = settings.dx || Math.floor((Math.random()*10)) + 5;
if (fallToLeft) {
dx = -dx;
}
var copy = elem.clone();
copy.addClass('solitaire-victory-clone');
if (relativeToDocument) {
copy.css('position', 'absolute');
} else {
copy.css('position', 'fixed');
}
var originalOffset = elem.offset();
copy.offset({top: originalOffset.top, left: originalOffset.left});
body.append(copy);
setTimeout(function() {fallIteration(copy, height, copy.offset(), dx, 0);}, stagger);
};
if (clear) $('.solitaire-victory-clone').remove();
this.each(function(index) {
var obj = $(this);
if (relativeToDocument || obj.offset().top < $(window).height()) {
if (!obj.hasClass('solitaire-victory-clone')) {
startFall(obj, obj.height(), index*stagger);
}
}
});
};
}( jQuery ));
\ No newline at end of file
......@@ -3,8 +3,11 @@ package main
import (
"github.com/dtylman/gowd"
"github.com/dtylman/gowd/bootstrap"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/interfaces/contact"
"gitlab.com/elixxir/client/single"
"regexp"
"strconv"
"strings"
"time"
)
......@@ -15,32 +18,105 @@ var logPath = "client.log"
var botContactPath = "botContact.bin"
var botContact contact.Contact
var singleMngr *single.Manager
var singleMngr SingleManager
var client ClientAPI
var body *gowd.Element
var testMode = false
func main() {
initLog()
botContact = readBotContact()
_, singleMngr = initClient()
// creates a new bootstrap fluid container
body = bootstrap.NewContainer(false)
// add some elements using the object model
div := bootstrap.NewElement("div", "well")
row := bootstrap.NewRow(bootstrap.NewColumn(bootstrap.ColumnSmall, 3, div))
body.AddElement(row)
div.SetAttribute("style", "font-size:1.5em;margin-top:25px;")
body.AddElement(div)
logo := bootstrap.NewElement("img", "")
logo.SetAttribute("src", "img/xx_logo.svg")
logo.SetAttribute("style", "float:right;margin: -10px -10px 0 0;")
logo.SetAttribute("id", "logo")
div.AddElement(logo)
progressBarTitle := bootstrap.NewElement(gowd.Heading4, "")
progressBarTitle.SetAttribute("style", "text-align:center;")
progressBarTitle.SetText("Connecting to network")
spinner := bootstrap.NewElement("span", "spinner-grow")
spinner.SetAttribute("role", "status")
spinner.SetAttribute("style", "width: 3rem; height: 3rem;text-align:center;margin:0 auto;")
spinnerContainer := bootstrap.NewElement("div", "")
spinnerContainer.SetAttribute("style", "text-align: center")
spinnerContainer.AddElement(spinner)
div.AddElement(progressBarTitle)
div.AddElement(spinnerContainer)
err := body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
botContact = readBotContact()
client, singleMngr = initClient(testMode)
div.RemoveElement(spinnerContainer)
div.RemoveElement(progressBarTitle)
progressBarTitle = bootstrap.NewElement(gowd.Heading4, "")
progressBarTitle.SetAttribute("style", "text-align:center;")
progressBarTitle.SetText("Generating Keys and Registering with Network")
div.AddElement(progressBarTitle)
progressBar := bootstrap.NewProgressBar()
progressBar.Kids[0].SetAttribute("style", "background:#037281;")
div.AddElement(progressBar.Element)
go func() {
for {
time.Sleep(100 * time.Millisecond)
registeredNodes, totalNodes, err := client.GetNodeRegistrationStatus()
if err != nil {
jww.FATAL.Panicf("Failed to get node registration status: %+v", err)
}
max := (totalNodes * 8) / 10
progressBar.SetText(strconv.Itoa(registeredNodes) + "/" + strconv.Itoa(totalNodes))
err = progressBar.SetValue(registeredNodes, totalNodes)
if err != nil {
jww.ERROR.Printf("Failed to set progress bar value: %+v", err)
}
err = body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
if registeredNodes >= max {
break
}
}
div.RemoveElement(progressBarTitle)
div.RemoveElement(progressBar.Element)
printForm(div)
}()
row.SetAttribute("style", "font-size:1.5em")
// Start the ui loop
err = gowd.Run(body)
if err != nil {
jww.ERROR.Printf("Failed to start ui loop: %+v", err)
}
}
func printForm(div *gowd.Element) {
ethAddr := bootstrap.NewFormInput(bootstrap.InputTypeText, "Ethereum Address:")
ethAddr.Element.Kids[1].SetAttribute("style", "font-family:'Roboto Mono', 'Courier New', Courier, monospace;")
ethAddr.Element.Kids[1].SetAttribute("style", "font-family:'Roboto Mono', Consolas, 'Courier New', Courier, monospace;")
sendText := bootstrap.NewFormInput(bootstrap.InputTypeText, "Message:")
// FIXME: remove this
// ethAddr.SetValue("0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7")
div.AddElement(ethAddr.Element)
div.AddElement(sendText.Element)
......@@ -48,92 +124,142 @@ func main() {
btn := bootstrap.NewButton(bootstrap.ButtonPrimary, "Send over xx")
btn.SetAttribute("style", "background:#037281;background-color:#037281")
rtnDiv := bootstrap.NewElement("div", "well")
rtnRow := bootstrap.NewRow(bootstrap.NewColumn(bootstrap.ColumnSmall, 3, rtnDiv))
body.AddElement(rtnRow)
body.AddElement(rtnDiv)
btnEvent := func(sender *gowd.Element, event *gowd.EventElement) {
btnClicked(sender, event, ethAddr.Element.Kids[1], sendText.Element.Kids[1], rtnDiv)
}
btn.OnEvent(gowd.OnClick, btnEvent)
div.AddElement(btn)
// div.AddHTML(`
// <label for="fname">Ethereum address:</label><br>
// <input type="text" id="ethaddr" name="ethaddr"><br>
// <label for="lname">Message:</label><br>
// <input type="text" id="message" name="message"><br><br>`, nil)
//
// // add a button
// btn := bootstrap.NewButton(bootstrap.ButtonPrimary, "Send")
// btn.OnEvent(gowd.OnClick, btnClicked)
// row.AddElement(bootstrap.NewColumn(bootstrap.ColumnSmall, 3, bootstrap.NewElement("div", "well", btn)))
// start the ui loop
gowd.Run(body)
err := body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
}
var lastElement *gowd.Element
var lastElement, btnMessage, ethAddrFailure *gowd.Element
// happens when the 'start' button is clicked
func btnClicked(sender *gowd.Element, event *gowd.EventElement, ethAddr,
func btnClicked(sender *gowd.Element, _ *gowd.EventElement, ethAddr,
sendText *gowd.Element, div *gowd.Element) {
sender.SetAttribute("disabled", "true")
sender.Parent.AddHTML(`<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>`, nil)
body.Render()
// makes the body stop responding to user events
body.Disable()
if ethAddrFailure != nil {
ethAddr.Parent.RemoveElement(ethAddrFailure)
}
if !validEthereumAddress(ethAddr.GetValue()) {
ethAddrFailure = bootstrap.NewElement("span", bootstrap.AlertWarning+" very-small")
ethAddrFailure.SetText("Must be valid Ethereum address.")
ethAddr.Parent.AddElement(ethAddrFailure)
return
}
sender.SetAttribute("disabled", "")
spinner := bootstrap.NewElement("span", "spinner-grow")
spinner.SetAttribute("role", "status")
spinner.SetAttribute("style", "width: 3rem; height: 3rem;text-align:center;margin:0 auto;")
div.SetAttribute("style", "text-align: center")
div.AddElement(spinner)
if lastElement != nil {
div.RemoveElement(lastElement)
}
if btnMessage != nil {
sender.Parent.RemoveElement(btnMessage)
}
// adds test to the body
// makes the body stop responding to user events
body.Disable()
err := body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
// Send the message
message := ethAddr.GetValue() + ";" + sendText.GetValue()
defer func() {
time.Sleep(1 * time.Second)
sender.RemoveAttribute("disabled")
body.Render()
div.RemoveElement(spinner)
div.RemoveAttribute("style")
err := body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
body.Enable()
}()
//text.SetText(message)
replyString := make(chan string)
replyString := make(chan string, 1)
// Inline function to print message from client to page, callback for upcoming function
replyFunc := func(payload []byte, err error) {
sender.Parent.RemoveElement(btnMessage)
btnMessage = bootstrap.NewElement("span", "")
var result string
if err != nil {
result = err.Error()
btnMessage.SetText("Failed to receive response.")
btnMessage.SetAttribute("style", "font-size:0.75em;padding:0.5em;color:#d62424;")
result = "ERROR: " + err.Error()
} else {
btnMessage.SetText("Received response.")
btnMessage.SetAttribute("style", "font-size:0.75em;padding:0.5em;color:#24d627;")
result = string(payload)
}
replyString <- result
//sender.SetText("Start")
//body.RemoveElement(text)
//body.Enable()
sender.Parent.AddElement(btnMessage)
}
err := singleMngr.TransmitSingleUse(botContact, []byte(message),
err = singleMngr.TransmitSingleUse(botContact, []byte(message),
"xxCoinGame", 10, replyFunc, 30*time.Second)
if err != nil {
//body.Enable()
lastElement = div.AddElement(gowd.NewStyledText(err.Error(), gowd.BoldText))
//sender.SetText("Start")
//body.RemoveElement(text)
//body.Enable()
return
if btnMessage != nil {
sender.Parent.RemoveElement(btnMessage)
}
result := <- replyString
btnMessage = bootstrap.NewElement("span", "")
btnMessage.SetText("Message failed to send.")
btnMessage.SetAttribute("style", "font-size:0.75em;padding:0.5em;color:#d62424;")
sender.Parent.AddElement(btnMessage)
err := body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
return
} else {
if btnMessage != nil {
sender.Parent.RemoveElement(btnMessage)
}
time.Sleep(1 * time.Second)
btnMessage = bootstrap.NewElement("span", "")
btnMessage.SetAttribute("style", "font-size:0.75em;padding:0.5em;color:#24d627;")
sender.Parent.AddElement(btnMessage)
btnMessage.SetText("Message sent successfully. Waiting for response.")
err = body.Render()
if err != nil {
jww.ERROR.Printf("Failed to render body: %+v", err)
}
}
result := <-replyString
lastElement = div.AddElement(gowd.NewStyledText(result, gowd.BoldText))
lastElementStyle := "font-size:1.25em;line-height:1.25em;"
lastElement.SetAttribute("style", lastElementStyle)
if strings.Contains(result, "ERROR: ") {
lastElement.SetAttribute("style", lastElementStyle+"color:#d62424;")
}
}
func validEthereumAddress(address string) bool {
r, err := regexp.Compile("^0x[0-9a-fA-F]{40}$")
if err != nil {
jww.ERROR.Print(err)
}
return r.MatchString(address)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment