diff options
Diffstat (limited to 'tests/manyloc/keineschweine/enet_server')
6 files changed, 675 insertions, 0 deletions
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim new file mode 100644 index 000000000..7aa7b9c2f --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim @@ -0,0 +1,229 @@ +import enet, strutils, + sfml, sfml_colors, sg_gui, input_helpers, + math_helpers, sg_packets, estreams, tables, + json, sg_assets, client_helpers +if enetInit() != 0: + quit "Could not initialize ENet" +type + TClientSettings = object + resolution*: TVideoMode + offlineFile: string + dirserver: tuple[host: string, port: int16] + website*: string +var + clientSettings: TClientSettings + event: enet.TEvent + bConnected = false + runServer = true + gui = newGuiContainer() + zonelist = newGuiContainer() + kc = newKeyClient(setActive = true) + clock = newClock() + chatBox: PMessageArea + chatInput: PTextEntry + loginBtn, playBtn: PButton + fpsText = newText("", guiFont, 18) + connectionButtons: seq[PButton] + connectButton: PButton + u_alias, u_passwd: PTextEntry + dirServer: PServer + zone: PServer + showZoneList = false + myCreds = newScLogin(0, "", "") ##my session token + +proc handleChat(server: PServer; buf: PBuffer) = + let msg = readScChat(buf) + chatBox.add msg +proc handlePlayerLogin(server: PServer; buf: PBuffer) = + let login = readScLogin(buf) + myCreds = login + echo("I am ", $myCreds) + + +kc.registerHandler MouseLeft, down, proc() = + gui.click(input_helpers.getMousePos()) + +block: + var pos = vec2f(15, 550) + chatBox = gui.newMessageArea(pos) + pos.y += 20 + chatInput = gui.newTextEntry("...", pos, proc() = + sendPubChat dirServer, chatInput.getText() + chatInput.clearText()) + +gui.setActive(chatInput) + +proc dispMessage(args: varargs[string, `$`]) = + var s = "" + for it in items(args): + s.add it + chatbox.add(s) +proc dispMessage(text: string) {.inline.} = + chatbox.add(text) +proc dispError(text: string) {.inline.} = + chatBox.add(newScChat(kind = CError, text = text)) + +proc updateButtons() = + let conn = dirServer.connected + for b in connectionButtons: setEnabled(b, conn) + if conn: + connectButton.setString "Disconnect" + else: + connectButton.setString "Connect" + +proc poll(serv: PServer; timeout: cuint = 30) = + if serv.isNil or serv.host.isNil: return + if serv.connected: + while serv.host.hostService(event, timeout) > 0: + case event.kind + of EvtReceive: + var buf = newBuffer(event.packet) + + serv.handlePackets(buf) + + event.packet.destroy() + of EvtDisconnect: + dispMessage "Disconnected" + serv.connected = false + event.peer.data = nil + updateButtons() + of EvtNone: discard + else: + echo repr(event) + else: + if serv.host.hostService(event, timeout) > 0 and event.kind == EvtConnect: + dispMessage "Connected" + serv.connected = true + if serv.peer != event.peer: + serv.peer = event.peer + event.peer.data = serv + updateButtons() + +proc tryLogin*(b: PButton) = + var login = newCsLogin( + alias = u_alias.getText(), + passwd = u_passwd.getText()) + dirServer.send HLogin, login +proc tryTransition*(b: PButton) = + discard + #zone.writePkt HZoneJoinReq, myCreds +proc tryConnect*(b: PButton) = + if not dirServer.connected: + var error: string + if not dirServer.connect( + clientSettings.dirServer.host, + clientSettings.dirServer.port, + error): + dispError(error) + else: + dirServer.peer.disconnect(1) + +proc playOffline*(b: PButton) = + var errors: seq[string] = @[] + if loadSettingsFromFile(clientSettings.offlineFile, errors): + transition() + else: + dispMessage "Errors reading the file (", clientSettings.offlineFile, "):" + for e in errors: dispError(e) + +proc getClientSettings*(): TClientSettings = + result = clientSettings + + +proc lobbyInit*() = + var s = json.parseFile("./client_settings.json") + clientSettings.offlineFile = "data/" + clientSettings.offlineFile.add s["default-file"].str + let dirserv = s["directory-server"] + clientSettings.dirserver.host = dirserv["host"].str + clientSettings.dirserver.port = dirserv["port"].num.int16 + clientSettings.resolution.width = s["resolution"][0].num.cint + clientSettings.resolution.height= s["resolution"][1].num.cint + clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint + clientSettings.website = s["website"].str + zonelist.setPosition(vec2f(200.0, 100.0)) + connectionButtons = @[] + + var pos = vec2f(10, 10) + u_alias = gui.newTextEntry( + if s.hasKey("alias"): s["alias"].str else: "alias", + pos) + pos.y += 20 + u_passwd = gui.newTextEntry("buzz", pos) + pos.y += 20 + connectionButtons.add(gui.newButton( + text = "Login", + position = pos, + onClick = tryLogin, + startEnabled = false)) + pos.y += 20 + fpsText.setPosition pos + pos.y += 20 + connectButton = gui.newButton( + text = "Connect", + position = pos, + onClick = tryConnect) + pos.y += 20 + gui.newButton("Test Files", position = pos, onClick = proc(b: PButton) = + var req = newCsZoneJoinReq(myCreds) + dirServer.send HZoneJoinReq, req) + pos.y += 20 + connectionButtons.add(gui.newButton( + text = "Test Chat", + position = pos, + onClick = (proc(b: PButton) = + var pkt = newCsChat(text = "ohai") + dirServer.send HChat, pkt), + startEnabled = false)) + pos.y += 20 + downloadProgress.setPosition(pos) + downloadProgress.bg.setFillColor(color(34, 139, 34)) + downloadProgress.bg.setSize(vec2f(0, 0)) + gui.add(downloadProgress) + + playBtn = gui.newButton( + text = "Play", + position = vec2f(680.0, 8.0), + onClick = tryTransition, + startEnabled = false) + gui.newButton( + text = "Play Offline", + position = vec2f(680.0, 28.0), + onClick = playOffline) + discard """gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) = + messageArea.scrollBack += 1 + update(messageArea)) + gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = + messageArea.scrollBack -= 1 + update(messageArea)) + gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) = + for i in 0..< 30: + dispMessage($i))""" + dirServer = newServer() + dirServer.addHandler HChat, handleChat + dirServer.addHandler HLogin, handlePlayerLogin + dirServer.addHandler HFileTransfer, client_helpers.handleFilePartRecv + dirServer.addHandler HChallengeResult, client_helpers.handleFileChallengeResult + dirServer.addHandler HFileChallenge, client_helpers.handleFileChallenge + +proc lobbyReady*() = + kc.setActive() + gui.setActive(u_alias) + +var i = 0 +proc lobbyUpdate*(dt: float) = + dirServer.poll() + #let res = disp.poll() + gui.update(dt) + i = (i + 1) mod 60 + if i == 0: + fpsText.setString("FPS: " & ff(1.0/dt)) + +proc lobbyDraw*(window: PRenderWindow) = + window.clear(Black) + window.draw chatBox + window.draw gui + window.draw fpsText + if showZonelist: window.draw zonelist + window.display() + diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim new file mode 100644 index 000000000..86d0ab360 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim @@ -0,0 +1,294 @@ +import enet, strutils, idgen, tables, math_helpers, + estreams, sg_packets, server_utils, sg_assets, client_helpers +when appType == "gui": + import sfml, sfml_colors, sg_gui, + input_helpers, sfml_stuff +else: + import times +type + TCallback = proc(client: PClient; buffer: PBuffer) +var + server: PHost + dirServer: PServer + standAloneMode = true + event: enet.TEvent + clientID = newIDGen[int32]() + clients = initTable[int32, PClient](64) + handlers = initTable[char, TCallback](32) + +when appType == "gui": + var + gui = newGuiContainer() + chatBox = gui.newMessageArea(vec2f(15, 550)) + window = newRenderWindow(videoMode(800, 600, 32), "Sup yo", sfDefaultSTyle) + mousepos = newText("", guiFont, 16) + fpsText = mousePos.copy() + inputClient = newKeyClient(setActive = true) + chatBox.sizeVisible = 30 + mousePos.setColor(Green) + fpsText.setposition(vec2f(0, 20)) + inputClient.registerHandler MouseLeft, down, proc() = + gui.click(input_helpers.getMousePos()) + inputClient.registerHandler MouseMiddle, down, proc() = + let pos = input_helpers.getMousePos() + mousePos.setString("($1,$2)".format(ff(pos.x), ff(pos.y))) + mousePos.setPosition(pos) + proc dispMessage(args: varargs[string, `$`]) = + var s = "" + for it in items(args): + s.add it + chatbox.add(s) + proc dispError(args: varargs[string, `$`]) = + var s = "" + for it in items(args): s.add(it) + chatBox.add(newScChat(kind = CError, text = s)) +else: + proc dispMessage(args: varargs[string, `$`]) = + var m = "" + for it in items(args): m.add(it) + echo "<msg> ", m + proc dispError(args: varargs[string, `$`]) = + var m = "" + for it in items(args): m.add(it) + echo "**", m + + +var pubChatQueue = newBuffer(1024) +proc queuePub(sender: PClient, msg: CsChat) = + var chat = newScChat(kind = CPub, fromPlayer = sender.alias, text = msg.text) + pubChatQueue.write(HChat) + pubChatQueue.pack(chat) +proc flushPubChat() = + if pubChatQueue.isDirty: + let packet = pubChatQueue.toPacket(FlagReliable) + for id, client in pairs(clients): + discard client.peer.send(0.cuchar, packet) + pubChatQueue.flush() + +handlers[HChat] = proc(client: PClient; buffer: PBuffer) = + var chat = readCsChat(buffer) + + if not client.auth: + client.sendError("You are not logged in.") + return + #if chat.target != "": ##private + # if alias2client.hasKey(chat.target): + # alias2client[chat.target].forwardPrivate(client, chat.text) + #else: + + dispmessage("<", client.alias, "> ", chat.text) + queuePub(client, chat) + +handlers[HLogin] = proc(client: PClient; buffer: PBuffer) = + var info = readCsLogin(buffer) + if client.auth: + client.sendError "You are already logged in." + return + client.alias = info.alias + client.auth = true + var resp = newScLogin(client.id, client.alias, "sessionkeylulz") + client.send HLogin, resp + client.sendMessage "welcome" + dispMessage("Client logged in: ", client) + + +handlers[HFileTransfer] = server_utils.handleFilePartAck +handlers[HFileChallenge] = server_utils.handleFileChallengeResp + +handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) = + var info = readCsZoneJoinReq(buffer) + dispmessage "Got zone join request" + client.startVerifyingFiles() + + + +when true: + import parseopt, os, json + + + if enetInit() != 0: + quit "Could not initialize ENet" + + var address: enet.TAddress + + block: + var zoneCfgFile = "./server_settings.json" + for kind, key, val in getopt(): + case kind + of cmdShortOption, cmdLongOption: + case key + of "f", "file": + if fileExists(val): + zoneCfgFile = val + else: + echo("File does not exist: ", val) + else: + echo("Unknown option: ", key," ", val) + else: + echo("Unknown option: ", key, " ", val) + var jsonSettings = parseFile(zoneCfgFile) + let + port = uint16(jsonSettings["port"].num) + zoneFile = jsonSettings["settings"].str + dirServerInfo = jsonSettings["dirserver"] + + address.host = EnetHostAny + address.port = port + + var path = getAppDir()/../"data"/zoneFile + if not fileExists(path): + echo("Zone settings file does not exist: ../data/", zoneFile) + echo(path) + quit(1) + + discard """block: + var + TestFile: FileChallengePair + contents = repeat("abcdefghijklmnopqrstuvwxyz", 2) + testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) + testFile.file = checksumStr(contents) + myAssets.add testFile""" + + setCurrentDir getAppDir().parentDir() + let zonesettings = readFile(path) + var + errors: seq[string] = @[] + if not loadSettings(zoneSettings, errors): + echo("You have errors in your zone settings:") + for e in errors: echo("**", e) + quit(1) + errors.setLen 0 + + var pair: FileChallengePair + pair.challenge.file = zoneFile + pair.challenge.assetType = FZoneCfg + pair.challenge.fullLen = zoneSettings.len.int32 + pair.file = checksumStr(zoneSettings) + myAssets.add pair + + allAssets: + if not load(asset): + echo "Invalid or missing file ", file + else: + var pair: FileChallengePair + pair.challenge.file = file + pair.challenge.assetType = assetType + pair.challenge.fullLen = getFileSize( + expandPath(assetType, file)).int32 + pair.file = asset.contents + myAssets.add pair + + echo "Zone has ", myAssets.len, " associated assets" + + dirServer = newServer() + + dirServer.addHandler HDsMsg, proc(serv: PServer; buffer: PBuffer) = + var m = readDsMsg(buffer) + dispMessage("<DirServer> ", m.msg) + dirServer.addHandler HZoneLogin, proc(serv: PServer; buffer: PBuffer) = + let loggedIn = readDsZoneLogin(buffer).status + if loggedIn: + #dirServerConnected = true + + if dirServerInfo.kind == JArray: + var error: string + if not dirServer.connect(dirServerInfo[0].str, dirServerInfo[1].num.int16, error): + dispError("<DirServer> "&error) + + + server = enet.createHost(address, 32, 2, 0, 0) + if server == nil: + quit "Could not create the server!" + + dispMessage("Listening on port ", address.port) + + var + serverRunning = true + when appType == "gui": + var frameRate = newClock() + var pubChatDelay = newClock() + else: + var frameRate = epochTime() + var pubChatDelay = frameRate + + while serverRunning: + when appType == "gui": + let dt = frameRate.restart.asMilliseconds().float / 1000.0 + + for event in window.filterEvents(): + case event.kind + of sfml.EvtClosed: + window.close() + serverRunning = false + else: + discard + else: + let dt = epochTime() - frameRate ##is this right? probably not + frameRate = epochTime() + + while server.hostService(event, 10) > 0: + case event.kind + of EvtConnect: + var client = newClient() + clients[client.id] = client + + event.peer.data = addr client.id + client.peer = event.peer + + dispMessage("New client connected ", client) + + var + msg = "hello" + resp = createPacket(cstring(msg), msg.len + 1, FlagReliable) + + if event.peer.send(0.cuchar, resp) < 0: + echo "FAILED" + else: + echo "Replied" + of EvtReceive: + let client = clients[cast[ptr int32](event.peer.data)[]] + + var buf = newBuffer(event.packet) + let k = buf.readChar() + if handlers.hasKey(k): + handlers[k](client, buf) + else: + dispError("Unknown packet from ", client) + + destroy(event.packet) + of EvtDisconnect: + var + id = cast[ptr int32](event.peer.data)[] + client = clients[id] + if client.isNil: + disperror("CLIENT IS NIL!") + dispmessage(event.peer.data.isNil) + else: + dispMessage(clients[id], " disconnected") + GCUnref(clients[id]) + clients.del id + + event.peer.data = nil + else: + discard + + when appType == "gui": + fpsText.setString(ff(1.0/dt)) + if pubChatDelay.getElapsedTime.asSeconds > 0.25: + pubChatDelay.restart() + flushPubChat() + else: + pubChatDelay -= dt + if frameRate - pubChatDelay > 0.25: + flushPubChat() + + when appType == "gui": + window.clear(Black) + window.draw(GUI) + window.draw chatbox + window.draw mousePos + window.draw fpstext + window.display() + + server.destroy() + enetDeinit() diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim new file mode 100644 index 000000000..3764c6271 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim @@ -0,0 +1,13 @@ +import nake +nakeimports + +const + ServerDefines = "-d:NoSFML --forceBuild" + +task "server", "build the server": + if shell("nim", ServerDefines, "-r", "compile", "enet_server") != 0: + quit "Failed to build" +task "gui", "build the server GUI mode": + if shell("nim", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0: + quit "Failed to build" + diff --git a/tests/manyloc/keineschweine/enet_server/nim.cfg b/tests/manyloc/keineschweine/enet_server/nim.cfg new file mode 100644 index 000000000..72ef47ee0 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/nim.cfg @@ -0,0 +1,9 @@ +path = ".." +path = "../dependencies/sfml" +path = "../dependencies/enet" +path = "../dependencies/nake" +path = "../dependencies/genpacket" +path = "../lib" +define = "noChipmunk" +define = "noSFML" + diff --git a/tests/manyloc/keineschweine/enet_server/server_settings.json b/tests/manyloc/keineschweine/enet_server/server_settings.json new file mode 100644 index 000000000..7d2f1d822 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/server_settings.json @@ -0,0 +1,8 @@ +{ + "name": "Alpha Zone", + "desc": "Beta Testing", + "host": "localhost", + "port": 8024, + "settings": "alphazone.json", + "dirserver":["localhost",2049,"alphazone","skittles"] +} diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim new file mode 100644 index 000000000..3940dcf01 --- /dev/null +++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim @@ -0,0 +1,122 @@ +import ../../../../dist/checksums/src/checksums/md5 + +import enet, sg_packets, estreams, zlib_helpers, client_helpers, strutils, + idgen, sg_assets, tables, os +type + PClient* = ref object + id*: int32 + auth*: bool + alias*: string + peer*: PPeer + + FileChallengePair* = tuple[challenge: ScFileChallenge; file: TChecksumFile] + PFileChallengeSequence* = ref TFileChallengeSequence + TFileChallengeSequence = object + index: int #which file is active + transfer: ScFileTransfer + file: ptr FileChallengePair +var + clientID = newIdGen[int32]() + myAssets*: seq[FileChallengePair] = @[] + fileChallenges = initTable[int32, PFileChallengeSequence](32) +const FileChunkSize = 256 + +proc free(client: PClient) = + if client.id != 0: + fileChallenges.del client.id + clientID.del client.id +proc newClient*(): PClient = + new(result, free) + result.id = clientID.next() + result.alias = "billy" + +proc `$`*(client: PClient): string = + result = "$1:$2".format(client.id, client.alias) + +proc send*[T](client: PClient; pktType: char; pkt: var T) = + var buf = newBuffer(128) + buf.write pktType + buf.pack pkt + discard client.peer.send(0.cuchar, buf, flagReliable) + +proc sendMessage*(client: PClient; txt: string) = + var m = newScChat(CSystem, text = txt) + client.send HChat, m +proc sendError*(client: PClient; error: string) = + var m = newScChat(CError, text = error) + client.send HChat, m + + + + +proc next*(challenge: PFileChallengeSequence, client: PClient) +proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) + +proc startVerifyingFiles*(client: PClient) = + var fcs: PFileChallengeSequence + new(fcs) + fcs.index = -1 + fileChallenges[client.id] = fcs + next(fcs, client) + +proc next*(challenge: PFileChallengeSequence, client: PClient) = + inc(challenge.index) + if challenge.index >= myAssets.len: + client.sendMessage "You are cleared to enter" + fileChallenges.del client.id + return + else: + echo myAssets.len, "assets" + challenge.file = addr myAssets[challenge.index] + client.send HFileChallenge, challenge.file.challenge # :rolleyes: + echo "sent challenge" + +proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) = + let size = min(FileChunkSize, challenge.transfer.fileSize - challenge.transfer.pos) + challenge.transfer.data.setLen size + copyMem( + addr challenge.transfer.data[0], + addr challenge.file.file.compressed[challenge.transfer.pos], + size) + client.send HFileTransfer, challenge.transfer + echo "chunk sent" + +proc startSend*(challenge: PFileChallengeSequence, client: PClient) = + challenge.transfer.fileSize = challenge.file.file.compressed.len().int32 + challenge.transfer.pos = 0 + challenge.transfer.data = "" + challenge.transfer.data.setLen FileChunkSize + challenge.sendChunk(client) + echo "starting xfer" + +## HFileTransfer +proc handleFilePartAck*(client: PClient; buffer: PBuffer) = + echo "got filepartack" + var + ftrans = readCsFilepartAck(buffer) + fcSeq = fileChallenges[client.id] + fcSeq.transfer.pos = ftrans.lastPos + fcSeq.sendChunk client + +## HFileCHallenge +proc handleFileChallengeResp*(client: PClient; buffer: PBuffer) = + echo "got file challenge resp" + var + fcResp = readCsFileChallenge(buffer) + fcSeq = fileChallenges[client.id] + let index = $(fcSeq.index + 1) / $(myAssets.len) + if fcResp.needFile: + client.sendMessage "Sending file... "&index + fcSeq.startSend(client) + else: + var resp = newScChallengeResult(false) + if fcResp.checksum == fcSeq.file.file.sum: ##client is good + client.sendMessage "Checksum is good. "&index + resp.status = true + client.send HChallengeResult, resp + fcSeq.next(client) + else: + client.sendMessage "Checksum is bad, sending file... "&index + client.send HChallengeResult, resp + fcSeq.startSend(client) + |