You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

237 lines
6.4 KiB

package app
import (
"encoding/json"
"io"
"os"
"os/user"
"github.com/jinzhu/gorm"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/wailsapp/wails"
"github.com/grvlle/constellation_wallet/backend/api"
"github.com/grvlle/constellation_wallet/backend/models"
)
// WalletApplication holds all application specific objects
// such as the Client/Server event bus and logger
type WalletApplication struct {
Version string
RT *wails.Runtime
log *logrus.Logger
wallet models.Wallet
DB *gorm.DB
killSignal chan struct{}
Network struct {
URL string
Handles struct {
Send string // Takes TX Object, returns TX Hash (200)
Transaction string // Takes TX Object, returns TX Hash (200)
Balance string // Polls the wallets available balance
}
BlockExplorer struct {
URL string
Handles struct {
Transactions string // Takes TX Hash, returns TX info
Checkpoints string // Takes Checkpoint block hash, returns checkpoint block info
Snapshots string // Takes SnapshotHash, returns info
CollectTX string // Takes DAG address, returns tx objects
}
}
}
paths struct {
HomeDir string
DAGDir string
TMPDir string
EncryptedDir string
EmptyTXFile string
PrevTXFile string
LastTXFile string
AddressFile string
ImageDir string
Java string
}
KeyStoreAccess bool
TransactionFinished bool
TransactionFailed bool
UserLoggedIn bool
NewUser bool
WalletImported bool
FirstTX bool
SecondTX bool
WidgetRunning struct {
PassKeysToFrontend bool
DashboardWidgets bool
}
WalletCLI struct {
URL string
Version string
}
}
// WailsShutdown is called when the application is closed
func (a *WalletApplication) WailsShutdown() {
a.wallet = models.Wallet{}
close(a.killSignal) // Kills the Go Routines
a.DB.Close()
}
// WailsInit initializes the Client and Server side bindings
func (a *WalletApplication) WailsInit(runtime *wails.Runtime) error {
var err error
a.log = logrus.New()
err = a.initDirectoryStructure()
if err != nil {
a.log.Errorln("Unable to set up directory structure. Reason: ", err)
}
a.initLogger()
err = api.InitRPCServer()
if err != nil {
a.log.Panicf("Unable to initialize RPC Server. Reason: %v", err)
}
a.log.Infoln("RPC Server initialized.")
a.UserLoggedIn = false
a.NewUser = false
a.TransactionFinished = true
a.RT = runtime
a.killSignal = make(chan struct{}) // Used to kill go routines and hand back system resources
a.wallet.Currency = "USD" // Set default currency
a.WalletCLI.URL = "https://github.com/Constellation-Labs/constellation/releases/download"
a.WalletCLI.Version = "2.6.0"
a.Version = "1.2.0"
a.DB, err = gorm.Open("sqlite3", a.paths.DAGDir+"/store.db")
if err != nil {
a.log.Panicln("failed to connect database", err)
}
// Migrate the schema
a.DB.AutoMigrate(&models.Wallet{}, &models.TXHistory{}, &models.Path{})
a.detectJavaPath()
a.initMainnetConnection()
a.newReleaseAvailable()
return nil
}
// initLogger writes logs to STDOUT and a.paths.DAGDir/wallet.log
func (a *WalletApplication) initLogger() {
logFile, err := os.OpenFile(a.paths.DAGDir+"/wallet.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664)
if err != nil {
a.log.Fatal("Unable to create log file.")
}
mw := io.MultiWriter(os.Stdout, logFile)
a.log.SetOutput(mw)
a.log.SetFormatter(&log.TextFormatter{
ForceColors: true,
FullTimestamp: true,
})
}
// Initializes the Directory Structure and stores the paths to the WalletApplication struct.
func (a *WalletApplication) initDirectoryStructure() error {
user, err := user.Current()
if err != nil {
return err
}
a.paths.HomeDir = user.HomeDir // Home directory of the user
a.paths.DAGDir = a.paths.HomeDir + "/.dag" // DAG directory for configuration files and wallet specific data
a.paths.TMPDir = a.paths.DAGDir + "/tmp"
a.paths.LastTXFile = a.paths.TMPDir + "/last_tx"
a.paths.PrevTXFile = a.paths.TMPDir + "/prev_tx"
a.paths.EmptyTXFile = a.paths.TMPDir + "/genesis_tx"
a.paths.ImageDir = "./frontend/src/assets/img/" // Image Folder
a.log.Info("DAG Directory: ", a.paths.DAGDir)
err = a.directoryCreator(a.paths.DAGDir, a.paths.TMPDir)
if err != nil {
return err
}
return nil
}
// initMainnetConnection populates the WalletApplication struct with mainnet data
func (a *WalletApplication) initMainnetConnection() {
a.Network.URL = "http://lb.constellationnetwork.io:9000" // Temp
a.Network.Handles.Send = "/send"
a.Network.Handles.Transaction = "/transaction"
a.Network.Handles.Balance = "/address/"
a.Network.BlockExplorer.URL = "https://xju69fets2.execute-api.us-west-1.amazonaws.com/cl-block-explorer-mainnet"
a.Network.BlockExplorer.Handles.Transactions = "/transactions/"
a.Network.BlockExplorer.Handles.Checkpoints = "/checkpoints/"
a.Network.BlockExplorer.Handles.Snapshots = "/snapshots/"
a.Network.BlockExplorer.Handles.CollectTX = "/transactions?sender="
}
// APIError reported by the blockexplerer/loadbalancer are reported in the following format
// {"error": "Cannot find transactions for sender"}
type APIError struct {
Error string
}
// verifyAPIResponse takes API response converted to a byte array and checks if the API returned
// an error. If it did, it'll return the error message.
func (a *WalletApplication) verifyAPIResponse(r []byte) (bool, string) {
APIErr := APIError{}
if string(r[3:8]) == "error" {
err := json.Unmarshal(r, &APIErr)
if err != nil {
a.log.Errorln("Unable to parse API error. Reason: ", err)
}
return false, APIErr.Error
}
return true, ""
}
func (a *WalletApplication) sendSuccess(msg string) {
if len(msg) > 200 {
msg = string(msg[:200]) // Restrict error size for frontend
a.RT.Events.Emit("success", msg)
return
}
a.RT.Events.Emit("success", msg)
}
func (a *WalletApplication) sendWarning(msg string) {
if len(msg) > 200 {
msg = string(msg[:200]) // Restrict error size for frontend
a.RT.Events.Emit("warning", msg)
return
}
a.RT.Events.Emit("warning", msg)
}
func (a *WalletApplication) sendError(msg string, err error) {
var errStr string
if err != nil {
b := []byte(err.Error())
if len(b) > 80 {
errStr = string(b[:80]) // Restrict error size for frontend
} else if len(b) < 80 {
errStr = string(b)
} else {
errStr = ""
}
a.RT.Events.Emit("error_handling", msg, errStr+" ...")
} else {
a.RT.Events.Emit("error_handling", msg+" ...")
}
}