-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Complete initial ECNQueue.py Python 3 rewrite
- Loading branch information
Justin Campbell
committed
Jul 26, 2020
1 parent
a63c80c
commit 8d6c5fe
Showing
1 changed file
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
# TODO: Add ECNQueue module documentation | ||
|
||
#------------------------------------------------------------------------------# | ||
# Imports | ||
#------------------------------------------------------------------------------# | ||
import os, time, email, re | ||
from typing import Union | ||
|
||
|
||
|
||
#------------------------------------------------------------------------------# | ||
# Configuration | ||
#------------------------------------------------------------------------------# | ||
|
||
# The directory where queue items are | ||
queueDirectory = "/Users/justincampbell/GitHub/ecn-queue/webqueue/q-snapshot" | ||
|
||
|
||
|
||
#------------------------------------------------------------------------------# | ||
# Classes | ||
#------------------------------------------------------------------------------# | ||
class Item: | ||
# TODO: Add Item class documentation | ||
|
||
def __init__(self, queue: str, number: int) -> None: | ||
self.queue = queue | ||
self.number = number | ||
|
||
self.__path = "/".join([queueDirectory, self.queue, str(self.number)]) | ||
self.lastUpdated = self.__getLastUpdated() | ||
self.__rawItem = self.__getRawItem() | ||
self.headers = self.__parseHeaders() | ||
self.content = self.__getContent() | ||
self.isLocked = self.__isLocked() | ||
|
||
def __getLastUpdated(self) -> float: | ||
"""Returns last modified time of item reported by the filesystem in mm-dd-yy hh:mm am/pm format. | ||
Example: | ||
07-23-20 10:34 AM | ||
Returns: | ||
float: last modified time of item reported by the filesystem in mm-dd-yy hh:mm am/pm format. | ||
""" | ||
unixTime = os.path.getmtime(self.__path) | ||
formattedTime = time.strftime('%m-%d-%y %I:%M %p', time.localtime(unixTime)) | ||
return formattedTime | ||
|
||
def __getRawItem(self) -> list: | ||
"""Returns a list of all lines in the item file | ||
Returns: | ||
list: List of all the lines in the item file | ||
""" | ||
with open(self.__path) as file: | ||
return file.readlines() | ||
|
||
def __getHeaderBoundary(self) -> int: | ||
"""Returns the 0 based line number where the Item headers stop. | ||
Example: The header end would be on line 13 | ||
12: X-ECN-Queue-Original-URL: | ||
13: | ||
14: I need help. | ||
Returns: | ||
int: line number where the Item headers end | ||
""" | ||
for lineNumber, line in enumerate(self.__rawItem): | ||
if line == "\n": | ||
return lineNumber | ||
|
||
def __parseHeaders(self) -> list: | ||
"""Returns a list containing dictionaries of header type and data. | ||
Removes queue prefixes and whitespace. | ||
Examples: | ||
"[ce] QStatus: Dont Delete\\nFrom: Justin Campbell <campb303@purdue.edu>\\n" | ||
becomes | ||
[ | ||
{"QStatus": "Don't Delete"}, | ||
{"From": "Justin Campbell <campb303@purdue.edu>"} | ||
] | ||
Returns: | ||
list: Header dicts | ||
""" | ||
headerString = "" | ||
|
||
# Remove '[queue] ' prefixes: | ||
# Example: | ||
# [ce] QTime-Updated-By: campb303 becomes | ||
# QTime-Updated-By: campb303 | ||
queuePrefixPattern = re.compile("\[.*\] {1}") | ||
for lineNumber in range(self.__getHeaderBoundary() - 1): | ||
line = self.__rawItem[lineNumber] | ||
lineHasQueuePrefix = queuePrefixPattern.match(line) | ||
|
||
if lineHasQueuePrefix: | ||
queuePrefix = line[ lineHasQueuePrefix.regs[0][0] : lineHasQueuePrefix.regs[0][1]] | ||
line = line.replace(queuePrefix, "") | ||
|
||
headerString += line | ||
|
||
message = email.message_from_string(headerString + "".join(self.__getContent())) | ||
|
||
headers = [] | ||
for key in message.keys(): | ||
headers.append( { "type": key, "content": message[key] } ) | ||
|
||
return headers | ||
|
||
# TODO: Implement attachment parsing | ||
|
||
def __getContent(self) -> list: | ||
"""Returns a dictionary lines of the item body. | ||
Example: | ||
"Hello. I need help.\\n\\n*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\\nDont Delete" becomes | ||
[ | ||
"Hello. I need help.\\n", | ||
"\\n", | ||
"*** Status updated by: campb303 at: 6/23/2020 13:26:55 ***\\n", | ||
"Don't Delete", | ||
] | ||
Returns: | ||
list: Lines of the body item. | ||
""" | ||
contentStart = self.__getHeaderBoundary() + 1 | ||
contentEnd = len(self.__rawItem) - 1 | ||
return self.__rawItem[ contentStart : contentEnd ] | ||
|
||
# TODO: Implement section parsing. | ||
|
||
def __isLocked(self) -> Union[str, bool]: | ||
"""Returns a string info about the lock if true and a bool False if false | ||
Example: A file is locked | ||
"CE 100 is locked by campb303 using qvi" | ||
Example: a file is not locked | ||
False | ||
Returns: | ||
Union[str, bool]: String with info about lock if true, bool False if false | ||
""" | ||
lockFile = self.__path + ".lck" | ||
if os.path.exists(lockFile): | ||
with open(lockFile) as file: | ||
lockInfo = file.readline().split(" ") | ||
lockedBy = lockInfo[4] | ||
lockedUsing = lockInfo[1] | ||
return "{queue} {number} is locked by {lockedBy} using {lockedUsing}".format(queue=self.queue, number=self.number, lockedBy=lockedBy, lockedUsing=lockedUsing) | ||
else: | ||
return False | ||
|
||
def __repr__(self) -> str: | ||
return self.queue + str(self.number) | ||
|
||
class Queue: | ||
# TODO: Add Queue class documentation | ||
|
||
def __init__(self, name: str) -> None: | ||
self.name = name | ||
self.__directory = queueDirectory + "/" + self.name + "/" | ||
self.items = self.__getItems() | ||
self.length = len(self) | ||
|
||
def __getItems(self) -> list: | ||
"""Returns a list of items for this Queue | ||
Returns: | ||
list: a list of items for this Queue | ||
""" | ||
items = [] | ||
|
||
for item in os.listdir(self.__directory): | ||
itemPath = self.__directory + "/" + item | ||
|
||
isFile = True if os.path.isfile(itemPath) else False | ||
|
||
itemPattern = re.compile("^[0123456789]{1,3}$") | ||
isItem = True if itemPattern.match(item) else False | ||
|
||
if isFile and isItem: | ||
items.append( Item(self.name, item) ) | ||
|
||
return items | ||
|
||
def __len__(self) -> int: | ||
return len(self.items) | ||
|
||
if __name__ == "__main__": | ||
# queue = Queue("ce") | ||
item = Item("ce", 9) | ||
print("s") |