mirror of
https://github.com/darmiel/yaxc.git
synced 2025-09-30 02:15:57 +08:00
Some cleanup
This commit is contained in:
parent
a8e405fbe7
commit
d04cc64c27
7 changed files with 206 additions and 172 deletions
186
cmd/watch.go
186
cmd/watch.go
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
28
internal/client/client.go
Normal 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,
|
||||
}
|
||||
}
|
67
internal/client/watch_client.go
Normal file
67
internal/client/watch_client.go
Normal 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
|
||||
}
|
76
internal/client/watch_server.go
Normal file
76
internal/client/watch_server.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue