mirror of
https://github.com/darmiel/yaxc.git
synced 2025-10-06 05:16: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
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/atotto/clipboard"
|
"github.com/darmiel/yaxc/internal/client"
|
||||||
"github.com/darmiel/yaxc/internal/api"
|
"github.com/spf13/cobra"
|
||||||
"github.com/darmiel/yaxc/internal/common"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
watchAnywherePath string
|
watchAnywherePath string
|
||||||
watchPassphrase string
|
watchPassphrase string
|
||||||
)
|
watchIgnoreServer bool
|
||||||
|
watchIgnoreClient bool
|
||||||
var (
|
|
||||||
errors int
|
|
||||||
|
|
||||||
lastClipboardData string
|
|
||||||
lastClipboardHash string
|
|
||||||
ignoreClipboardHash string
|
|
||||||
|
|
||||||
mu = sync.Mutex{}
|
|
||||||
errMu = sync.Mutex{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// watchCmd represents the watch command
|
// watchCmd represents the watch command
|
||||||
|
@ -51,161 +37,35 @@ var watchCmd = &cobra.Command{
|
||||||
Use: "watch",
|
Use: "watch",
|
||||||
Long: `Watch Clipboard`,
|
Long: `Watch Clipboard`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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
|
if !watchIgnoreServer {
|
||||||
// clipboard
|
log.Println(" [~] Starting Server Update Watcher")
|
||||||
go watchClipboard(watchAnywherePath, watchPassphrase, d)
|
go client.WatchServer(check, 1*time.Second, done)
|
||||||
go watchServer(watchAnywherePath, watchPassphrase, d)
|
}
|
||||||
|
|
||||||
|
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.")
|
log.Println("Started clipboard-watcher. Press CTRL-C to stop.")
|
||||||
sc := make(chan os.Signal, 1)
|
sc := make(chan os.Signal, 1)
|
||||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM)
|
||||||
<-sc
|
<-sc
|
||||||
|
|
||||||
// stop watchers
|
// Stopping server watcher
|
||||||
d <- 1
|
done <- true
|
||||||
d <- 1
|
|
||||||
|
|
||||||
log.Println("Stopped.")
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
func init() {
|
||||||
rootCmd.AddCommand(watchCmd)
|
rootCmd.AddCommand(watchCmd)
|
||||||
|
|
||||||
|
@ -213,4 +73,6 @@ func init() {
|
||||||
cobra.CheckErr(cobra.MarkFlagRequired(watchCmd.Flags(), "anywhere"))
|
cobra.CheckErr(cobra.MarkFlagRequired(watchCmd.Flags(), "anywhere"))
|
||||||
|
|
||||||
watchCmd.Flags().StringVarP(&watchPassphrase, "passphrase", "s", "", "Encryption Key")
|
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")
|
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
|
var resp *req.Resp
|
||||||
if resp, err = req.Get(a.ServerURL + "/" + path); err != nil {
|
if resp, err = req.Get(a.ServerURL + "/" + path); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -33,7 +33,7 @@ func (a *api) GetContent(path, passphrase string) (res string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *api) SetContent(path, passphrase, content string) (err error) {
|
func (a *Api) SetContent(path, passphrase, content string) (err error) {
|
||||||
if passphrase != "" {
|
if passphrase != "" {
|
||||||
var b []byte
|
var b []byte
|
||||||
if b, err = common.Encrypt(content, passphrase); err != nil {
|
if b, err = common.Encrypt(content, passphrase); err != nil {
|
||||||
|
@ -45,7 +45,7 @@ func (a *api) SetContent(path, passphrase, content string) (err error) {
|
||||||
return
|
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
|
var resp *req.Resp
|
||||||
if resp, err = req.Get(a.ServerURL + "/hash/" + path); err != nil {
|
if resp, err = req.Get(a.ServerURL + "/hash/" + path); err != nil {
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,13 +2,13 @@ package api
|
||||||
|
|
||||||
import "github.com/spf13/viper"
|
import "github.com/spf13/viper"
|
||||||
|
|
||||||
type api struct {
|
type Api struct {
|
||||||
ServerURL string
|
ServerURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func API() *api {
|
func API() *Api {
|
||||||
server := viper.GetString("server")
|
server := viper.GetString("server")
|
||||||
return &api{
|
return &Api{
|
||||||
ServerURL: server,
|
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"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var NotPiped = errors.New("not piped")
|
var NotPiped = errors.New("not piped")
|
||||||
|
@ -14,15 +15,12 @@ func ReadPipe() (res string, err error) {
|
||||||
if info, err = os.Stdin.Stat(); err != nil {
|
if info, err = os.Stdin.Stat(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Mode()&os.ModeCharDevice != 0 || info.Size() <= 0 {
|
if info.Mode()&os.ModeCharDevice != 0 || info.Size() <= 0 {
|
||||||
err = NotPiped
|
err = NotPiped
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
var output []rune
|
var output []rune
|
||||||
|
|
||||||
for {
|
for {
|
||||||
input, _, err := reader.ReadRune()
|
input, _, err := reader.ReadRune()
|
||||||
if err != nil && err == io.EOF {
|
if err != nil && err == io.EOF {
|
||||||
|
@ -30,7 +28,10 @@ func ReadPipe() (res string, err error) {
|
||||||
}
|
}
|
||||||
output = append(output, input)
|
output = append(output, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
res = string(output)
|
res = string(output)
|
||||||
|
// remove new line at the end
|
||||||
|
if strings.HasSuffix(res, "\n") {
|
||||||
|
res = res[:len(res)-1]
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue