Removed lab and .vscode directories
This commit is contained in:
parent
5244f87411
commit
2efb8c4130
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.vscode/
|
||||||
|
lab/
|
22
.vscode/tasks.json
vendored
22
.vscode/tasks.json
vendored
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
||||||
// for the documentation about the tasks.json format
|
|
||||||
"version": "2.0.0",
|
|
||||||
"tasks": [
|
|
||||||
{
|
|
||||||
"label": "Go run file",
|
|
||||||
"type": "shell",
|
|
||||||
"command": "go run ${file}",
|
|
||||||
"args": [],
|
|
||||||
"group": "none",
|
|
||||||
"presentation": {
|
|
||||||
"echo": true,
|
|
||||||
"reveal": "always",
|
|
||||||
"focus": true,
|
|
||||||
"panel": "shared",
|
|
||||||
"showReuseMessage": false,
|
|
||||||
"clear": true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
74
lab/TODO.md
74
lab/TODO.md
|
@ -1,74 +0,0 @@
|
||||||
- Implement a core package that will be in charge of file comparison, transfer
|
|
||||||
|
|
||||||
- Implement protocol :
|
|
||||||
- Be careful about metadata, large files, error handling and performance
|
|
||||||
- Implement the sql version
|
|
||||||
- Implement the tls version
|
|
||||||
|
|
||||||
- Create configuration file :
|
|
||||||
- server address
|
|
||||||
- sync mode
|
|
||||||
- sync interval
|
|
||||||
|
|
||||||
- Enhanced error handling :
|
|
||||||
- Only use panic during uncoverable situations
|
|
||||||
- Use more explicit error types
|
|
||||||
|
|
||||||
- Use json/yaml config format (see viper)
|
|
||||||
|
|
||||||
- Authentication :
|
|
||||||
- Use a token based authentication system
|
|
||||||
- Use a secure way to store the token (KMS ?)
|
|
||||||
|
|
||||||
- Maintain a data structure to track the synchronization state of files :
|
|
||||||
- Local status
|
|
||||||
- Remote status
|
|
||||||
- Synchronization status
|
|
||||||
|
|
||||||
- See io/ioutil or io/fs to read/write files
|
|
||||||
|
|
||||||
- Break functions into little functions
|
|
||||||
|
|
||||||
- Use appropriate data structures to represent files and folders. Consider using a map to store file information for faster lookups.
|
|
||||||
|
|
||||||
- Improve logging (using a library like logrus or zap) ?
|
|
||||||
|
|
||||||
- Unit & integration tests
|
|
||||||
|
|
||||||
- Improve code style
|
|
||||||
|
|
||||||
- Document
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Gemini
|
|
||||||
|
|
||||||
- Implement a CLI :
|
|
||||||
- Use a library like cobra or urfave/cli
|
|
||||||
|
|
||||||
- Implement a GUI :
|
|
||||||
- Use a library like fltk or qt
|
|
||||||
|
|
||||||
- Implement a web interface :
|
|
||||||
- Use a library like gin or echo
|
|
||||||
|
|
||||||
- Implement a daemon :
|
|
||||||
- Use a library like daemon or godo
|
|
||||||
|
|
||||||
- Implement a service :
|
|
||||||
- Use a library like consul or etcd
|
|
||||||
|
|
||||||
- Implement a cloud storage integration :
|
|
||||||
- Use a library like aws-sdk-go or google-cloud-go
|
|
||||||
|
|
||||||
- Implement a version control system integration :
|
|
||||||
- Use a library like git or mercurial
|
|
||||||
|
|
||||||
- Implement a backup system integration :
|
|
||||||
- Use a library like restic or borg
|
|
||||||
|
|
||||||
- Implement a file system watcher :
|
|
||||||
- Use a library like fsnotify or inotify
|
|
|
@ -1,91 +0,0 @@
|
||||||
package lab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleMain() {
|
|
||||||
// Choose either server or client mode
|
|
||||||
if len(os.Args) > 1 && os.Args[1] == "server" {
|
|
||||||
runServer()
|
|
||||||
} else {
|
|
||||||
runClient()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runServer() {
|
|
||||||
listener, err := net.Listen("tcp", ":8080")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
fmt.Println("Server listening on :8080")
|
|
||||||
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error accepting connection:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
go handleConnection(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleConnection(conn net.Conn) {
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
reader := bufio.NewReader(conn)
|
|
||||||
for {
|
|
||||||
message, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
fmt.Println("Client disconnected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("Error reading from client:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("Received from client:", message)
|
|
||||||
|
|
||||||
// Process the message (e.g., send a response)
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Send a response to the client
|
|
||||||
_, err = conn.Write([]byte("Server received your message\n"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error writing to client:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runClient() {
|
|
||||||
conn, err := net.Dial("tcp", "localhost:8080")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
fmt.Println("Connected to server")
|
|
||||||
|
|
||||||
// Send a message to the server
|
|
||||||
_, err = conn.Write([]byte("Hello from the client!\n"))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error writing to server:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the server's response
|
|
||||||
reader := bufio.NewReader(conn)
|
|
||||||
message, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error reading from server:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("Received from server:", message)
|
|
||||||
}
|
|
24
lab/algo.txt
24
lab/algo.txt
|
@ -1,24 +0,0 @@
|
||||||
1. [On first setup] configure what files must be saved and their ID, configure sync mode you want to use (reflect up, reflect down, or bidirectionnal)
|
|
||||||
2. authenticate to the serv
|
|
||||||
3. [On first setup] Choose if you want to download or upload existing files
|
|
||||||
4. // index the files
|
|
||||||
5. // Check if changes were made, if not, do nothing
|
|
||||||
6. // Encode the files
|
|
||||||
7. Transfer the files over tcp with ssl
|
|
||||||
8. // Decode the files
|
|
||||||
9. // [On server] [if there are conflicts] take the last modified file
|
|
||||||
10. Reupdate every hour
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Authentication:
|
|
||||||
Register:
|
|
||||||
- client sends registration request to the server
|
|
||||||
- server returns fail/success code and a token
|
|
||||||
- client stores the token locally then authenticate
|
|
||||||
|
|
||||||
Authenticate:
|
|
||||||
- client sends token
|
|
||||||
- server returns bool isTokenValid and link client to the token temporarly
|
|
116
lab/core.gone
116
lab/core.gone
|
@ -1,116 +0,0 @@
|
||||||
// core/sync.go
|
|
||||||
package lab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// File represents file metadata
|
|
||||||
type File struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
Size int64
|
|
||||||
Checksum string
|
|
||||||
ModTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync compares local and remote files and performs synchronization
|
|
||||||
func Sync(localRoot, remoteRoot string) error {
|
|
||||||
// 1. Scan local files
|
|
||||||
localFiles, err := scanFiles(localRoot)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error scanning local files: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Scan remote files (replace with actual server communication)
|
|
||||||
remoteFiles, err := scanFiles(remoteRoot)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error scanning remote files: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Compare and synchronize
|
|
||||||
for _, localFile := range localFiles {
|
|
||||||
// Check if file exists remotely
|
|
||||||
remoteFile, found := remoteFiles[localFile.Path]
|
|
||||||
if !found {
|
|
||||||
// Upload file
|
|
||||||
err := uploadFile(localFile.Path, remoteRoot)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error uploading file: %w", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Compare timestamps
|
|
||||||
if localFile.ModTime.After(remoteFile.ModTime) {
|
|
||||||
// Upload updated file
|
|
||||||
err := uploadFile(localFile.Path, remoteRoot)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error uploading file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Delete files that are no longer present locally
|
|
||||||
for _, remoteFile := range remoteFiles {
|
|
||||||
if _, found := localFiles[remoteFile.Path]; !found {
|
|
||||||
// Delete file remotely
|
|
||||||
err := deleteFile(remoteFile.Path, remoteRoot)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error deleting file: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanFiles recursively scans a directory and returns a map of file metadata
|
|
||||||
func scanFiles(root string) (map[string]*File, error) {
|
|
||||||
files := make(map[string]*File)
|
|
||||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !info.IsDir() {
|
|
||||||
data, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
checksum := calculateChecksum(data)
|
|
||||||
files[path] = &File{
|
|
||||||
Name: info.Name(),
|
|
||||||
Path: path,
|
|
||||||
Size: info.Size(),
|
|
||||||
Checksum: checksum,
|
|
||||||
ModTime: info.ModTime(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return files, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadFile uploads a file to the remote server
|
|
||||||
func uploadFile(localPath, remoteRoot string) error {
|
|
||||||
// Implement file upload logic
|
|
||||||
// ...
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteFile deletes a file from the remote server
|
|
||||||
func deleteFile(remotePath, remoteRoot string) error {
|
|
||||||
// Implement file deletion logic
|
|
||||||
// ...
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateChecksum calculates the checksum of a file
|
|
||||||
func calculateChecksum(data []byte) string {
|
|
||||||
// Implement checksum calculation logic
|
|
||||||
// ...
|
|
||||||
return ""
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
package lab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net"
|
|
||||||
// "os"
|
|
||||||
"time"
|
|
||||||
// "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NotMain() {
|
|
||||||
|
|
||||||
TestServer()
|
|
||||||
// f, err := os.Open("/home/shared/Workplan/CoSync/lab/")
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// files, err := f.Readdir(0)
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for _, v := range files {
|
|
||||||
// println(v.Name(), v.IsDir())
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
func Server() {
|
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "localhost:4945")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
msg, err := io.ReadAll(conn)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
conn.Write([]byte("hello from server"))
|
|
||||||
io.Closer.Close(conn)
|
|
||||||
|
|
||||||
print("[SERVER] ", conn.RemoteAddr().String(), " : ")
|
|
||||||
println(string(msg))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func Client(message string) {
|
|
||||||
srv, err := net.Dial("tcp", "localhost:4945")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer srv.Close()
|
|
||||||
|
|
||||||
// format message
|
|
||||||
// msg := make([]byte, 0)
|
|
||||||
// msg = append(msg, []byte(message)...)
|
|
||||||
msg2 := []byte(message)
|
|
||||||
|
|
||||||
srv.Write(msg2)
|
|
||||||
println("[Client] Wrote msg")
|
|
||||||
|
|
||||||
//TODO: reprise
|
|
||||||
var b []byte
|
|
||||||
b2, err :=srv.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
println("[Client] Read msg : " + string(b2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServer() {
|
|
||||||
go Server()
|
|
||||||
go Client("this is a test")
|
|
||||||
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
println("[Main] finished")
|
|
||||||
}
|
|
|
@ -1,172 +0,0 @@
|
||||||
package lab
|
|
||||||
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"os/user"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
// "fmt"
|
|
||||||
// "io"q
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"cosync/internal/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
colorRed = "\033[0;31m"
|
|
||||||
colorGreen = "\033[1;32m"
|
|
||||||
colorNone = "\033[0m"
|
|
||||||
separator = "\n ============================================== \n\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
currentUser, _ = user.Current()
|
|
||||||
configFolder = "/home/" + currentUser.Username + "/.config/cosync/"
|
|
||||||
configFilePath = configFolder + "files.sync"
|
|
||||||
server = "https://sync.oblic-parallels.fr"
|
|
||||||
)
|
|
||||||
|
|
||||||
type file struct {
|
|
||||||
path string
|
|
||||||
modTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
// Print logo
|
|
||||||
println(" ______ ______ \n .' ___ | .' ____ \\ \n/ .' \\_| .--. | (___ \\_| _ __ _ .--. .---. \n| | / .'`\\ \\ _.____`. [ \\ [ ][ `.-. | / /'`\\] \n\\ `.___.'\\| \\__. || \\____) | \\ '/ / | | | | | \\__. \n `.____ .' '.__.' \\______.'[\\_: / [___||__]'.___.' \n \\__.' ")
|
|
||||||
|
|
||||||
// Open config file or create it if doesn't exists
|
|
||||||
configFile, err := os.Open(configFilePath)
|
|
||||||
if err == nil {
|
|
||||||
client.Setup()
|
|
||||||
}
|
|
||||||
defer configFile.Close()
|
|
||||||
|
|
||||||
// Get status from the server
|
|
||||||
resp, err := http.Get(server)
|
|
||||||
if err != nil {
|
|
||||||
print("\n\n" + colorRed)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
// Print server status
|
|
||||||
print(separator)
|
|
||||||
println("using server: ", server)
|
|
||||||
println("Response status:", resp.Status)
|
|
||||||
|
|
||||||
// Authenticate
|
|
||||||
// I'll do it later
|
|
||||||
|
|
||||||
print(separator)
|
|
||||||
println("Checking files :")
|
|
||||||
|
|
||||||
// Check if config file isn't empty
|
|
||||||
configFileStats, _ := configFile.Stat()
|
|
||||||
if configFileStats.Size() == 0 {
|
|
||||||
println("\n No files listed in config. There is nothing to do.")
|
|
||||||
println("\n\n > Exiting ...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and index all lines from config
|
|
||||||
|
|
||||||
configFileScanner := bufio.NewScanner(configFile)
|
|
||||||
register := make(map[string]file)
|
|
||||||
|
|
||||||
for configFileScanner.Scan() {
|
|
||||||
line := configFileScanner.Text()
|
|
||||||
|
|
||||||
print("\n ", line)
|
|
||||||
|
|
||||||
if line != "" {
|
|
||||||
index(line, register)
|
|
||||||
print(colorGreen + " ✔" + colorNone)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
|
|
||||||
// Read from server
|
|
||||||
// scanner := bufio.NewScanner(resp.Body)
|
|
||||||
// for scanner.Scan() {
|
|
||||||
// println(scanner.Text())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if err := scanner.Err(); err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
//test
|
|
||||||
// f, err := os.Open("/home/guillem/.vscode/extensions/extensions.json")
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err)
|
|
||||||
// }
|
|
||||||
// defer f.Close()
|
|
||||||
|
|
||||||
// fs, _ := f.Stat()
|
|
||||||
// if fs.ModTime().Before()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func index(line string, register map[string]file) {
|
|
||||||
|
|
||||||
decomposedLine := strings.Split(line, " : ")
|
|
||||||
|
|
||||||
// check separator
|
|
||||||
if len(decomposedLine) != 2 {
|
|
||||||
println(colorRed + " ✘\n\nThis line is not valid" + colorNone)
|
|
||||||
panic(line + " is not a valid syntax")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if id is valid
|
|
||||||
if !IsValidID(decomposedLine[0]) {
|
|
||||||
println(colorRed + " ✘\n\nThis line is not valid" + colorNone)
|
|
||||||
panic("Id must be composed only by alphanumerical characters")
|
|
||||||
}
|
|
||||||
|
|
||||||
appendFiles(decomposedLine[0], decomposedLine[1], register)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsValidID(id string) bool {
|
|
||||||
return strings.ContainsFunc(id, IsSpecialRune)
|
|
||||||
}
|
|
||||||
func IsSpecialRune(r rune) bool {
|
|
||||||
return (r < 'A' || r > 'z' || (r > 'Z' && r < 'a')) && (r < '0' || r > '9') && r != '_'
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendFiles(id string, path string, register map[string]file) {
|
|
||||||
|
|
||||||
// get subfiles and subfolders
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
println(colorRed + " ✘\n\n" + colorNone)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
fstat, err := f.Stat()
|
|
||||||
if err != nil {
|
|
||||||
println(colorRed + " ✘\n\n" + colorNone)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if path points to a folder
|
|
||||||
if fstat.IsDir() {
|
|
||||||
files, err := f.ReadDir(0)
|
|
||||||
if err != nil {
|
|
||||||
println(colorRed + " ✘\n\n" + colorNone)
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// call this function recursively for all subfiles and folders
|
|
||||||
for i := 0; i < len(files); i++ {
|
|
||||||
appendFiles(id+"-"+files[i].Name(), path+"/"+files[i].Name(), register)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
register[id] = file{path, fstat.ModTime()}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue