Some cleanup

This commit is contained in:
darmiel 2021-03-28 16:21:48 +02:00
parent a8e405fbe7
commit d04cc64c27
7 changed files with 206 additions and 172 deletions

View file

@ -16,34 +16,20 @@ limitations under the License.
package cmd
import (
"github.com/atotto/clipboard"
"github.com/darmiel/yaxc/internal/api"
"github.com/darmiel/yaxc/internal/common"
"github.com/darmiel/yaxc/internal/client"
"github.com/spf13/cobra"
"log"
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"
"github.com/spf13/cobra"
)
var (
watchAnywherePath string
watchPassphrase string
)
var (
errors int
lastClipboardData string
lastClipboardHash string
ignoreClipboardHash string
mu = sync.Mutex{}
errMu = sync.Mutex{}
watchIgnoreServer bool
watchIgnoreClient bool
)
// watchCmd represents the watch command
@ -51,161 +37,35 @@ var watchCmd = &cobra.Command{
Use: "watch",
Long: `Watch Clipboard`,
Run: func(cmd *cobra.Command, args []string) {
check := client.NewCheck(watchAnywherePath, watchPassphrase)
done := make(chan bool)
d := make(chan int, 1)
log.Println("Starting watchers:")
// start watcher
// clipboard
go watchClipboard(watchAnywherePath, watchPassphrase, d)
go watchServer(watchAnywherePath, watchPassphrase, d)
if !watchIgnoreServer {
log.Println(" [~] Starting Server Update Watcher")
go client.WatchServer(check, 1*time.Second, done)
}
if !watchIgnoreClient {
log.Println(" [~] Starting Client Update Watcher")
go client.WatchClient(check, 100*time.Millisecond, done)
}
if watchIgnoreServer && watchIgnoreClient {
log.Println("WARN :: Ignoring Client & Server")
}
log.Println("Started clipboard-watcher. Press CTRL-C to stop.")
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
<-sc
// stop watchers
d <- 1
d <- 1
log.Println("Stopped.")
// Stopping server watcher
done <- true
},
}
func handleErr(err error, m string) {
errMu.Lock()
errors++
errMu.Unlock()
log.Println("[err]", "(", m, ") ::", errors, "errors:", err)
}
func watchClipboard(path, pass string, done chan int) {
a := api.API()
t := time.NewTicker(100 * time.Millisecond)
for {
select {
case <-t.C:
mu.Lock()
data, err := clipboard.ReadAll()
if err != nil {
mu.Unlock()
continue
}
errors = 0
// strip data
data = strings.TrimSpace(data)
if lastClipboardData == data {
mu.Unlock()
continue
}
log.Println("[o] Changed!")
// calculate new hash
lastClipboardData = data
lastClipboardHash = common.MD5Hash(data)
// check if server has current clipboard
serverHash, err := a.GetHash(path)
if err != nil && err != api.ErrErrResponse {
handleErr(err, "read-server-hash")
mu.Unlock()
continue
}
if err != api.ErrErrResponse {
if serverHash == lastClipboardHash {
log.Println("[ ~ ] (rea) Server Hash == Local Hash")
mu.Unlock()
continue
}
}
ignoreClipboardHash = serverHash
// update server hash
if err := a.SetContent(path, pass, data); err != nil {
mu.Unlock()
handleErr(err, "set-server-content")
continue
}
log.Println("[ ok] Updated contents.")
mu.Unlock()
break
case <-done:
log.Println("[ ok] Stopping watch clipboard")
return
}
}
}
func watchServer(path, pass string, done chan int) {
a := api.API()
t := time.NewTicker(1 * time.Second)
for {
select {
case <-t.C:
time.Sleep(1 * time.Second)
mu.Lock()
hash, err := a.GetHash(path)
if err != nil {
if err != api.ErrErrResponse {
handleErr(err, "read-server-hash")
}
mu.Unlock()
continue
}
if hash == lastClipboardHash || hash == ignoreClipboardHash {
mu.Unlock()
continue
}
// get data
data, err := a.GetContent(path, pass)
if err != nil {
mu.Unlock()
handleErr(err, "read-server-contents")
continue
}
// empty
if strings.TrimSpace(data) == "" {
log.Println("[wrn] Received empty data")
mu.Unlock()
continue
}
log.Println("[ ~ ] Received new data:", data)
lastClipboardData = data
lastClipboardHash = common.MD5Hash(data)
if err := clipboard.WriteAll(data); err != nil {
ignoreClipboardHash = hash
handleErr(err, "write-clipboard")
mu.Unlock()
continue
}
log.Println("[ ok] Wrote client content")
mu.Unlock()
break
case <-done:
log.Println("[ ok] Stopping watch server")
return
}
}
}
func init() {
rootCmd.AddCommand(watchCmd)
@ -213,4 +73,6 @@ func init() {
cobra.CheckErr(cobra.MarkFlagRequired(watchCmd.Flags(), "anywhere"))
watchCmd.Flags().StringVarP(&watchPassphrase, "passphrase", "s", "", "Encryption Key")
watchCmd.Flags().BoolVar(&watchIgnoreServer, "ignore-server", false, "Ignore Server Updates")
watchCmd.Flags().BoolVar(&watchIgnoreClient, "ignore-client", false, "Ignore Client Updates")
}

View file

@ -10,7 +10,7 @@ var (
ErrErrResponse = errors.New("invalid response")
)
func (a *api) GetContent(path, passphrase string) (res string, err error) {
func (a *Api) GetContent(path, passphrase string) (res string, err error) {
var resp *req.Resp
if resp, err = req.Get(a.ServerURL + "/" + path); err != nil {
return
@ -33,7 +33,7 @@ func (a *api) GetContent(path, passphrase string) (res string, err error) {
return
}
func (a *api) SetContent(path, passphrase, content string) (err error) {
func (a *Api) SetContent(path, passphrase, content string) (err error) {
if passphrase != "" {
var b []byte
if b, err = common.Encrypt(content, passphrase); err != nil {
@ -45,7 +45,7 @@ func (a *api) SetContent(path, passphrase, content string) (err error) {
return
}
func (a *api) GetHash(path string) (res string, err error) {
func (a *Api) GetHash(path string) (res string, err error) {
var resp *req.Resp
if resp, err = req.Get(a.ServerURL + "/hash/" + path); err != nil {
return

View file

@ -2,13 +2,13 @@ package api
import "github.com/spf13/viper"
type api struct {
type Api struct {
ServerURL string
}
func API() *api {
func API() *Api {
server := viper.GetString("server")
return &api{
return &Api{
ServerURL: server,
}
}

28
internal/client/client.go Normal file
View file

@ -0,0 +1,28 @@
package client
import (
"errors"
"github.com/darmiel/yaxc/internal/api"
"sync"
)
var (
ErrEmptyHash = errors.New("empty hash")
ErrUnsupported = errors.New("clipboard unsupported")
)
type Check struct {
a *api.Api
mu sync.Mutex
path string
pass string
}
func NewCheck(path, pass string) *Check {
return &Check{
a: api.API(),
mu: sync.Mutex{},
path: path,
pass: pass,
}
}

View file

@ -0,0 +1,67 @@
package client
import (
"github.com/atotto/clipboard"
"github.com/darmiel/yaxc/internal/common"
"log"
"strings"
"time"
)
func WatchClient(c *Check, d time.Duration, done chan bool) {
t := time.NewTicker(d)
for {
select {
case <-done:
log.Println("[Watch Client] Stopping ...")
return
case <-t.C:
if err := c.CheckClient(); err != nil {
log.Println("[Watch Client] WARN:", err)
}
break
}
}
}
func (c *Check) CheckClient() (err error) {
// check if clipboard actions are available
if clipboard.Unsupported {
return ErrUnsupported
}
// lock
c.mu.Lock()
defer c.mu.Unlock()
// get clipboard
var cb string
cb, _ = clipboard.ReadAll()
// ignore empty clipboard
if strings.TrimSpace(cb) == "" {
return
}
// calculate hash
var ch string
if ch = common.MD5Hash(cb); ch == "" {
err = ErrEmptyHash
return
}
// get hash from server
var sh string
sh, _ = c.a.GetHash(c.path)
if strings.TrimSpace(sh) != "" {
// compare hashes
if ch == sh {
return
}
}
// upload to server
err = c.a.SetContent(c.path, c.pass, cb)
log.Println("Wrote: '" + cb + "' to server")
return
}

View file

@ -0,0 +1,76 @@
package client
import (
"github.com/atotto/clipboard"
"github.com/darmiel/yaxc/internal/api"
"github.com/darmiel/yaxc/internal/common"
"log"
"time"
)
func WatchServer(c *Check, d time.Duration, done chan bool) {
t := time.NewTicker(d)
for {
select {
case <-done:
log.Println("[Watch Server] Stopping ...")
return
case <-t.C:
if err := c.CheckServer(); err != nil {
log.Println("[Watch Server] WARN:", err)
}
break
}
}
}
func (c *Check) CheckServer() (err error) {
// check if clipboard actions are available
if clipboard.Unsupported {
return ErrUnsupported
}
// lock
c.mu.Lock()
defer c.mu.Unlock()
// get hash from server
var sh string
if sh, err = c.a.GetHash(c.path); err != nil {
if err == api.ErrErrResponse {
err = nil
}
return
}
if sh == "" {
return ErrEmptyHash
}
// get clipboard
var cb string
cb, _ = clipboard.ReadAll()
if cb != "" {
// calculate hash
var ch string
if ch = common.MD5Hash(cb); ch == "" {
err = ErrEmptyHash
return
}
// compare hashes
if ch == sh {
return
}
}
// get data from server
var sd string
if sd, err = c.a.GetContent(c.path, c.pass); err != nil {
return
}
// update contents
err = clipboard.WriteAll(sd)
log.Println("Wrote: '" + sd + "' to client")
return
}

View file

@ -5,6 +5,7 @@ import (
"errors"
"io"
"os"
"strings"
)
var NotPiped = errors.New("not piped")
@ -14,15 +15,12 @@ func ReadPipe() (res string, err error) {
if info, err = os.Stdin.Stat(); err != nil {
return
}
if info.Mode()&os.ModeCharDevice != 0 || info.Size() <= 0 {
err = NotPiped
return
}
reader := bufio.NewReader(os.Stdin)
var output []rune
for {
input, _, err := reader.ReadRune()
if err != nil && err == io.EOF {
@ -30,7 +28,10 @@ func ReadPipe() (res string, err error) {
}
output = append(output, input)
}
res = string(output)
// remove new line at the end
if strings.HasSuffix(res, "\n") {
res = res[:len(res)-1]
}
return
}