Created stable-ish version of cfyne
This commit is contained in:
parent
31b2707c23
commit
feb5d22b2a
7
cmd/cfyne/actions.go
Normal file
7
cmd/cfyne/actions.go
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
ACTION_SET_SCENE_NICKNAME = 1 + iota
|
||||||
|
ACTION_SET_SCENE_MAIN
|
||||||
|
ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
)
|
61
cmd/cfyne/conUsers.go
Normal file
61
cmd/cfyne/conUsers.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
userCenter UserCenter
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserCenter struct {
|
||||||
|
UsersSTOI map[string]uint16
|
||||||
|
UsersITOS map[uint16]string
|
||||||
|
Mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserCenter) Init() {
|
||||||
|
u.UsersSTOI = make(map[string]uint16)
|
||||||
|
u.UsersITOS = make(map[uint16]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserCenter) AddUser(name string, id uint16) error {
|
||||||
|
u.Mu.Lock()
|
||||||
|
defer u.Mu.Unlock()
|
||||||
|
_, alreadyHave := u.UsersSTOI[name]
|
||||||
|
if alreadyHave {
|
||||||
|
return ERROR_ALREADY_HAVE
|
||||||
|
}
|
||||||
|
log.Printf("Users: add %s with %d id\n", name, id)
|
||||||
|
u.UsersITOS[id] = name
|
||||||
|
u.UsersSTOI[name] = id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserCenter) DeleteIfHaveOne(id uint16) {
|
||||||
|
name, found := u.UsersITOS[id]
|
||||||
|
if !found {
|
||||||
|
log.Printf("User with %d id is not found; Can not delete\n", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(u.UsersITOS, id)
|
||||||
|
delete(u.UsersSTOI, name)
|
||||||
|
log.Printf("User with %s name and %d id was found; User is deleted\n", name, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserCenter) GetID(name string) (uint16, error) {
|
||||||
|
id, have := u.UsersSTOI[name]
|
||||||
|
if !have {
|
||||||
|
return 0, ERROR_DONT_HAVE
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserCenter) GetName(id uint16) (string, error) {
|
||||||
|
name, have := u.UsersITOS[id]
|
||||||
|
if !have {
|
||||||
|
return "", ERROR_DONT_HAVE
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
15
cmd/cfyne/funcs.go
Normal file
15
cmd/cfyne/funcs.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "fyne.io/fyne/v2/widget"
|
||||||
|
com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSendMessageFuncToIntercom(intercom chan *com.Message, id uint8, data []byte) func() {
|
||||||
|
return func() {
|
||||||
|
intercom <- &com.Message{
|
||||||
|
ID: id,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
cmd/cfyne/linksmuar.go
Normal file
31
cmd/cfyne/linksmuar.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Non-Generic variant
|
||||||
|
type MutexLinksArray struct {
|
||||||
|
Ar []com.Link
|
||||||
|
Mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateMutexLinksArray() *MutexLinksArray {
|
||||||
|
var tmp []com.Link
|
||||||
|
return &MutexLinksArray{
|
||||||
|
Ar: tmp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexLinksArray) Add(v com.Link) {
|
||||||
|
ma.Mu.Lock()
|
||||||
|
ma.Ar = append(ma.Ar, v)
|
||||||
|
ma.Mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexLinksArray) GetArray() []com.Link {
|
||||||
|
ma.Mu.RLock()
|
||||||
|
defer ma.Mu.RUnlock()
|
||||||
|
return ma.Ar
|
||||||
|
}
|
648
cmd/cfyne/main.go
Normal file
648
cmd/cfyne/main.go
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/app"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/driver/desktop"
|
||||||
|
"fyne.io/fyne/v2/layout"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
|
||||||
|
com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/env"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func updateTime(clock *widget.Label) {
|
||||||
|
formatted := time.Now().Format("Time: 03:04:05")
|
||||||
|
clock.SetText(formatted)
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalApp *MutableApplication
|
||||||
|
var globalCfg *FyneConfig
|
||||||
|
|
||||||
|
var (
|
||||||
|
ecdhKeyReceived = false
|
||||||
|
ecdhKeySent = false
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
globalClipboardChannel = make(chan string)
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
tlepCenter.Init()
|
||||||
|
userCenter.Init()
|
||||||
|
loadingFileName := env.ServerFullchainFileName
|
||||||
|
cert, err := os.ReadFile(loadingFileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("client: load root cert: %s", err)
|
||||||
|
}
|
||||||
|
log.Printf("Certificate %s loaded successfully!\n", loadingFileName)
|
||||||
|
//
|
||||||
|
roots := x509.NewCertPool()
|
||||||
|
if ok := roots.AppendCertsFromPEM(cert); !ok {
|
||||||
|
log.Fatalf("client: failed to parse root certificate")
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &tls.Config{
|
||||||
|
RootCAs: roots,
|
||||||
|
}
|
||||||
|
host := "chat.qowevisa.click"
|
||||||
|
port := 3232
|
||||||
|
service := fmt.Sprintf("%s:%d", host, port)
|
||||||
|
log.Printf("client: connecting to %s", service)
|
||||||
|
conn, err := tls.Dial("tcp", service, config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("client: dial: %s", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
log.Printf("client: connected to %s", service)
|
||||||
|
//
|
||||||
|
|
||||||
|
a := app.New()
|
||||||
|
w := a.NewWindow("gotell-fyne")
|
||||||
|
// w.Resize(fyne.NewSize(640, 400))
|
||||||
|
|
||||||
|
// dispatch clipboardChannel
|
||||||
|
go func(w fyne.Window) {
|
||||||
|
for val := range globalClipboardChannel {
|
||||||
|
w.Clipboard().SetContent(val)
|
||||||
|
}
|
||||||
|
}(w)
|
||||||
|
|
||||||
|
clock := widget.NewLabel("")
|
||||||
|
go func() {
|
||||||
|
for range time.Tick(time.Second) {
|
||||||
|
updateTime(clock)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
btn := widget.NewButtonWithIcon("testBtn", theme.AccountIcon(), func() {
|
||||||
|
fmt.Println("I'm pressed!")
|
||||||
|
})
|
||||||
|
|
||||||
|
mainContainer := container.New(layout.NewVBoxLayout(), clock, btn)
|
||||||
|
|
||||||
|
w.SetContent(mainContainer)
|
||||||
|
// w.SetContent(widget.NewLabel("Hello World!"))
|
||||||
|
// w2 := a.NewWindow("Larger")
|
||||||
|
// w2.SetContent(widget.NewLabel("More content"))
|
||||||
|
// w2.Resize(fyne.NewSize(100, 100))
|
||||||
|
// w2.Show()
|
||||||
|
intercomFromServer := make(chan *com.Message, 16)
|
||||||
|
intercomToServer := make(chan *com.Message, 16)
|
||||||
|
actionsChannel := make(chan int)
|
||||||
|
cfg := FyneConfig{
|
||||||
|
App: a,
|
||||||
|
Window: w,
|
||||||
|
}
|
||||||
|
globalCfg = &cfg
|
||||||
|
|
||||||
|
go readFromServer(conn, intercomFromServer)
|
||||||
|
go analyzeMessages(intercomFromServer, actionsChannel)
|
||||||
|
go actOnActions(cfg, actionsChannel, intercomToServer)
|
||||||
|
go readFromIntercom(intercomToServer, conn)
|
||||||
|
w.ShowAndRun()
|
||||||
|
}
|
||||||
|
|
||||||
|
var r com.RegisteredUser
|
||||||
|
var tmpLink *com.Link
|
||||||
|
var tmpNick string
|
||||||
|
|
||||||
|
func readFromServer(conn net.Conn, intercom chan *com.Message) {
|
||||||
|
buf := make([]byte, 70000)
|
||||||
|
for {
|
||||||
|
err := conn.SetDeadline(time.Now().Add(1 * time.Minute))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: conn.SetDeadline: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: client: read: %s", err)
|
||||||
|
if errors.Is(err, net.ErrClosed) {
|
||||||
|
log.Printf("caught ErrClosed!")
|
||||||
|
}
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||||
|
log.Println("caught! Read timeout occurred")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg, err := com.Decode(buf[:n])
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: %#v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if msg == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("client: readServer: received message from server: %v", *msg)
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_SERVER_APPROVE_CLIENT_NICKNAME:
|
||||||
|
newID := binary.BigEndian.Uint16(msg.Data)
|
||||||
|
msg.FromID = newID
|
||||||
|
msg.Data = []byte{}
|
||||||
|
r.ID = newID
|
||||||
|
if tmpNick != "" {
|
||||||
|
r.Name = tmpNick
|
||||||
|
}
|
||||||
|
r.IsRegistered = true
|
||||||
|
case com.ID_SERVER_APPROVE_CLIENT_LINK:
|
||||||
|
if tmpLink == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.ToID = tmpLink.UseCount
|
||||||
|
msg.Data = tmpLink.Data
|
||||||
|
// Crypto stuff
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.FromID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = t.ECDHApplyOtherKeyBytes(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: ECDHApplyOtherKeyBytes: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fromName, err := userCenter.GetName(msg.FromID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: userCenter: GetName: %v\n", err)
|
||||||
|
} else {
|
||||||
|
msg.Data = []byte(fromName)
|
||||||
|
}
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.FromID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cbes, err := t.DecryptMessageEA(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: DecryptMessageEA: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = t.CBESSetFromBytes(cbes)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: CBESSetFromBytes: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fromName, err := userCenter.GetName(msg.FromID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: userCenter: GetName: %v\n", err)
|
||||||
|
} else {
|
||||||
|
msg.Data = []byte(fromName)
|
||||||
|
}
|
||||||
|
// message
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.FromID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
decrypedMsg, err := t.DecryptMessageAtMax(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: DecryptMessageAtMax: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.Data = decrypedMsg
|
||||||
|
// switch
|
||||||
|
}
|
||||||
|
// user stuff
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
|
||||||
|
userCenter.AddUser(string(msg.Data), msg.FromID)
|
||||||
|
}
|
||||||
|
log.Printf("client: readServer: sending message to websocket: %v", *msg)
|
||||||
|
intercom <- msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func analyzeMessages(intercomFromServer chan *com.Message, actionsChannel chan int) {
|
||||||
|
for msg := range intercomFromServer {
|
||||||
|
if msg == nil {
|
||||||
|
log.Printf("ERROR: msg is nil")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("Handling %v from server", *msg)
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_SERVER_ASK_CLIENT_NICKNAME:
|
||||||
|
actionsChannel <- ACTION_SET_SCENE_NICKNAME
|
||||||
|
case com.ID_SERVER_APPROVE_CLIENT_NICKNAME:
|
||||||
|
actionsChannel <- ACTION_SET_SCENE_MAIN
|
||||||
|
case com.ID_SERVER_DECLINE_CLIENT_NICKNAME:
|
||||||
|
// TODO
|
||||||
|
// Link stuff
|
||||||
|
case com.ID_SERVER_APPROVE_CLIENT_LINK:
|
||||||
|
globalApp.ArrayBundle.LinksMuAr.Add(*tmpLink)
|
||||||
|
globalApp.Tabs.LinkTab.Content.Refresh()
|
||||||
|
case com.ID_SERVER_SEND_CLIENT_ANOTHER_ID:
|
||||||
|
selTab := globalApp.Tabs.AppTabs.Selected()
|
||||||
|
id := msg.ToID
|
||||||
|
userStr := getStdUserName(id, string(msg.Data))
|
||||||
|
globalApp.Widgets.UsersSelect.Options = append(globalApp.Widgets.UsersSelect.Options, userStr)
|
||||||
|
globalApp.Tabs.ConnsNoty++
|
||||||
|
globalApp.ArrayBundle.UsersOpts[userStr] = &UserOptions{
|
||||||
|
Status: USER_STATUS_VISIBLE,
|
||||||
|
ToID: id,
|
||||||
|
}
|
||||||
|
_, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
globalApp.ArrayBundle.UserShortcuts[id] = userStr
|
||||||
|
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
|
||||||
|
}
|
||||||
|
if selTab != globalApp.Tabs.ConnectionTab {
|
||||||
|
updateTabsBasedOnNotyVals(&globalApp.Tabs)
|
||||||
|
}
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE:
|
||||||
|
selTab := globalApp.Tabs.AppTabs.Selected()
|
||||||
|
id := msg.FromID
|
||||||
|
userStr := getStdUserName(id, string(msg.Data))
|
||||||
|
globalApp.Widgets.UsersSelect.Options = append(globalApp.Widgets.UsersSelect.Options, userStr)
|
||||||
|
globalApp.Tabs.ConnsNoty++
|
||||||
|
globalApp.ArrayBundle.UsersOpts[userStr] = &UserOptions{
|
||||||
|
Status: USER_STATUS_HANDSHAKE_INIT,
|
||||||
|
ToID: id,
|
||||||
|
}
|
||||||
|
_, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
globalApp.ArrayBundle.UserShortcuts[id] = userStr
|
||||||
|
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
|
||||||
|
}
|
||||||
|
if selTab != globalApp.Tabs.ConnectionTab {
|
||||||
|
updateTabsBasedOnNotyVals(&globalApp.Tabs)
|
||||||
|
}
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
case com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
|
||||||
|
id := msg.FromID
|
||||||
|
userStr := getStdUserName(id, string(msg.Data))
|
||||||
|
var shortcut string
|
||||||
|
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
globalApp.ArrayBundle.UserShortcuts[id] = userStr
|
||||||
|
globalApp.ArrayBundle.UserShortcutsRev[userStr] = id
|
||||||
|
shortcut = userStr
|
||||||
|
} else {
|
||||||
|
shortcut = val
|
||||||
|
}
|
||||||
|
u, exists := globalApp.ArrayBundle.UsersOpts[shortcut]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", shortcut)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
u.Status = USER_STATUS_HANDSHAKE_ACCEPTED
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
|
||||||
|
id := msg.FromID
|
||||||
|
if ecdhKeySent {
|
||||||
|
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING!!: UserShortcuts[%d] NOT exists!", id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
u, exists := globalApp.ArrayBundle.UsersOpts[val]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", val)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
u.Status = USER_STATUS_ECDH_ESTABLISHED
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
}
|
||||||
|
ecdhKeyReceived = true
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
|
||||||
|
id := msg.FromID
|
||||||
|
val, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING!!: UserShortcuts[%d] NOT exists!", id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
u, exists := globalApp.ArrayBundle.UsersOpts[val]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING!!: UserOpts[%s] NOT exists!", val)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
u.Status = USER_STATUS_ECDH_CBES_ESTABLISHED
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
//
|
||||||
|
log.Printf("Checkin Messages tab")
|
||||||
|
userStr := getStdUserName(id, string(msg.Data))
|
||||||
|
var shortcut string
|
||||||
|
if !exists {
|
||||||
|
globalApp.ArrayBundle.UserShortcuts[id] = userStr
|
||||||
|
shortcut = userStr
|
||||||
|
} else {
|
||||||
|
shortcut = val
|
||||||
|
}
|
||||||
|
//
|
||||||
|
haveUser := false
|
||||||
|
for _, v := range globalApp.Widgets.MessagesSelect.Options {
|
||||||
|
if v == shortcut {
|
||||||
|
haveUser = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf("MessagesSelect.Options1 are %v\n", globalApp.Widgets.MessagesSelect.Options)
|
||||||
|
log.Printf("have user is : %t\n", haveUser)
|
||||||
|
if !haveUser {
|
||||||
|
log.Printf("MessagesSelect.Options1.5 shortcut is '%s'\n", shortcut)
|
||||||
|
// LOL wtf
|
||||||
|
// globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.UsersSelect.Options, shortcut)
|
||||||
|
globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.MessagesSelect.Options, shortcut)
|
||||||
|
log.Printf("MessagesSelect.Options2 are %v\n", globalApp.Widgets.MessagesSelect.Options)
|
||||||
|
globalApp.Tabs.UsersNoty++
|
||||||
|
globalApp.Widgets.MessagesSelect.Refresh()
|
||||||
|
updateTabsBasedOnNotyVals(&globalApp.Tabs)
|
||||||
|
}
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
|
||||||
|
id := msg.FromID
|
||||||
|
shortcut, exists := globalApp.ArrayBundle.UserShortcuts[id]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("WARNING: UserShortcuts[%d] NOT exists!", id)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msgs, exists := globalApp.ArrayBundle.Messages[shortcut]
|
||||||
|
mBoardMsg := widgets.MBoardMessage{
|
||||||
|
LeftAlign: true,
|
||||||
|
Data: widget.NewLabel(string(msg.Data)),
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
tmp := CreateMutexArray[widgets.MBoardMessage]()
|
||||||
|
tmp.Add(mBoardMsg)
|
||||||
|
globalApp.ArrayBundle.Messages[shortcut] = &tmp
|
||||||
|
globalApp.Widgets.MBoardCaretacker.Refresh()
|
||||||
|
globalApp.Tabs.UsersTab.Content.Refresh()
|
||||||
|
} else {
|
||||||
|
msgs.Add(mBoardMsg)
|
||||||
|
globalApp.Widgets.MBoardCaretacker.Refresh()
|
||||||
|
globalApp.Tabs.UsersTab.Content.Refresh()
|
||||||
|
}
|
||||||
|
haveUser := false
|
||||||
|
for _, v := range globalApp.Widgets.MessagesSelect.Options {
|
||||||
|
if v == shortcut {
|
||||||
|
haveUser = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !haveUser {
|
||||||
|
globalApp.Widgets.MessagesSelect.Options = append(globalApp.Widgets.MessagesSelect.Options, shortcut)
|
||||||
|
globalApp.Tabs.UsersNoty++
|
||||||
|
updateTabsBasedOnNotyVals(&globalApp.Tabs)
|
||||||
|
globalApp.Widgets.MessagesSelect.Refresh()
|
||||||
|
}
|
||||||
|
//
|
||||||
|
mBoard, exists := globalApp.Widgets.MBoardMap[shortcut]
|
||||||
|
if exists {
|
||||||
|
mBoard.Add(mBoardMsg)
|
||||||
|
}
|
||||||
|
// TODO
|
||||||
|
default:
|
||||||
|
log.Printf("Can not handle msg with id %d", msg.ID)
|
||||||
|
log.Printf("Msg is different : %v", *msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func actOnActions(cfg FyneConfig, actionsChannel chan int, intercomToServer chan *com.Message) {
|
||||||
|
for action := range actionsChannel {
|
||||||
|
log.Printf("Receive action %d", action)
|
||||||
|
switch action {
|
||||||
|
case ACTION_SET_SCENE_NICKNAME:
|
||||||
|
// cfg.Window.Content()
|
||||||
|
scene := GetNicknameScene(intercomToServer)
|
||||||
|
cfg.Window.Resize(fyne.NewSize(640, 400))
|
||||||
|
cfg.Window.SetContent(scene)
|
||||||
|
case ACTION_SET_SCENE_MAIN:
|
||||||
|
scene, app := GetMainScene(intercomToServer, MainSceneConfig{
|
||||||
|
UserNickcname: tmpNick,
|
||||||
|
UserNameSet: true,
|
||||||
|
UserId: r.ID,
|
||||||
|
UserIdSet: true,
|
||||||
|
})
|
||||||
|
globalApp = app
|
||||||
|
globalApp.App.App = cfg.App
|
||||||
|
globalApp.App.Window = cfg.Window
|
||||||
|
// shortcuts
|
||||||
|
ctrl1 := &desktop.CustomShortcut{KeyName: fyne.Key1, Modifier: fyne.KeyModifierControl}
|
||||||
|
ctrl2 := &desktop.CustomShortcut{KeyName: fyne.Key2, Modifier: fyne.KeyModifierControl}
|
||||||
|
ctrl3 := &desktop.CustomShortcut{KeyName: fyne.Key3, Modifier: fyne.KeyModifierControl}
|
||||||
|
cfg.Window.Canvas().AddShortcut(ctrl1, func(shortcut fyne.Shortcut) {
|
||||||
|
app.Tabs.AppTabs.Select(app.Tabs.LinkTab)
|
||||||
|
})
|
||||||
|
cfg.Window.Canvas().AddShortcut(ctrl2, func(shortcut fyne.Shortcut) {
|
||||||
|
app.Tabs.AppTabs.Select(app.Tabs.ConnectionTab)
|
||||||
|
})
|
||||||
|
cfg.Window.Canvas().AddShortcut(ctrl3, func(shortcut fyne.Shortcut) {
|
||||||
|
app.Tabs.AppTabs.Select(app.Tabs.UsersTab)
|
||||||
|
})
|
||||||
|
// cfg.Window.Resize(fyne.NewSize(640, 400))
|
||||||
|
cfg.Window.SetContent(scene)
|
||||||
|
// ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
case ACTION_UPDATE_USER_OPTS_CONTS:
|
||||||
|
for _, u := range globalApp.ArrayBundle.UsersOpts {
|
||||||
|
switch u.Status {
|
||||||
|
case USER_STATUS_VISIBLE:
|
||||||
|
btn := widget.NewButton("Init Handhake", func() {})
|
||||||
|
btn.OnTapped = func() {
|
||||||
|
intercomToServer <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
ToID: u.ToID,
|
||||||
|
}
|
||||||
|
btn.Hide()
|
||||||
|
}
|
||||||
|
u.OptsContainer = container.NewGridWithRows(1, btn)
|
||||||
|
cTaker := globalApp.Widgets.UserOptsCaretaker
|
||||||
|
cTaker.RemoveAll()
|
||||||
|
cTaker.Add(u.OptsContainer)
|
||||||
|
case USER_STATUS_HANDSHAKE_INIT:
|
||||||
|
btn := widget.NewButton("Accept Handhake", func() {})
|
||||||
|
btn.OnTapped = func() {
|
||||||
|
intercomToServer <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE,
|
||||||
|
ToID: u.ToID,
|
||||||
|
}
|
||||||
|
btn.Hide()
|
||||||
|
u.Status = USER_STATUS_HANDSHAKE_ACCEPTED
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
}
|
||||||
|
u.OptsContainer = container.NewGridWithRows(1, btn)
|
||||||
|
cTaker := globalApp.Widgets.UserOptsCaretaker
|
||||||
|
cTaker.RemoveAll()
|
||||||
|
cTaker.Add(u.OptsContainer)
|
||||||
|
case USER_STATUS_HANDSHAKE_ACCEPTED:
|
||||||
|
btn := widget.NewButton("Send ECDH PubKey", func() {})
|
||||||
|
btn.OnTapped = func() {
|
||||||
|
intercomToServer <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY,
|
||||||
|
ToID: u.ToID,
|
||||||
|
}
|
||||||
|
btn.Hide()
|
||||||
|
if ecdhKeyReceived {
|
||||||
|
u.Status = USER_STATUS_ECDH_ESTABLISHED
|
||||||
|
actionsChannel <- ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
}
|
||||||
|
ecdhKeySent = true
|
||||||
|
}
|
||||||
|
u.OptsContainer = container.NewGridWithRows(1, btn)
|
||||||
|
cTaker := globalApp.Widgets.UserOptsCaretaker
|
||||||
|
cTaker.RemoveAll()
|
||||||
|
cTaker.Add(u.OptsContainer)
|
||||||
|
case USER_STATUS_ECDH_ESTABLISHED:
|
||||||
|
btn := widget.NewButton("Send CBES Specs", func() {})
|
||||||
|
btn.OnTapped = func() {
|
||||||
|
intercomToServer <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_SEND_CLIENT_CBES_SPECS,
|
||||||
|
ToID: u.ToID,
|
||||||
|
}
|
||||||
|
btn.Hide()
|
||||||
|
}
|
||||||
|
u.OptsContainer = container.NewGridWithRows(1, btn)
|
||||||
|
cTaker := globalApp.Widgets.UserOptsCaretaker
|
||||||
|
cTaker.RemoveAll()
|
||||||
|
cTaker.Add(u.OptsContainer)
|
||||||
|
case USER_STATUS_ECDH_CBES_ESTABLISHED:
|
||||||
|
btn := widget.NewButton("TBC", func() {})
|
||||||
|
btn.OnTapped = func() {
|
||||||
|
log.Println("TODO:: 1001")
|
||||||
|
}
|
||||||
|
u.OptsContainer = container.NewGridWithRows(1, btn)
|
||||||
|
cTaker := globalApp.Widgets.UserOptsCaretaker
|
||||||
|
cTaker.RemoveAll()
|
||||||
|
cTaker.Add(u.OptsContainer)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// globalApp.Tabs.ConnectionTab.Content.Refresh()
|
||||||
|
// ACTION_UPDATE_USER_OPTS_CONTS
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFromIntercom(intercom chan *com.Message, conn net.Conn) {
|
||||||
|
for msg := range intercom {
|
||||||
|
log.Printf("client: received message from Intercom: %v", msg)
|
||||||
|
msg.Version = com.V1
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_CLIENT_SEND_SERVER_NICKNAME:
|
||||||
|
tmpNick = string(msg.Data)
|
||||||
|
case com.ID_CLIENT_SEND_SERVER_LINK:
|
||||||
|
if !r.IsRegistered {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l, err := r.GenerateLink(msg.ToID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: link: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tmpLink = &l
|
||||||
|
answ, err := com.ClientSendServerLink(r.ID, l)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error: com: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("client: readWS: sending data to server: %v", answ)
|
||||||
|
conn.Write(answ)
|
||||||
|
continue
|
||||||
|
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_DECLINE_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY,
|
||||||
|
com.ID_CLIENT_SEND_CLIENT_CBES_SPECS,
|
||||||
|
com.ID_CLIENT_SEND_CLIENT_MKLG_FINGERPRINT,
|
||||||
|
com.ID_CLIENT_DECLINE_CLIENT_MKLG_FINGERPRINT,
|
||||||
|
com.ID_CLIENT_SEND_CLIENT_MESSAGE:
|
||||||
|
if !r.IsRegistered {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.FromID = r.ID
|
||||||
|
// switch
|
||||||
|
}
|
||||||
|
// user stuff
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
|
||||||
|
if r.IsRegistered {
|
||||||
|
msg.Data = []byte(r.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Crypto stuff
|
||||||
|
switch msg.ID {
|
||||||
|
case com.ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
com.ID_CLIENT_APPROVE_CLIENT_HANDSHAKE:
|
||||||
|
err := tlepCenter.AddTLEP(msg.ToID, fmt.Sprintf("%s-%d", r.Name, msg.ToID))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlepCenter.AddUser: %v\n", err)
|
||||||
|
}
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_ECDH_PUBKEY:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.ToID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key, err := t.ECDHGetPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: ECDHGetPublicKey: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.Data = key
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_CBES_SPECS:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.ToID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = t.CBESInitRandom()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: CBESInitRandom: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cbes, err := t.CBESGetBytes()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: ECDHGetPublicKey: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cbesEAEncr, err := t.EncryptMessageEA(cbes)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: EncryptMessageEA: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.Data = cbesEAEncr
|
||||||
|
// message
|
||||||
|
case com.ID_CLIENT_SEND_CLIENT_MESSAGE:
|
||||||
|
t, err := tlepCenter.GetTLEP(msg.ToID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: GetTLEP: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
encrypedMsg, err := t.EncryptMessageAtMax(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR: tlep: EncryptMessageAtMax: %v\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.Data = encrypedMsg
|
||||||
|
// switch
|
||||||
|
}
|
||||||
|
encodedMsg, err := msg.Bytes()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Encoding error: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("client: readWS: sending data to server: %v", encodedMsg)
|
||||||
|
conn.Write(encodedMsg)
|
||||||
|
}
|
||||||
|
}
|
377
cmd/cfyne/scenes.go
Normal file
377
cmd/cfyne/scenes.go
Normal file
|
@ -0,0 +1,377 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/layout"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
|
||||||
|
// "fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/extfyne/layouts"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetNicknameScene(intercom chan *com.Message) *fyne.Container {
|
||||||
|
// button := widget.NewButtonWithIcon(
|
||||||
|
// "Send",
|
||||||
|
// theme.ConfirmIcon(),
|
||||||
|
// getSendMessageFuncToIntercom(intercom, com.ID_CLIENT_SEND_SERVER_NICKNAME, []byte("test")))
|
||||||
|
entry := widget.NewEntry()
|
||||||
|
entry.SetPlaceHolder("Enter Nickname:")
|
||||||
|
btn := widget.NewButtonWithIcon("Send", theme.MailSendIcon(), func() {
|
||||||
|
log.Println("Nickname submitted:", entry.Text)
|
||||||
|
intercom <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_SEND_SERVER_NICKNAME,
|
||||||
|
Data: []byte(entry.Text),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
contentInner := container.New(layout.NewVBoxLayout(), entry, btn)
|
||||||
|
return container.NewGridWithRows(3,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
container.NewGridWithColumns(3,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
contentInner,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMainScene(intercom chan *com.Message, cfg MainSceneConfig) (*fyne.Container, *MutableApplication) {
|
||||||
|
headerWidget := widget.NewLabel(fmt.Sprintf("Hello, %s! Your ID: %d", cfg.UserNickcname, cfg.UserId))
|
||||||
|
header := container.NewGridWithColumns(3,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
headerWidget,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
)
|
||||||
|
|
||||||
|
linksSS, linksArr := GetLinksSubScene(intercom, header)
|
||||||
|
linksTab := container.NewTabItemWithIcon("Links", theme.MailComposeIcon(), linksSS)
|
||||||
|
conSS, conBundle, conWidgets := GetConnectionsSubScene(intercom, header)
|
||||||
|
connsTab := container.NewTabItemWithIcon("Connections", theme.ComputerIcon(), conSS)
|
||||||
|
userSS, userBundle, userWidgets := GetUsersSubScene(intercom, header, conBundle.UserShortcutsRev)
|
||||||
|
usersTab := container.NewTabItemWithIcon("Users", theme.AccountIcon(), userSS)
|
||||||
|
tabs := container.NewAppTabs(
|
||||||
|
linksTab,
|
||||||
|
connsTab,
|
||||||
|
usersTab,
|
||||||
|
)
|
||||||
|
tabs.SetTabLocation(container.TabLocationLeading)
|
||||||
|
|
||||||
|
return container.NewGridWithColumns(1,
|
||||||
|
tabs),
|
||||||
|
&MutableApplication{
|
||||||
|
Tabs: MutableStructAboutTabs{
|
||||||
|
AppTabs: tabs,
|
||||||
|
LinkTab: linksTab,
|
||||||
|
LinksBT: "Links",
|
||||||
|
LinksNoty: 0,
|
||||||
|
ConnectionTab: connsTab,
|
||||||
|
ConnsBT: "Connections",
|
||||||
|
ConnsNoty: 0,
|
||||||
|
UsersTab: usersTab,
|
||||||
|
UsersBT: "Users",
|
||||||
|
UsersNoty: 0,
|
||||||
|
},
|
||||||
|
ArrayBundle: BundleOfMutexArrays{
|
||||||
|
LinksMuAr: linksArr,
|
||||||
|
UsersMuAr: conBundle.UsersMuAr,
|
||||||
|
UsersOpts: conBundle.UsersOpts,
|
||||||
|
UserShortcuts: conBundle.UserShortcuts,
|
||||||
|
UserShortcutsRev: conBundle.UserShortcutsRev,
|
||||||
|
Messages: userBundle.Messages,
|
||||||
|
},
|
||||||
|
Widgets: MutableStructAboutWidgets{
|
||||||
|
UsersSelect: conWidgets.UsersSelect,
|
||||||
|
UserOptsCaretaker: conWidgets.UserOptsCaretaker,
|
||||||
|
MessagesSelect: userWidgets.MessagesSelect,
|
||||||
|
MBoardCaretacker: userWidgets.MBoardCaretacker,
|
||||||
|
MsgButton: userWidgets.MsgButton,
|
||||||
|
MBoardMap: userWidgets.MBoardMap,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLinksSubScene(intercom chan *com.Message, header *fyne.Container) (*fyne.Container, *MutexLinksArray) {
|
||||||
|
entry := widget.NewEntry()
|
||||||
|
entry.SetPlaceHolder("Count:")
|
||||||
|
entry.Validator = func(s string) error {
|
||||||
|
val, err := strconv.ParseUint(s, 10, 16)
|
||||||
|
if err == nil && val == 0 {
|
||||||
|
return errors.New("Use count can't be 0")
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
btn := widget.NewButtonWithIcon("Generate", theme.MailSendIcon(), func() {
|
||||||
|
count, err := strconv.ParseUint(entry.Text, 10, 16)
|
||||||
|
if err != nil || count == 0 {
|
||||||
|
log.Printf("dafuq: GetLinksSubScene: %v ; %d\n", err, count)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
intercom <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_SEND_SERVER_LINK,
|
||||||
|
ToID: uint16(count),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
entry.SetOnValidationChanged(func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
btn.Hide()
|
||||||
|
} else {
|
||||||
|
if btn.Hidden {
|
||||||
|
btn.Show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
contentInner := container.NewGridWithColumns(2, entry, btn)
|
||||||
|
// /
|
||||||
|
linksMutAt := CreateMutexLinksArray()
|
||||||
|
linksList := widget.NewList(func() int {
|
||||||
|
return len(linksMutAt.GetArray())
|
||||||
|
}, func() fyne.CanvasObject {
|
||||||
|
return widget.NewLabel("template")
|
||||||
|
}, func(lii widget.ListItemID, co fyne.CanvasObject) {
|
||||||
|
link := linksMutAt.Ar[lii]
|
||||||
|
str := fmt.Sprintf("Count: %d ; %s", link.UseCount, link.Data)
|
||||||
|
co.(*widget.Label).SetText(str)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
linksList.OnSelected = func(id widget.ListItemID) {
|
||||||
|
link := linksMutAt.Ar[id]
|
||||||
|
globalClipboardChannel <- string(link.Data)
|
||||||
|
}
|
||||||
|
// //
|
||||||
|
linksGetEntry := widget.NewEntry()
|
||||||
|
linksGetEntry.SetPlaceHolder("Link:")
|
||||||
|
linksGetEntry.Validator = func(s string) error {
|
||||||
|
validated, err := com.IsThisALinkData(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !validated {
|
||||||
|
return errors.New("Link is not validated")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
linksGetBtn := widget.NewButtonWithIcon("Get", theme.MailReplyIcon(), func() {
|
||||||
|
link := linksGetEntry.Text
|
||||||
|
validated, err := com.IsThisALinkData(link)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("linksGetBtn: Error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !validated {
|
||||||
|
log.Printf("linksGetBtn: Error: link %v not validated\n", link)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
intercom <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_ASK_SERVER_LINK,
|
||||||
|
Data: []byte(link),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
linksGetEntry.SetOnValidationChanged(func(err error) {
|
||||||
|
if err != nil {
|
||||||
|
linksGetBtn.Hide()
|
||||||
|
} else {
|
||||||
|
if linksGetBtn.Hidden {
|
||||||
|
linksGetBtn.Show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
contentInner2 := container.NewGridWithColumns(2, linksGetEntry, linksGetBtn)
|
||||||
|
// /
|
||||||
|
// //
|
||||||
|
return container.NewGridWithRows(3,
|
||||||
|
header,
|
||||||
|
container.New(
|
||||||
|
layouts.NewVariableGridWithColumns(
|
||||||
|
6, []int{2, 1, 3}),
|
||||||
|
container.NewGridWithRows(3,
|
||||||
|
container.NewGridWithColumns(3,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
widget.NewLabel("Create link:"),
|
||||||
|
layout.NewSpacer()),
|
||||||
|
contentInner,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
linksList,
|
||||||
|
),
|
||||||
|
container.New(
|
||||||
|
layouts.NewVariableGridWithColumns(
|
||||||
|
6, []int{2, 4}),
|
||||||
|
container.NewGridWithRows(3,
|
||||||
|
container.NewGridWithColumns(3,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
widget.NewLabel("Get user from link:"),
|
||||||
|
layout.NewSpacer()),
|
||||||
|
contentInner2,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
), linksMutAt
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConnectionsSubScene(intercom chan *com.Message, header *fyne.Container) (*fyne.Container, BundleOfMutexArrays, MutableStructAboutWidgets) {
|
||||||
|
optionsHeaderLabel := widget.NewLabel("Options for user: ")
|
||||||
|
usersMuAr := CreateMutexStringArray()
|
||||||
|
usersOptions := make(map[string]*UserOptions)
|
||||||
|
userShortcuts := make(map[uint16]string)
|
||||||
|
userShortcutsRev := make(map[string]uint16)
|
||||||
|
userOptsCaretaker := container.NewGridWithRows(1)
|
||||||
|
optsContainer := container.NewGridWithRows(2,
|
||||||
|
optionsHeaderLabel,
|
||||||
|
userOptsCaretaker,
|
||||||
|
)
|
||||||
|
userSelect := widget.NewSelect(usersMuAr.Ar, func(s string) {
|
||||||
|
optionsHeaderLabel.SetText(fmt.Sprintf("Options for user: %s", s))
|
||||||
|
uOpts, exists := usersOptions[s]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("GetConnectionsSubScene::1 : TODO!!\n")
|
||||||
|
// TODO
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userOptsCaretaker.RemoveAll()
|
||||||
|
userOptsCaretaker.Add(uOpts.OptsContainer)
|
||||||
|
optsContainer.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
contentInner := container.New(layout.NewVBoxLayout(), userSelect, optsContainer)
|
||||||
|
return container.New(
|
||||||
|
layout.NewVBoxLayout(),
|
||||||
|
header,
|
||||||
|
container.New(
|
||||||
|
layout.NewHBoxLayout(),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
contentInner,
|
||||||
|
layout.NewSpacer(),
|
||||||
|
),
|
||||||
|
), BundleOfMutexArrays{
|
||||||
|
UsersMuAr: usersMuAr,
|
||||||
|
UsersOpts: usersOptions,
|
||||||
|
UserShortcuts: userShortcuts,
|
||||||
|
UserShortcutsRev: userShortcutsRev,
|
||||||
|
}, MutableStructAboutWidgets{
|
||||||
|
UsersSelect: userSelect,
|
||||||
|
UserOptsCaretaker: userOptsCaretaker,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUsersSubScene(intercom chan *com.Message, header *fyne.Container, userShortcutsRev map[string]uint16) (*fyne.Container, BundleOfMutexArrays, MutableStructAboutWidgets) {
|
||||||
|
msgHeader := widget.NewLabel("Messages With User: ")
|
||||||
|
usersMessages := make(map[string]*MutexArray[widgets.MBoardMessage])
|
||||||
|
usersMBoards := make(map[string]*widgets.MessageBoard)
|
||||||
|
msgEntry := widget.NewEntry()
|
||||||
|
msgEntry.SetPlaceHolder("Message...")
|
||||||
|
userMsgSendBtn := widget.NewButtonWithIcon("Send", theme.MailSendIcon(), func() {})
|
||||||
|
mBoardCareTaker := container.NewGridWithRows(1)
|
||||||
|
userMsgsSelect := widget.NewSelect([]string{}, func(s string) {
|
||||||
|
msgHeader.SetText(fmt.Sprintf("Messages With User: %s", s))
|
||||||
|
msgsMuAr, exists := usersMessages[s]
|
||||||
|
if !exists {
|
||||||
|
tmp := CreateMutexArray[widgets.MBoardMessage]()
|
||||||
|
usersMessages[s] = &tmp
|
||||||
|
msgsMuAr = &tmp
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mBoardCareTaker.RemoveAll()
|
||||||
|
mmBoard := widgets.NewMessageBoard(msgsMuAr.Ar)
|
||||||
|
usersMBoards[s] = mmBoard
|
||||||
|
mBoardCareTaker.Add(mmBoard)
|
||||||
|
mBoardCareTaker.Refresh()
|
||||||
|
id, exists := userShortcutsRev[s]
|
||||||
|
if !exists {
|
||||||
|
log.Printf("GetUsersSubScene::2 : TODO!!\n")
|
||||||
|
// TODO
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userMsgSendBtn.Text = fmt.Sprintf("%s", s)
|
||||||
|
userMsgSendBtn.OnTapped = func() {
|
||||||
|
intercom <- &com.Message{
|
||||||
|
ID: com.ID_CLIENT_SEND_CLIENT_MESSAGE,
|
||||||
|
ToID: id,
|
||||||
|
Data: []byte(msgEntry.Text),
|
||||||
|
}
|
||||||
|
msg := widgets.MBoardMessage{
|
||||||
|
LeftAlign: false,
|
||||||
|
Data: widget.NewLabel(msgEntry.Text),
|
||||||
|
}
|
||||||
|
msgsMuAr.Add(msg)
|
||||||
|
mmBoard.Add(msg)
|
||||||
|
msgEntry.Text = ""
|
||||||
|
msgEntry.Refresh()
|
||||||
|
mBoardCareTaker.Refresh()
|
||||||
|
mmBoard.Refresh()
|
||||||
|
}
|
||||||
|
userMsgSendBtn.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
// entryWithButton := container.NewHBox(
|
||||||
|
// layout.NewSpacer(),
|
||||||
|
// container.NewPadded(msgEntry),
|
||||||
|
// userMsgSendBtn,
|
||||||
|
// )
|
||||||
|
entryWithButton := container.New(
|
||||||
|
layouts.NewEntryBtn7030(),
|
||||||
|
msgEntry,
|
||||||
|
userMsgSendBtn,
|
||||||
|
)
|
||||||
|
fs := globalCfg.Window.Canvas().Size()
|
||||||
|
|
||||||
|
scene := container.New(
|
||||||
|
layout.NewVBoxLayout(),
|
||||||
|
header,
|
||||||
|
container.NewGridWithColumns(2,
|
||||||
|
container.New(
|
||||||
|
layout.NewVBoxLayout(),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
container.New(
|
||||||
|
layout.NewHBoxLayout(),
|
||||||
|
userMsgsSelect,
|
||||||
|
msgHeader,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
container.New(
|
||||||
|
layout.NewVBoxLayout(),
|
||||||
|
container.New(
|
||||||
|
layouts.NewFullWidthWithSize(fyne.NewSize(0, fs.Height*0.8)),
|
||||||
|
mBoardCareTaker,
|
||||||
|
),
|
||||||
|
layout.NewSpacer(),
|
||||||
|
entryWithButton,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// container.New(
|
||||||
|
// layouts.NewVariableGridWithRows(3, []int{1, 2}),
|
||||||
|
// header,
|
||||||
|
// container.New(
|
||||||
|
// layouts.NewVariableGridWithColumns(4, []int{1, 3}),
|
||||||
|
// container.NewGridWithColumns(3,
|
||||||
|
// layout.NewSpacer(),
|
||||||
|
// container.NewVBox(userMsgsSelect, msgHeader),
|
||||||
|
// layout.NewSpacer()),
|
||||||
|
// container.New(
|
||||||
|
// layouts.NewVariableGridWithRows(6, []int{5, 1}),
|
||||||
|
// mBoardCareTaker,
|
||||||
|
// container.NewHBox(msgEntry, userMsgSendBtn),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// )
|
||||||
|
return scene, BundleOfMutexArrays{
|
||||||
|
Messages: usersMessages,
|
||||||
|
}, MutableStructAboutWidgets{
|
||||||
|
MessagesSelect: userMsgsSelect,
|
||||||
|
MBoardCaretacker: mBoardCareTaker,
|
||||||
|
MsgButton: userMsgSendBtn,
|
||||||
|
MBoardMap: usersMBoards,
|
||||||
|
}
|
||||||
|
}
|
66
cmd/cfyne/tleps.go
Normal file
66
cmd/cfyne/tleps.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/gmyerr"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/tlep"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tlepCenter TlepCenter
|
||||||
|
)
|
||||||
|
|
||||||
|
type TlepCenter struct {
|
||||||
|
TLEPs map[uint16]*tlep.TLEP
|
||||||
|
Mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TlepCenter) Init() {
|
||||||
|
t.TLEPs = make(map[uint16]*tlep.TLEP)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ERROR_ALREADY_HAVE = errors.New("Already taken")
|
||||||
|
ERROR_DONT_HAVE = errors.New("Not found")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *TlepCenter) AddTLEP(id uint16, name string) error {
|
||||||
|
t.Mu.Lock()
|
||||||
|
defer t.Mu.Unlock()
|
||||||
|
_, alreadyHave := t.TLEPs[id]
|
||||||
|
if alreadyHave {
|
||||||
|
return ERROR_ALREADY_HAVE
|
||||||
|
}
|
||||||
|
val, err := tlep.InitTLEP(name)
|
||||||
|
if err != nil {
|
||||||
|
return gmyerr.WrapPrefix("tlep.InitTLEP", err)
|
||||||
|
}
|
||||||
|
val.Debug = true
|
||||||
|
t.TLEPs[id] = val
|
||||||
|
log.Printf("TLEPs: add %p for %d id\n", val, id)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TlepCenter) DeleteIfHaveOne(id uint16) {
|
||||||
|
t.Mu.Lock()
|
||||||
|
defer t.Mu.Unlock()
|
||||||
|
val, found := t.TLEPs[id]
|
||||||
|
if !found {
|
||||||
|
log.Printf("TLEP with %d id is not found; Can not delete\n", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(t.TLEPs, id)
|
||||||
|
log.Printf("TLEP with %v val and %d id was found; TLEP is deleted\n", val, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TlepCenter) GetTLEP(id uint16) (*tlep.TLEP, error) {
|
||||||
|
log.Printf("Getting tlep by id = %d\n", id)
|
||||||
|
name, have := t.TLEPs[id]
|
||||||
|
if !have {
|
||||||
|
return nil, ERROR_DONT_HAVE
|
||||||
|
}
|
||||||
|
return name, nil
|
||||||
|
}
|
125
cmd/cfyne/types.go
Normal file
125
cmd/cfyne/types.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.qowevisa.me/Qowevisa/gotell/extfyne/widgets"
|
||||||
|
// com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FyneConfig struct {
|
||||||
|
App fyne.App
|
||||||
|
Window fyne.Window
|
||||||
|
}
|
||||||
|
|
||||||
|
type MainSceneConfig struct {
|
||||||
|
UserNickcname string
|
||||||
|
// Just for my calmness
|
||||||
|
UserNameSet bool
|
||||||
|
UserId uint16
|
||||||
|
// Just for my calmness
|
||||||
|
UserIdSet bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutableStructAboutTabs struct {
|
||||||
|
AppTabs *container.AppTabs
|
||||||
|
LinkTab *container.TabItem
|
||||||
|
LinksBT string
|
||||||
|
LinksNoty uint
|
||||||
|
ConnectionTab *container.TabItem
|
||||||
|
ConnsBT string
|
||||||
|
ConnsNoty uint
|
||||||
|
UsersTab *container.TabItem
|
||||||
|
UsersBT string
|
||||||
|
UsersNoty uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutableStructAboutWidgets struct {
|
||||||
|
UsersSelect *widget.Select
|
||||||
|
UserOptsCaretaker *fyne.Container
|
||||||
|
MessagesSelect *widget.Select
|
||||||
|
MBoardCaretacker *fyne.Container
|
||||||
|
MsgButton *widget.Button
|
||||||
|
MBoardMap map[string]*widgets.MessageBoard
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserOptions struct {
|
||||||
|
OptsContainer *fyne.Container
|
||||||
|
Status int
|
||||||
|
ToID uint16
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BundleOfMutexArrays struct {
|
||||||
|
LinksMuAr *MutexLinksArray
|
||||||
|
UsersMuAr *MutexStringArray
|
||||||
|
UsersOpts map[string]*UserOptions
|
||||||
|
UserShortcuts map[uint16]string
|
||||||
|
UserShortcutsRev map[string]uint16
|
||||||
|
Messages map[string]*MutexArray[widgets.MBoardMessage]
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutableApp struct {
|
||||||
|
App fyne.App
|
||||||
|
Window fyne.Window
|
||||||
|
}
|
||||||
|
|
||||||
|
type MutableApplication struct {
|
||||||
|
Tabs MutableStructAboutTabs
|
||||||
|
Widgets MutableStructAboutWidgets
|
||||||
|
ArrayBundle BundleOfMutexArrays
|
||||||
|
App MutableApp
|
||||||
|
}
|
||||||
|
|
||||||
|
// I don't know if it is a good idea
|
||||||
|
type MutexArray[T any] struct {
|
||||||
|
Ar []T
|
||||||
|
Mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateMutexArray[T any]() MutexArray[T] {
|
||||||
|
var tmp []T
|
||||||
|
return MutexArray[T]{
|
||||||
|
Ar: tmp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexArray[T]) Add(v T) {
|
||||||
|
ma.Mu.Lock()
|
||||||
|
ma.Ar = append(ma.Ar, v)
|
||||||
|
ma.Mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexArray[T]) GetArray() []T {
|
||||||
|
ma.Mu.RLock()
|
||||||
|
defer ma.Mu.RUnlock()
|
||||||
|
return ma.Ar
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-Generic variant
|
||||||
|
type MutexStringArray struct {
|
||||||
|
Ar []string
|
||||||
|
Mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateMutexStringArray() *MutexStringArray {
|
||||||
|
var tmp []string
|
||||||
|
return &MutexStringArray{
|
||||||
|
Ar: tmp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexStringArray) Add(v string) {
|
||||||
|
ma.Mu.Lock()
|
||||||
|
ma.Ar = append(ma.Ar, v)
|
||||||
|
ma.Mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ma *MutexStringArray) GetArray() []string {
|
||||||
|
ma.Mu.RLock()
|
||||||
|
defer ma.Mu.RUnlock()
|
||||||
|
return ma.Ar
|
||||||
|
}
|
36
cmd/cfyne/uset_statuses.go
Normal file
36
cmd/cfyne/uset_statuses.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "log"
|
||||||
|
//
|
||||||
|
// "fyne.io/fyne/v2"
|
||||||
|
// "fyne.io/fyne/v2/container"
|
||||||
|
// "fyne.io/fyne/v2/widget"
|
||||||
|
// com "git.qowevisa.me/Qowevisa/gotell/communication"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
USER_STATUS_NOT_VISIBLE = 0 + iota
|
||||||
|
USER_STATUS_VISIBLE
|
||||||
|
USER_STATUS_HANDSHAKE_INIT
|
||||||
|
USER_STATUS_HANDSHAKE_ACCEPTED
|
||||||
|
USER_STATUS_ECDH_ESTABLISHED
|
||||||
|
USER_STATUS_ECDH_CBES_ESTABLISHED
|
||||||
|
USER_STATUS_ECDH_CBES_MKLG_ESTABLISHED
|
||||||
|
)
|
||||||
|
|
||||||
|
// func getUserOptsContainer(userStatus int, intercom chan *com.Message) *fyne.Container {
|
||||||
|
// switch {
|
||||||
|
// case USER_STATUS_HANDSHAKE_INIT:
|
||||||
|
// btn := widget.NewButton("Init Hadnshake", func() {
|
||||||
|
// intercom <- &com.Message{
|
||||||
|
// ID: ID_CLIENT_ASK_CLIENT_HANDSHAKE,
|
||||||
|
// ToID: ,
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// return container.NewGridWithRows(1, )
|
||||||
|
// default:
|
||||||
|
// log.Printf("ERROR: getUserOptsContainer: status %d was not handled!", userStatus)
|
||||||
|
// return container.NewGridWithRows(1, widget.NewLabel("ERROR: 500"))
|
||||||
|
// }
|
||||||
|
// }
|
18
cmd/cfyne/util.go
Normal file
18
cmd/cfyne/util.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func getStdUserName(userID uint16, userName string) string {
|
||||||
|
return fmt.Sprintf("User: %s; ID: %d", userName, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTabNameBasedOnBaseTextAndNoty(baseText string, noty uint) string {
|
||||||
|
return fmt.Sprintf("%s (%d)", baseText, noty)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTabsBasedOnNotyVals(tabs *MutableStructAboutTabs) {
|
||||||
|
tabs.LinkTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.LinksBT, tabs.LinksNoty)
|
||||||
|
tabs.ConnectionTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.ConnsBT, tabs.ConnsNoty)
|
||||||
|
tabs.UsersTab.Text = getTabNameBasedOnBaseTextAndNoty(tabs.UsersBT, tabs.UsersNoty)
|
||||||
|
tabs.AppTabs.Refresh()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user