Homework 12a
MUST BE DONE WITH YOUR PARTNER
MUST USE CHECKED-SIGNATURES!
Due Date Tues at 9:00pm (Week 12)
Purpose Implement a chat program, with rate limiting & blocking, via universe and a shared server.
Exercises
In this assignment, you will build a chat program, using big-bang and universe, that connects to a single server that is shared by all students in the class. Once you have finished, you will be able to send and recieve messages from other students, as well as block particular students and turn on and off rate limiting.
The most important thing, when writing universe programs, is understanding the messages you can send to the server, and messages that the server will send to you. See a complete specification below:
CLIENT TO SERVER MESSAGES: |
------------------------- |
|
STRING: |
A string sent to the server is a message sent that should be broadcast to |
all other connected clients. Your name will be attached to the message when |
it is sent. |
|
SERVER TO CLIENT MESSAGES: |
-------------------------- |
(list 'users [ListOf String]): |
A list of all connected client names. These are the same names as will |
be attached to messages when they are broadcast. This message will be |
sent to all users every time a user connects or disconnects from the |
server. |
|
(list 'send String String): |
A message sent from a user. The first string is the users full name, the |
second string is the message they are sending |
From this description, you can see that when you send messages, you just include the message, but when you receive messages, they have your full name attached. How is that done? We will give you each a unique code that you should use when you initialize big-bang (look out for them). Please design your program in the following way:
; main : String -> ... (define (main code) (big-bang ... (name code) ... ...))
i.e., you should make your main program take, as an argument, a String that will be the unique code we assign to you. This should be used in the "name" clause of big-bang. Then when you want to run your program, in the interactions window type (main "YOURCODE") to start the program.
Connecting to the server
The server we have is running on a college machine, which should be accessible anywhere on campus (as long as you are connected to campus internet). You should include in your big-bang invocation a clause (register "lambda-chat.dbp.io"), and it should have (port 20000) as well. If you don’t have those two clauses, or are not on campus (or using a VPN to connect), you won’t be able to connect to the server (though, you can and should write & test your handlers before connecting for the first time: don’t subject your classmates to your buggy code!).
IMPORTANT: You are responsible for any message that is sent to the server using your code, so our recommendation is to not share it with your partner (don’t save it in the file, just run it when you start the program). If you decide to do that, it’s up to you, but know all messages are logged on the server, and we will respond to any abusive, discriminatory, or hateful messages with severe consequences (to the person whose code is used), both at the course level (decide whether failing the course is worth what you are sending) and sending it up to the university level as well.
We suggest that you design this program iteratively, but unlike in previous assignments, we are going to only give you rough guidelines as to what you should have in each part. It is up to you to design the world state, define any helpers, etc.
Exercise 1 Receiving Messages. One half of the core of the chat program is receiving and displaying messages. Your world state should be able to capture some number of messages (it need not be arbitrary, since your window likely will only show a certain number, and you are not implementing scrolling), and you should have an on-receive handler that processes the corresponding SERVER TO CLIENT message to add a new one. Your to-draw handler should display all the messages in some way.
Exercise 2 Sending Messages. The other core is sending messages. To do this, you should collect keyboard input in your world state until you hit a "\r" (carriage return character), which indicates that the user has hit enter. You should probably support delete (the "\b" keyboard event). Once enter has been hit, use (make-package ...) to both update your world state and send a the message to the server (look at the 2htdp/universe documentation for more details about make-package).
Exercise 3 User List. Knowing who else is connected is helpful, if you want to talk to them! Ensure your world state includes a user list, update your on-receive to handle the message that the server sends updating this, and update your to-draw handler to display the list of users somewhere on the screen.
At this point, you have a functioning chat client. But, just as important as the communication of messages in the design of programs like chat clients are dealing with malicious content, abuse, etc. Now, we certainly aren’t going to see any of that in our chat, but it is pervasive on the internet. In the next two problems, you will implement some very basic moderation tools. Tools that you give to users to control their experience are as important, if not more, that the "core functionality" in programs that involve communication with strangers, and products shouldn’t be considered "viable" until these types of things are in place (and work).
Exercise 4 Blocking. One of the simplest way of handling someone who is sending messages you don’t want to recieve is to be able to block them. In your world state, you should add a list of blocked people, and in your on-receive, you should not add messages that come from them to your list of messages (just completely ignore them). How do people get blocked or unblocked? You should implement this by clicking on the persons name. This requires you to add an on-mouse handler, and to do some arithmetic with the x & y coordinate to tell if the click is on a name (and which one). You may end up wanting to redo the rendering of the user list to make this easier (overlaying every name on a rectangle of the same size, for example). When you do that rendering, you probably want to indicate if a given user is blocked or not.
Exercise 5 Rate Limiting. In this exercise, we want you to add some mechanism to turn on a "rate limit". The idea is that if someone logs on and suddenly starts sending a huge number of messages, you want to be able to limit how many messages you get and drop after that (like with blocking, just don’t store them at all).
You are welcome to come up with your own idea, as long as it seems like a reasonable idea to handle this kind of abuse, but the idea we suggest is the following: if the rate limit is turned on (add another "click target" somewhere in your program, and update your on-mouse accordingly to turn this "on" and "off"), there should be a budget of messages every second (e.g., 4). When you receive messages, you decrement this; if it hits 0, you stop accepting messages. In an on-tick handler (use the second parameter, which says how frequently to invoke it, to have it run every 1s), reset the budget. This way, if there are only a few messages, the rate limit has no effect, but if there are a lot, only 4 per second will get through. Obviously, this has the (severe) limitation that it is not tied to users: you are welcome to implement a fancier version, but if you do, please describe the strategy you are taking in a paragraph comment.