def send_download_notification(self, workspace_id, user_id, share_id, inode_id, commit_id, pubws_email_id, login_type=KCD_KWS_LOGIN_TYPE_SECURE, minor=0, cmd=""): # Build ANP arguments list. am = kanp.ANP_msg() # Workspace bound arguments am.add_u64(workspace_id) am.add_u64(int(time.time())) am.add_u32(login_type) am.add_u32(user_id) am.add_u32(minor) am.add_bin(cmd) # Other arguments am.add_u32(share_id) am.add_u64(inode_id) am.add_u64(commit_id) am.add_u64(pubws_email_id) # Send notification to KCD database. ext_am, res_am = self.workspace_bound_request('notify_file_download', am.get_payload()) log.debug("Download notification posted for workspace %i." % \ ( workspace_id ) )
def phase_2_create_commit_submessage(self, hash): subm = PhaseTwoCommitSubMessage() subm.anpm = kanp.ANP_msg() subm.anpm.add_u32(3) subm.anpm.add_u32(kanp.KANP_KFS_SUBMESSAGE_COMMIT) subm.anpm.add_bin(hash) return subm
def workspace_bound_request(self, stored_proc_name, args_payload): # Connect or reuse DB connection. self.db_connect() # Do the query. query = "SELECT %s('%s')" % (stored_proc_name, pgdb.escape_bytea(args_payload)) cur = kpg.exec_pg_query_rb_on_except(self.db_conn, query) row = cur.fetchone() self.db_conn.commit() # Handle result. am = kanp.ANP_msg() am.parse(row[0].value) # Get generic error status. error_status = am.get_u32() if error_status == -1: # Generic error. err_msg = am.get_str() raise Exception("Error: '%s'." % (err_msg)) else: # No generic error... continue parsing. # Get result type. res_type = am.get_u32() res_buf = am.get_bin() res_error = am.get_u32() if res_type == kanp.KANP_RES_OK: # Success ext_buf_am = am res_buf_am = kanp.ANP_msg() res_buf_am.parse(res_buf) return ext_buf_am, res_buf_am else: # Specific error am = kanp.ANP_msg() am.parse(res_buf) err_code = am.get_u32() err_msg = am.get_str() raise Exception("Error: '%s' stored procedure failed: error: %i ('%s')" % \ ( stored_proc_name, err_code, err_msg ) )
def phase_2_create_chunk_submessage(self, data): # Prepare anp message subm = PhaseTwoChunkSubMessage() subm.anpm = kanp.ANP_msg() subm.anpm.add_u32(3) subm.anpm.add_u32(kanp.KANP_KFS_SUBMESSAGE_CHUNK) subm.anpm.add_bin(data) return subm
def connect_workspace(self, workspace_id, last_evt_id=0, last_evt_timestamp=0, user_id=0, real_name='', email_address='', email_id='', ticket='', password='', delete_on_login=0): # Create ANP command. m = kanp.ANP_msg() m.add_u64(workspace_id) m.add_u32(delete_on_login) m.add_u64(last_evt_id) m.add_u64(last_evt_timestamp) m.add_u32(user_id) m.add_str(real_name) m.add_str(email_address) m.add_str(email_id) m.add_bin(ticket) m.add_str(password) # Send the command to KCD. payload = m.get_payload() self.send_command_header(kanp.KANP_CMD_KWS_CONNECT_KWS, len(payload)) log.debug("Sent anp command to connect to workspace %i." % (workspace_id)) self.write(payload) # Get command result. h, m = kanp.get_anpt_all(self) if h.type != kanp.KANP_RES_KWS_CONNECT_KWS: assert h.type == kanp.KANP_RES_FAIL raise kanp.KANPFailure(m.get_u32(), m.get_str()) # Decode result. result = m.get_u32() error = m.get_str() user_id = m.get_u32() email_id = m.get_str() last_evt_id = m.get_u64() secure = m.get_u32() password_assigned = m.get_u32() kwmo_server = m.get_str() if result != kanp.KANP_KWS_LOGIN_OK: raise kanp.KANPFailure(result, error) log.debug("Connected to workspace %i." % (workspace_id))
def set_freemium_user(self, email, license): # Connect to database if needed. self.db_connect() # Build ANP arguments list. m = kanp.ANP_msg() m.add_str(email) m.add_str(license) # Do the query. query = "SELECT set_freemium_user('%s')" % ( pgdb.escape_bytea(m.get_payload()) ) cur = kpg.exec_pg_query_rb_on_except(self.db_conn, query) row = cur.fetchone() self.db_conn.commit() return 0
def select_role(self, role): log.debug("select_role() called") # send request m = kanp.ANP_msg() m.add_u32(role) payload = m.get_payload() self.send_command_header(kanp.KANP_CMD_MGT_SELECT_ROLE, len(payload)) self.write(payload) # get response h, m = kanp.get_anpt_all(self) if h.type != kanp.KANP_RES_OK: assert h.type == kanp.KANP_RES_FAIL raise kanp.KANPFailure(m.get_u32(), m.get_str()) assert h.type == kanp.KANP_RES_OK log.debug("Role %i selected." % (role))
def save_notification_policy(self, workspace_id, user_id, notification_policy): # Connect to database if needed. self.db_connect() # Build ANP arguments list. am = kanp.ANP_msg() am.add_u64(int(workspace_id)) am.add_u32(int(user_id)) am.add_u32(notification_policy) # Do the query. query = "SELECT do_notif_mgt(E'%s')" % (pgdb.escape_bytea( am.get_payload())) cur = kpg.exec_pg_query_rb_on_except(self.db_conn, query) row = cur.fetchone() self.db_conn.commit() return 0
def get_kcd_upload_ticket(self, workspace_id, share_id, user_id, email_id='kwmo'): # Connect to KCD. self.connect() # Select workspace role. self.select_role(kanp.KANP_KCD_ROLE_WORKSPACE) # Connect to workspace. self.connect_workspace(workspace_id=int(workspace_id), user_id=user_id, email_id=email_id, password=self.conf.kcd_passwd) # Send the command to KCD. am = kanp.ANP_msg() am.add_u64(workspace_id) am.add_u32(share_id) payload = am.get_payload() self.send_command_header(kanp.KANP_CMD_KFS_UPLOAD_REQ, len(payload)) self.write(payload) log.debug("Sent upload request to KCD for workspace %i, share %i." % (workspace_id, share_id)) # Get command result. h, m = kanp.get_anpt_all(self) # Close KCD connection. self.close() # Handle result. if h.type != kanp.KANP_RES_KFS_UPLOAD_REQ: log.debug("Got result type '%s'." % (kanp.get_kanp_constant(h.type, 'KANP_'))) assert h.type == kanp.KANP_RES_FAIL raise kanp.KANPFailure(m.get_u32(), m.get_str()) ticket = m.get_bin() return ticket
class FreemiumKcdClient: # Constructor # parameters: # conf: configuration object, or None def __init__(self, conf, db_conn=None): # Get config object. self.conf = conf # Get db connection if provited. self.db_conn = db_conn # Command ID. self.command_id = 0 # Initialize parent class, but do not connect. #tcp_client.TcpClient.__init__(self, self.conf.kcd_host, self.conf.kcd_port, use_openssl=True, allow_dh=True) # This method connects or reuse a DB connection to KCD. def db_connect(self): if not self.db_conn: self.db_conn = get_kcd_db_conn(self.conf) def set_freemium_user(self, email, license): # Connect to database if needed. try: self.db_connect() except Exception, e: raise KcdDbConnectException("Couldn't connect to kcd db: " + str(e)) # Build ANP arguments list. m = kanp.ANP_msg() m.add_str(email) m.add_str(license) # Do the query. query = "SELECT set_freemium_user(E'%s')" % ( pgdb.escape_bytea(m.get_payload()) ) cur = kpg.exec_pg_query_rb_on_except(self.db_conn, query) row = cur.fetchone() self.db_conn.commit() return 0
def send_invitation(self, workspace_id, message, invitees): # Create command. m = kanp.ANP_msg() m.add_u64(workspace_id) m.add_str(message) m.add_u32(len(invitees)) for invitee in invitees: m.add_str(invitee.real_name) m.add_str(invitee.email_address) m.add_u64(invitee.key_id) m.add_str(invitee.org_name) m.add_str(invitee.password) m.add_u32(int(invitee.send_mail)) # Send the command to KCD. payload = m.get_payload() self.send_command_header(kanp.KANP_CMD_KWS_INVITE_KWS, len(payload)) log.debug("Sent anp invite command for workspace %i." % (workspace_id)) self.write(payload) # Get command result. h, m = kanp.get_anpt_all(self) if h.type != kanp.KANP_RES_KWS_INVITE_KWS: log.debug("Received type '%s'." % (str(h.type))) assert h.type == kanp.KANP_RES_FAIL raise kanp.KANPFailure(m.get_u32(), m.get_str()) # Decode the result. ws_url = m.get_str() invitees_nb = m.get_u32() for i in range(0, invitees_nb): invitees[i].email_id = m.get_str() invitees[i].url = m.get_str() invitees[i].error = m.get_str() return ws_url, invitees
def phase_2_send_message_with_one_submessage(self, subm): # Prepare ANP message. message = PhaseTwoMessage() message.anpm = kanp.ANP_msg() message.anpm.add_u32(1) # Send only one sub-message # Calculate base messasge size. message.size = message.anpm.get_payload_size() #log.debug("Base message size: %i bytes." % ( message.size )) # Calculate total sub-message size. subm.size = subm.anpm.get_payload_size() log.debug("Chunk sub-message size: %i bytes." % (subm.size)) total_size = message.size + subm.size # Sent ANP transport header #log.debug("Phase 2: sending ANPT header with data size %i." % ( total_size )) self.writer.send_command_header(kanp.KANP_CMD_KFS_PHASE_2, total_size) #log.debug("Phase 2: sent ANPT header, size %i." % ( total_size )) # Send base message. kanp.send_anpt_msg(self.writer, message.anpm) # Send sub-message. kanp.send_anpt_msg(self.writer, subm.anpm) # get response #log.debug("Phase 2: getting reply.") h, m = kanp.get_anpt_all(self.reader) #log.debug("ANP RESPONSE DUMP: %s" % (str(m.dump()))) #log.debug("Phase 2: got reply.") if h.type == kanp.KANP_RES_FAIL: raise kanp.KANPFailure(m.get_u32(), m.get_str()) assert h.type == kanp.KANP_RES_OK
def prepare_phase_two(self): message = None files_iter = iter(self.kfs_entries) switch_file = True switch_message = True commit_file = False switch_chunk = True exit = False while 1: if exit or switch_message: switch_message = False if message and len(message.sub_messages) > 0: # Finish ANPT message preparation. message.anpm = kanp.ANP_msg() message.anpm.add_u32(len(message.sub_messages)) message.size += message.anpm.get_payload_size() # Append ANPT message to list. self.phase_two_messages.append(message) # Init new ANPT message. message = PhaseTwoMessage() if exit: break if commit_file: commit_file = False # Prepare a file commit sub-message. log.debug("Committing file.") # Prepare a partial anp message (missing an ANP bin field for the MD5 signature of the file). subm = PhaseTwoCommitSubMessage() subm.anpm = kanp.ANP_msg() subm.anpm.add_u32(3) subm.anpm.add_u32(kanp.KANP_KFS_SUBMESSAGE_COMMIT) #hash = kfs_compute_hash(kfs_entry.fd) #subm.anpm.add_bin(kfs_entry.hash) # Calculate total sub-message size. subm.size = subm.anpm.get_payload_size( ) + 5 + 16 # partial anp mesg + anp bin header + md5 sign. log.debug("Commit sub-message has %i bytes in total." % (subm.size)) # Append sub-message to current ANPT message. log.debug("Appending commit sub-message to ANPT message.") message.sub_messages.append(subm) message.size += subm.size # Switch to next file. switch_file = True continue if not message: # Init new message. log.debug("Initiating a new message.") message = PhaseTwoMessage() if switch_file: switch_file = False try: # Get next file. kfs_entry = files_iter.next() log.debug("Got new file: '%s'." % (kfs_entry.name)) # Start again with file chunk. chunks_iter = iter(kfs_entry.chunks) switch_chunk = True continue except StopIteration: # No more file in list. log.debug("No more file.") exit = True continue if kfs_entry.kfs_op != kanp.KANP_KFS_OP_CREATE_FILE and kfs_entry.kfs_op != kanp.KANP_KFS_OP_UPDATE_FILE: # That operation does not need any phase 2 messsage. log.debug("No phase two needed for that operation.") switch_file = True continue if kfs_entry.kfs_error: # This file cannot be uploaded. Pass to next file. log.debug("Skipping file '%s' because it had an error in phase 1: '%s'." % \ (kfs_entry.name, kfs_entry.kfs_error )) switch_file = True continue if switch_chunk: switch_chunk = False try: # Get next KFS file chunk. chunk = chunks_iter.next() log.debug("Got a new chunk of %i bytes." % (chunk.size)) except StopIteration: # No more chunks. Commit file. commit_file = True continue # Add chunk to current ANPT message. # Prepare a partial anp message (missing an ANP bin field for the chunk data). subm = PhaseTwoChunkSubMessage() subm.anpm = kanp.ANP_msg() subm.anpm.add_u32(3) subm.anpm.add_u32(kanp.KANP_KFS_SUBMESSAGE_CHUNK) #subm.anpm.add_bin(chunk.read()) # Set sub-message chunk. subm.chunk = chunk # Calculate total sub-message size. subm.size = subm.anpm.get_payload_size( ) + 5 + chunk.size # partial anp mesg + anp bin header + chunk data log.debug("Chunk sub-message has %i bytes in total." % (subm.size)) if (message.size + subm.size + 100000) > kanp.ANPT_MSG_MAX_SIZE: # Current ANPT message cannot accept chunk. # Switch ANPT message. switch_message = True # Do not switch chunk (implicit). #switch_chunk = False continue # Append sub-message to this message. log.debug("Appending chunk sub-message to ANPT message.") message.sub_messages.append(subm) message.size += subm.size switch_chunk = True
def phase_one(self, email_id, ticket): # Prepare phase one ANP message. m = kanp.ANP_msg() m.add_bin(ticket) m.add_u64(email_id) m.add_u32(len(self.kfs_entries)) for kfs_entry in self.kfs_entries: if kfs_entry.kfs_op == kanp.KANP_KFS_OP_CREATE_FILE: m.add_u32(5) # nb of elements m.add_u32(kfs_entry.kfs_op) m.add_u64(kfs_entry.parent_inode_id) m.add_u64(kfs_entry.parent_commit_id) m.add_str(kfs_entry.name) elif kfs_entry.kfs_op == kanp.KANP_KFS_OP_UPDATE_FILE: m.add_u32(4) # nb of elements m.add_u32(kfs_entry.kfs_op) m.add_u64(kfs_entry.inode) m.add_u64(kfs_entry.commit_id) elif kfs_entry.kfs_op == kanp.KANP_KFS_OP_CREATE_DIR: m.add_u32(5) # nb of elements m.add_u32(kfs_entry.kfs_op) m.add_u64(kfs_entry.parent_inode_id) m.add_u64(kfs_entry.parent_commit_id) m.add_str(kfs_entry.name) elif kfs_entry.kfs_op == kanp.KANP_KFS_OP_DELETE_DIR: m.add_u32(4) # nb of elements m.add_u32(kfs_entry.kfs_op) m.add_u64(kfs_entry.inode_id) m.add_u64(kfs_entry.commit_id) elif kfs_entry.kfs_op == kanp.KANP_KFS_OP_DELETE_FILE: m.add_u32(4) # nb of elements m.add_u32(kfs_entry.kfs_op) m.add_u64(kfs_entry.inode_id) m.add_u64(kfs_entry.commit_id) else: raise Exception("Unexpected KFS operation: '%s'." % (str(kfs_entry.kfs_op))) # Send phase one ANP message to KCD. payload = m.get_payload() self.writer.send_command_header(kanp.KANP_CMD_KFS_PHASE_1, len(payload)) self.writer.write(payload) log.debug("Phase 1 data sent.") # Get phase one result. h, m = kanp.get_anpt_all(self.reader) if h.type != kanp.KANP_RES_KFS_PHASE_1: assert h.type == kanp.KANP_RES_FAIL raise kanp.KANPFailure(m.get_u32(), m.get_str()) log.debug("Got phase 1 reply.") # Handle phase one reply. phase_two_needed = False commit_id = m.get_u64() nb_op = m.get_u32() assert nb_op == len(self.kfs_entries) for i in range(0, nb_op): errno = m.get_u32() error = m.get_str() if error: log.debug( "Phase 1: KFS operation %i error: errno=%i, error='%s'" % \ ( i, errno, error )) self.kfs_entries[i].kfs_error = error