func (fs *FileSession) textHandler(incomingPacket packet.PacketStd) { //closes connection and removes session if client /quit if incomingPacket.Data == "quit" { fs.CloseSession = true fs.Connection.Close() fmt.Println("session " + strconv.Itoa(fs.User.Id) + " closed connection") //send session to channel to invoke container deletion fs_asSession := Session{fs.User, fs.SessionChan, fs.CloseSession, fs.RootDir} //morphs FileSession to Session fs.SessionChan <- fs_asSession } newPacket := packet.PacketStd{packet.Packet{"text", ""}, "SEND_TEXT_DONE"} go newPacket.SendPacket(fs.Connection) }
func (fs *FileSession) FileSession_Authenticate(p packet.PacketStd) { fmt.Println("Authenticating new user") db, error := sql.Open("sqlite3", fs.RootDir+"/gypo.db") if error != nil { fmt.Println(error.Error()) } else { username := p.Data[:strings.Index(p.Data, "|")] password := p.Data[strings.Index(p.Data, "|")+1:] fmt.Println("username: "******" - password: "******"SELECT id FROM users WHERE username = ? AND password = ?", username, password).Scan(&fs.User.Id) if error != nil { newPacket := packet.PacketStd{packet.Packet{"text", "login"}, "USER_AUTHENTICATED_FALSE"} go newPacket.SendPacket(fs.Connection) fmt.Println("auth fail") } else { newPacket := packet.PacketStd{packet.Packet{"text", "login"}, "USER_AUTHENTICATED_TRUE"} go newPacket.SendPacket(fs.Connection) //send session to channel to invoke session container insertion fs_asSession := Session{fs.User, fs.SessionChan, fs.CloseSession, fs.RootDir} //morphs FileSession to Session fs.SessionChan <- fs_asSession fmt.Println("auth success, id set to ", fs.User.Id) //creates user folder if needed error = os.Chdir(fs.RootDir + "/user-" + strconv.Itoa(fs.User.Id) + "/") if error != nil { fmt.Println("Creating folder for user: "******"/user-"+strconv.Itoa(fs.User.Id), 07777) //liberal chmod if error != nil { fmt.Println(error.Error()) } } else { os.Chdir("..") //moves back up } fs.RootDir = fs.RootDir + "/user-" + strconv.Itoa(fs.User.Id) + "/" //moves RootDir to session working directory _ = os.Chdir(fs.RootDir) fmt.Println("current working directory: " + fs.RootDir) //initializes tempHash fs.tempHash = make(map[string]packet.PacketStd) } db.Close() } }
func (fs *FileSession) ReadFromSocket() { fs.CloseSession = false var recievedSize bool var readBuffer [4096]byte var incomingBytes int //read til session closes for fs.CloseSession == false { chunkSize, error := fs.Connection.Read(readBuffer[:10]) //checks if first 10 bytes are packet size integer if chunkSize == 10 { incomingBytesStr := string(readBuffer[:10]) incomingBytesStr = strings.Trim(incomingBytesStr, " ") incomingBytes, error = strconv.Atoi(incomingBytesStr) //check if first 11 bytes are readable as int if error == nil { fmt.Println("incoming package size: ", incomingBytes) recievedSize = true } else { fmt.Println(error.Error()) recievedSize = false } //variable to hold number of bytes written to buffer writtenBytes := 0 for recievedSize == true { if writtenBytes < incomingBytes { chunkSize, _ = fs.Connection.Read(readBuffer[writtenBytes:incomingBytes]) writtenBytes = writtenBytes + chunkSize fmt.Println("recieved: ", writtenBytes, " / ", incomingBytes, " from: "+strconv.Itoa(fs.User.Id)) //check if all bytes have been written to buffer if writtenBytes == incomingBytes { recievedSize = false data := readBuffer[:incomingBytes] fmt.Println("packet done, data size: ", len(data)) var incomingPacket packet.PacketStd error = json.Unmarshal(data, &incomingPacket) if error == nil { fmt.Println("json parse successful - data: ", incomingPacket.Data, " | contentType: "+incomingPacket.ContentType+" | name: "+incomingPacket.Name+"\n") //authenticates user if fs.User.Id < 0 { if incomingPacket.ContentType == "text" && incomingPacket.Name == "login" { fs.FileSession_Authenticate(incomingPacket) } else { newPacket := packet.PacketStd{packet.Packet{"text", ""}, "You need to login first"} go newPacket.SendPacket(fs.Connection) } } else { //basic string packets if incomingPacket.ContentType == "text" { fs.textHandler(incomingPacket) //hash packets } else if incomingPacket.ContentType == "hash" { fs.hashHandler(incomingPacket) //file packets } else if incomingPacket.ContentType == "file" { fs.fileHandler(incomingPacket) //filesystem events through FSEvents wrapper Watchdog } else if incomingPacket.ContentType == "fs_event" { fs.fs_eventHandler(incomingPacket) //push } else if incomingPacket.ContentType == "push" { fs.pushHandler(incomingPacket) } else if incomingPacket.ContentType == "pull" { fs.pullHandler(incomingPacket) } } } else { fmt.Println(error.Error()) } } } } //if nothing on socket, sleep for half a second to save cpu } else { time.Sleep(500 * time.Millisecond) } } }
func (fs *FileSession) pullHandler(incomingPacket packet.PacketStd) { if incomingPacket.Name == "REQ_FILELIST" { //db initializing db, error := sql.Open("sqlite3", "../gypo.db") //tells client pull request recieved newPacket := packet.PacketStd{packet.Packet{"pull", "REQ_FILELIST_RECV"}, ""} go newPacket.SendPacket(fs.Connection) //creates list of server files and sends back to client if error != nil { fmt.Println(error.Error()) } else { //PacketList instance for server files(db) var server_fileList packet.PacketList //get number of files from db to use for file server_fileList.Data size var dbFileCount int error = db.QueryRow("SELECT count(*) AS number FROM files WHERE user_id = ?", fs.User.Id).Scan(&dbFileCount) if error != nil { fmt.Println(error.Error()) } else { //sets PacketList instance variables server_fileList.Data = make([]packet.PacketStd, dbFileCount) server_fileList.ContentType = "pull" server_fileList.Name = "RESP_FILELIST" //get fileList from db rows, error := db.Query("SELECT filename, path, hash, is_dir FROM files WHERE user_id = ?", fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { var rowPacket packet.PacketStd var filename, path, hash string var is_dir int i := 0 for rows.Next() { error = rows.Scan(&filename, &path, &hash, &is_dir) if error != nil { fmt.Println(error.Error()) } else { if is_dir == 1 { rowPacket.ContentType = "folder" rowPacket.Name = path rowPacket.Data = "" } else { rowPacket.ContentType = "hash" rowPacket.Name = path + filename rowPacket.Data = hash } } server_fileList.Data[i] = rowPacket i++ } go server_fileList.SendPacket(fs.Connection) fmt.Println("server_fileList size: ", len(server_fileList.Data)) } } } } else if incomingPacket.Name == "REQ_FILE" { //wraps file in packet and sends it newPacket := packet.PacketStd{packet.Packet{"pull", "RESP_FILE"}, incomingPacket.Data} go newPacket.SendFilePacket(fs.Connection) } }
func (fs *FileSession) pushHandler(incomingPacket packet.PacketStd) { fmt.Println("processing push") //getting pushList from socket incomingBytes, _ := strconv.Atoi(incomingPacket.Data) pushListB := make([]byte, incomingBytes) i := 0 for i < incomingBytes { chunkSize, _ := fs.Connection.Read(pushListB[i:]) i = i + chunkSize fmt.Println("read so far: ", i) } //unmarshal data from socket to PacketList instance var client_pushList packet.PacketList client_pushList.ContentType = "push" client_pushList.Name = "client" flsize, _ := strconv.Atoi(incomingPacket.Name) flObj := make([]packet.PacketStd, flsize) client_pushList.Data = flObj error := json.Unmarshal(pushListB, &client_pushList) if error == nil { fmt.Println("push recieved, " + incomingPacket.Name + " entries\n") } else { fmt.Println(error.Error()) } //tells client push was recieved newPacket := packet.PacketStd{packet.Packet{"push", ""}, "PUSH_RECIEVED"} go newPacket.SendPacket(fs.Connection) //PacketList instance for server files(db) var server_fileList packet.PacketList db, error := sql.Open("sqlite3", "../gypo.db") if error != nil { fmt.Println(error.Error()) } else { //get number of files from db to use for file array size var dbFileCount int error = db.QueryRow("SELECT count(*) AS number FROM files WHERE user_id = ?", fs.User.Id).Scan(&dbFileCount) if error != nil { fmt.Println(error.Error()) } else { server_fileList.Data = make([]packet.PacketStd, dbFileCount) //fetches files from db and adds them to server_fileList rows, error := db.Query("SELECT filename, path, hash, is_dir FROM files WHERE user_id = ?", fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { var is_dir int var rowContentType, rowName, rowData string var rowPacket packet.PacketStd //populates server_fileList.Data i = 0 for rows.Next() { error = rows.Scan(&rowContentType, &rowName, &rowData, &is_dir) //fmt.Println(i, " | ", is_dir) if error != nil { fmt.Println(error.Error()) } if is_dir == 1 { rowPacket.ContentType = "folder" rowPacket.Name = rowName rowPacket.Data = "" } else { rowPacket.ContentType = "hash" rowPacket.Name = rowName + rowContentType rowPacket.Data = rowData } server_fileList.Data[i] = rowPacket i++ } fmt.Println("server_fileList size: ", len(server_fileList.Data)) fmt.Println("client_pushList size: ", len(client_pushList.Data)) /* i = 0 for i < len(server_fileList.Data) { fmt.Println("ContentType: " + server_fileList.Data[i].ContentType + " | Name: " + server_fileList.Data[i].Name + " | Data: " + server_fileList.Data[i].Data) i++ } fmt.Println("\n\n\n\n") i = 0 for i < len(client_pushList.Data) { fmt.Println("ContentType: " + client_pushList.Data[i].ContentType + " | Name: " + client_pushList.Data[i].Name + " | Data: " + server_fileList.Data[i].Data) i++ }*/ //compares client_pushList to server_fileList nilPacket := packet.PacketStd{packet.Packet{"", ""}, ""} //to flag list entries as solved i = 0 j := 0 for i < len(client_pushList.Data) { //check if i is allready solved if len(client_pushList.Data[i].ContentType) > 0 { for j < len(server_fileList.Data) { //file if client_pushList.Data[i].ContentType == "hash" { //match if client_pushList.Data[i].Name == server_fileList.Data[j].Name { //update file if needed if client_pushList.Data[i].Data != server_fileList.Data[j].Data { client_pushList.Data[i].Data = "1" + client_pushList.Data[i].Data //adds '1' to indicate UPDATE(existing file) fs.tempHash[client_pushList.Data[i].Name] = client_pushList.Data[i] fmt.Println("hash for: " + client_pushList.Data[i].Name + " added to tempHash") //fmt.Println("path and filename the same, different hash | client: " + client_pushList.Data[i].Data + " server: " + server_fileList.Data[j].Data) newPacket := packet.PacketStd{packet.Packet{"hash", client_pushList.Data[i].Name}, "SEND_FILE_TRUE"} go newPacket.SendPacket(fs.Connection) fmt.Println(client_pushList.Data[i].Name + " exist, different hash, send\n") //flag list entries as solved client_pushList.Data[i] = nilPacket server_fileList.Data[j] = nilPacket } else { //files are identical, flag list entries as solved client_pushList.Data[i] = nilPacket server_fileList.Data[j] = nilPacket } } //path } else if client_pushList.Data[i].ContentType == "folder" { //match if client_pushList.Data[i].Name == server_fileList.Data[j].Name { //if both paths exist on server and client, flag list entries as solved client_pushList.Data[i] = nilPacket server_fileList.Data[j] = nilPacket } } j++ //increase server_fileList index } } j = 0 //resets server_fileList index i++ //increase client_pushList index } //client_pushList entries not flagged as handled are treated as new files and folders and will be downloaded an/or created i = 0 for i < len(client_pushList.Data) { if client_pushList.Data[i].ContentType == "hash" { //file //adds hash to tempHash, if file recieve is successful; tempHash is dumped to db client_pushList.Data[i].Data = "0" + client_pushList.Data[i].Data //adds '0' to indicate INSERT(new file) fs.tempHash[client_pushList.Data[i].Name] = client_pushList.Data[i] fmt.Println("hash for: " + client_pushList.Data[i].Name + " added to tempHash") newPacket := packet.PacketStd{packet.Packet{"hash", client_pushList.Data[i].Name}, "SEND_FILE_TRUE"} go newPacket.SendPacket(fs.Connection) fmt.Println(client_pushList.Data[i].Name + " not exist, send\n") //flag list entry as solved client_pushList.Data[i] = nilPacket } else if client_pushList.Data[i].ContentType == "folder" { //folder error = os.MkdirAll(client_pushList.Data[i].Name[1:], 07777) //liberal chmod if error != nil { fmt.Println(error.Error()) //adds folder to db } else { _, error := db.Exec("INSERT INTO files (path, is_dir, user_id) VALUES (?, ?, ?)", client_pushList.Data[i].Name, 1, fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { fmt.Println("folder: " + client_pushList.Data[i].Name + " created and added to db") } } } i++ } fmt.Println("tempHash size: ", len(fs.tempHash)) //server_fileList entries not flagged as handled are threated as deleted files and gets deleted i = 0 for i < len(server_fileList.Data) { if server_fileList.Data[i].ContentType == "hash" { //file //delete db entry _, error := db.Exec("DELETE FROM files WHERE path = ? AND hash = ? AND user_id = ?", server_fileList.Data[i].Name[:strings.LastIndex(server_fileList.Data[i].Name, "/")+1], server_fileList.Data[i].Data, fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { //delete file _ = os.RemoveAll(fs.RootDir + server_fileList.Data[i].Name) /*if error != nil { fmt.Println(error.Error()) }*/ } //flag list entry as solved server_fileList.Data[i] = nilPacket } else if server_fileList.Data[i].ContentType == "folder" { //delete db entry _, error := db.Exec("DELETE FROM files WHERE path = ? AND is_dir = ? AND user_id = ?", server_fileList.Data[i].Name, 1, fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { //delete folder _ = os.RemoveAll(fs.RootDir + server_fileList.Data[i].Name) /*if error != nil { fmt.Println(error.Error()) }*/ } //flag list entry as solved server_fileList.Data[i] = nilPacket } i++ } } } } }
func (fs *FileSession) fs_eventHandler(incomingPacket packet.PacketStd) { db, error := sql.Open("sqlite3", "../gypo.db") if error != nil { fmt.Println(error.Error()) } else { //rename_file & rename_folder & move_file & move_folder if incomingPacket.Name == "rename_file" || incomingPacket.Name == "rename_folder" || incomingPacket.Name == "move_file" || incomingPacket.Name == "move_folder" { sourceDir := incomingPacket.Data[:strings.Index(incomingPacket.Data, "|")] destDir := incomingPacket.Data[len(sourceDir)+1:] //rename also moves, truncate errors as multiple moves in one directory will result in failed renames _ = os.Rename(sourceDir[1:], destDir[1:]) //updates db if incomingPacket.Name == "rename_file" { //rename_file _, error := db.Exec("UPDATE files SET filename = ? WHERE filename = ? AND path = ? AND user_id = ?", destDir[strings.LastIndex(destDir, "/")+1:], sourceDir[strings.LastIndex(sourceDir, "/")+1:], sourceDir[:strings.LastIndex(sourceDir, "/")+1], fs.User.Id) if error != nil { fmt.Println(error.Error()) } } else if incomingPacket.Name == "rename_folder" || incomingPacket.Name == "move_folder" { //rename_folder & move_folder _, error := db.Exec("UPDATE files SET path = ? WHERE path = ? AND user_id = ?", destDir, sourceDir, fs.User.Id) if error != nil { fmt.Println(error.Error()) } } else if incomingPacket.Name == "move_file" { //move_file _, error := db.Exec("UPDATE files SET path = ? WHERE path = ? AND filename = ? AND user_id = ?", destDir[:strings.LastIndex(destDir, "/")+1], sourceDir[:strings.LastIndex(sourceDir, "/")+1], destDir[strings.LastIndex(destDir, "/")+1:], fs.User.Id) if error != nil { fmt.Println(error.Error()) } } //create_folder } else if incomingPacket.Name == "create_folder" { //check if folder allready exist, if not make error = os.Chdir(incomingPacket.Data[1:]) if error != nil { error = os.MkdirAll(incomingPacket.Data[1:], 07777) //liberal chmod if error != nil { fmt.Println(error.Error()) //adds folder to db } else { _, error := db.Exec("INSERT INTO files (path, is_dir, user_id) VALUES (?, ?, ?)", incomingPacket.Data, 1, fs.User.Id) if error != nil { fmt.Println(error.Error()) } } } else { //mave back to root _ = os.Chdir(fs.RootDir) } //delete_file } else if incomingPacket.Name == "delete_file" { error = os.Remove(fs.RootDir + incomingPacket.Data[1:]) if error != nil { fmt.Println(error.Error()) } else { //updates db _, error := db.Exec("DELETE FROM files WHERE filename = ? AND path = ? AND user_id = ?", incomingPacket.Data[strings.LastIndex(incomingPacket.Data, "/")+1:], incomingPacket.Data[:strings.LastIndex(incomingPacket.Data, "/")+1], fs.User.Id) if error != nil { fmt.Println(error.Error()) } } //delete_folder } else if incomingPacket.Name == "delete_folder" { error = os.RemoveAll(fs.RootDir + incomingPacket.Data[1:]) if error != nil { fmt.Println(error.Error()) } else { //updates db _, error := db.Exec("DELETE FROM files WHERE path = ? AND user_id = ?", incomingPacket.Data, fs.User.Id) if error != nil { fmt.Println(error.Error()) } } } //tells client fs_event done newPacket := packet.PacketStd{packet.Packet{"fs_event", ""}, "FS_EVENT_DONE"} go newPacket.SendPacket(fs.Connection) db.Close() } }
func (fs *FileSession) fileHandler(incomingPacket packet.PacketStd) { var readBuffer [4096]byte //creates folders for file if nesecary if strings.LastIndex(incomingPacket.Name, "/") > 0 { error := os.MkdirAll(incomingPacket.Name[1:strings.LastIndex(incomingPacket.Name, "/")+1], 07777) //liberal chmod if error != nil { fmt.Println(error.Error()) } else { error = os.Chdir(incomingPacket.Name[1 : strings.LastIndex(incomingPacket.Name, "/")+1]) if error != nil { fmt.Println(error.Error()) } } } //writes file file, _ := os.Create(incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:] + ".incomplete") //adds .incomplete extension during download i := 0 incomingBytes, _ := strconv.Atoi(incomingPacket.Data) for i < incomingBytes { if (i + 4096) > incomingBytes { chunkSize, _ := fs.Connection.Read(readBuffer[:incomingBytes-i]) _, _ = file.Write(readBuffer[:incomingBytes-i]) i = i + chunkSize //fi, _ := file.Stat() //fmt.Println("ferdig", chunkSize , " recieved so far ", i, "/", incomingBytes, "written so far: ", fi.Size()) } else { chunkSize, _ := fs.Connection.Read(readBuffer[:]) _, _ = file.Write(readBuffer[:chunkSize]) //fi, _ := file.Stat() i = i + chunkSize //fmt.Println("skriver", chunkSize, " recived so far ", i, "/", incomingBytes, "written so far: ", fi.Size()) } } file.Close() //after all bytes are written file extension .incomplete is removed _ = os.Rename(incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:]+".incomplete", incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:]) //moves back to root _ = os.Chdir(fs.RootDir) //adds/updates file hash from session to db db, error := sql.Open("sqlite3", "../gypo.db") if error != nil { fmt.Println(error.Error()) } else { if fs.tempHash[incomingPacket.Name].Data[0:1] == "0" { _, error := db.Exec("INSERT INTO files (path, filename, hash, user_id) VALUES (?, ?, ?, ?)", incomingPacket.Name[:strings.LastIndex(incomingPacket.Name, "/")+1], incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:], fs.tempHash[incomingPacket.Name].Data[1:], fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { delete(fs.tempHash, incomingPacket.Name) //removes file from tempHash } } else { _, error := db.Exec("UPDATE files SET hash = ? WHERE path = ? AND filename = ? AND user_id = ?", fs.tempHash[incomingPacket.Name].Data[1:], incomingPacket.Name[:strings.LastIndex(incomingPacket.Name, "/")+1], incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:], fs.User.Id) if error != nil { fmt.Println(error.Error()) } else { delete(fs.tempHash, incomingPacket.Name) //removes file from tempHash } } db.Close() } //tells client file has completed newPacket := packet.PacketStd{packet.Packet{"file", ""}, "SEND_FILE_DONE"} go newPacket.SendPacket(fs.Connection) fmt.Println(incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:], " - SEND_FILE_DONE\n\n") }
func (fs *FileSession) hashHandler(incomingPacket packet.PacketStd) { //connects to db to comapre hash db, error := sql.Open("sqlite3", "../gypo.db") if error != nil { fmt.Println(error.Error()) } else { var hash string error := db.QueryRow("SELECT hash FROM files WHERE path = ? AND filename = ? AND user_id = ?", incomingPacket.Name[:strings.LastIndex(incomingPacket.Name, "/")+1], incomingPacket.Name[strings.LastIndex(incomingPacket.Name, "/")+1:], fs.User.Id).Scan(&hash) if error != nil { newPacket := packet.PacketStd{packet.Packet{"hash", incomingPacket.Name}, "SEND_FILE_TRUE"} go newPacket.SendPacket(fs.Connection) fmt.Println("file not exist, send file") //adds hash to tempHash, if file recieve is successful; tempHash is dumped to db incomingPacket.Data = "0" + incomingPacket.Data //adds '0' to indicate INSERT(new file) fs.tempHash[incomingPacket.Name] = incomingPacket } else if hash != incomingPacket.Data { newPacket := packet.PacketStd{packet.Packet{"hash", incomingPacket.Name}, "SEND_FILE_TRUE"} go newPacket.SendPacket(fs.Connection) fmt.Println("hash different, send file") //adds hash to tempHash, if file recieve is successful; tempHash is dumped to db incomingPacket.Data = "1" + incomingPacket.Data //adds '1' to indicate UPDATE(existing file) fs.tempHash[incomingPacket.Name] = incomingPacket } else if hash == incomingPacket.Data { newPacket := packet.PacketStd{packet.Packet{"hash", incomingPacket.Name}, "SEND_FILE_FALSE"} go newPacket.SendPacket(fs.Connection) fmt.Println("hash same, no send file") } db.Close() } }