SWconstruction 02
SWconstruction 02
Abbottabad Campus
Department of Computer Science
FALL 2024
Assignment # 02
Submitted to: Ma’am Hifza Ali
Submitted by:
Group Members:
Rijaab Ali (SP22-BSE-156)
Safa Noor (SP22-BSE-089)
Samra Rehman (SP22-BSE-092)
Qurat Ul Ain (SP22-BSE-084)
Assignment 2
Task
Construct an email system using any programming language of your choice. The system
should exhibit these features of concurrent programming like threads, non-blocking
threads, atomic operations, event driven programming etc.
Solution:
Server Process: Acts as the mail server, consuming emails from the queue to send them to
recipients.
Client Processes: Act as users of the system, performing operations like drafting, sending,
and deleting emails.
We'll use threads to handle tasks like sending emails without blocking the main
program.
We'll use a queue to manage email drafts and send emails in the background
Code:
import threading
import time
from queue import Queue, Empty
def __repr__(self):
return f"Email(to: {self.recipient}, subject: {self.subject})"
# Client Functions
def send_email(recipient, subject, body):
email = Email(recipient, subject, body)
email_queue.put(email)
print(f"Email queued for sending: {email}")
def delete_draft(recipient):
global drafts
# Find draft by recipient and remove it
drafts = [draft for draft in drafts if draft.recipient != recipient]
print(f"Drafts after deletion for recipient '{recipient}':
{[str(draft) for draft in drafts]}")
def view_contacts():
print("Contacts:")
for contact in contacts:
print(f"- {contact}")
def view_sent_emails():
print("Sent Emails:")
for email in sent_emails:
print(email)
# Main Simulation
if __name__ == "__main__":
# Start email server thread
server_thread = threading.Thread(target=email_server, daemon=True)
server_thread.start()
while True:
print("\nMenu:")
print("1. View Contacts")
print("2. Create Draft")
print("3. Delete Draft")
print("4. Send Email")
print("5. View Sent Emails")
print("6. Exit")
if choice == '1':
view_contacts()
elif choice == '2':
recipient = input("Enter recipient: ")
subject = input("Enter subject: ")
body = input("Enter body: ")
create_draft(recipient, subject, body)
elif choice == '3':
recipient = input("Enter recipient of draft to delete: ")
delete_draft(recipient)
elif choice == '4':
recipient = input("Enter recipient: ")
subject = input("Enter subject: ")
body = input("Enter body: ")
send_email(recipient, subject, body)
elif choice == '5':
view_sent_emails()
elif choice == '6':
print("Exiting...")
break
else:
print("Invalid choice, please try again.")
Code Explanation:
Imports
import threading: This line brings in the threading module, which allows the program to
run multiple tasks concurrently (like sending emails in the background).
import time: This imports the time module, used for pausing the program's execution for
a specific duration (simulating email sending time).
from queue import Queue, Empty:
o Queue is a thread-safe queue that allows multiple threads to safely add or remove
items.
o Empty is an exception that is raised when trying to get an item from an empty
queue.
email_queue = Queue(): This initializes a queue to hold emails that need to be sent.
sent_emails = []: This creates an empty list called sent_emails that will store emails after
they've been "sent."
class Email:: This defines a simple class to represent an email.
o __init__ Method: This method is the constructor, which is called when a new
Email object is created. It initializes the recipient, subject, and body of the email.
o __repr__ Method: This method returns a string representation of the Email
object, which helps when printing emails for debugging.
def email_server():This defines a function called email_server that simulates the behavior of an
email server.
o print("Email server started."): Notifies that the email server has started.
o while True:: This creates an infinite loop that keeps the server running.
o try:: Tries to execute the block of code that follows.
email = email_queue.get(timeout=5): Attempts to retrieve an email from
the queue. If the queue is empty for 5 seconds, it raises an Empty
exception.
print(f"Processing {email}..."): Prints the email currently being
processed.
time.sleep(1): Simulates the time taken to send an email.
sent_emails.append(email): Adds the sent email to the sent_emails list.
email_queue.task_done(): Marks this email as processed, signaling that
it’s done.
o except Empty: If the queue is empty:
print("No emails to process, server is idle..."): Notifies that there are no
emails to process.
time.sleep(1): Waits for a short time before checking the queue again.
o except Exception as e: Catches any other exceptions and prints an error message.
Client Functions
def send_email(recipient, subject, body):This function creates an email and adds it to the
queue.
o for contact in contacts:: Iterates over the list of contacts and prints each one.
o for email in sent_emails:: Iterates over the list of sent emails and prints each one.
Initialization
contacts = [...]: Initializes a list of email contacts.
Main Simulation
o if __name__ == "__main__": Ensures that the code block runs only when the script is
executed directly (not imported).
o server_thread = threading.Thread(target=email_server, daemon=True): Creates a
new thread to run the email_server function. The daemon=True means this thread will
automatically close when the main program exits.
o server_thread.start(): Starts the email server thread.
o while True:Begins an infinite loop to display a menu and handle user input.
o email_queue.join(): Waits until all items in the queue have been processed before
exiting.
o print("All emails have been processed."): Confirms that all emails are done processing.
Output: