def get_file_content(self, file_name, user_id): ''' :param file_name: (string) :param user_id: (string) :return: content from the file (string) ''' global dir_files file_path = os.path.join(dir_files, file_name) limited_files = self.limited_files_from_config(user_id) content, resp_code = "", RESP.OK lock.acquire() config = self.server_config_file() if os.path.isfile(file_path): # Check user's permissions if file_name not in limited_files: with open(file_path, "r") as f: content = f.read() else: resp_code = RESP.PERMISSION_ERROR else: resp_code = RESP.FILE_DOES_NOT_EXIST am_i_owner = self.is_user_owner_of_file(config, file_name, user_id) am_i_owner = "1" if am_i_owner else "0" file_access = self.get_file_access(config, file_name) lock.release() sending_data = pack_list([am_i_owner, file_access, content]) return resp_code, sending_data
def notify(self, command, change): # Send notifications to all other users except the master if self.notify_me: sending_data = pack_list(change) tcp_send(self.__sock, command, sending_data) # Set current thread to "receive notifications" state self.notify_me = True
def change_access_to_file(self, user_id, file_name, needed_access): ''' :param user_id: (string) :param file_name: (string) :param needed_access: (enum) :return: response code ''' global lock resp_code = RESP.OK lock.acquire() config = self.server_config_file() # Only owner can edit the access of the file if self.is_user_owner_of_file(config, file_name, user_id): files = value_of_option_from_config(config, "LIMITED_FILES", user_id) files = files.split(SEP) if files else [] # Access to the file should be public if needed_access == ACCESS.PUBLIC: # Make access public by removing file from limited files if file_name in files: files.remove(file_name) # Access to the file should be private else: # Add file to limited files (means file is private) if file_name not in files: files.append(file_name) config.set("LIMITED_FILES", user_id, pack_list(files)) self.save_config(config) # User wants to change access, but he/she is not owner of the file else: resp_code = RESP.PERMISSION_ERROR lock.release() return resp_code
def remove_file(self, file_name, user_id): global dir_files, lock ''' :param file_name: (string) :param user_id: (string) :return: response code (enum) ''' file_path = os.path.join(dir_files, file_name) resp_code = RESP.OK lock.acquire() config = self.server_config_file() if self.is_user_owner_of_file(config, file_name, user_id): try: os.remove(file_path) # remove file from config self.remove_option_from_config(config, "OWNERS_FILES", file_name) # Remove file from limited files from config files = value_of_option_from_config(config, "LIMITED_FILES", user_id) files = files.split(SEP) if files else [] if file_name in files: files.remove(file_name) config.set("LIMITED_FILES", user_id, pack_list(files)) except: resp_code = RESP.FAIL else: resp_code = RESP.FILE_ALREADY_EXISTS self.save_config(config) lock.release() return resp_code
def run(self): global dir_files, lock current_thread = threading.current_thread() connection_n = current_thread.getName().split("-")[1] current_thread.socket = self.__sock LOG.debug("Client %s connected:" % connection_n) LOG.debug("Client's socket info : %s:%d:" % self.__sock.getsockname()) user_id = "" while True: msg = tcp_receive(self.__sock) resp_code, sending_data = RESP.OK, "" # Msg received successfully if msg: command, data = parse_query(msg) LOG.debug( "Client's request (%s) - %s|%s" % (self.__sock.getsockname(), command, data[:10] + "...")) # Case: some problem with receiving data else: LOG.debug("Client(%s) closed the connection" % connection_n) break if command == COMMAND.GENERATE_USER_ID: # make a unique user_id based on the host ID and current time user_id = uuid.uuid1() resp_code, sending_data = RESP.OK, user_id LOG.debug( "Server generated a new user_id (%s) and sent it to client" % user_id) elif command == COMMAND.NOTIFY_ABOUT_USER_ID: user_id = data LOG.debug("Client sent his existing user_id (%s)" % user_id) resp_code = RESP.OK LOG.debug( "Empty request with acknowledgement about receiving user_id was sent to client" ) elif command == COMMAND.LIST_OF_ACCESIBLE_FILES: LOG.debug( "Client requested to get a list of available files (client:%s...)" % user_id[:7]) all_files = [ f for f in os.listdir(dir_files) if os.path.isfile(os.path.join(dir_files, f)) ] limited_files = self.server.limited_files_from_config(user_id) available_files = set(all_files) - set(limited_files) resp_code, sending_data = RESP.OK, pack_list(available_files) LOG.debug( "List of available files was sent to client (:%s...)" % user_id[:7]) elif command == COMMAND.GET_FILE: file_name = data LOG.debug( "Client requested to get file \"%s\" (client:%s...)" % (file_name, user_id[:7])) resp_code, sending_data = self.server.get_file_content( file_name, user_id) LOG.debug( "Response (code:%s) on getting requested file was sent to client (:%s...)" % (resp_code, user_id[:7])) elif command == COMMAND.CREATE_NEW_FILE: LOG.debug( "Client requested to create a new file (client:%s...)" % user_id[:7]) # print(data, SEP) file_name, access = data.split(SEP) resp_code = self.server.create_file(file_name, user_id, access) LOG.debug( "Response(code:%s) of file creation was sent to client (:%s...)" % (resp_code, user_id[:7])) # If access is public and result of file creation is OK, then notify other clients if access == ACCESS.PUBLIC and resp_code == RESP.OK: change = [COMMAND.NOTIFICATION.FILE_CREATION, [file_name]] self.add_notification(change) elif command == COMMAND.DELETE_FILE: LOG.debug( "Client requested to delete a file \"%s\" (client:%s...)" % (data, user_id[:7])) file_name = data resp_code = self.server.remove_file(file_name, user_id=user_id) LOG.debug( "Response(code:%s) of file deletion was sent to client (:%s...)" % (resp_code, user_id[:7])) # If response is OK, notify other clients about deletion of this file if resp_code == RESP.OK: change = [COMMAND.NOTIFICATION.FILE_DELETION, [file_name]] self.add_notification(change) elif command == COMMAND.UPDATE_FILE: LOG.debug("Client requested to update a file (client:%s...)" % user_id[:7]) file_name, change_type, pos, key = parse_change( data, case_update_file=True) resp_code = self.server.update_file(file_name, change_type, pos, key) LOG.debug( "Response(code:%s) of change in file was sent to client (:%s...)" % (resp_code, user_id[:7])) # Add change from client into the queue "changes" change = [ COMMAND.NOTIFICATION.UPDATE_FILE, [file_name, change_type, pos, key] ] self.add_notification(change) elif command == COMMAND.CHANGE_ACCESS_TO_FILE: LOG.debug("Client requested to update a file (client:%s...)" % user_id[:7]) file_name, needed_access = parse_query(data) resp_code = self.server.change_access_to_file( user_id, file_name, needed_access) LOG.debug( "Response(code:%s) of change in file was sent to client (:%s...)" % (resp_code, user_id[:7])) # If response is OK, notify other clients about deletion of this file if resp_code == RESP.OK: change = [ COMMAND.NOTIFICATION.CHANGED_ACCESS_TO_FILE, [file_name, needed_access] ] self.add_notification(change) # Send response on requested command res = tcp_send(self.__sock, resp_code, sending_data) # Trigger notify_clients function (if there're some changes in the queue, it will process them) self.server.notify_other_clients() # Case: some problem with receiving data if not res: LOG.debug("Client(%s, %s) closed the connection" % self.__sock.getsockname()) break close_socket(self.__sock, 'Close client socket.')