-
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.
WIP
- Loading branch information
Showing
2 changed files
with
426 additions
and
40 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 |
---|---|---|
@@ -1,54 +1,75 @@ | ||
import gleam/bit_array | ||
import gleam/bytes_builder | ||
import cipher | ||
import client.{type Client, Client} | ||
import gleam/erlang | ||
import gleam/erlang/process | ||
import gleam/int | ||
import gleam/io | ||
import gleam/option.{None} | ||
import gleam/option | ||
import gleam/otp/actor | ||
import gleam/result | ||
import gleam/string | ||
import glisten.{Packet, User} | ||
import glisten | ||
|
||
const port = 4000 | ||
// TODO: Make this configurable. The defaults in UO's login.cfg specify 4 login | ||
// servers running on two different ports (7775 and 7776). | ||
const port = 7775 | ||
|
||
// Number of login servers * pool size = login server concurrency | ||
const pool_size = 10 | ||
|
||
type Connection = | ||
glisten.Connection(Client) | ||
|
||
type Message = | ||
glisten.Message(Client) | ||
|
||
pub fn main() { | ||
let assert Ok(_) = | ||
glisten.handler(fn(_conn) { #(Nil, None) }, fn(msg, state, conn) { | ||
case msg { | ||
Packet(bit_array) -> { | ||
let assert Ok(info) = glisten.get_client_info(conn) | ||
let ip = glisten.ip_address_to_string(info.ip_address) | ||
let ip_and_port = ip <> ":" <> int.to_string(info.port) | ||
let bytes = bit_array.inspect(bit_array) | ||
let n = bit_array.byte_size(bit_array) | ||
let text = | ||
bit_array.to_string(bit_array) | ||
|> result.unwrap("(error)") | ||
|> string.trim() | ||
|
||
io.println( | ||
ip_and_port | ||
<> ": " | ||
<> text | ||
<> " (" | ||
<> int.to_string(n) | ||
<> " bytes)\n\t" | ||
<> bytes, | ||
) | ||
|
||
let assert Ok(_) = | ||
glisten.send(conn, bytes_builder.from_string("ok\n")) | ||
|
||
actor.continue(state) | ||
} | ||
User(_user_message) -> { | ||
todo | ||
} | ||
} | ||
}) | ||
glisten.handler(on_init, on_message) | ||
|> glisten.with_pool_size(pool_size) | ||
|> glisten.with_close(on_close) | ||
|> glisten.serve(port) | ||
|
||
io.println("Listening on port " <> int.to_string(port)) | ||
|
||
process.sleep_forever() | ||
} | ||
|
||
fn on_init(connection: Connection) { | ||
let client = Client(connection, <<>>, client.Unauthenticated, cipher.nil()) | ||
|
||
io.println("new connection from " <> client.inspect_socket(client)) | ||
|
||
#(client, option.None) | ||
} | ||
|
||
fn on_message(message: Message, client: Client, conn: Connection) { | ||
// This assertion is safe because on_init doesn't return a selector, so there | ||
// won't ever be any User-type messages. | ||
let assert glisten.Packet(data) = message | ||
|
||
// TODO: check data size and halt if > max_packet_size | ||
|
||
// TODO: check client state – no need to store more data if the client is | ||
// about to be disconnected. | ||
|
||
// Clients often send partial or multiple commands at one time, so here all | ||
// that needs to be done is append the incoming data to the client's buffer, | ||
// then wait for the next read. | ||
let new_client = Client(..client, conn: conn, buf: <<client.buf:bits, data:bits>>) | ||
io.println(client.inspect(new_client)) | ||
|
||
case client.do_work(new_client) { | ||
Ok(client) -> actor.continue(client) | ||
Error(err) -> { | ||
io.println( | ||
client.inspect_socket(client) <> ": error! " <> erlang.format(err), | ||
) | ||
actor.Stop(process.Normal) | ||
} | ||
} | ||
} | ||
|
||
fn on_close(client: Client) { | ||
// The connection has already been closed, so writes will fail in here. | ||
io.println(client.inspect(client) <> ": connection closed.") | ||
// TODO: flag client as disconnected? | ||
} |
Oops, something went wrong.