What does the IRC edge server do? These things:

2 minute timeout
11 minute timeout
5 minute ping interval
20 second room server send
20 second room server recv
up to 10 queued commands per connection
510 byte max send line
2048 byte max recv line


can print how many objects of each type are in memory (does every 60s)

parses irc format lines into command/source/args

dies slowly when its parent has died .. every second for the next 60,
it disconnects 1/60th of its clients (checks every second)

generates a uuid to identify the process

logs a stacktrace if the loop is blocked for 5 seconds


listens on the pubsub exchange for messages
event:privmsg has json data of "nick", "session_id", "room", and "body"
event:admin_message has json data of "nick", "room", and "body"


accepts incoming TCP connections:
  makes a GET request to clue server's "/ip_banned" with parameter "ip"
    on error, drops connection
    otherwise, loads json and checks "allowed" key, drops on false/null/""
  creates client object, initializes client

generates globally-unique opaque-string ids for its clients

can answer whether a client is in a channel, and if a nick is in a channel

can (un)subscribe a client to a room


privmsg:
  makes a POST request to clue server's "/privmsg" with parameters "login", "session_id", "room", "body", "ip"
  on error, we're done
  looks at the list of actions in the response's (json) body:
    unknown types are ignored
    "room_message" means we "announce_privmsg"
    "admin_message" means we "announce_admin_message"
    "session_message" means if we find the session with the id specified, we send them the privmsg listed
    "action" of "drop_connection" means if we find the session specified, we kill it

"announce_privmsg" means we make a POST request to the pubsub exchange with parameters "event", and "data"
  "event" is "privmsg"
  "data" is json of "nick", "session_id", "room", "body"

"announce_admin_message" means we make a POST request to the pubsub exchange with parameters "event" and "data"
  "event" is "admin_message"
  "data" is json of "nick", "room", "body"


when we get a "privmsg" from the pubsub exchange, we look for a matching room. we then send the message to all members of the room, exept for ones that have a matching session id .. IRC says you don't get your own messages

when we get an "admin_message" from the pubsub exchange, we look for a matching room. we then wend the message to all members of the room who have identified as one of our clients ("twitchclient > 0"), except for ones that have a matching session id


check authentication by making a GET reuqest to the clue server's "/authenticate" with parameters "login", "password", "ip"
  on error, kill the connection
  de-json the response, check the "allowed" flag and kill the session if it's falsey
  send MOTD to the user, set timeouts for pinging the session and killing it if it's idle


when the client wants to join a room they're not in already
  make a GET request to clue server's "/join_permission" with parameters "login", "room", "ip"
  de-json response, look for "room", "visible", "allowed"
  if allowed, subscribe the session to room updates and tell the session they're in the room
  look at the list of "actions":
    if it's a "session_message", send that to the client
    if it's an "action" of "drop_connection", drop the client


when we want to send a join message .. for every session in the room:
  if the nick matches the session's, do nothing
  if the client has identified as "twitchclient >= 2", do nothing
  send the message to the session

when we want to send a part message .. it's the same as for join

when we want to send a specialness message .. for every session in the room:
  make a specialuser message for every "specialness" we want to send (staff/admin/global_mod)
  make a +o mode message if the prefix we want to communicate includes "@", otherwise make a -o mode message


sends membership updates to the room server:
  if our view of the room hasn't changed, we only tell the room server about it if we're doing a "full" update, which happens every 10-15 updates
  if we just synced a room state with the room server, and we both agree it's empty, we're allowed to forget about it
receives membership updates from the room server for all rooms we know about
  when we get an update set from the room server, we sent joins, parts, and specialness messages to the users in the room


we can generate several kinds of messages to send to IRC users:
  PRIVMSG with full sender info
  JOIN
  PART
  MODE from jtv user
  PRIVMSG from jtv user about a SPECIALUSER
  PRIVMSG with short sender info (for admin messages)
  353 (NAMES list)
  366 (end of NAMES list)

we look for "<policy-file-request/>", and send the crossdomain policy in return

if we get lots of bytes without a newline, we kill the session

we interpret incoming bytes as utf-8, split them on '\n' and dispatch to the line-based reader


when a connection starts (after we've checked the ip-ban status), we start a two-minute timer for the session to authenticate

when we get a line:
  if the session has authenticated, we set timers for:
    killing the session in 11 minutes
    sending a ping in 4-5 minutes (uniformly distributed)
  if the line includes '\x00', we'll add NUL terminators to lines we send to the client forevermore
  we then process the line:
    because we get lines as they come vs when we're ready to process them, we've got a limit of 10 queued commands

commands we know:
  GET (for http, for crossdomain.xml)
  PASS
  NICK
  PRIVMSG
  JOIN
  PART
  QUIT
  PING
  PONG
  WHO
  JTVCLIENT
  TWITCHCLIENT
  EXTERNALUSER
  GLOBALBAN
  JTVROOMS
  USER
  MODE
  (empty string)

when the client authenticates successfully:
  we send the MOTD:
    001
    002
    003
    004
    375
    372
    376
  we set an 11 minute timeout for killing the session
  we set a 4-5 minute timeout for pinging the session

to tell the user that they've joined a room:
  we add the room to their list
  we send them a JOIN message for themselves
  we send them the NAMES list for the other members we know about
    unless they're "twitchclient >= 2" - then we only tell them about themselves
  we send them MODE +o messages for the special users with prefix including '@'
  we send them SPECIALUSER messages for the staff/admins/global_mods in the room

to tell the user that they've left a room:
  we remove the room from their list
  we tell the global server object that they're unsubscribed
  we send them a PART message for themselves


if we get a command that's not on our list, we send a 421 message to the user

if we get a PASS and we already know the user's password, we kill the session
if there's not exactly one arg, we kill the session
otherwise, we set the session's password

if we get a NICK and we've already authenticated, we kill the session
if there's not exactly one arg, we kill the session
if there's a space in the arg, we kill the session
otherwise, we set the nick to the lowercased arg, and check if we've got a valid nick/pass

if we get a PRIVMSG and we're not authed, we ignore it
if we don't get exactly two args, we ignore it
otherwise, we try to send the privmsg (via the clue server)

if we get a JOIN and we're not authed, we ignore it
if we got no args, we ignore it
otherwise, we split the first arg on ',' and join all of those rooms

PART is the same as JOIN (but for part)

QUIT kills the session

if we get a PING with no args, we respond with "PONG $(servername)"
othervise, we respond with ":$(servername) PONG $(servername) :$(arg[0])"

we ignore PONGs

if we get a JTVCLIENT command, we set twitchclient to 1

if we get a TWITCHCLIENT command, we set twitchclient to the max of 1 or the first argument

we ignore:
  EXTERNALUSER
  GLOBALBAN
  JTVROOMS
  USER
  MODE

if we have a GET "command" and the first "argument" is "/crossdomain.xml", we assume it's an http request .. we send the crossdomain policy and kill the connection

