-
-
Save amcgregor/4332627 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/python | |
from __future__ import print_function | |
# This makes Python use the newer print() syntax. | |
import socket | |
import time | |
import sys | |
import twitter | |
from weakref import proxy | |
class Client(object): | |
def __init__(self, server, socket, ip, port): | |
super(Client, self).__init__() | |
self.server = proxy(server) # this helps Python manage memory | |
self.socket = socket | |
self.ip = ip | |
print("Received connection from: ", ip, ":", port, sep='') | |
def close(self): | |
"""Close the connection and update the server.""" | |
print("Goodbye from", self.ip) | |
# Don't client.send here; the connection may already be dead! | |
self.socket.close() | |
# Remove from the server tracking of current connections. | |
del self.server.clients[self.socket] | |
def send(self, data): | |
"""Send data to the client.""" | |
# We wrap it in str() here (for Python 2) because sockets only communicate in binary data. | |
# On Python 3 you'd use bytes() instead. | |
self.socket.send(str(data)) | |
def read(self): | |
"""There is data available for reading.""" | |
data = self.socket.recv(1024) | |
# this is bad since \n won't actually return! | |
# recv(1024) either gets exactly 1KB of data or returns when the client disconnects | |
# Implementing a line-based buffer is left as an exercise for the reader! | |
# Continuing with the assumption that data is a line of text, not a 1KB chunk. | |
print("CLIENT_REQUEST", self.ip, ">>", data) | |
# Now, manually checking for each command as a substring is not very efficient. | |
# If we assume a command is always the prefix of the string with at least one space | |
# separating the argument(s)... | |
command, sep, argument = data.partition(' ') | |
fn = getattr(self, 'cmd_' + command, None) | |
if fn: | |
if sep: # sep will evaluate to False if there was no space, otherwise it will be a space | |
fn(argument) | |
return | |
fn() | |
return | |
self.send("Unknown command: " + command + "\n") | |
def menu(self): | |
self.send('''############################## | |
Choose option from the menu: | |
############################## | |
1) Open Shell | |
2) Lists files in current working directory | |
3) Get Twitter feed from <uid> | |
4) Shuts down socket! | |
############################# | |
''') | |
def cmd_shell(self): | |
'''This function creates a shell with basic system commands.''' | |
pass | |
def cmd_ls(self): | |
'''This function lists which current directory the client is in.''' | |
def cmd_twitter(self, user): | |
'''This function gets twitter with uid given as argument.''' | |
status = self.server.api.GetUserTimeline(count=5, screen_name=user) | |
output = [message.text for message in status] | |
for tweet in output: | |
self.send(tweet) | |
def cmd_exit(self): | |
self.send("Bye!") | |
self.close() | |
def cmd_time(self): | |
"""return the local time""" | |
date = time.asctime() | |
self.send(date) | |
def cmd_help(self): | |
'''This function returns help for commands no args given.''' | |
# The indentation would have been sent, too! | |
self.send('''shell open a shell to the host machine and gain access to system shell commands. | |
ls lists the file in the current working directory. | |
twitter this command requires 1 argument <id> and will fetch the last 5 tweets. | |
exit will close the connection. | |
help will open up the current help menu. | |
time will get local time. | |
''') | |
class Server(object): | |
def __init__(self, host, port): | |
super(Server, self).__init__() | |
self.api = twitter.Api() | |
self.socket = socket.socket() | |
self.socket.bind((host, port)) | |
self.socket.listen(5) # 5 is the 'backlog' size | |
self.clients = {} | |
def start(self): | |
# This shouldn't be a while True; there's no way to exit! | |
while True: | |
# Prepare the list of sockets which can be read from or have errors. | |
listeners = [self.socket] + self.clients.keys() | |
readers, writers, errors = socket.select(listeners, self.connections, listeners) | |
if errors: | |
1/0 # die horribly, something went wrong; TODO: handle this better ;) | |
if self.socket in readers: | |
# A new connection is available since our server socket can be 'read'. | |
socket, (ip, port) = self.socket.accept() | |
# Create a new Client object and let it know which server and client socket to use. | |
client = Client(self, socket, ip, port) | |
# Keep track of the connection. | |
self.clients[socket] = client | |
for socket in readers: | |
if socket is self.socket: continue # skip the server socket | |
# Now all we have are sockets with outstanding data to read. | |
self.clients[socket].read() | |
if __name__ == '__main__': | |
service = Server('127.0.0.1', 5050) | |
service.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment