"github.com/rivo/tview"
"github.com/stretchr/testify/mock"
"go.uber.org/zap"
- "gopkg.in/yaml.v2"
+ "gopkg.in/yaml.v3"
"math/big"
"math/rand"
"net"
}
type ClientPrefs struct {
- Username string `yaml:"Username"`
- IconID int `yaml:"IconID"`
- Bookmarks []Bookmark `yaml:"Bookmarks"`
- Tracker string `yaml:"Tracker"`
+ Username string `yaml:"Username"`
+ IconID int `yaml:"IconID"`
+ Bookmarks []Bookmark `yaml:"Bookmarks"`
+ Tracker string `yaml:"Tracker"`
+ EnableBell bool `yaml:"EnableBell"`
}
func (cp *ClientPrefs) IconBytes() []byte {
prefs := ClientPrefs{}
decoder := yaml.NewDecoder(fh)
- decoder.SetStrict(true)
if err := decoder.Decode(&prefs); err != nil {
return nil, err
}
UI *UI
- Inbox chan *Transaction
+ Inbox chan *Transaction
}
func NewClient(cfgPath string, logger *zap.SugaredLogger) *Client {
prefs, err := readConfig(cfgPath)
if err != nil {
- fmt.Printf("unable to read config file %s", cfgPath)
- os.Exit(1)
+ logger.Fatal(fmt.Sprintf("unable to read config file %s\n", cfgPath))
}
c.pref = prefs
return db.TextView.Write(p)
}
-// Sync is a noop function that exists to satisfy the zapcore.WriteSyncer interface
+// Sync is a noop function that dataFile to satisfy the zapcore.WriteSyncer interface
func (db *DebugBuffer) Sync() error {
return nil
}
Handler: handleTranServerMsg,
},
tranKeepAlive: clientTransaction{
- Name: "tranKeepAlive",
+ Name: "tranKeepAlive",
Handler: func(client *Client, transaction *Transaction) (t []Transaction, err error) {
return t, err
},
return res, err
}
+func (c *Client) showErrMsg(msg string) {
+ time := time.Now().Format(time.RFC850)
+
+ title := "| Error |"
+
+ msgBox := tview.NewTextView().SetScrollable(true)
+ msgBox.SetText(msg).SetBackgroundColor(tcell.ColorDarkRed)
+ msgBox.SetTitle(title).SetBorder(true)
+ msgBox.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
+ switch event.Key() {
+ case tcell.KeyEscape:
+ c.UI.Pages.RemovePage("serverMsgModal" + time)
+ }
+ return event
+ })
+
+ centeredFlex := tview.NewFlex().
+ AddItem(nil, 0, 1, false).
+ AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
+ AddItem(nil, 0, 1, false).
+ AddItem(msgBox, 0, 2, true).
+ AddItem(nil, 0, 1, false), 0, 2, true).
+ AddItem(nil, 0, 1, false)
+
+ c.UI.Pages.AddPage("serverMsgModal"+time, centeredFlex, true, true)
+ c.UI.App.Draw() // TODO: errModal doesn't render without this. wtf?
+}
+
func handleGetFileNameList(c *Client, t *Transaction) (res []Transaction, err error) {
+ if t.IsError() {
+ c.showErrMsg(string(t.GetField(fieldError).Data))
+ c.Logger.Infof("Error: %s", t.GetField(fieldError).Data)
+ return res, err
+ }
+
fTree := tview.NewTreeView().SetTopLevel(1)
root := tview.NewTreeNode("Root")
fTree.SetRoot(root).SetCurrentNode(root)
entry := selectedNode.GetReference().(*FileNameWithInfo)
- if bytes.Equal(entry.Type, []byte("fldr")) {
- c.Logger.Infow("get new directory listing", "name", string(entry.Name))
+ if bytes.Equal(entry.Type[:], []byte("fldr")) {
+ c.Logger.Infow("get new directory listing", "name", string(entry.name))
- c.filePath = append(c.filePath, string(entry.Name))
+ c.filePath = append(c.filePath, string(entry.name))
f := NewField(fieldFilePath, EncodeFilePath(strings.Join(c.filePath, "/")))
if err := c.UI.HLClient.Send(*NewTransaction(tranGetFileNameList, nil, f)); err != nil {
}
} else {
// TODO: initiate file download
- c.Logger.Infow("download file", "name", string(entry.Name))
+ c.Logger.Infow("download file", "name", string(entry.name))
}
}
for _, f := range t.Fields {
var fn FileNameWithInfo
- _, _ = fn.Read(f.Data)
+ err = fn.UnmarshalBinary(f.Data)
+ if err != nil {
+ return nil, nil
+ }
- if bytes.Equal(fn.Type, []byte("fldr")) {
- node := tview.NewTreeNode(fmt.Sprintf("[blue::]📁 %s[-:-:-]", fn.Name))
+ if bytes.Equal(fn.Type[:], []byte("fldr")) {
+ node := tview.NewTreeNode(fmt.Sprintf("[blue::]📁 %s[-:-:-]", fn.name))
node.SetReference(&fn)
root.AddChild(node)
} else {
- size := binary.BigEndian.Uint32(fn.FileSize) / 1024
+ size := binary.BigEndian.Uint32(fn.FileSize[:]) / 1024
- node := tview.NewTreeNode(fmt.Sprintf(" %-40s %10v KB", fn.Name, size))
+ node := tview.NewTreeNode(fmt.Sprintf(" %-40s %10v KB", fn.name, size))
node.SetReference(&fn)
root.AddChild(node)
}
newsTextView.SetBorder(true).SetTitle("News")
c.UI.Pages.AddPage("news", newsTextView, true, true)
- //c.UI.Pages.SwitchToPage("news")
- //c.UI.App.SetFocus(newsTextView)
+ // c.UI.Pages.SwitchToPage("news")
+ // c.UI.App.SetFocus(newsTextView)
c.UI.App.Draw()
return res, err
return res, err
}
-const readBuffSize = 1024000 // 1KB - TODO: what should this be?
-
-func (c *Client) ReadLoop() error {
- tranBuff := make([]byte, 0)
- tReadlen := 0
- // Infinite loop where take action on incoming client requests until the connection is closed
- for {
- buf := make([]byte, readBuffSize)
- tranBuff = tranBuff[tReadlen:]
-
- readLen, err := c.Connection.Read(buf)
- if err != nil {
- return err
- }
- tranBuff = append(tranBuff, buf[:readLen]...)
-
- // We may have read multiple requests worth of bytes from Connection.Read. readTransactions splits them
- // into a slice of transactions
- var transactions []Transaction
- if transactions, tReadlen, err = readTransactions(tranBuff); err != nil {
- c.Logger.Errorw("Error handling transaction", "err", err)
- }
-
- // iterate over all of the transactions that were parsed from the byte slice and handle them
- for _, t := range transactions {
- if err := c.HandleTransaction(&t); err != nil {
- c.Logger.Errorw("Error handling transaction", "err", err)
- }
- }
- }
-}
-
-func (c *Client) GetTransactions() error {
- tranBuff := make([]byte, 0)
- tReadlen := 0
-
- buf := make([]byte, readBuffSize)
- tranBuff = tranBuff[tReadlen:]
-
- readLen, err := c.Connection.Read(buf)
- if err != nil {
- return err
- }
- tranBuff = append(tranBuff, buf[:readLen]...)
-
- return nil
-}
-
func handleClientGetUserNameList(c *Client, t *Transaction) (res []Transaction, err error) {
var users []User
for _, field := range t.Fields {
}
func handleClientChatMsg(c *Client, t *Transaction) (res []Transaction, err error) {
+ if c.pref.EnableBell {
+ fmt.Println("\a")
+ }
+
_, _ = fmt.Fprintf(c.UI.chatBox, "%s \n", t.GetField(fieldData).Data)
return res, err
agreement := string(t.GetField(fieldData).Data)
agreement = strings.ReplaceAll(agreement, "\r", "\n")
- c.UI.agreeModal = tview.NewModal().
+ agreeModal := tview.NewModal().
SetText(agreement).
AddButtons([]string{"Agree", "Disagree"}).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
},
)
- c.Logger.Debug("show agreement page")
- c.UI.Pages.AddPage("agreement", c.UI.agreeModal, false, true)
- c.UI.Pages.ShowPage("agreement ")
- c.UI.App.Draw()
+ c.UI.Pages.AddPage("agreement", agreeModal, false, true)
return res, err
}
}
func (c *Client) Handshake() error {
- //Protocol ID 4 ‘TRTP’ 0x54 52 54 50
- //Sub-protocol ID 4 User defined
- //Version 2 1 Currently 1
- //Sub-version 2 User defined
+ // Protocol ID 4 ‘TRTP’ 0x54 52 54 50
+ // Sub-protocol ID 4 User defined
+ // Version 2 1 Currently 1
+ // Sub-version 2 User defined
if _, err := c.Connection.Write(ClientHandshake); err != nil {
return fmt.Errorf("handshake write err: %s", err)
}
return err
}
- if bytes.Compare(replyBuf, ServerHandshake) == 0 {
+ if bytes.Equal(replyBuf, ServerHandshake) {
return nil
}
NewField(fieldUserIconID, c.pref.IconBytes()),
NewField(fieldUserLogin, negateString([]byte(login))),
NewField(fieldUserPassword, negateString([]byte(password))),
- NewField(fieldVersion, []byte{0, 2}),
),
)
}
requestNum := binary.BigEndian.Uint16(t.Type)
tID := binary.BigEndian.Uint32(t.ID)
- //handler := TransactionHandlers[requestNum]
+ // handler := TransactionHandlers[requestNum]
// if transaction is NOT reply, add it to the list to transactions we're expecting a response for
if t.IsReply == 0 {
var n int
var err error
- if n, err = c.Connection.Write(t.Payload()); err != nil {
+ b, err := t.MarshalBinary()
+ if err != nil {
+ return err
+ }
+ if n, err = c.Connection.Write(b); err != nil {
return err
}
c.Logger.Debugw("Sent Transaction",
}
requestNum := binary.BigEndian.Uint16(t.Type)
- c.Logger.Infow(
- "Received Transaction",
- "RequestType", requestNum,
- )
+ c.Logger.Debugw("Received Transaction", "RequestType", requestNum)
if handler, ok := c.Handlers[requestNum]; ok {
outT, _ := handler.Handle(c, t)
return nil
}
-func (c *Client) Connected() bool {
- // c.Agreed == true &&
- if c.UserAccess != nil {
- return true
- }
- return false
-}
-
func (c *Client) Disconnect() error {
- err := c.Connection.Close()
- if err != nil {
- return err
- }
- return nil
+ return c.Connection.Close()
}