Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
3
Task/Chat-server/00-META.yaml
Normal file
3
Task/Chat-server/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Chat_server
|
||||
note: Networking and Web Interaction
|
||||
5
Task/Chat-server/00-TASK.txt
Normal file
5
Task/Chat-server/00-TASK.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
;Task:
|
||||
Write a server for a minimal text based chat.
|
||||
|
||||
People should be able to connect via ‘telnet’, sign on with a nickname, and type messages which will then be seen by all other connected users. Arrivals and departures of chat members should generate appropriate notification messages.
|
||||
<br><br>
|
||||
85
Task/Chat-server/Ada/chat-server.ada
Normal file
85
Task/Chat-server/Ada/chat-server.ada
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
with Ada.Containers.Vectors;
|
||||
with Ada.Command_Line; use Ada.Command_Line;
|
||||
with Ada.Exceptions; use Ada.Exceptions;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
|
||||
with Sockets; use Sockets;
|
||||
|
||||
procedure Chat_Server is
|
||||
|
||||
package Client_Vectors is new Ada.Containers.Vectors
|
||||
(Element_Type => Socket_FD, Index_Type => Positive);
|
||||
All_Clients : Client_Vectors.Vector;
|
||||
|
||||
procedure Write (S : String) is
|
||||
procedure Output (Position : Client_Vectors.Cursor) is
|
||||
Sock : Socket_FD := Client_Vectors.Element (Position);
|
||||
begin
|
||||
Put_Line (Sock, S);
|
||||
end Output;
|
||||
begin
|
||||
All_Clients.Iterate (Output'Access);
|
||||
end Write;
|
||||
|
||||
task type Client_Task is
|
||||
entry Start (FD : Socket_FD);
|
||||
end Client_Task;
|
||||
|
||||
task body Client_Task is
|
||||
Sock : Socket_FD;
|
||||
Sock_ID : Positive;
|
||||
Name : Unbounded_String;
|
||||
begin
|
||||
select
|
||||
accept Start (FD : Socket_FD) do
|
||||
Sock := FD;
|
||||
end Start;
|
||||
or
|
||||
terminate;
|
||||
end select;
|
||||
|
||||
while Name = Null_Unbounded_String loop
|
||||
Put (Sock, "Enter Name:");
|
||||
Name := To_Unbounded_String (Get_Line (Sock));
|
||||
end loop;
|
||||
Write (To_String (Name) & " joined.");
|
||||
All_Clients.Append (Sock);
|
||||
Sock_ID := All_Clients.Find_Index (Sock);
|
||||
loop
|
||||
declare
|
||||
Input : String := Get_Line (Sock);
|
||||
begin
|
||||
Write (To_String (Name) & ": " & Input);
|
||||
end;
|
||||
end loop;
|
||||
exception
|
||||
when Connection_Closed =>
|
||||
Put_Line ("Connection closed");
|
||||
Shutdown (Sock, Both);
|
||||
All_Clients.Delete (Sock_ID);
|
||||
Write (To_String (Name) & " left.");
|
||||
end Client_Task;
|
||||
|
||||
Accepting_Socket : Socket_FD;
|
||||
Incoming_Socket : Socket_FD;
|
||||
|
||||
type Client_Access is access Client_Task;
|
||||
Dummy : Client_Access;
|
||||
begin
|
||||
if Argument_Count /= 1 then
|
||||
Raise_Exception (Constraint_Error'Identity,
|
||||
"Usage: " & Command_Name & " port");
|
||||
end if;
|
||||
Socket (Accepting_Socket, PF_INET, SOCK_STREAM);
|
||||
Setsockopt (Accepting_Socket, SOL_SOCKET, SO_REUSEADDR, 1);
|
||||
Bind (Accepting_Socket, Positive'Value (Argument (1)));
|
||||
Listen (Accepting_Socket);
|
||||
loop
|
||||
Put_Line ("Waiting for new connection");
|
||||
Accept_Socket (Accepting_Socket, Incoming_Socket);
|
||||
Put_Line ("New connection acknowledged");
|
||||
|
||||
Dummy := new Client_Task;
|
||||
Dummy.Start (Incoming_Socket);
|
||||
end loop;
|
||||
end Chat_Server;
|
||||
35
Task/Chat-server/BaCon/chat-server.bacon
Normal file
35
Task/Chat-server/BaCon/chat-server.bacon
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
DECLARE user$ ASSOC STRING
|
||||
DECLARE connect ASSOC long
|
||||
OPEN "localhost:51000" FOR SERVER AS mynet
|
||||
WHILE TRUE
|
||||
IF WAIT(mynet, 30) THEN
|
||||
fd = ACCEPT(mynet)
|
||||
connect(GETPEER$(fd)) = fd
|
||||
SEND "Enter your name: " TO fd
|
||||
ELSE
|
||||
FOR con$ IN OBTAIN$(connect)
|
||||
IF WAIT(connect(con$), 10) THEN
|
||||
RECEIVE in$ FROM connect(con$)
|
||||
IF user$(GETPEER$(connect(con$))) = "" THEN
|
||||
user$(GETPEER$(connect(con$))) = CHOP$(in$)
|
||||
chat$ = chat$ & user$(GETPEER$(connect(con$))) & " joined the chat." & NL$
|
||||
SEND "Welcome, " & CHOP$(in$) & "!" & NL$ TO connect(con$)
|
||||
ELIF LEFT$(in$, 4) = "quit" THEN
|
||||
SEND "You're disconnected!" & NL$ TO connect(con$)
|
||||
chat$ = chat$ & user$(GETPEER$(connect(con$))) & " left the chat." & NL$
|
||||
FREE user$(GETPEER$(connect(con$)))
|
||||
FREE connect(con$)
|
||||
CLOSE SERVER connect(con$)
|
||||
ELIF LEFT$(in$, 4) = "say " THEN
|
||||
chat$ = chat$ & user$(GETPEER$(connect(con$))) & " said: " & MID$(in$, 5)
|
||||
ENDIF
|
||||
ENDIF
|
||||
NEXT
|
||||
IF LEN(chat$) > 0 THEN
|
||||
FOR con$ IN OBTAIN$(connect)
|
||||
IF user$(GETPEER$(connect(con$))) <> "" THEN SEND chat$ TO connect(con$)
|
||||
NEXT
|
||||
chat$ = ""
|
||||
ENDIF
|
||||
ENDIF
|
||||
WEND
|
||||
144
Task/Chat-server/C-sharp/chat-server.cs
Normal file
144
Task/Chat-server/C-sharp/chat-server.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace ChatServer {
|
||||
class State {
|
||||
private TcpClient client;
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public State(string name, TcpClient client) {
|
||||
Name = name;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public void Add(byte b) {
|
||||
sb.Append((char)b);
|
||||
}
|
||||
|
||||
public void Send(string text) {
|
||||
var bytes = Encoding.ASCII.GetBytes(string.Format("{0}\r\n", text));
|
||||
client.GetStream().Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
class Program {
|
||||
static TcpListener listen;
|
||||
static Thread serverthread;
|
||||
static Dictionary<int, State> connections = new Dictionary<int, State>();
|
||||
|
||||
static void Main(string[] args) {
|
||||
listen = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), 4004);
|
||||
serverthread = new Thread(new ThreadStart(DoListen));
|
||||
serverthread.Start();
|
||||
}
|
||||
|
||||
private static void DoListen() {
|
||||
// Listen
|
||||
listen.Start();
|
||||
Console.WriteLine("Server: Started server");
|
||||
|
||||
while (true) {
|
||||
Console.WriteLine("Server: Waiting...");
|
||||
TcpClient client = listen.AcceptTcpClient();
|
||||
Console.WriteLine("Server: Waited");
|
||||
|
||||
// New thread with client
|
||||
Thread clientThread = new Thread(new ParameterizedThreadStart(DoClient));
|
||||
clientThread.Start(client);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoClient(object client) {
|
||||
// Read data
|
||||
TcpClient tClient = (TcpClient)client;
|
||||
|
||||
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId);
|
||||
byte[] bytes = Encoding.ASCII.GetBytes("Enter name: ");
|
||||
tClient.GetStream().Write(bytes, 0, bytes.Length);
|
||||
|
||||
string name = string.Empty;
|
||||
bool done = false;
|
||||
do {
|
||||
if (!tClient.Connected) {
|
||||
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId);
|
||||
tClient.Close();
|
||||
Thread.CurrentThread.Abort(); // Kill thread.
|
||||
}
|
||||
|
||||
name = Receive(tClient);
|
||||
done = true;
|
||||
|
||||
if (done) {
|
||||
foreach (var cl in connections) {
|
||||
var state = cl.Value;
|
||||
if (state.Name == name) {
|
||||
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ");
|
||||
tClient.GetStream().Write(bytes, 0, bytes.Length);
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
connections.Add(Thread.CurrentThread.ManagedThreadId, new State(name, tClient));
|
||||
Console.WriteLine("\tTotal connections: {0}", connections.Count);
|
||||
Broadcast(string.Format("+++ {0} arrived +++", name));
|
||||
|
||||
do {
|
||||
string text = Receive(tClient);
|
||||
if (text == "/quit") {
|
||||
Broadcast(string.Format("Connection from {0} closed.", name));
|
||||
connections.Remove(Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("\tTotal connections: {0}", connections.Count);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!tClient.Connected) {
|
||||
break;
|
||||
}
|
||||
Broadcast(string.Format("{0}> {1}", name, text));
|
||||
} while (true);
|
||||
|
||||
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId);
|
||||
tClient.Close();
|
||||
Thread.CurrentThread.Abort();
|
||||
}
|
||||
|
||||
private static string Receive(TcpClient client) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
do {
|
||||
if (client.Available > 0) {
|
||||
while (client.Available > 0) {
|
||||
char ch = (char)client.GetStream().ReadByte();
|
||||
if (ch == '\r') {
|
||||
//ignore
|
||||
continue;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
return sb.ToString();
|
||||
}
|
||||
sb.Append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Pause
|
||||
Thread.Sleep(100);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
private static void Broadcast(string text) {
|
||||
Console.WriteLine(text);
|
||||
foreach (var oClient in connections) {
|
||||
if (oClient.Key != Thread.CurrentThread.ManagedThreadId) {
|
||||
State state = oClient.Value;
|
||||
state.Send(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
248
Task/Chat-server/C/chat-server.c
Normal file
248
Task/Chat-server/C/chat-server.c
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
|
||||
int tsocket;
|
||||
struct sockaddr_in tsockinfo;
|
||||
fd_set status, current;
|
||||
void ClientText(int handle, char *buf, int buf_len);
|
||||
|
||||
struct client
|
||||
{
|
||||
char buffer[4096];
|
||||
int pos;
|
||||
char name[32];
|
||||
} *connections[FD_SETSIZE];
|
||||
|
||||
void AddConnection(int handle)
|
||||
{
|
||||
connections[handle] = malloc(sizeof(struct client));
|
||||
connections[handle]->buffer[0] = '\0';
|
||||
connections[handle]->pos = 0;
|
||||
connections[handle]->name[0] = '\0';
|
||||
}
|
||||
|
||||
void CloseConnection(int handle)
|
||||
{
|
||||
char buf[512];
|
||||
int j;
|
||||
|
||||
FD_CLR(handle, &status);
|
||||
|
||||
if (connections[handle]->name[0])
|
||||
{
|
||||
sprintf(buf, "* Disconnected: %s\r\n", connections[handle]->name);
|
||||
|
||||
for (j = 0; j < FD_SETSIZE; j++)
|
||||
{
|
||||
if (handle != j && j != tsocket && FD_ISSET(j, &status))
|
||||
{
|
||||
if (write(j, buf, strlen(buf)) < 0)
|
||||
{
|
||||
CloseConnection(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
printf ("-- Connection %d disconnected\n", handle);
|
||||
}
|
||||
if (connections[handle])
|
||||
{
|
||||
free(connections[handle]);
|
||||
}
|
||||
close(handle);
|
||||
}
|
||||
|
||||
void strip(char *buf)
|
||||
{
|
||||
char *x;
|
||||
|
||||
x = strchr(buf, '\n');
|
||||
if (x) { *x='\0'; }
|
||||
x = strchr(buf, '\r');
|
||||
if (x) { *x='\0'; }
|
||||
}
|
||||
|
||||
int RelayText(int handle)
|
||||
{
|
||||
char *begin, *end;
|
||||
int ret = 0;
|
||||
begin = connections[handle]->buffer;
|
||||
if (connections[handle]->pos == 4000)
|
||||
{
|
||||
if (begin[3999] != '\n')
|
||||
begin[4000] = '\0';
|
||||
else {
|
||||
begin[4000] = '\n';
|
||||
begin[4001] = '\0';
|
||||
}
|
||||
} else {
|
||||
begin[connections[handle]->pos] = '\0';
|
||||
}
|
||||
|
||||
end = strchr(begin, '\n');
|
||||
while (end != NULL)
|
||||
{
|
||||
char output[8000];
|
||||
output[0] = '\0';
|
||||
if (!connections[handle]->name[0])
|
||||
{
|
||||
strncpy(connections[handle]->name, begin, 31);
|
||||
connections[handle]->name[31] = '\0';
|
||||
|
||||
strip(connections[handle]->name);
|
||||
sprintf(output, "* Connected: %s\r\n", connections[handle]->name);
|
||||
ret = 1;
|
||||
} else
|
||||
{
|
||||
sprintf(output, "%s: %.*s\r\n", connections[handle]->name,
|
||||
end-begin, begin);
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (output[0])
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < FD_SETSIZE; j++)
|
||||
{
|
||||
if (handle != j && j != tsocket && FD_ISSET(j, &status))
|
||||
{
|
||||
if (write(j, output, strlen(output)) < 0)
|
||||
{
|
||||
CloseConnection(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
begin = end+1;
|
||||
end = strchr(begin, '\n');
|
||||
}
|
||||
|
||||
strcpy(connections[handle]->buffer, begin);
|
||||
connections[handle]->pos -= begin - connections[handle]->buffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ClientText(int handle, char *buf, int buf_len)
|
||||
{
|
||||
int i, j;
|
||||
if (!connections[handle])
|
||||
return;
|
||||
j = connections[handle]->pos;
|
||||
|
||||
for (i = 0; i < buf_len; ++i, ++j)
|
||||
{
|
||||
connections[handle]->buffer[j] = buf[i];
|
||||
|
||||
if (j == 4000)
|
||||
{
|
||||
while (RelayText(handle));
|
||||
j = connections[handle]->pos;
|
||||
}
|
||||
}
|
||||
connections[handle]->pos = j;
|
||||
|
||||
while (RelayText(handle));
|
||||
}
|
||||
|
||||
|
||||
int ChatLoop()
|
||||
{
|
||||
int i, j;
|
||||
FD_ZERO(&status);
|
||||
|
||||
FD_SET(tsocket, &status);
|
||||
FD_SET(0, &status);
|
||||
|
||||
while(1)
|
||||
{
|
||||
current = status;
|
||||
if (select(FD_SETSIZE, ¤t, NULL, NULL, NULL)==-1)
|
||||
{
|
||||
perror("Select");
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < FD_SETSIZE; ++i)
|
||||
{
|
||||
if (FD_ISSET(i, ¤t))
|
||||
{
|
||||
if (i == tsocket)
|
||||
{
|
||||
struct sockaddr_in cliinfo;
|
||||
socklen_t addrlen = sizeof(cliinfo);
|
||||
int handle;
|
||||
handle = accept(tsocket, &cliinfo, &addrlen);
|
||||
if (handle == -1)
|
||||
{
|
||||
perror ("Couldn't accept connection");
|
||||
} else if (handle > FD_SETSIZE)
|
||||
{
|
||||
printf ("Unable to accept new connection.\n");
|
||||
close(handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (write(handle, "Enter name: ", 12) >= 0)
|
||||
{
|
||||
printf("-- New connection %d from %s:%hu\n",
|
||||
handle,
|
||||
inet_ntoa (cliinfo.sin_addr),
|
||||
ntohs(cliinfo.sin_port));
|
||||
FD_SET(handle, &status);
|
||||
|
||||
AddConnection(handle);
|
||||
}
|
||||
}
|
||||
} /* Read data, relay to others. */
|
||||
else
|
||||
{
|
||||
char buf[512];
|
||||
int b;
|
||||
|
||||
b = read(i, buf, 500);
|
||||
if (b <= 0)
|
||||
{
|
||||
CloseConnection(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientText(i, buf, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* While 1 */
|
||||
}
|
||||
|
||||
int main (int argc, char*argv[])
|
||||
{
|
||||
tsocket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
tsockinfo.sin_family = AF_INET;
|
||||
tsockinfo.sin_port = htons(7070);
|
||||
if (argc > 1)
|
||||
{
|
||||
tsockinfo.sin_port = htons(atoi(argv[1]));
|
||||
}
|
||||
tsockinfo.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
printf ("Socket %d on port %hu\n", tsocket, ntohs(tsockinfo.sin_port));
|
||||
|
||||
if (bind(tsocket, &tsockinfo, sizeof(tsockinfo)) == -1)
|
||||
{
|
||||
perror("Couldn't bind socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(tsocket, 10) == -1)
|
||||
{
|
||||
perror("Couldn't listen to port");
|
||||
}
|
||||
|
||||
ChatLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
107
Task/Chat-server/CoffeeScript/chat-server.coffee
Normal file
107
Task/Chat-server/CoffeeScript/chat-server.coffee
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
net = require("net")
|
||||
sys = require("sys")
|
||||
EventEmitter = require("events").EventEmitter
|
||||
|
||||
isNicknameLegal = (nickname) ->
|
||||
return false unless nickname.replace(/[A-Za-z0-9]*/, "") is ""
|
||||
for used_nick of @chatters
|
||||
return false if used_nick is nickname
|
||||
true
|
||||
|
||||
class ChatServer
|
||||
constructor: ->
|
||||
@chatters = {}
|
||||
@server = net.createServer @handleConnection
|
||||
@server.listen 1212, "localhost"
|
||||
|
||||
handleConnection: (connection) =>
|
||||
console.log "Incoming connection from " + connection.remoteAddress
|
||||
connection.setEncoding "utf8"
|
||||
chatter = new Chatter(connection, this)
|
||||
chatter.on "chat", @handleChat
|
||||
chatter.on "join", @handleJoin
|
||||
chatter.on "leave", @handleLeave
|
||||
|
||||
handleChat: (chatter, message) =>
|
||||
@sendToEveryChatterExcept chatter, chatter.nickname + ": " + message
|
||||
|
||||
handleJoin: (chatter) =>
|
||||
console.log chatter.nickname + " has joined the chat."
|
||||
@sendToEveryChatter chatter.nickname + " has joined the chat."
|
||||
@addChatter chatter
|
||||
|
||||
handleLeave: (chatter) =>
|
||||
console.log chatter.nickname + " has left the chat."
|
||||
@removeChatter chatter
|
||||
@sendToEveryChatter chatter.nickname + " has left the chat."
|
||||
|
||||
addChatter: (chatter) =>
|
||||
@chatters[chatter.nickname] = chatter
|
||||
|
||||
removeChatter: (chatter) =>
|
||||
delete @chatters[chatter.nickname]
|
||||
|
||||
sendToEveryChatter: (data) =>
|
||||
for nickname of @chatters
|
||||
@chatters[nickname].send data
|
||||
|
||||
sendToEveryChatterExcept: (chatter, data) =>
|
||||
for nickname of @chatters
|
||||
@chatters[nickname].send data unless nickname is chatter.nickname
|
||||
|
||||
|
||||
class Chatter extends EventEmitter
|
||||
constructor: (socket, server) ->
|
||||
EventEmitter.call this
|
||||
@socket = socket
|
||||
@server = server
|
||||
@nickname = ""
|
||||
@lineBuffer = new SocketLineBuffer(socket)
|
||||
@lineBuffer.on "line", @handleNickname
|
||||
@socket.on "close", @handleDisconnect
|
||||
@send "Welcome! What is your nickname?"
|
||||
|
||||
handleNickname: (nickname) =>
|
||||
if isNicknameLegal(nickname)
|
||||
@nickname = nickname
|
||||
@lineBuffer.removeAllListeners "line"
|
||||
@lineBuffer.on "line", @handleChat
|
||||
@send "Welcome to the chat, " + nickname + "!"
|
||||
@emit "join", this
|
||||
else
|
||||
@send "Sorry, but that nickname is not legal or is already in use!"
|
||||
@send "What is your nickname?"
|
||||
|
||||
handleChat: (line) =>
|
||||
@emit "chat", this, line
|
||||
|
||||
handleDisconnect: =>
|
||||
@emit "leave", this
|
||||
|
||||
send: (data) =>
|
||||
@socket.write data + "\r\n"
|
||||
|
||||
|
||||
class SocketLineBuffer extends EventEmitter
|
||||
constructor: (socket) ->
|
||||
EventEmitter.call this
|
||||
@socket = socket
|
||||
@buffer = ""
|
||||
@socket.on "data", @handleData
|
||||
|
||||
handleData: (data) =>
|
||||
console.log "Handling data", data
|
||||
i = 0
|
||||
|
||||
while i < data.length
|
||||
char = data.charAt(i)
|
||||
@buffer += char
|
||||
if char is "\n"
|
||||
@buffer = @buffer.replace("\r\n", "")
|
||||
@buffer = @buffer.replace("\n", "")
|
||||
@emit "line", @buffer
|
||||
console.log "incoming line: #{@buffer}"
|
||||
@buffer = ""
|
||||
i++
|
||||
|
||||
server = new ChatServer()
|
||||
175
Task/Chat-server/Common-Lisp/chat-server.lisp
Normal file
175
Task/Chat-server/Common-Lisp/chat-server.lisp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
(ql:quickload '(:usocket :simple-actors :bordeaux-threads))
|
||||
|
||||
(defpackage :chat-server
|
||||
(:use :common-lisp :usocket :simple-actors :bordeaux-threads)
|
||||
(:export :accept-connections))
|
||||
|
||||
(in-package :chat-server)
|
||||
|
||||
(defvar *whitespace* '(#\Space #\Tab #\Page #\Vt #\Newline #\Return))
|
||||
|
||||
(defun send-message (users from-user message)
|
||||
(loop for (nil . actor) in users
|
||||
do (send actor :message from-user message)))
|
||||
|
||||
(defun socket-format (socket format-control &rest format-arguments)
|
||||
(apply #'format (socket-stream socket) format-control format-arguments)
|
||||
(finish-output (socket-stream socket)))
|
||||
|
||||
(defvar *log* *standard-output*)
|
||||
|
||||
(defmacro log-errors (&body body)
|
||||
`(handler-case
|
||||
(progn ,@body)
|
||||
(t (err)
|
||||
(format *log* "Error: ~a" err))))
|
||||
|
||||
(defparameter *user-manager*
|
||||
(let ((users nil))
|
||||
(actor (action &rest args)
|
||||
(format *log* "Handling message ~s~%" (cons action args))
|
||||
(ecase action
|
||||
(:newuser
|
||||
(destructuring-bind (username session-actor)
|
||||
args
|
||||
(cond ((assoc username users :test #'equalp)
|
||||
(send session-actor :rejected
|
||||
(format nil "Username ~a is already taken. Send /NICK new-nick with a valid name to enter the chat~%" username)))
|
||||
((equalp username "Server")
|
||||
(send session-actor :rejected
|
||||
(format nil "Server is not a valid username. Send /NICK new-nick with a valid name to enter the chat~%")))
|
||||
(t (send-message users "Server" (format nil "~a has joined the chat." username))
|
||||
(send session-actor :accepted
|
||||
(format nil "Welcome to the Rosetta Code chat server in Common Lisp. ~a users connected.~%"
|
||||
(length users)))
|
||||
(pushnew (cons username session-actor)
|
||||
users
|
||||
:key #'car
|
||||
:test #'equalp)))))
|
||||
(:who
|
||||
(destructuring-bind (username) args
|
||||
(let ((actor (cdr (assoc username users :test #'equalp))))
|
||||
(send actor :message "Server"
|
||||
"Users connected right now:")
|
||||
(loop for (user . nil) in users
|
||||
do (send actor :message "Server" user)))))
|
||||
(:message
|
||||
(apply #'send-message users args))
|
||||
(:dropuser
|
||||
(destructuring-bind (username) args
|
||||
(let ((user-actor (cdr (assoc username users :test #'equalp))))
|
||||
(send user-actor :close)
|
||||
(send user-actor 'stop))
|
||||
(setf users (remove username users
|
||||
:key #'car
|
||||
:test #'equalp))
|
||||
(send-message users "Server" (format nil "~a has left." username))))))))
|
||||
|
||||
(defmacro drop-connection-on-error (&body body)
|
||||
`(handler-case (progn ,@body)
|
||||
(t (err)
|
||||
(format *log* "Error: ~a; Closing connection" err)
|
||||
(send self :close)
|
||||
(send self 'stop)
|
||||
(send *user-manager* :dropuser username))))
|
||||
|
||||
(defun parse-command (message)
|
||||
(let* ((space-at (position #\Space message))
|
||||
(after-space (and space-at
|
||||
(position-if (lambda (ch)
|
||||
(not (char= ch #\Space)))
|
||||
message :start (1+ space-at)))))
|
||||
(values (subseq message 0 space-at)
|
||||
(and after-space
|
||||
(string-trim *whitespace*
|
||||
(subseq message after-space))))))
|
||||
|
||||
(defun help (socket)
|
||||
(socket-format socket "/QUIT to quit, /WHO to list users.~%"))
|
||||
|
||||
(defun make-user (username socket)
|
||||
(let* ((state :unregistered)
|
||||
(actor
|
||||
(actor (message &rest args)
|
||||
(drop-connection-on-error
|
||||
(ecase message
|
||||
(:register
|
||||
(send *user-manager* :newuser username self))
|
||||
(:accepted
|
||||
(destructuring-bind (message) args
|
||||
(write-string message (socket-stream socket))
|
||||
(finish-output (socket-stream socket))
|
||||
(setf state :registered)))
|
||||
(:rejected
|
||||
(destructuring-bind (message) args
|
||||
(write-string message (socket-stream socket))
|
||||
(finish-output (socket-stream socket))
|
||||
(setf state :unregistered)))
|
||||
(:user-typed
|
||||
(destructuring-bind (message) args
|
||||
(when (> (length message) 0)
|
||||
(if (char= (aref message 0) #\/)
|
||||
(multiple-value-bind (cmd arg)
|
||||
(parse-command message)
|
||||
(cond ((equalp cmd "/nick")
|
||||
(ecase state
|
||||
(:unregistered
|
||||
(setf username arg)
|
||||
(send *user-manager* :newuser username self))
|
||||
(:registered
|
||||
(socket-format socket
|
||||
"Can't change your name after successfully registering~%"))))
|
||||
((equalp cmd "/help")
|
||||
(help socket))
|
||||
((equalp cmd "/who")
|
||||
(send *user-manager* :who username))
|
||||
((equalp cmd "/quit")
|
||||
(socket-format socket
|
||||
"Goodbye.~%")
|
||||
(send *user-manager* :dropuser username))
|
||||
(t
|
||||
(socket-format socket
|
||||
"Unknown command~%"))))
|
||||
(send *user-manager* :message username message)))))
|
||||
(:message
|
||||
(destructuring-bind (from-user message) args
|
||||
(socket-format socket "<~a> ~a~%" from-user message)))
|
||||
(:close
|
||||
(log-errors
|
||||
(close (socket-stream socket)))))))))
|
||||
(bt:make-thread (lambda ()
|
||||
(handler-case
|
||||
(loop for line = (read-line (socket-stream socket) nil :eof)
|
||||
do (if (eq line :eof)
|
||||
(send *user-manager* :dropuser username)
|
||||
(send actor :user-typed (remove #\Return line))))
|
||||
(t () (send *user-manager* :dropuser username))))
|
||||
|
||||
:name "Reader thread")
|
||||
actor))
|
||||
|
||||
|
||||
(defun initialize-user (socket)
|
||||
(bt:make-thread
|
||||
(lambda ()
|
||||
(format *log* "Handling new connection ~s" socket)
|
||||
(log-errors
|
||||
(loop do
|
||||
(socket-format socket "Your name: ")
|
||||
(let ((name (string-trim *whitespace* (read-line (socket-stream socket)))))
|
||||
(format *log* "Registering user ~a" name)
|
||||
(cond ((equalp name "Server")
|
||||
(socket-format socket
|
||||
"Server is not a valid username.~%"))
|
||||
(t (send *user-manager*
|
||||
:newuser name (make-user name socket))
|
||||
(return)))))))
|
||||
:name "INITIALIZE-USER"))
|
||||
|
||||
|
||||
(defun accept-connections ()
|
||||
(let ((accepting-socket (socket-listen "0.0.0.0" 7070)))
|
||||
(loop for new-connection = (socket-accept accepting-socket)
|
||||
do (initialize-user new-connection))))
|
||||
|
||||
(make-thread #'accept-connections)
|
||||
159
Task/Chat-server/D/chat-server.d
Normal file
159
Task/Chat-server/D/chat-server.d
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
import std.getopt;
|
||||
import std.socket;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
struct client {
|
||||
int pos;
|
||||
char[] name;
|
||||
char[] buffer;
|
||||
Socket socket;
|
||||
}
|
||||
|
||||
void broadcast(client[] connections, size_t self, const char[] message) {
|
||||
writeln(message);
|
||||
for (size_t i = 0; i < connections.length; i++) {
|
||||
if (i == self) continue;
|
||||
|
||||
connections[i].socket.send(message);
|
||||
connections[i].socket.send("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool registerClient(client[] connections, size_t self) {
|
||||
for (size_t i = 0; i < connections.length; i++) {
|
||||
if (i == self) continue;
|
||||
|
||||
if (icmp(connections[i].name, connections[self].name) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void main(string[] args) {
|
||||
ushort port = 4004;
|
||||
|
||||
auto helpInformation = getopt
|
||||
(
|
||||
args,
|
||||
"port|p", "The port to listen to chat clients on [default is 4004]", &port
|
||||
);
|
||||
|
||||
if (helpInformation.helpWanted) {
|
||||
defaultGetoptPrinter("A simple chat server based on a task in rosettacode.", helpInformation.options);
|
||||
return;
|
||||
}
|
||||
|
||||
auto listener = new TcpSocket();
|
||||
assert(listener.isAlive);
|
||||
listener.blocking = false;
|
||||
listener.bind(new InternetAddress(port));
|
||||
listener.listen(10);
|
||||
writeln("Listening on port: ", port);
|
||||
|
||||
enum MAX_CONNECTIONS = 60;
|
||||
auto socketSet = new SocketSet(MAX_CONNECTIONS + 1);
|
||||
client[] connections;
|
||||
|
||||
while(true) {
|
||||
socketSet.add(listener);
|
||||
|
||||
foreach (con; connections) {
|
||||
socketSet.add(con.socket);
|
||||
}
|
||||
|
||||
Socket.select(socketSet, null, null);
|
||||
|
||||
for (size_t i = 0; i < connections.length; i++) {
|
||||
if (socketSet.isSet(connections[i].socket)) {
|
||||
char[1024] buf;
|
||||
auto datLength = connections[i].socket.receive(buf[]);
|
||||
|
||||
if (datLength == Socket.ERROR) {
|
||||
writeln("Connection error.");
|
||||
} else if (datLength != 0) {
|
||||
if (buf[0] == '\n' || buf[0] == '\r') {
|
||||
if (connections[i].buffer == "/quit") {
|
||||
connections[i].socket.close();
|
||||
if (connections[i].name.length > 0) {
|
||||
writeln("Connection from ", connections[i].name, " closed.");
|
||||
} else {
|
||||
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
|
||||
}
|
||||
|
||||
connections[i] = connections[$-1];
|
||||
connections.length--;
|
||||
i--;
|
||||
|
||||
writeln("\tTotal connections: ", connections.length);
|
||||
continue;
|
||||
} else if (connections[i].name.length == 0) {
|
||||
connections[i].buffer = strip(connections[i].buffer);
|
||||
if (connections[i].buffer.length > 0) {
|
||||
connections[i].name = connections[i].buffer;
|
||||
if (registerClient(connections, i)) {
|
||||
connections.broadcast(i, "+++ " ~ connections[i].name ~ " arrived +++");
|
||||
} else {
|
||||
connections[i].socket.send("Name already registered. Please enter your name: ");
|
||||
connections[i].name.length = 0;
|
||||
}
|
||||
} else {
|
||||
connections[i].socket.send("A name is required. Please enter your name: ");
|
||||
}
|
||||
} else {
|
||||
connections.broadcast(i, connections[i].name ~ "> " ~ connections[i].buffer);
|
||||
}
|
||||
connections[i].buffer.length = 0;
|
||||
} else {
|
||||
connections[i].buffer ~= buf[0..datLength];
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (connections[i].name.length > 0) {
|
||||
writeln("Connection from ", connections[i].name, " closed.");
|
||||
} else {
|
||||
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
|
||||
}
|
||||
} catch (SocketException) {
|
||||
writeln("Connection closed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (socketSet.isSet(listener)) {
|
||||
Socket sn = null;
|
||||
scope(failure) {
|
||||
writeln("Error accepting");
|
||||
|
||||
if (sn) {
|
||||
sn.close();
|
||||
}
|
||||
}
|
||||
sn = listener.accept();
|
||||
assert(sn.isAlive);
|
||||
assert(listener.isAlive);
|
||||
|
||||
if (connections.length < MAX_CONNECTIONS) {
|
||||
client newclient;
|
||||
|
||||
writeln("Connection from ", sn.remoteAddress(), " established.");
|
||||
sn.send("Enter name: ");
|
||||
|
||||
newclient.socket = sn;
|
||||
connections ~= newclient;
|
||||
|
||||
writeln("\tTotal connections: ", connections.length);
|
||||
} else {
|
||||
writeln("Rejected connection from ", sn.remoteAddress(), "; too many connections.");
|
||||
sn.close();
|
||||
assert(!sn.isAlive);
|
||||
assert(listener.isAlive);
|
||||
}
|
||||
}
|
||||
|
||||
socketSet.reset();
|
||||
}
|
||||
}
|
||||
63
Task/Chat-server/Erlang/chat-server.erl
Normal file
63
Task/Chat-server/Erlang/chat-server.erl
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
-module(chat).
|
||||
|
||||
-export([start/0, start/1]).
|
||||
|
||||
-record(client, {name=none, socket=none}).
|
||||
|
||||
start() -> start(8080).
|
||||
start(Port) ->
|
||||
register(server, spawn(fun() -> server() end)),
|
||||
{ok, LSocket} = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]),
|
||||
accept(LSocket).
|
||||
|
||||
% main loop for message dispatcher
|
||||
server() -> server([]).
|
||||
server(Clients) ->
|
||||
receive
|
||||
{join, Client=#client{name = Name, socket = Socket}} ->
|
||||
self() ! {say, Socket, "has joined." ++ [10, 13]},
|
||||
server(Clients ++ [Client]);
|
||||
{leave, Socket} ->
|
||||
{value, #client{name = Name}, List} = lists:keytake(Socket, 3, Clients),
|
||||
self() ! {say, none, Message = "has left."},
|
||||
server(List);
|
||||
{say, Socket, Data} ->
|
||||
{value, #client{name = From}, List} = lists:keytake(Socket, 3, Clients),
|
||||
Message = From ++ " : " ++ Data,
|
||||
lists:map(fun(#client{socket = S}) ->
|
||||
gen_tcp:send(S, Message)
|
||||
end, List)
|
||||
end,
|
||||
server(Clients).
|
||||
|
||||
% accepts connections then spawns the client handler
|
||||
accept(LSocket) ->
|
||||
{ok, Socket} = gen_tcp:accept(LSocket),
|
||||
spawn(fun() -> connecting(Socket) end),
|
||||
accept(LSocket).
|
||||
|
||||
% when client is first connect send prompt for user name
|
||||
connecting(Socket) ->
|
||||
gen_tcp:send(Socket, "What is your name? "),
|
||||
case listen(Socket) of
|
||||
{ok, N} ->
|
||||
Name = binary_to_list(N),
|
||||
server ! {join, #client{name = lists:sublist(Name, 1, length(Name) - 2), socket = Socket} },
|
||||
client(Socket);
|
||||
_ -> ok
|
||||
end.
|
||||
|
||||
% main client loop that listens for data
|
||||
client(Socket) ->
|
||||
case listen(Socket) of
|
||||
{ok, Data} ->
|
||||
server ! {say, Socket, binary_to_list(Data)},
|
||||
client(Socket);
|
||||
_ -> server ! {leave, Socket}
|
||||
end.
|
||||
|
||||
% utility function that listens for data on a socket
|
||||
listen(Socket) ->
|
||||
case gen_tcp:recv(Socket, 0) of
|
||||
Response -> Response
|
||||
end.
|
||||
182
Task/Chat-server/Go/chat-server.go
Normal file
182
Task/Chat-server/Go/chat-server.go
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetPrefix("chat: ")
|
||||
addr := flag.String("addr", "localhost:4000", "listen address")
|
||||
flag.Parse()
|
||||
log.Fatal(ListenAndServe(*addr))
|
||||
}
|
||||
|
||||
// A Server represents a chat server that accepts incoming connections.
|
||||
type Server struct {
|
||||
add chan *conn // To add a connection
|
||||
rem chan string // To remove a connection by name
|
||||
msg chan string // To send a message to all connections
|
||||
stop chan bool // To stop early
|
||||
}
|
||||
|
||||
// ListenAndServe listens on the TCP network address addr for
|
||||
// new chat client connections.
|
||||
func ListenAndServe(addr string) error {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Println("Listening for connections on", addr)
|
||||
defer ln.Close()
|
||||
s := &Server{
|
||||
add: make(chan *conn),
|
||||
rem: make(chan string),
|
||||
msg: make(chan string),
|
||||
stop: make(chan bool),
|
||||
}
|
||||
go s.handleConns()
|
||||
for {
|
||||
// TODO use AcceptTCP() so that we can get a TCPConn on which
|
||||
// we can call SetKeepAlive() and SetKeepAlivePeriod()
|
||||
rwc, err := ln.Accept()
|
||||
if err != nil {
|
||||
// TODO Could handle err.(net.Error).Temporary()
|
||||
// here by adding a backoff delay.
|
||||
close(s.stop)
|
||||
return err
|
||||
}
|
||||
log.Println("New connection from", rwc.RemoteAddr())
|
||||
go newConn(s, rwc).welcome()
|
||||
}
|
||||
}
|
||||
|
||||
// handleConns is run as a go routine to handle adding and removal of
|
||||
// chat client connections as well as broadcasting messages to them.
|
||||
func (s *Server) handleConns() {
|
||||
// We define the `conns` map here rather than within Server,
|
||||
// and we use local function literals rather than methods to be
|
||||
// extra sure that the only place that touches this map is this
|
||||
// method. In this way we forgo any explicit locking needed as
|
||||
// we're the only go routine that can see or modify this.
|
||||
conns := make(map[string]*conn)
|
||||
|
||||
var dropConn func(string)
|
||||
writeAll := func(str string) {
|
||||
log.Printf("Broadcast: %q", str)
|
||||
// TODO handle blocked connections
|
||||
for name, c := range conns {
|
||||
c.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
_, err := c.Write([]byte(str))
|
||||
if err != nil {
|
||||
log.Printf("Error writing to %q: %v", name, err)
|
||||
c.Close()
|
||||
delete(conns, name)
|
||||
// Defer all the disconnect messages until after
|
||||
// we've closed all currently problematic conns.
|
||||
defer dropConn(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dropConn = func(name string) {
|
||||
if c, ok := conns[name]; ok {
|
||||
log.Printf("Closing connection with %q from %v",
|
||||
name, c.RemoteAddr())
|
||||
c.Close()
|
||||
delete(conns, name)
|
||||
} else {
|
||||
log.Printf("Dropped connection with %q", name)
|
||||
}
|
||||
str := fmt.Sprintf("--- %q disconnected ---\n", name)
|
||||
writeAll(str)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
writeAll("Server stopping!\n")
|
||||
for _, c := range conns {
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case c := <-s.add:
|
||||
if _, exists := conns[c.name]; exists {
|
||||
fmt.Fprintf(c, "Name %q is not available\n", c.name)
|
||||
go c.welcome()
|
||||
continue
|
||||
}
|
||||
str := fmt.Sprintf("+++ %q connected +++\n", c.name)
|
||||
writeAll(str)
|
||||
conns[c.name] = c
|
||||
go c.readloop()
|
||||
case str := <-s.msg:
|
||||
writeAll(str)
|
||||
case name := <-s.rem:
|
||||
dropConn(name)
|
||||
case <-s.stop:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A conn represents the server side of a single chat connection.
|
||||
// Note we embed the bufio.Reader and net.Conn (and specifically in
|
||||
// that order) so that a conn gets the appropriate methods from each
|
||||
// to be a full io.ReadWriteCloser.
|
||||
type conn struct {
|
||||
*bufio.Reader // buffered input
|
||||
net.Conn // raw connection
|
||||
server *Server // the Server on which the connection arrived
|
||||
name string
|
||||
}
|
||||
|
||||
func newConn(s *Server, rwc net.Conn) *conn {
|
||||
return &conn{
|
||||
Reader: bufio.NewReader(rwc),
|
||||
Conn: rwc,
|
||||
server: s,
|
||||
}
|
||||
}
|
||||
|
||||
// welcome requests a name from the client before attempting to add the
|
||||
// named connect to the set handled by the server.
|
||||
func (c *conn) welcome() {
|
||||
var err error
|
||||
for c.name = ""; c.name == ""; {
|
||||
fmt.Fprint(c, "Enter your name: ")
|
||||
c.name, err = c.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Printf("Reading name from %v: %v", c.RemoteAddr(), err)
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
c.name = strings.TrimSpace(c.name)
|
||||
}
|
||||
// The server will take this *conn and do a final check
|
||||
// on the name, possibly starting c.welcome() again.
|
||||
c.server.add <- c
|
||||
}
|
||||
|
||||
// readloop is started as a go routine by the server once the initial
|
||||
// welcome phase has completed successfully. It reads single lines from
|
||||
// the client and passes them to the server for broadcast to all chat
|
||||
// clients (including us).
|
||||
// Once done, we ask the server to remove (and close) our connection.
|
||||
func (c *conn) readloop() {
|
||||
for {
|
||||
msg, err := c.ReadString('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
//msg = strings.TrimSpace(msg)
|
||||
c.server.msg <- c.name + "> " + msg
|
||||
}
|
||||
c.server.rem <- c.name
|
||||
}
|
||||
156
Task/Chat-server/Groovy/chat-server.groovy
Normal file
156
Task/Chat-server/Groovy/chat-server.groovy
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
class ChatServer implements Runnable {
|
||||
private int port = 0
|
||||
private List<Client> clientList = new ArrayList<>()
|
||||
|
||||
ChatServer(int port) {
|
||||
this.port = port
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyInfiniteLoopStatement")
|
||||
@Override
|
||||
void run() {
|
||||
try {
|
||||
ServerSocket serverSocket = new ServerSocket(port)
|
||||
while (true) {
|
||||
Socket socket = serverSocket.accept()
|
||||
new Thread(new Client(socket)).start()
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean registerClient(Client client) {
|
||||
for (Client other : clientList) {
|
||||
if (other.clientName.equalsIgnoreCase(client.clientName)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
clientList.add(client)
|
||||
return true
|
||||
}
|
||||
|
||||
private void deRegisterClient(Client client) {
|
||||
boolean wasRegistered
|
||||
synchronized (this) {
|
||||
wasRegistered = clientList.remove(client)
|
||||
}
|
||||
if (wasRegistered) {
|
||||
broadcast(client, "--- " + client.clientName + " left ---")
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized String getOnlineListCSV() {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
sb.append(clientList.size()).append(" user(s) online: ")
|
||||
def it = clientList.iterator()
|
||||
if (it.hasNext()) {
|
||||
sb.append(it.next().clientName)
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
sb.append(", ")
|
||||
sb.append(it.next().clientName)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private void broadcast(Client fromClient, String msg) {
|
||||
// Copy client list (don't want to hold lock while doing IO)
|
||||
List<Client> clients
|
||||
synchronized (this) {
|
||||
clients = new ArrayList<>(this.clientList)
|
||||
}
|
||||
for (Client client : clients) {
|
||||
if (client == fromClient) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
client.write(msg + "\r\n")
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Client implements Runnable {
|
||||
private Socket socket = null
|
||||
private Writer output = null
|
||||
private String clientName = null
|
||||
|
||||
Client(Socket socket) {
|
||||
this.socket = socket
|
||||
}
|
||||
|
||||
@Override
|
||||
void run() {
|
||||
try {
|
||||
socket.setSendBufferSize(16384)
|
||||
socket.setTcpNoDelay(true)
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))
|
||||
output = new OutputStreamWriter(socket.getOutputStream())
|
||||
write("Please enter your name: ")
|
||||
String line
|
||||
while (null != (line = input.readLine())) {
|
||||
if (null == clientName) {
|
||||
line = line.trim()
|
||||
if (line.isEmpty()) {
|
||||
write("A name is required. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
clientName = line
|
||||
if (!registerClient(this)) {
|
||||
clientName = null
|
||||
write("Name already registered. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
write(getOnlineListCSV() + "\r\n")
|
||||
broadcast(this, "+++ " + clientName + " arrived +++")
|
||||
continue
|
||||
}
|
||||
if (line.equalsIgnoreCase("/quit")) {
|
||||
return
|
||||
}
|
||||
broadcast(this, clientName + "> " + line)
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
} finally {
|
||||
deRegisterClient(this)
|
||||
output = null
|
||||
try {
|
||||
socket.close()
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
}
|
||||
socket = null
|
||||
}
|
||||
}
|
||||
|
||||
void write(String msg) {
|
||||
output.write(msg)
|
||||
output.flush()
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean equals(client) {
|
||||
return (null != client) && (client instanceof Client) && (null != clientName) && clientName == client.clientName
|
||||
}
|
||||
|
||||
@Override
|
||||
int hashCode() {
|
||||
int result
|
||||
result = (socket != null ? socket.hashCode() : 0)
|
||||
result = 31 * result + (output != null ? output.hashCode() : 0)
|
||||
result = 31 * result + (clientName != null ? clientName.hashCode() : 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
static void main(String[] args) {
|
||||
int port = 4004
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0])
|
||||
}
|
||||
new ChatServer(port).run()
|
||||
}
|
||||
}
|
||||
84
Task/Chat-server/Haskell/chat-server-1.hs
Normal file
84
Task/Chat-server/Haskell/chat-server-1.hs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
import Network
|
||||
import System.IO
|
||||
import Control.Concurrent
|
||||
import qualified Data.Text as T
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text.IO as T
|
||||
import qualified Data.Map as M
|
||||
import Data.Map (Map)
|
||||
import Control.Monad.Reader
|
||||
import Control.Monad.Error
|
||||
import Control.Exception
|
||||
import Data.Monoid
|
||||
import Control.Applicative
|
||||
|
||||
type ServerApp = ReaderT ThreadData IO
|
||||
data Speaker = Server | Client Text
|
||||
data ThreadData = ThreadData { threadHandle :: Handle
|
||||
, userTableMV :: MVar (Map Text Handle)}
|
||||
|
||||
echoLocal = liftIO . T.putStrLn
|
||||
echoRemote = echoMessage . (">> "<>)
|
||||
echoMessage msg = viewHandle >>= \h -> liftIO $ T.hPutStrLn h msg
|
||||
getRemoteLine = viewHandle >>= liftIO . T.hGetLine
|
||||
putMVarT = (liftIO.) . putMVar
|
||||
takeMVarT = liftIO . takeMVar
|
||||
readMVarT = liftIO . readMVar
|
||||
modifyUserTable fn = viewUsers >>= \mv ->
|
||||
liftIO $ modifyMVar_ mv (return . fn)
|
||||
viewHandle = threadHandle <$> ask
|
||||
viewUsers = userTableMV <$> ask
|
||||
|
||||
userChat :: ServerApp ()
|
||||
userChat = do
|
||||
name <- addUser
|
||||
echoLocal name
|
||||
h <- viewHandle
|
||||
(flip catchError) (\_ -> removeUser name) $
|
||||
do echoLocal $ "Accepted " <> name
|
||||
forever $ getRemoteLine >>= broadcast (Client name)
|
||||
|
||||
removeUser :: Text -> ServerApp ()
|
||||
removeUser name = do
|
||||
echoLocal $ "Exception with " <> name <> ", removing from userTable"
|
||||
broadcast Server $ name <> " has left the server"
|
||||
modifyUserTable (M.delete name)
|
||||
|
||||
addUser :: ServerApp Text
|
||||
addUser = do
|
||||
h <- viewHandle
|
||||
usersMV <- viewUsers
|
||||
echoRemote "Enter username"
|
||||
name <- T.filter (/='\r') <$> getRemoteLine
|
||||
userTable <- takeMVarT usersMV
|
||||
if name `M.member` userTable
|
||||
then do echoRemote "Username already exists!"
|
||||
putMVarT usersMV userTable
|
||||
addUser
|
||||
else do putMVarT usersMV (M.insert name h userTable)
|
||||
broadcast Server $ name <> " has joined the server"
|
||||
echoRemote "Welcome to the server!\n>> Other users:"
|
||||
readMVarT usersMV >>=
|
||||
mapM_ (echoRemote . ("*" <>) . fst)
|
||||
. filter ((/=name). fst) . M.toList
|
||||
return name
|
||||
|
||||
broadcast :: Speaker -> Text -> ServerApp ()
|
||||
broadcast user msg =
|
||||
viewUsers >>= readMVarT >>= mapM_ (f . snd) . fn . M.toList
|
||||
where f h = liftIO $ T.hPutStrLn h $ nm <> msg
|
||||
(fn, nm) = case user of
|
||||
Server -> (id, ">> ")
|
||||
Client t -> (filter ((/=t) . fst), t <> "> ")
|
||||
|
||||
clientLoop socket users = do
|
||||
(h, _, _) <- accept socket
|
||||
hSetBuffering h LineBuffering
|
||||
forkIO $ runReaderT userChat (ThreadData h users)
|
||||
clientLoop socket users
|
||||
|
||||
main = do
|
||||
server <- listenOn $ PortNumber 5002
|
||||
T.putStrLn "Server started"
|
||||
newMVar (M.empty) >>= clientLoop server
|
||||
27
Task/Chat-server/Haskell/chat-server-2.hs
Normal file
27
Task/Chat-server/Haskell/chat-server-2.hs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
global mlck, nCons, cons
|
||||
|
||||
procedure main()
|
||||
mlck := mutex()
|
||||
nCons := 0
|
||||
cons := mutex(set())
|
||||
while f := open(":12321","na") do {
|
||||
handle_client(f)
|
||||
critical mlck: if nCons <= 0 then close(f)
|
||||
}
|
||||
end
|
||||
|
||||
procedure handle_client(f)
|
||||
critical mlck: nCons +:= 1
|
||||
thread {
|
||||
select(f,1000) & {
|
||||
writes(f, "Name? ")
|
||||
nick := (read(f) ? tab(upto('\n\r')))
|
||||
every write(!cons, nick," has joined.")
|
||||
insert(cons, f)
|
||||
while s := read(f) do every write(!cons, nick,": ",s)
|
||||
}
|
||||
delete(cons, f)
|
||||
every write(!cons, nick," has left.")
|
||||
critical mlck: nCons -:= 1
|
||||
}
|
||||
end
|
||||
152
Task/Chat-server/Java/chat-server.java
Normal file
152
Task/Chat-server/Java/chat-server.java
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
public class ChatServer implements Runnable
|
||||
{
|
||||
private int port = 0;
|
||||
private List<Client> clients = new ArrayList<Client>();
|
||||
|
||||
public ChatServer(int port)
|
||||
{ this.port = port; }
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
ServerSocket ss = new ServerSocket(port);
|
||||
while (true)
|
||||
{
|
||||
Socket s = ss.accept();
|
||||
new Thread(new Client(s)).start();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{ e.printStackTrace(); }
|
||||
}
|
||||
|
||||
private synchronized boolean registerClient(Client client)
|
||||
{
|
||||
for (Client otherClient : clients)
|
||||
if (otherClient.clientName.equalsIgnoreCase(client.clientName))
|
||||
return false;
|
||||
clients.add(client);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void deregisterClient(Client client)
|
||||
{
|
||||
boolean wasRegistered = false;
|
||||
synchronized (this)
|
||||
{ wasRegistered = clients.remove(client); }
|
||||
if (wasRegistered)
|
||||
broadcast(client, "--- " + client.clientName + " left ---");
|
||||
}
|
||||
|
||||
private synchronized String getOnlineListCSV()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(clients.size()).append(" user(s) online: ");
|
||||
for (int i = 0; i < clients.size(); i++)
|
||||
sb.append((i > 0) ? ", " : "").append(clients.get(i).clientName);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void broadcast(Client fromClient, String msg)
|
||||
{
|
||||
// Copy client list (don't want to hold lock while doing IO)
|
||||
List<Client> clients = null;
|
||||
synchronized (this)
|
||||
{ clients = new ArrayList<Client>(this.clients); }
|
||||
for (Client client : clients)
|
||||
{
|
||||
if (client.equals(fromClient))
|
||||
continue;
|
||||
try
|
||||
{ client.write(msg + "\r\n"); }
|
||||
catch (Exception e)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public class Client implements Runnable
|
||||
{
|
||||
private Socket socket = null;
|
||||
private Writer output = null;
|
||||
private String clientName = null;
|
||||
|
||||
public Client(Socket socket)
|
||||
{
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.setSendBufferSize(16384);
|
||||
socket.setTcpNoDelay(true);
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||
output = new OutputStreamWriter(socket.getOutputStream());
|
||||
write("Please enter your name: ");
|
||||
String line = null;
|
||||
while ((line = input.readLine()) != null)
|
||||
{
|
||||
if (clientName == null)
|
||||
{
|
||||
line = line.trim();
|
||||
if (line.isEmpty())
|
||||
{
|
||||
write("A name is required. Please enter your name: ");
|
||||
continue;
|
||||
}
|
||||
clientName = line;
|
||||
if (!registerClient(this))
|
||||
{
|
||||
clientName = null;
|
||||
write("Name already registered. Please enter your name: ");
|
||||
continue;
|
||||
}
|
||||
write(getOnlineListCSV() + "\r\n");
|
||||
broadcast(this, "+++ " + clientName + " arrived +++");
|
||||
continue;
|
||||
}
|
||||
if (line.equalsIgnoreCase("/quit"))
|
||||
return;
|
||||
broadcast(this, clientName + "> " + line);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{ }
|
||||
finally
|
||||
{
|
||||
deregisterClient(this);
|
||||
output = null;
|
||||
try
|
||||
{ socket.close(); }
|
||||
catch (Exception e)
|
||||
{ }
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void write(String msg) throws IOException
|
||||
{
|
||||
output.write(msg);
|
||||
output.flush();
|
||||
}
|
||||
|
||||
public boolean equals(Client client)
|
||||
{
|
||||
return (client != null) && (client instanceof Client) && (clientName != null) && (client.clientName != null) && clientName.equals(client.clientName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
int port = 4004;
|
||||
if (args.length > 0)
|
||||
port = Integer.parseInt(args[0]);
|
||||
new ChatServer(port).run();
|
||||
}
|
||||
}
|
||||
148
Task/Chat-server/JavaScript/chat-server.js
Normal file
148
Task/Chat-server/JavaScript/chat-server.js
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
const net = require("net");
|
||||
const EventEmitter = require("events").EventEmitter;
|
||||
|
||||
/*******************************************************************************
|
||||
* ChatServer
|
||||
*
|
||||
* Manages connections, users, and chat messages.
|
||||
******************************************************************************/
|
||||
|
||||
class ChatServer {
|
||||
constructor() {
|
||||
this.chatters = {};
|
||||
this.server = net.createServer(this.handleConnection.bind(this));
|
||||
this.server.listen(1212, "localhost");
|
||||
}
|
||||
isNicknameLegal(nickname) {
|
||||
// A nickname may contain letters or numbers only,
|
||||
// and may only be used once.
|
||||
if (nickname.replace(/[A-Za-z0-9]*/, '') !== "") {
|
||||
return false;
|
||||
}
|
||||
for (const used_nick in this.chatters) {
|
||||
if (used_nick === nickname) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
handleConnection(connection) {
|
||||
console.log(`Incoming connection from ${connection.remoteAddress}`);
|
||||
connection.setEncoding("utf8");
|
||||
|
||||
let chatter = new Chatter(connection, this);
|
||||
chatter.on("chat", this.handleChat.bind(this));
|
||||
chatter.on("join", this.handleJoin.bind(this));
|
||||
chatter.on("leave", this.handleLeave.bind(this));
|
||||
}
|
||||
handleChat(chatter, message) {
|
||||
this.sendToEveryChatterExcept(chatter, chatter.nickname + ": " + message);
|
||||
}
|
||||
handleJoin(chatter) {
|
||||
console.log(`${chatter.nickname} has joined the chat.`);
|
||||
this.sendToEveryChatter(`${chatter.nickname} has joined the chat.`);
|
||||
this.addChatter(chatter);
|
||||
}
|
||||
handleLeave(chatter) {
|
||||
console.log(`${chatter.nickname} has left the chat.`);
|
||||
this.removeChatter(chatter);
|
||||
this.sendToEveryChatter(`${chatter.nickname} has left the chat.`);
|
||||
}
|
||||
addChatter(chatter) {
|
||||
this.chatters[chatter.nickname] = chatter;
|
||||
}
|
||||
removeChatter(chatter) {
|
||||
delete this.chatters[chatter.nickname];
|
||||
}
|
||||
sendToEveryChatter(data) {
|
||||
for (const nickname in this.chatters) {
|
||||
this.chatters[nickname].send(data);
|
||||
}
|
||||
}
|
||||
sendToEveryChatterExcept(chatter, data) {
|
||||
for (const nickname in this.chatters) {
|
||||
if (nickname !== chatter.nickname) {
|
||||
this.chatters[nickname].send(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Chatter
|
||||
*
|
||||
* Represents a single user/connection in the chat server.
|
||||
******************************************************************************/
|
||||
|
||||
class Chatter extends EventEmitter {
|
||||
constructor(socket, server) {
|
||||
super();
|
||||
|
||||
this.socket = socket;
|
||||
this.server = server;
|
||||
this.nickname = "";
|
||||
this.lineBuffer = new SocketLineBuffer(socket);
|
||||
|
||||
this.lineBuffer.on("line", this.handleNickname.bind(this));
|
||||
this.socket.on("close", this.handleDisconnect.bind(this));
|
||||
|
||||
this.send("Welcome! What is your nickname?");
|
||||
}
|
||||
handleNickname(nickname) {
|
||||
if (server.isNicknameLegal(nickname)) {
|
||||
this.nickname = nickname;
|
||||
this.lineBuffer.removeAllListeners("line");
|
||||
this.lineBuffer.on("line", this.handleChat.bind(this));
|
||||
this.send(`Welcome to the chat, ${nickname}!`);
|
||||
this.emit("join", this);
|
||||
} else {
|
||||
this.send("Sorry, but that nickname is not legal or is already in use!");
|
||||
this.send("What is your nickname?");
|
||||
}
|
||||
}
|
||||
handleChat(line) {
|
||||
this.emit("chat", this, line);
|
||||
}
|
||||
handleDisconnect() {
|
||||
this.emit("leave", this);
|
||||
}
|
||||
send(data) {
|
||||
this.socket.write(data + "\r\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* SocketLineBuffer
|
||||
*
|
||||
* Listens for and buffers incoming data on a socket and emits a 'line' event
|
||||
* whenever a complete line is detected.
|
||||
******************************************************************************/
|
||||
|
||||
class SocketLineBuffer extends EventEmitter {
|
||||
constructor(socket) {
|
||||
super();
|
||||
|
||||
this.socket = socket;
|
||||
this.buffer = "";
|
||||
|
||||
this.socket.on("data", this.handleData.bind(this));
|
||||
}
|
||||
handleData(data) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const char = data.charAt(i);
|
||||
this.buffer += char;
|
||||
if (char == "\n") {
|
||||
this.buffer = this.buffer.replace("\r\n", "");
|
||||
this.buffer = this.buffer.replace("\n", "");
|
||||
this.emit("line", this.buffer);
|
||||
this.buffer = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Start the server!
|
||||
server = new ChatServer();
|
||||
82
Task/Chat-server/Julia/chat-server.julia
Normal file
82
Task/Chat-server/Julia/chat-server.julia
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
using HttpServer
|
||||
using WebSockets
|
||||
|
||||
const connections = Dict{Int,WebSocket}()
|
||||
const usernames = Dict{Int,String}()
|
||||
|
||||
function decodeMessage( msg )
|
||||
String(copy(msg))
|
||||
end
|
||||
|
||||
|
||||
wsh = WebSocketHandler() do req, client
|
||||
global connections
|
||||
@show connections[client.id] = client
|
||||
println("req is $req")
|
||||
notifyonline = "Connection from user number $(client.id) is now online."
|
||||
for (k,v) in connections
|
||||
if k != client.id
|
||||
try
|
||||
write(v, notifyonline)
|
||||
catch
|
||||
continue
|
||||
end
|
||||
end
|
||||
end
|
||||
while true
|
||||
try
|
||||
msg = read(client)
|
||||
catch
|
||||
telloffline = "User $(usernames[client.id]) disconnected."
|
||||
println(telloffline, "(The client id was $(client.id).)")
|
||||
delete!(connections, client.id)
|
||||
if haskey(usernames, client.id)
|
||||
delete!(usernames, client.id)
|
||||
end
|
||||
for (k,v) in connections
|
||||
try
|
||||
write(v, telloffline)
|
||||
catch
|
||||
continue
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
msg = decodeMessage(msg)
|
||||
if startswith(msg, "setusername:")
|
||||
println("SETTING USERNAME: $msg")
|
||||
usernames[client.id] = msg[13:end]
|
||||
notifyusername = "User number $(client.id) chose $(usernames[client.id]) as name handle."
|
||||
for (k,v) in connections
|
||||
try
|
||||
write(v, notifyusername)
|
||||
catch
|
||||
println("Caught exception writing to user $k")
|
||||
continue
|
||||
end
|
||||
end
|
||||
end
|
||||
if startswith(msg, "say:")
|
||||
println("EMITTING MESSAGE: $msg")
|
||||
for (k,v) in connections
|
||||
if k != client.id
|
||||
try
|
||||
write(v, (usernames[client.id] * ": " * msg[5:end]))
|
||||
catch
|
||||
println("Caught exception writing to user $k")
|
||||
continue
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
onepage = readstring(Pkg.dir("WebSockets","examples","chat-client.html"))
|
||||
httph = HttpHandler() do req::Request, res::Response
|
||||
Response(onepage)
|
||||
end
|
||||
|
||||
server = Server(httph, wsh)
|
||||
println("Chat server listening on 8000...")
|
||||
run(server,8000)
|
||||
153
Task/Chat-server/Kotlin/chat-server.kotlin
Normal file
153
Task/Chat-server/Kotlin/chat-server.kotlin
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.io.Writer
|
||||
import java.net.ServerSocket
|
||||
import java.net.Socket
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
class ChatServer private constructor(private val port: Int) : Runnable {
|
||||
private val clients = ArrayList<Client>()
|
||||
|
||||
private val onlineListCSV: String
|
||||
@Synchronized get() {
|
||||
val sb = StringBuilder()
|
||||
sb.append(clients.size).append(" user(s) online: ")
|
||||
for (i in clients.indices) {
|
||||
sb.append(if (i > 0) ", " else "").append(clients[i].clientName)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
try {
|
||||
val ss = ServerSocket(port)
|
||||
while (true) {
|
||||
val s = ss.accept()
|
||||
Thread(Client(s)).start()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun registerClient(client: Client): Boolean {
|
||||
for (otherClient in clients) {
|
||||
if (otherClient.clientName!!.equals(client.clientName!!, ignoreCase = true)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
clients.add(client)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun deRegisterClient(client: Client) {
|
||||
var wasRegistered = false
|
||||
synchronized(this) {
|
||||
wasRegistered = clients.remove(client)
|
||||
}
|
||||
if (wasRegistered) {
|
||||
broadcast(client, "--- " + client.clientName + " left ---")
|
||||
}
|
||||
}
|
||||
|
||||
private fun broadcast(fromClient: Client, msg: String) {
|
||||
// Copy client list (don't want to hold lock while doing IO)
|
||||
var clients: List<Client> = Collections.emptyList()
|
||||
synchronized(this) {
|
||||
clients = ArrayList(this.clients)
|
||||
}
|
||||
for (client in clients) {
|
||||
if (client.equals(fromClient)) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
client.write(msg + "\r\n")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inner class Client internal constructor(private var socket: Socket?) : Runnable {
|
||||
private var output: Writer? = null
|
||||
var clientName: String? = null
|
||||
|
||||
override fun run() {
|
||||
try {
|
||||
socket!!.sendBufferSize = 16384
|
||||
socket!!.tcpNoDelay = true
|
||||
val input = BufferedReader(InputStreamReader(socket!!.getInputStream()))
|
||||
output = OutputStreamWriter(socket!!.getOutputStream())
|
||||
write("Please enter your name: ")
|
||||
var line: String
|
||||
while (true) {
|
||||
line = input.readLine()
|
||||
if (null == line) {
|
||||
break
|
||||
}
|
||||
if (clientName == null) {
|
||||
line = line.trim { it <= ' ' }
|
||||
if (line.isEmpty()) {
|
||||
write("A name is required. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
clientName = line
|
||||
if (!registerClient(this)) {
|
||||
clientName = null
|
||||
write("Name already registered. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
write(onlineListCSV + "\r\n")
|
||||
broadcast(this, "+++ $clientName arrived +++")
|
||||
continue
|
||||
}
|
||||
if (line.equals("/quit", ignoreCase = true)) {
|
||||
return
|
||||
}
|
||||
broadcast(this, "$clientName> $line")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
deRegisterClient(this)
|
||||
output = null
|
||||
try {
|
||||
socket!!.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
socket = null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
internal fun write(msg: String) {
|
||||
output!!.write(msg)
|
||||
output!!.flush()
|
||||
}
|
||||
|
||||
internal fun equals(client: Client?): Boolean {
|
||||
return (client != null
|
||||
&& clientName != null
|
||||
&& client.clientName != null
|
||||
&& clientName == client.clientName)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
var port = 4004
|
||||
if (args.isNotEmpty()) {
|
||||
port = Integer.parseInt(args[0])
|
||||
}
|
||||
ChatServer(port).run()
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Task/Chat-server/Nim/chat-server.nim
Normal file
42
Task/Chat-server/Nim/chat-server.nim
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import asyncnet, asyncdispatch
|
||||
|
||||
type
|
||||
Client = tuple
|
||||
socket: AsyncSocket
|
||||
name: string
|
||||
connected: bool
|
||||
|
||||
var clients {.threadvar.}: seq[Client]
|
||||
|
||||
proc sendOthers(client: Client, line: string) {.async.} =
|
||||
for c in clients:
|
||||
if c != client and c.connected:
|
||||
await c.socket.send(line & "\c\L")
|
||||
|
||||
proc processClient(socket: AsyncSocket) {.async.} =
|
||||
await socket.send("Please enter your name: ")
|
||||
var client: Client = (socket, await socket.recvLine(), true)
|
||||
|
||||
clients.add(client)
|
||||
asyncCheck client.sendOthers("+++ " & client.name & " arrived +++")
|
||||
|
||||
while true:
|
||||
let line = await client.socket.recvLine()
|
||||
if line == "":
|
||||
asyncCheck client.sendOthers("--- " & client.name & " leaves ---")
|
||||
client.connected = false
|
||||
return
|
||||
asyncCheck client.sendOthers(client.name & "> " & line)
|
||||
|
||||
proc serve() {.async.} =
|
||||
clients = @[]
|
||||
var server = newAsyncSocket()
|
||||
server.bindAddr(Port(4004))
|
||||
server.listen()
|
||||
|
||||
while true:
|
||||
let socket = await server.accept()
|
||||
asyncCheck processClient(socket)
|
||||
|
||||
asyncCheck serve()
|
||||
runForever()
|
||||
109
Task/Chat-server/Objeck/chat-server.objeck
Normal file
109
Task/Chat-server/Objeck/chat-server.objeck
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
use System.IO.Net;
|
||||
use System.Concurrency;
|
||||
use Collection;
|
||||
|
||||
bundle Default {
|
||||
class ChatServer {
|
||||
@clients : StringMap;
|
||||
@clients_mutex : ThreadMutex;
|
||||
|
||||
New() {
|
||||
@clients := StringMap->New();
|
||||
@clients_mutex := ThreadMutex->New("clients_mutex");
|
||||
}
|
||||
|
||||
method : ValidLogin(login_name : String, clients : StringMap) ~ Bool {
|
||||
if(clients->Has(login_name)) {
|
||||
return false;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function : Main(args : String[]) ~ Nil {
|
||||
chat_server := ChatServer->New();
|
||||
chat_server->Run();
|
||||
}
|
||||
|
||||
method : public : Broadcast(message : String, sender : Client) ~ Nil {
|
||||
client_array : Vector;
|
||||
critical(@clients_mutex) {
|
||||
client_array := @clients->GetValues();
|
||||
};
|
||||
each(i : client_array) {
|
||||
client := client_array->Get(i)->As(Client);
|
||||
if(client <> sender) {
|
||||
client->Send(message);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
method : public : Disconnect(sender : Client) ~ Nil {
|
||||
send_name := sender->GetName();
|
||||
Broadcast("+++ {$send_name} has left +++", sender);
|
||||
critical(@clients_mutex) {
|
||||
@clients->Remove(sender->GetName());
|
||||
};
|
||||
sender->Close();
|
||||
}
|
||||
|
||||
method : public : Run() ~ Nil {
|
||||
server := TCPSocketServer->New(4661);
|
||||
if(server->Listen(5)) {
|
||||
while(true) {
|
||||
client_sock := server->Accept();
|
||||
critical(@clients_mutex) {
|
||||
client_sock->WriteString("login: ");
|
||||
login_name := client_sock->ReadString();
|
||||
if(ValidLogin(login_name, @clients)) {
|
||||
client := Client->New(login_name, client_sock, @self);
|
||||
@clients->Insert(client->GetName(), client);
|
||||
client->Execute(Nil);
|
||||
}
|
||||
else {
|
||||
client_sock->WriteString("+++ login in use +++\r\n");
|
||||
client_sock->Close();
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
server->Close();
|
||||
}
|
||||
}
|
||||
|
||||
class Client from Thread {
|
||||
@client_sock : TCPSocket;
|
||||
@server : ChatServer;
|
||||
|
||||
New(login_name : String, client_sock : TCPSocket, server : ChatServer) {
|
||||
Parent(login_name);
|
||||
@client_sock := client_sock;
|
||||
@server := server;
|
||||
}
|
||||
|
||||
method : public : Close() ~ Nil {
|
||||
@client_sock->Close();
|
||||
}
|
||||
|
||||
method : public : Send(message : String) ~ Nil {
|
||||
if(@client_sock->IsOpen() & message->Size() > 0) {
|
||||
@client_sock->WriteString("{$message}\r\n");
|
||||
}
|
||||
else {
|
||||
@server->Disconnect(@self);
|
||||
};
|
||||
}
|
||||
|
||||
method : public : Run(param : Base) ~ Nil {
|
||||
client_name := GetName();
|
||||
@server->Broadcast("+++ {$client_name} has arrived +++", @self);
|
||||
|
||||
message := @client_sock->ReadString();
|
||||
while(message->Size() > 0 & message->Equals("/quit") = false) {
|
||||
@server->Broadcast("{$client_name}> {$message}", @self);
|
||||
message := @client_sock->ReadString();
|
||||
};
|
||||
@server->Disconnect(@self);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Task/Chat-server/Ol/chat-server.ol
Normal file
68
Task/Chat-server/Ol/chat-server.ol
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
(define (timestamp) (syscall 201 "%c"))
|
||||
|
||||
(fork-server 'chat-room (lambda ()
|
||||
(let this ((visitors #empty))
|
||||
(let* ((envelope (wait-mail))
|
||||
(sender msg envelope))
|
||||
(case msg
|
||||
(['join who name]
|
||||
(let ((visitors (put visitors who name)))
|
||||
(for-each (lambda (who)
|
||||
(print-to (car who) name " joined to as"))
|
||||
(ff->alist visitors))
|
||||
(this visitors)))
|
||||
(['talk message]
|
||||
(for-each (lambda (who)
|
||||
(print-to (car who) (cdr who) ": " message))
|
||||
(ff->alist visitors))
|
||||
(this visitors))
|
||||
(['part who]
|
||||
(for-each (lambda (who)
|
||||
(print-to (car who) (visitors (car who) "unknown") " leaved"))
|
||||
(ff->alist visitors))
|
||||
(let ((visitors (del visitors who)))
|
||||
(this visitors))))))))
|
||||
|
||||
|
||||
(define (on-accept name fd)
|
||||
(lambda ()
|
||||
(print "# " (timestamp) "> we got new visitor: " name)
|
||||
(mail 'chat-room ['join fd name])
|
||||
|
||||
(let*((ss1 ms1 (clock)))
|
||||
(let loop ((str #null) (stream (force (port->bytestream fd))))
|
||||
(cond
|
||||
((null? stream)
|
||||
#false)
|
||||
((function? stream)
|
||||
(mail 'chat-room ['talk (list->string (reverse str))])
|
||||
(loop #null (force stream)))
|
||||
(else
|
||||
(loop (cons (car stream) str) (cdr stream)))))
|
||||
(syscall 3 fd)
|
||||
(let*((ss2 ms2 (clock)))
|
||||
(print "# " (timestamp) "> visitor leave us. It takes " (+ (* (- ss2 ss1) 1000) (- ms2 ms1)) "ms.")))
|
||||
(mail 'chat-room ['part fd])
|
||||
))
|
||||
|
||||
(define (run port)
|
||||
(let ((socket (syscall 41)))
|
||||
; bind
|
||||
(let loop ((port port))
|
||||
(if (not (syscall 49 socket port)) ; bind
|
||||
(loop (+ port 2))
|
||||
(print "Server binded to " port)))
|
||||
; listen
|
||||
(if (not (syscall 50 socket)) ; listen
|
||||
(shutdown (print "Can't listen")))
|
||||
|
||||
; accept
|
||||
(let loop ()
|
||||
(if (syscall 23 socket) ; select
|
||||
(let ((fd (syscall 43 socket))) ; accept
|
||||
;(print "\n# " (timestamp) ": new request from " (syscall 51 fd))
|
||||
(fork (on-accept (syscall 51 fd) fd))))
|
||||
(sleep 0)
|
||||
(loop))))
|
||||
|
||||
(run 8080)
|
||||
108
Task/Chat-server/Perl/chat-server-1.pl
Normal file
108
Task/Chat-server/Perl/chat-server-1.pl
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use threads;
|
||||
use threads::shared;
|
||||
|
||||
use IO::Socket::INET;
|
||||
use Time::HiRes qw(sleep ualarm);
|
||||
|
||||
my $HOST = "localhost";
|
||||
my $PORT = 4004;
|
||||
|
||||
my @open;
|
||||
my %users : shared;
|
||||
|
||||
sub broadcast {
|
||||
my ($id, $message) = @_;
|
||||
print "$message\n";
|
||||
foreach my $i (keys %users) {
|
||||
if ($i != $id) {
|
||||
$open[$i]->send("$message\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub sign_in {
|
||||
my ($conn) = @_;
|
||||
|
||||
state $id = 0;
|
||||
|
||||
threads->new(
|
||||
sub {
|
||||
while (1) {
|
||||
$conn->send("Please enter your name: ");
|
||||
$conn->recv(my $name, 1024, 0);
|
||||
|
||||
if (defined $name) {
|
||||
$name = unpack('A*', $name);
|
||||
|
||||
if (exists $users{$name}) {
|
||||
$conn->send("Name entered is already in use.\n");
|
||||
}
|
||||
elsif ($name ne '') {
|
||||
$users{$id} = $name;
|
||||
broadcast($id, "+++ $name arrived +++");
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
++$id;
|
||||
push @open, $conn;
|
||||
}
|
||||
|
||||
my $server = IO::Socket::INET->new(
|
||||
Timeout => 0,
|
||||
LocalPort => $PORT,
|
||||
Proto => "tcp",
|
||||
LocalAddr => $HOST,
|
||||
Blocking => 0,
|
||||
Listen => 1,
|
||||
Reuse => 1,
|
||||
);
|
||||
|
||||
local $| = 1;
|
||||
print "Listening on $HOST:$PORT\n";
|
||||
|
||||
while (1) {
|
||||
my ($conn) = $server->accept;
|
||||
|
||||
if (defined($conn)) {
|
||||
sign_in($conn);
|
||||
}
|
||||
|
||||
foreach my $i (keys %users) {
|
||||
|
||||
my $conn = $open[$i];
|
||||
my $message;
|
||||
|
||||
eval {
|
||||
local $SIG{ALRM} = sub { die "alarm\n" };
|
||||
ualarm(500);
|
||||
$conn->recv($message, 1024, 0);
|
||||
ualarm(0);
|
||||
};
|
||||
|
||||
if ($@ eq "alarm\n") {
|
||||
next;
|
||||
}
|
||||
|
||||
if (defined($message)) {
|
||||
if ($message ne '') {
|
||||
$message = unpack('A*', $message);
|
||||
broadcast($i, "$users{$i}> $message");
|
||||
}
|
||||
else {
|
||||
broadcast($i, "--- $users{$i} leaves ---");
|
||||
delete $users{$i};
|
||||
undef $open[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep(0.1);
|
||||
}
|
||||
80
Task/Chat-server/Perl/chat-server-2.pl
Normal file
80
Task/Chat-server/Perl/chat-server-2.pl
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict; # http://www.rosettacode.org/wiki/Chat_server
|
||||
use warnings;
|
||||
use IO::Socket;
|
||||
use IO::Select; # with write queueing
|
||||
|
||||
my $port = shift // 6666;
|
||||
my (%nicks, @users, %data);
|
||||
|
||||
my $listen = IO::Socket::INET->new(LocalPort => $port, Listen => 9,
|
||||
Reuse => 1) or die "$@ opening socket on port $port";
|
||||
my $rsel = IO::Select->new($listen);
|
||||
my $wsel = IO::Select->new();
|
||||
print "ready on $port...\n";
|
||||
|
||||
sub to
|
||||
{
|
||||
my $text = pop;
|
||||
for ( @_ )
|
||||
{
|
||||
length $data{$_}{out} or $wsel->add( $_ );
|
||||
length( $data{$_}{out} .= $text ) > 1e4 and left( $_ );
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub left
|
||||
{
|
||||
my $h = shift;
|
||||
@users = grep $h != $_, @users;
|
||||
if( defined( my $nick = delete $nicks{$h} ) )
|
||||
{
|
||||
print to @users, "$nick has left\n";
|
||||
}
|
||||
delete $data{$h};
|
||||
$rsel->remove($h);
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
my ($reads, $writes) = IO::Select->select($rsel, $wsel, undef, 5);
|
||||
for my $h ( @{ $writes // [] } )
|
||||
{
|
||||
my $len = syswrite $h, $data{$h}{out};
|
||||
$len and substr $data{$h}{out}, 0, $len, '';
|
||||
length $data{$h}{out} or $wsel->remove( $h );
|
||||
}
|
||||
for my $h ( @{ $reads // [] } )
|
||||
{
|
||||
if( $h == $listen ) # new connection
|
||||
{
|
||||
$rsel->add( my $client = $h->accept );
|
||||
$data{$client} = { h => $client, out => "enter nick: ", in => '' };
|
||||
$wsel->add( $client );
|
||||
}
|
||||
elsif( not sysread $h, $data{$h}{in}, 4096, length $data{$h}{in} ) # closed
|
||||
{
|
||||
left $h;
|
||||
}
|
||||
elsif( exists $nicks{$h} ) # user is signed in
|
||||
{
|
||||
my @others = grep $h != $_, @users;
|
||||
to @others, "$nicks{$h}> $&" while $data{$h}{in} =~ s/.*\n//;
|
||||
}
|
||||
elsif( $data{$h}{in} =~ s/^(\w+)\r?\n.*//s and
|
||||
not grep lc $1 eq lc, values %nicks )
|
||||
{ # user has joined
|
||||
my $all = join ' ', sort values %nicks;
|
||||
$nicks{$h} = $1;
|
||||
push @users, $h;
|
||||
print to @users, "$nicks{$h} has joined $all\n";
|
||||
}
|
||||
else # bad nick
|
||||
{
|
||||
to $h, "nick invalid or in use, enter nick: ";
|
||||
$data{$h}{in} = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
171
Task/Chat-server/Phix/chat-server-1.phix
Normal file
171
Task/Chat-server/Phix/chat-server-1.phix
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
(notonline)-->
|
||||
<span style="color: #000080;font-style:italic;">--
|
||||
-- demo\rosetta\ChatServer.exw
|
||||
-- ========================
|
||||
--
|
||||
-- translation of (qchat) chatServ.exw
|
||||
--
|
||||
-- Run this first, then ChatClient.exw, see also IRC_Gateway.exw
|
||||
--
|
||||
-- Note that I've only got a 32-bit windows eulibnet.dll, but it should not
|
||||
-- be dificult to use a "real" libnet.dll/so, or something a little newer.
|
||||
--</span>
|
||||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">dl</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`Download rosetta\eulibnet\ from http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Eulibnet`</span>
|
||||
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"eulibnet"</span><span style="color: #0000FF;">)=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">/</span><span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">.</span><span style="color: #000000;">ew</span>
|
||||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">log_window</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timer</span>
|
||||
|
||||
<span style="color: #004080;">atom</span> <span style="color: #000000;">listconn</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"127.0.0.1"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"29029"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">IPaddress</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">":"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">port</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">MAX_MSG</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">550</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">connections</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{},</span>
|
||||
<span style="color: #000000;">nicknames</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">max_log_len</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">300</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">log_to_window</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"COUNT"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">max_log_len</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">-</span><span style="color: #000000;">max_log_len</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"REMOVEITEM"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"APPENDITEM"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TOPITEM"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"COUNT"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">args</span><span style="color: #0000FF;">={})</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">args</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span><span style="color: #000000;">args</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">log_to_window</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Shutting down euLibnet..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing connection!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">listconn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing listconn!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_shutdown</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error shutting down euLibnet!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- Send msg to all clients</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">atom</span> <span style="color: #000000;">ci</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Sending to connection %d (%s)"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending to connection %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing euLibnet..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_init</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing euLibnet!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing driver..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_initdriver</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">!=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing WinSock driver!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Opening port "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">IPaddress</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">"..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_openconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">IPaddress</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Couldn't open connection (server already running?)"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_listen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">listconn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error trying to listen to port"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Listening on port "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">IPaddress</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*timer*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_poll_listen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">listconn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">!=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">connections</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">conn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nicknames</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nicknames</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"New connection open from "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">net_getpeer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
|
||||
<span style="color: #000080;font-style:italic;">-- Check for messages from clients</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ci</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_query_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #000080;font-style:italic;">--Get the message</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_receive_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">MAX_MSG</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"received msg \"%s\" of length %d from %d aka %s"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ni</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">--Exit on error</span>
|
||||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_ignore_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Server error: some data may be lost"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">exit</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">4</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/n:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)],</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/nt"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending to %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">prevname</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ni</span>
|
||||
<span style="color: #000000;">ni</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)]</span>
|
||||
<span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ni</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">prevname</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/j:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has joined"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- send fake "has joined"s to the new joiner,
|
||||
-- so that it can build a full members list (see allj)</span>
|
||||
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nicknames</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">i</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"/j:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has joined"</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending to connection %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span>
|
||||
<span style="color: #008080;">exit</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/c:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">prevname</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has changed name to "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/d"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"/l:"</span><span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has left"</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">exit</span>
|
||||
<span style="color: #000080;font-style:italic;">-- Aside: bunch of popup and file transfer stuff was here in qchat.exw,
|
||||
-- all ripped out in the name of keeping this short and sweet.</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">": "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (Add nickname to message)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">close_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">log_list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupList</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=YES, CANFOCUS=NO, MULTIPLE=YES"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">statusbar</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Loading..."</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">log_window</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #008000;">`TITLE="Chat Server", RASTERSIZE=400x400`</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_window</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CLOSE_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"close_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_window</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">500</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
|
||||
<!--
|
||||
243
Task/Chat-server/Phix/chat-server-2.phix
Normal file
243
Task/Chat-server/Phix/chat-server-2.phix
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
(notonline)-->
|
||||
<span style="color: #000080;font-style:italic;">--
|
||||
-- demo\rosetta\ChatClient.exw
|
||||
-- ===========================
|
||||
--
|
||||
-- translation of (qchat) QChat.exw
|
||||
--
|
||||
-- Probably best to run ChatServer.exw before this.
|
||||
--</span>
|
||||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">bViaGateway</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
|
||||
<span style="color: #000080;font-style:italic;">--constant bool bViaGateway = true -- see IRC_Gateway.exw</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">dl</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`Download rosetta\eulibnet\ from http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Eulibnet`</span>
|
||||
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"eulibnet"</span><span style="color: #0000FF;">)=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">include</span> <span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">/</span><span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">.</span><span style="color: #000000;">ew</span>
|
||||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">about</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">help</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">quit</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nickle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">login</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">memble</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">members</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">logle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">messle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">input</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">chat_window</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timer</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #004080;">bool</span> <span style="color: #000000;">allj</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span> <span style="color: #000080;font-style:italic;">-- (suppress initial flurry of fake "has joined" messages)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">conTextBack</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"127.0.0.1"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bViaGateway</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"29030"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"29029"</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- See IRC_Gateway.exw</span>
|
||||
<span style="color: #000000;">timeout</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">IPaddress</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">":"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">port</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">cr</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"\r\n"</span><span style="color: #0000FF;">,</span>
|
||||
<span style="color: #000000;">MAX_MSG</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">80</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">about_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
|
||||
Translated by Pete Lomax from qchat by Andrew/Norman (and win32lib ==> pGUI).
|
||||
Uses Libnet by George Foot and Chad Catlet as wrapped by Ray Smith."
|
||||
"""</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">about_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"About"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">about_text</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">constant</span> <span style="color: #000000;">help_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
|
||||
Make sure ChatServer.exw is running first...
|
||||
|
||||
Enter a nickname and press the Connect Button (or Return), then
|
||||
enter your messages in the message area.
|
||||
"""</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandln</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Chat client"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help_text</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- This should probably be cropped once it gets too long...</span>
|
||||
<span style="color: #000000;">conTextBack</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">message</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">cr</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">conTextBack</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"SCROLLTOPOS"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conTextBack</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"You must be connected to do this"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending message \'"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">"\'"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Disconnecting from server..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/d"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error disconnecting from server!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Shutting down euLibnet..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">></span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing connection!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_shutdown</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error shutting down euLibnet!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">quit_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">connect_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nick</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Opening connection..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_openconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Couldn't open connection."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Attempting to connect to chat server..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_connect_wait_time</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">IPaddress</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timeout</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error trying to establish connection."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Timeout trying to establish connection."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
|
||||
<span style="color: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
|
||||
|
||||
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Chat Client - "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">({</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">login</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/n:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">timer</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RUN"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetFocus</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing euLibnet..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_init</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing euLibnet!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing driver..."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_initdriver</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">!=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing WinSock driver!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetFocus</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">joiner</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ml</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">,</span><span style="color: #000000;">joiner</span><span style="color: #0000FF;">)),</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mt</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">leaver</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ml</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">leaver</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">ml</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
|
||||
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*timer*/</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_query_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">--Check for message</span>
|
||||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_receive_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">MAX_MSG</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error receiving message!"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_ignore_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/nt"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Nickname "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" already taken"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nick</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">"b"</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Trying "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" instead"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Type /n:nickname to try a different one"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/n:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000080;font-style:italic;">-- As per ChatServer, bunch of popup and file transfer stuff was
|
||||
-- all ripped out in the name of keeping this short and sweet.</span>
|
||||
<span style="color: #008080;">else</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/j:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" has joined"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">allj</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..$]</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/l:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" has left"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..$]</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/c:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #004080;">string</span> <span style="color: #000000;">shcnts</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" has changed name to "</span>
|
||||
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">shcnts</span><span style="color: #0000FF;">,</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
|
||||
<span style="color: #000000;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">shcnts</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</span>
|
||||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..$]</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000000;">allj</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'\r'</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">if</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">=</span><span style="color: #000000;">input</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">=</span><span style="color: #000000;">nickname</span> <span style="color: #008080;">then</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">connect_cb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">about</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"About"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"about_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #000000;">help</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Help"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"help_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #000000;">quit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Exit"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"quit_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #000000;">nickle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Nickname"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">nickname</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">login</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Connect"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"connect_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #000000;">memble</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Members online"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">members</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=VERTICAL, CANFOCUS=NO, MULTILINE=YES, SIZE=70x"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">logle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Incoming text"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">log_list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=YES, CANFOCUS=NO, MULTILINE=YES"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">messle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Message"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">input</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">({</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">input</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CUEBANNER"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"This Is Where You Type"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"NC"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">72</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- Max 72 characters allowed</span>
|
||||
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">statusbar</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Loading..."</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">chat_window</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">about</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help</span><span style="color: #0000FF;">,</span><span style="color: #000000;">quit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nickle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">login</span><span style="color: #0000FF;">},</span>
|
||||
<span style="color: #008000;">"NORMALIZESIZE=VERTICAL,GAP=10,MARGIN=5x5"</span><span style="color: #0000FF;">),</span>
|
||||
<span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">memble</span><span style="color: #0000FF;">,</span><span style="color: #000000;">members</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">logle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">})},</span>
|
||||
<span style="color: #008000;">"NGAP=10,NMARGIN=5x5"</span><span style="color: #0000FF;">),</span>
|
||||
<span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">messle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">input</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"GAP=10,MARGIN=5x5"</span><span style="color: #0000FF;">),</span>
|
||||
<span style="color: #000000;">statusbar</span><span style="color: #0000FF;">}),</span>
|
||||
<span style="color: #008000;">`TITLE="Chat Client", RASTERSIZE=400x400`</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CLOSE_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"quit_cb"</span><span style="color: #0000FF;">))</span>
|
||||
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"PARENTDIALOG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">500</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
|
||||
<!--
|
||||
28
Task/Chat-server/PicoLisp/chat-server.l
Normal file
28
Task/Chat-server/PicoLisp/chat-server.l
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
|
||||
|
||||
(de chat Lst
|
||||
(out *Sock
|
||||
(mapc prin Lst)
|
||||
(prinl) ) )
|
||||
|
||||
(setq *Port (port 4004))
|
||||
|
||||
(loop
|
||||
(setq *Sock (listen *Port))
|
||||
(NIL (fork) (close *Port))
|
||||
(close *Sock) )
|
||||
|
||||
(out *Sock
|
||||
(prin "Please enter your name: ")
|
||||
(flush) )
|
||||
(in *Sock (setq *Name (line T)))
|
||||
|
||||
(tell 'chat "+++ " *Name " arrived +++")
|
||||
|
||||
(task *Sock
|
||||
(in @
|
||||
(ifn (eof)
|
||||
(tell 'chat *Name "> " (line T))
|
||||
(tell 'chat "--- " *Name " left ---")
|
||||
(bye) ) ) )
|
||||
(wait)
|
||||
81
Task/Chat-server/Prolog/chat-server.pro
Normal file
81
Task/Chat-server/Prolog/chat-server.pro
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
:- initialization chat_server(5000).
|
||||
|
||||
chat_server(Port) :-
|
||||
tcp_socket(Socket),
|
||||
tcp_bind(Socket, Port),
|
||||
tcp_listen(Socket, 5),
|
||||
tcp_open_socket(Socket, AcceptFd, _),
|
||||
dispatch(AcceptFd).
|
||||
|
||||
dispatch(AcceptFd) :-
|
||||
tcp_accept(AcceptFd, Socket, _),
|
||||
thread_create(process_client(Socket, _), _, [detached(true)]),
|
||||
dispatch(AcceptFd).
|
||||
|
||||
process_client(Socket, _) :-
|
||||
setup_call_cleanup(
|
||||
tcp_open_socket(Socket, Str),
|
||||
handle_connection(Str),
|
||||
close(Str)).
|
||||
|
||||
% a connection was made, get the username and add the streams so the
|
||||
% client can be broadcast to.
|
||||
handle_connection(Str) :-
|
||||
send_msg(Str, msg_welcome, []),
|
||||
repeat,
|
||||
send_msg(Str, msg_username, []),
|
||||
read_line_to_string(Str, Name),
|
||||
connect_user(Name, Str), !.
|
||||
|
||||
% connections are stored here
|
||||
:- dynamic(connected/2).
|
||||
|
||||
connect_user(Name, Str) :-
|
||||
connected(Name, _),
|
||||
send_msg(Str, msg_username_taken, []),
|
||||
fail.
|
||||
connect_user(Name, Str) :-
|
||||
\+ connected(Name, _),
|
||||
send_msg(Str, msg_welcome_name, Name),
|
||||
|
||||
% make sure that the connection is removed when the client leaves.
|
||||
setup_call_cleanup(
|
||||
assert(connected(Name, Str)),
|
||||
(
|
||||
broadcast(Name, msg_joined, Name),
|
||||
chat_loop(Name, Str), !,
|
||||
broadcast(Name, msg_left, Name)
|
||||
),
|
||||
retractall(connected(Name, _))
|
||||
).
|
||||
|
||||
% wait for a line to be sent then broadcast to the rest of the clients
|
||||
% finish this goal when the client disconnects (end of stream)
|
||||
chat_loop(Name, Str) :-
|
||||
read_line_to_string(Str, S),
|
||||
dif(S, end_of_file),
|
||||
broadcast(Name, msg_by_user, [Name, S]),
|
||||
chat_loop(Name, Str).
|
||||
chat_loop(_, Str) :- at_end_of_stream(Str).
|
||||
|
||||
% send a message to all connected clients except Name (the sender)
|
||||
broadcast(Name, Msg, Params) :-
|
||||
forall(
|
||||
(connected(N, Str), dif(N, Name)),
|
||||
(send_msg(Str, Msg, Params), send_msg(Str, msg_new_line, []))
|
||||
).
|
||||
|
||||
send_msg(St, MsgConst, Params) :-
|
||||
call(MsgConst, Msg),
|
||||
format(St, Msg, Params),
|
||||
flush_output(St).
|
||||
|
||||
% constants for the various message types that are sent
|
||||
msg_welcome('Welcome to Chatalot\n\r').
|
||||
msg_username('Please enter your nickname: ').
|
||||
msg_welcome_name('Welcome ~p\n\r').
|
||||
msg_joined(' -- "~w" has joined the chat --').
|
||||
msg_left(' -- "~w" has left the chat. --').
|
||||
msg_username_taken('That username is already taken, choose another\n\r').
|
||||
msg_new_line('\n\r').
|
||||
msg_by_user('~w> ~w').
|
||||
78
Task/Chat-server/Python/chat-server.py
Normal file
78
Task/Chat-server/Python/chat-server.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import socket
|
||||
import thread
|
||||
import time
|
||||
|
||||
HOST = ""
|
||||
PORT = 4004
|
||||
|
||||
def accept(conn):
|
||||
"""
|
||||
Call the inner func in a thread so as not to block. Wait for a
|
||||
name to be entered from the given connection. Once a name is
|
||||
entered, set the connection to non-blocking and add the user to
|
||||
the users dict.
|
||||
"""
|
||||
def threaded():
|
||||
while True:
|
||||
conn.send("Please enter your name: ")
|
||||
try:
|
||||
name = conn.recv(1024).strip()
|
||||
except socket.error:
|
||||
continue
|
||||
if name in users:
|
||||
conn.send("Name entered is already in use.\n")
|
||||
elif name:
|
||||
conn.setblocking(False)
|
||||
users[name] = conn
|
||||
broadcast(name, "+++ %s arrived +++" % name)
|
||||
break
|
||||
thread.start_new_thread(threaded, ())
|
||||
|
||||
def broadcast(name, message):
|
||||
"""
|
||||
Send a message to all users from the given name.
|
||||
"""
|
||||
print message
|
||||
for to_name, conn in users.items():
|
||||
if to_name != name:
|
||||
try:
|
||||
conn.send(message + "\n")
|
||||
except socket.error:
|
||||
pass
|
||||
|
||||
# Set up the server socket.
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.setblocking(False)
|
||||
server.bind((HOST, PORT))
|
||||
server.listen(1)
|
||||
print "Listening on %s" % ("%s:%s" % server.getsockname())
|
||||
|
||||
# Main event loop.
|
||||
users = {}
|
||||
while True:
|
||||
try:
|
||||
# Accept new connections.
|
||||
while True:
|
||||
try:
|
||||
conn, addr = server.accept()
|
||||
except socket.error:
|
||||
break
|
||||
accept(conn)
|
||||
# Read from connections.
|
||||
for name, conn in users.items():
|
||||
try:
|
||||
message = conn.recv(1024)
|
||||
except socket.error:
|
||||
continue
|
||||
if not message:
|
||||
# Empty string is given on disconnect.
|
||||
del users[name]
|
||||
broadcast(name, "--- %s leaves ---" % name)
|
||||
else:
|
||||
broadcast(name, "%s> %s" % (name, message.strip()))
|
||||
time.sleep(.1)
|
||||
except (SystemExit, KeyboardInterrupt):
|
||||
break
|
||||
146
Task/Chat-server/R/chat-server.r
Normal file
146
Task/Chat-server/R/chat-server.r
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
chat_loop <- function(server, sockets, delay = 0.5) {
|
||||
repeat {
|
||||
Sys.sleep(delay) # Saves CPU resources
|
||||
|
||||
## Exhausts queue each iteration
|
||||
while (in_queue(server))
|
||||
sockets <- new_socket_entry(server, sockets)
|
||||
|
||||
## Update which sockets have sent messages
|
||||
sockets <- check_messages(sockets)
|
||||
|
||||
## No sockets, nothing to do
|
||||
if (nrow(sockets) == 0)
|
||||
next
|
||||
|
||||
## No new messages, nothing to do
|
||||
if (all(!sockets$message_ready))
|
||||
next
|
||||
|
||||
|
||||
sockets <- read_messages(sockets) # Messages are stored until sent
|
||||
sockets <- drop_dead(sockets) # Dead = ready to read, but no data
|
||||
|
||||
## In case all sockets were dropped
|
||||
if (nrow(sockets) == 0)
|
||||
next
|
||||
|
||||
sockets <- update_nicknames(sockets)
|
||||
sockets <- send_messages(sockets) # Only to users with nicknames
|
||||
}
|
||||
}
|
||||
|
||||
check_messages <- function(sockets) {
|
||||
if (nrow(sockets) != 0)
|
||||
sockets$message_ready <- socketSelect(sockets$conn, timeout = 0)
|
||||
|
||||
sockets
|
||||
}
|
||||
|
||||
drop_dead <- function(sockets) {
|
||||
lapply(with(sockets, conn[!alive]), close)
|
||||
dropped <- with(sockets, nickname[nickname_exists(sockets) & !alive])
|
||||
sockets <- sockets[sockets$alive, ]
|
||||
|
||||
if (length(dropped) != 0) {
|
||||
send_named(sockets, paste0(dropped, " has disconnected."))
|
||||
}
|
||||
|
||||
sockets
|
||||
}
|
||||
|
||||
in_queue <- function(server) socketSelect(list(server), timeout = 0)
|
||||
is_valid_name <- function(nicks) gsub("[A-Za-z0-9]*", "", nicks) == ""
|
||||
message_exists <- function(sockets) !is.na(sockets$message)
|
||||
|
||||
new_row <- function(df) {
|
||||
df[nrow(df) + 1, ] <- NA
|
||||
df
|
||||
}
|
||||
|
||||
new_socket_entry <- function(server, sockets) {
|
||||
sockets <- new_row(sockets)
|
||||
n <- nrow(sockets)
|
||||
within(sockets, {
|
||||
conn[[n]] <- new_user(server)
|
||||
alive[n] <- TRUE
|
||||
message_ready[n] <- FALSE
|
||||
})
|
||||
}
|
||||
|
||||
new_user <- function(server) {
|
||||
conn <- socketAccept(server)
|
||||
writeLines("Hello! Please enter a nickname.", conn)
|
||||
conn
|
||||
}
|
||||
|
||||
nickname_exists <- function(sockets) !is.na(sockets$nickname)
|
||||
|
||||
read_messages <- function(sockets) {
|
||||
if (all(!sockets$message_ready))
|
||||
return(sockets)
|
||||
|
||||
msgs <- lapply(with(sockets, conn[message_ready]), readLines, n = 1)
|
||||
empty_msgs <- sapply(msgs, identical, character(0))
|
||||
sockets <- within(sockets, alive[message_ready & empty_msgs] <- FALSE)
|
||||
msgs <- unlist(ifelse(empty_msgs, NA, msgs))
|
||||
within(sockets, message[message_ready] <- msgs)
|
||||
}
|
||||
|
||||
send_messages <- function(sockets) {
|
||||
named_message <- message_exists(sockets) & nickname_exists(sockets)
|
||||
|
||||
if (all(!named_message))
|
||||
return(sockets)
|
||||
|
||||
rows <- which(named_message)
|
||||
socksub <- sockets[rows, ]
|
||||
time <- format(Sys.time(), "[%H:%M:%S] ")
|
||||
with(socksub, send_named(sockets, paste0(time, nickname, ": ", message)))
|
||||
within(sockets, message[rows] <- NA)
|
||||
}
|
||||
|
||||
send_named <- function(sockets, msg) {
|
||||
has_nickname <- nickname_exists(sockets)
|
||||
invisible(lapply(sockets$conn[has_nickname], writeLines, text = msg))
|
||||
}
|
||||
|
||||
start_chat_server <- function(port = 50525) {
|
||||
server <- serverSocket(port) # Start listening
|
||||
on.exit(closeAllConnections()) # Cleanup connections
|
||||
|
||||
## All socket data is stored and passed using this object
|
||||
sockets <- data.frame(conn = I(list()), nickname = character(),
|
||||
message = character(), alive = logical(),
|
||||
message_ready = logical())
|
||||
|
||||
## Main event loop
|
||||
chat_loop(server, sockets)
|
||||
}
|
||||
|
||||
update_nicknames <- function(sockets) {
|
||||
sent_nickname <- message_exists(sockets) & !nickname_exists(sockets)
|
||||
nickname_valid <- is_valid_name(sockets$message)
|
||||
|
||||
if (all(!sent_nickname))
|
||||
return(sockets)
|
||||
|
||||
is_taken <- with(sockets, (tolower(message) %in% tolower(sockets$nickname)) &
|
||||
!is.na(message))
|
||||
sent_ok <- sent_nickname & nickname_valid & !is_taken
|
||||
sockets <- within(sockets, {
|
||||
nickname[sent_ok] <- message[sent_ok]
|
||||
message[sent_nickname] <- NA
|
||||
lapply(conn[sent_nickname & !nickname_valid], writeLines,
|
||||
text = "Alphanumeric characters only. Try again.")
|
||||
lapply(conn[is_taken], writeLines,
|
||||
text = "Name already taken. Try again.")
|
||||
})
|
||||
|
||||
if (any(sent_ok))
|
||||
send_named(sockets, paste0(sockets$nickname[sent_ok], " has connected."))
|
||||
|
||||
sockets
|
||||
}
|
||||
|
||||
start_chat_server()
|
||||
21
Task/Chat-server/Racket/chat-server.rkt
Normal file
21
Task/Chat-server/Racket/chat-server.rkt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#lang racket
|
||||
|
||||
(define outs (list (current-output-port)))
|
||||
(define ((tell-all who o) line)
|
||||
(for ([c outs] #:unless (eq? o c)) (displayln (~a who ": " line) c)))
|
||||
|
||||
(define ((client i o))
|
||||
(define nick (begin (display "Nick: " o) (read-line i)))
|
||||
(define tell (tell-all nick o))
|
||||
(let loop ([line "(joined)"])
|
||||
(if (eof-object? line)
|
||||
(begin (tell "(left)") (set! outs (remq o outs)) (close-output-port o))
|
||||
(begin (tell line) (loop (read-line i))))))
|
||||
|
||||
(define (chat-server listener)
|
||||
(define-values [i o] (tcp-accept listener))
|
||||
(for ([p (list i o)]) (file-stream-buffer-mode p 'none))
|
||||
(thread (client i o)) (set! outs (cons o outs)) (chat-server listener))
|
||||
|
||||
(void (thread (λ() (chat-server (tcp-listen 12321)))))
|
||||
((client (current-input-port) (current-output-port)))
|
||||
43
Task/Chat-server/Raku/chat-server.raku
Normal file
43
Task/Chat-server/Raku/chat-server.raku
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
react {
|
||||
my %connections;
|
||||
|
||||
whenever IO::Socket::Async.listen('localhost', 4004) -> $conn {
|
||||
my $name;
|
||||
|
||||
$conn.print: "Please enter your name: ";
|
||||
|
||||
whenever $conn.Supply.lines -> $message {
|
||||
if !$name {
|
||||
if %connections{$message} {
|
||||
$conn.print: "Name already taken, choose another one: ";
|
||||
}
|
||||
else {
|
||||
$name = $message;
|
||||
%connections{$name} = $conn;
|
||||
broadcast "+++ %s arrived +++", $name;
|
||||
}
|
||||
}
|
||||
else {
|
||||
broadcast "%s> %s", $name, $message;
|
||||
}
|
||||
LAST {
|
||||
broadcast "--- %s left ---", $name;
|
||||
%connections{$name}:delete;
|
||||
$conn.close ;
|
||||
}
|
||||
QUIT {
|
||||
default {
|
||||
say "oh no, $_";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub broadcast ($format, $from, *@message) {
|
||||
my $text = sprintf $format, $from, |@message;
|
||||
say $text;
|
||||
for %connections.kv -> $name, $conn {
|
||||
$conn.print: "$text\n" if $name ne $from;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Task/Chat-server/Ruby/chat-server.rb
Normal file
68
Task/Chat-server/Ruby/chat-server.rb
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
require 'gserver'
|
||||
|
||||
class ChatServer < GServer
|
||||
def initialize *args
|
||||
super
|
||||
|
||||
#Keep a list for broadcasting messages
|
||||
@chatters = []
|
||||
|
||||
#We'll need this for thread safety
|
||||
@mutex = Mutex.new
|
||||
end
|
||||
|
||||
#Send message out to everyone but sender
|
||||
def broadcast message, sender = nil
|
||||
#Need to use \r\n for our Windows friends
|
||||
message = message.strip << "\r\n"
|
||||
|
||||
#Mutex for safety - GServer uses threads
|
||||
@mutex.synchronize do
|
||||
@chatters.each do |chatter|
|
||||
begin
|
||||
chatter.print message unless chatter == sender
|
||||
rescue
|
||||
@chatters.delete chatter
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#Handle each connection
|
||||
def serve io
|
||||
io.print 'Name: '
|
||||
name = io.gets
|
||||
|
||||
#They might disconnect
|
||||
return if name.nil?
|
||||
|
||||
name.strip!
|
||||
|
||||
broadcast "--+ #{name} has joined +--"
|
||||
|
||||
#Add to our list of connections
|
||||
@mutex.synchronize do
|
||||
@chatters << io
|
||||
end
|
||||
|
||||
#Get and broadcast input until connection returns nil
|
||||
loop do
|
||||
message = io.gets
|
||||
|
||||
if message
|
||||
broadcast "#{name}> #{message}", io
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
broadcast "--+ #{name} has left +--"
|
||||
end
|
||||
end
|
||||
|
||||
#Start up the server on port 7000
|
||||
#Accept connections for any IP address
|
||||
#Allow up to 100 connections
|
||||
#Send information to stderr
|
||||
#Turn on informational messages
|
||||
ChatServer.new(7000, '0.0.0.0', 100, $stderr, true).start.join
|
||||
96
Task/Chat-server/Rust/chat-server.rust
Normal file
96
Task/Chat-server/Rust/chat-server.rust
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::io::BufReader;
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
|
||||
type Username = String;
|
||||
|
||||
/// Sends a message to all clients except the sending client.
|
||||
fn broadcast_message(
|
||||
user: &str,
|
||||
clients: &mut HashMap<String, TcpStream>,
|
||||
message: &str,
|
||||
) -> io::Result<()> {
|
||||
for (client, stream) in clients.iter_mut() {
|
||||
if client != user {
|
||||
writeln!(stream, "{}", message)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn chat_loop(listener: &TcpListener) -> io::Result<()> {
|
||||
let local_clients: Arc<RwLock<HashMap<Username, TcpStream>>> =
|
||||
Arc::new(RwLock::new(HashMap::new()));
|
||||
|
||||
println!("Accepting connections on {}", listener.local_addr()?.port());
|
||||
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
let client_clients = Arc::clone(&local_clients);
|
||||
thread::spawn(move || -> io::Result<()> {
|
||||
let mut reader = BufReader::new(stream.try_clone()?);
|
||||
let mut writer = stream;
|
||||
|
||||
let mut name = String::new();
|
||||
loop {
|
||||
write!(writer, "Please enter a username: ")?;
|
||||
reader.read_line(&mut name)?;
|
||||
name = name.trim().to_owned();
|
||||
|
||||
let clients = client_clients.read().unwrap();
|
||||
if !clients.contains_key(&name) {
|
||||
writeln!(writer, "Welcome, {}!", &name)?;
|
||||
break;
|
||||
}
|
||||
|
||||
writeln!(writer, "That username is taken.")?;
|
||||
name.clear();
|
||||
}
|
||||
|
||||
{
|
||||
let mut clients = client_clients.write().unwrap();
|
||||
clients.insert(name.clone(), writer);
|
||||
broadcast_message(
|
||||
&name,
|
||||
&mut *clients,
|
||||
&format!("{} has joined the chat room.", &name),
|
||||
)?;
|
||||
}
|
||||
|
||||
for line in reader.lines() {
|
||||
let mut clients = client_clients.write().unwrap();
|
||||
broadcast_message(&name, &mut *clients, &format!("{}: {}", &name, line?))?;
|
||||
}
|
||||
|
||||
{
|
||||
let mut clients = client_clients.write().unwrap();
|
||||
clients.remove(&name);
|
||||
broadcast_message(
|
||||
&name,
|
||||
&mut *clients,
|
||||
&format!("{} has left the chat room.", &name),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Connection failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let listener = TcpListener::bind(("localhost", 7000)).unwrap();
|
||||
chat_loop(&listener).unwrap();
|
||||
}
|
||||
61
Task/Chat-server/Tcl/chat-server.tcl
Normal file
61
Task/Chat-server/Tcl/chat-server.tcl
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package require Tcl 8.6
|
||||
|
||||
# Write a message to everyone except the sender of the message
|
||||
proc writeEveryoneElse {sender message} {
|
||||
dict for {who ch} $::cmap {
|
||||
if {$who ne $sender} {
|
||||
puts $ch $message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# How to read a line (up to 256 chars long) in a coroutine
|
||||
proc cgets {ch var} {
|
||||
upvar 1 $var v
|
||||
while {[gets $ch v] < 0} {
|
||||
if {[eof $ch] || [chan pending input $ch] > 256} {
|
||||
return false
|
||||
}
|
||||
yield
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
# The chatting, as seen by one user
|
||||
proc chat {ch addr port} {
|
||||
### CONNECTION CODE ###
|
||||
#Log "connection from ${addr}:${port} on channel $ch"
|
||||
fconfigure $ch -buffering none -blocking 0 -encoding utf-8
|
||||
fileevent $ch readable [info coroutine]
|
||||
global cmap
|
||||
try {
|
||||
|
||||
### GET THE NICKNAME OF THE USER ###
|
||||
puts -nonewline $ch "Please enter your name: "
|
||||
if {![cgets $ch name]} {
|
||||
return
|
||||
}
|
||||
#Log "Mapping ${addr}:${port} to ${name} on channel $ch"
|
||||
dict set cmap $name $ch
|
||||
writeEveryoneElse $name "+++ $name arrived +++"
|
||||
|
||||
### MAIN CHAT LOOP ###
|
||||
while {[cgets $ch line]} {
|
||||
writeEveryoneElse $name "$name> $line"
|
||||
}
|
||||
|
||||
} finally {
|
||||
### DISCONNECTION CODE ###
|
||||
if {[info exists name]} {
|
||||
writeEveryoneElse $name "--- $name left ---"
|
||||
dict unset cmap $name
|
||||
}
|
||||
close $ch
|
||||
#Log "disconnection from ${addr}:${port} on channel $ch"
|
||||
}
|
||||
}
|
||||
|
||||
# Service the socket by making corouines running [chat]
|
||||
socket -server {coroutine c[incr count] chat} 4004
|
||||
set ::cmap {}; # Dictionary mapping nicks to channels
|
||||
vwait forever; # Run event loop
|
||||
134
Task/Chat-server/Visual-Basic-.NET/chat-server.vb
Normal file
134
Task/Chat-server/Visual-Basic-.NET/chat-server.vb
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
Imports System.Net.Sockets
|
||||
Imports System.Text
|
||||
Imports System.Threading
|
||||
|
||||
Module Module1
|
||||
|
||||
Class State
|
||||
Private ReadOnly client As TcpClient
|
||||
Private ReadOnly sb As New StringBuilder
|
||||
|
||||
Public Sub New(name As String, client As TcpClient)
|
||||
Me.Name = name
|
||||
Me.client = client
|
||||
End Sub
|
||||
|
||||
Public ReadOnly Property Name As String
|
||||
|
||||
Public Sub Send(text As String)
|
||||
Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
|
||||
client.GetStream().Write(bytes, 0, bytes.Length)
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
ReadOnly connections As New Dictionary(Of Integer, State)
|
||||
Dim listen As TcpListener
|
||||
Dim serverThread As Thread
|
||||
|
||||
Sub Main()
|
||||
listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
|
||||
serverThread = New Thread(New ThreadStart(AddressOf DoListen))
|
||||
serverThread.Start()
|
||||
End Sub
|
||||
|
||||
Private Sub DoListen()
|
||||
listen.Start()
|
||||
Console.WriteLine("Server: Started server")
|
||||
|
||||
Do
|
||||
Console.Write("Server: Waiting...")
|
||||
Dim client = listen.AcceptTcpClient()
|
||||
Console.WriteLine(" Connected")
|
||||
|
||||
' New thread with client
|
||||
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))
|
||||
|
||||
clientThread.Start(client)
|
||||
Loop
|
||||
End Sub
|
||||
|
||||
Private Sub DoClient(client As TcpClient)
|
||||
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
|
||||
Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
|
||||
client.GetStream().Write(bytes, 0, bytes.Length)
|
||||
|
||||
Dim done As Boolean
|
||||
Dim name As String
|
||||
Do
|
||||
If Not client.Connected Then
|
||||
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
|
||||
client.Close()
|
||||
Thread.CurrentThread.Abort() ' Kill thread
|
||||
End If
|
||||
|
||||
name = Receive(client)
|
||||
done = True
|
||||
|
||||
For Each cl In connections
|
||||
Dim state = cl.Value
|
||||
If state.Name = name Then
|
||||
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
|
||||
client.GetStream().Write(bytes, 0, bytes.Length)
|
||||
done = False
|
||||
End If
|
||||
Next
|
||||
Loop While Not done
|
||||
|
||||
connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
|
||||
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
|
||||
Broadcast(String.Format("+++ {0} arrived +++", name))
|
||||
|
||||
Do
|
||||
Dim text = Receive(client)
|
||||
If text = "/quit" Then
|
||||
Broadcast(String.Format("Connection from {0} closed.", name))
|
||||
connections.Remove(Thread.CurrentThread.ManagedThreadId)
|
||||
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
|
||||
Exit Do
|
||||
End If
|
||||
|
||||
If Not client.Connected Then
|
||||
Exit Do
|
||||
End If
|
||||
|
||||
Broadcast(String.Format("{0}> {1}", name, text))
|
||||
Loop
|
||||
|
||||
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
|
||||
client.Close()
|
||||
Thread.CurrentThread.Abort()
|
||||
End Sub
|
||||
|
||||
Private Function Receive(client As TcpClient) As String
|
||||
Dim sb As New StringBuilder
|
||||
Do
|
||||
If client.Available > 0 Then
|
||||
While client.Available > 0
|
||||
Dim ch = Chr(client.GetStream.ReadByte())
|
||||
If ch = vbCr Then
|
||||
' ignore
|
||||
Continue While
|
||||
End If
|
||||
If ch = vbLf Then
|
||||
Return sb.ToString()
|
||||
End If
|
||||
sb.Append(ch)
|
||||
End While
|
||||
|
||||
' pause
|
||||
Thread.Sleep(100)
|
||||
End If
|
||||
Loop
|
||||
End Function
|
||||
|
||||
Private Sub Broadcast(text As String)
|
||||
Console.WriteLine(text)
|
||||
For Each client In connections
|
||||
If client.Key <> Thread.CurrentThread.ManagedThreadId Then
|
||||
Dim state = client.Value
|
||||
state.Send(text)
|
||||
End If
|
||||
Next
|
||||
End Sub
|
||||
|
||||
End Module
|
||||
199
Task/Chat-server/Wren/chat-server-1.wren
Normal file
199
Task/Chat-server/Wren/chat-server-1.wren
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/* chat_server.wren */
|
||||
|
||||
class Clients {
|
||||
foreign static max
|
||||
foreign static count
|
||||
foreign static isActive(vmi)
|
||||
foreign static connfd(vmi)
|
||||
foreign static uid(vmi)
|
||||
foreign static name(vmi)
|
||||
foreign static setName(vmi, s)
|
||||
foreign static printAddr(vmi)
|
||||
foreign static delete(vmi)
|
||||
}
|
||||
|
||||
class Mutex {
|
||||
foreign static clientsLock()
|
||||
foreign static clientsUnlock()
|
||||
|
||||
foreign static topicLock()
|
||||
foreign static topicUnlock()
|
||||
}
|
||||
|
||||
class Chat {
|
||||
// send message to all clients but the sender
|
||||
static sendMessage(s, uid) {
|
||||
Mutex.clientsLock()
|
||||
for (i in 0...Clients.max) {
|
||||
if (Clients.isActive(i) && Clients.uid(i) != uid) {
|
||||
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
|
||||
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Mutex.clientsUnlock()
|
||||
}
|
||||
|
||||
// send message to all clients
|
||||
static sendMessageAll(s) {
|
||||
Mutex.clientsLock()
|
||||
for (i in 0...Clients.max) {
|
||||
if (Clients.isActive(i)) {
|
||||
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
|
||||
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Mutex.clientsUnlock()
|
||||
}
|
||||
|
||||
// send message to sender
|
||||
static sendMessageSelf(s, connfd) {
|
||||
if (write(connfd, s, s.bytes.count) < 0) {
|
||||
Fiber.abort("Write to descriptor %(connfd) failed.")
|
||||
}
|
||||
}
|
||||
|
||||
// send message to client
|
||||
static sendMessageClient(s, uid) {
|
||||
Mutex.clientsLock()
|
||||
for (i in 0...Clients.max) {
|
||||
if (Clients.isActive(i) && Clients.uid(i) == uid) {
|
||||
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
|
||||
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Mutex.clientsUnlock()
|
||||
}
|
||||
|
||||
// send list of active clients
|
||||
static sendActiveClients(connfd) {
|
||||
Mutex.clientsLock()
|
||||
for (i in 0...Clients.max) {
|
||||
if (Clients.isActive(i)) {
|
||||
var s = "<< [%(Clients.uid(i))] %(Clients.name(i))\r\n"
|
||||
sendMessageSelf(s, connfd)
|
||||
}
|
||||
}
|
||||
Mutex.clientsUnlock()
|
||||
}
|
||||
|
||||
// handle all communication with the client
|
||||
static handleClient(vmi) {
|
||||
if (!Clients.isActive(vmi)) {
|
||||
Fiber.abort("The client handled by VM[%(vmi)] is inactive.")
|
||||
}
|
||||
var connfd = Clients.connfd(vmi)
|
||||
var uid = Clients.uid(vmi)
|
||||
var name = Clients.name(vmi)
|
||||
System.write("<< accept ")
|
||||
Clients.printAddr(vmi)
|
||||
System.print(" referenced by %(uid)")
|
||||
var buffOut = "<< %(name) has joined\r\n"
|
||||
sendMessageAll(buffOut)
|
||||
Mutex.topicLock()
|
||||
if (topic != "") {
|
||||
buffOut = "<< topic: %(topic)\r\n"
|
||||
sendMessageSelf(buffOut, connfd)
|
||||
}
|
||||
Mutex.topicUnlock()
|
||||
sendMessageSelf("<< see /help for assistance\r\n", connfd)
|
||||
|
||||
/* receive input from client */
|
||||
var buffIn = ""
|
||||
while ((buffIn = read(connfd, bufferSize/2 - 1)) && buffIn.bytes.count > 0) {
|
||||
buffOut = ""
|
||||
buffIn = buffIn.trimEnd("\r\n")
|
||||
|
||||
/* ignore empty buffer */
|
||||
if (buffIn == "") continue
|
||||
|
||||
/* special options */
|
||||
if (buffIn[0] == "/") {
|
||||
var split = buffIn.split(" ")
|
||||
var command = split[0]
|
||||
if (command == "/quit") {
|
||||
break
|
||||
} else if (command == "/ping") {
|
||||
sendMessageSelf("<< pong\r\n", connfd)
|
||||
} else if (command == "/topic") {
|
||||
if (split.count > 0) {
|
||||
Mutex.topicLock()
|
||||
topic = split[1..-1].join(" ")
|
||||
Mutex.topicUnlock()
|
||||
buffOut = "<< topic changed to: %(topic)\r\n"
|
||||
sendMessageAll(buffOut)
|
||||
} else {
|
||||
sendMessageSelf("<< message cannot be null\r\n", connfd)
|
||||
}
|
||||
} else if (command == "/nick") {
|
||||
if (split.count > 0) {
|
||||
var newName = split[1..-1].join(" ")
|
||||
buffOut = "<< %(name) is now known as %(newName)\r\n"
|
||||
Clients.setName(vmi, newName)
|
||||
name = newName
|
||||
sendMessageAll(buffOut)
|
||||
} else {
|
||||
sendMessageSelf("<< name cannot be null\r\n", connfd)
|
||||
}
|
||||
} else if (command == "/msg") {
|
||||
if (split.count > 0) {
|
||||
var toUid = Num.fromString(split[1])
|
||||
if (split.count > 1) {
|
||||
buffOut = "[PM][%(name)] "
|
||||
buffOut = buffOut + split[2..-1].join(" ") + "\r\n"
|
||||
sendMessageClient(buffOut, toUid)
|
||||
} else {
|
||||
sendMessageSelf("<< message cannot be null\r\n", connfd)
|
||||
}
|
||||
} else {
|
||||
sendMessageSelf("<< reference cannot be null\r\n", connfd)
|
||||
}
|
||||
} else if (command == "/list") {
|
||||
buffOut = "<< clients %(Clients.count)\r\n"
|
||||
sendMessageSelf(buffOut, connfd)
|
||||
sendActiveClients(connfd)
|
||||
} else if (command == "/help") {
|
||||
buffOut = ""
|
||||
buffOut = buffOut + "<< /quit Quit chatroom\r\n"
|
||||
buffOut = buffOut + "<< /ping Server test\r\n"
|
||||
buffOut = buffOut + "<< /topic <message> Set chat topic\r\n"
|
||||
buffOut = buffOut + "<< /nick <name> Change nickname\r\n"
|
||||
buffOut = buffOut + "<< /msg <reference> <message> Send private message\r\n"
|
||||
buffOut = buffOut + "<< /list Show active clients\r\n"
|
||||
buffOut = buffOut + "<< /help Show help\r\n"
|
||||
sendMessageSelf(buffOut, connfd)
|
||||
} else {
|
||||
sendMessageSelf("<< unknown command\r\n", connfd)
|
||||
}
|
||||
} else {
|
||||
/* send message */
|
||||
buffOut = "[%(name)] %(buffIn)\r\n"
|
||||
sendMessage(buffOut, uid)
|
||||
}
|
||||
}
|
||||
|
||||
/* close connection */
|
||||
buffOut = "<< [%(name)] has left\r\n"
|
||||
sendMessageAll(buffOut)
|
||||
close(connfd)
|
||||
|
||||
/* delete client from queue and yield thread (from C side) */
|
||||
System.write("<< quit ")
|
||||
Clients.printAddr(vmi)
|
||||
System.print(" referenced by %(uid)")
|
||||
Clients.delete(vmi)
|
||||
}
|
||||
|
||||
foreign static topic
|
||||
foreign static topic=(s)
|
||||
|
||||
foreign static bufferSize
|
||||
foreign static write(connfd, buf, count)
|
||||
foreign static read(connfd, count)
|
||||
foreign static close(connfd)
|
||||
}
|
||||
353
Task/Chat-server/Wren/chat-server-2.wren
Normal file
353
Task/Chat-server/Wren/chat-server-2.wren
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
/* gcc chat_server.c -o chat_server -lpthread -lwren -lm */
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <wren.h>
|
||||
|
||||
#define MAX_CLIENTS 10
|
||||
#define BUFFER_SZ 2048
|
||||
|
||||
static _Atomic unsigned int cli_count = 0;
|
||||
static int listenfd = 0, uid = 10;
|
||||
char *script = NULL;
|
||||
|
||||
/* Client structure */
|
||||
typedef struct {
|
||||
struct sockaddr_in addr; /* Client remote address */
|
||||
int connfd; /* Connection file descriptor */
|
||||
int uid; /* Client unique identifier */
|
||||
int vmi; /* The index of the VM which handles this client */
|
||||
char name[32]; /* Client name */
|
||||
} client_t;
|
||||
|
||||
client_t *clients[MAX_CLIENTS];
|
||||
|
||||
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static char topic[BUFFER_SZ/2];
|
||||
|
||||
pthread_mutex_t topic_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
WrenVM* vms[MAX_CLIENTS]; // array of VMs
|
||||
|
||||
/* add client to queue */
|
||||
void queue_add(client_t *cl){
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
for (int i = 0; i < MAX_CLIENTS; ++i) {
|
||||
if (!clients[i]) {
|
||||
cl->vmi = i;
|
||||
clients[i] = cl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
}
|
||||
|
||||
/* Delete client from queue */
|
||||
void queue_delete(int uid){
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
for (int i = 0; i < MAX_CLIENTS; ++i) {
|
||||
if (clients[i]) {
|
||||
if (clients[i]->uid == uid) {
|
||||
clients[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
}
|
||||
|
||||
/* print ip address */
|
||||
void print_client_addr(struct sockaddr_in addr){
|
||||
printf("%d.%d.%d.%d",
|
||||
addr.sin_addr.s_addr & 0xff,
|
||||
(addr.sin_addr.s_addr & 0xff00) >> 8,
|
||||
(addr.sin_addr.s_addr & 0xff0000) >> 16,
|
||||
(addr.sin_addr.s_addr & 0xff000000) >> 24);
|
||||
}
|
||||
|
||||
/* enable Wren to handle all client communication */
|
||||
void *handle_client(void *arg) {
|
||||
client_t *cli = (client_t *)arg;
|
||||
cli_count++;
|
||||
int vmi = cli->vmi;
|
||||
WrenHandle *callHandle = wrenMakeCallHandle(vms[vmi], "handleClient(_)");
|
||||
wrenEnsureSlots(vms[vmi], 2);
|
||||
wrenGetVariable(vms[vmi], "main", "Chat", 0);
|
||||
wrenSetSlotDouble(vms[vmi], 1, (double)vmi);
|
||||
wrenCall(vms[vmi], callHandle);
|
||||
}
|
||||
|
||||
/* C <= Wren interface functions */
|
||||
|
||||
void C_max(WrenVM* vm) {
|
||||
wrenSetSlotDouble(vm, 0, (double)MAX_CLIENTS);
|
||||
}
|
||||
|
||||
void C_count(WrenVM* vm) {
|
||||
wrenSetSlotDouble(vm, 0, (double)cli_count);
|
||||
}
|
||||
|
||||
void C_isActive(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
bool res = clients[vmi] != NULL;
|
||||
wrenSetSlotBool(vm, 0, res);
|
||||
}
|
||||
|
||||
void C_connfd(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)clients[vmi]->connfd);
|
||||
}
|
||||
|
||||
void C_uid(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
wrenSetSlotDouble(vm, 0, (double)clients[vmi]->uid);
|
||||
}
|
||||
|
||||
void C_name(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
wrenSetSlotString(vm, 0, (const char *)clients[vmi]->name);
|
||||
}
|
||||
|
||||
void C_setName(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
const char *name = wrenGetSlotString(vm, 2);
|
||||
size_t size = sizeof(clients[vmi]->name);
|
||||
strncpy(clients[vmi]->name, name, size);
|
||||
clients[vmi]->name[size-1] = '\0';
|
||||
}
|
||||
|
||||
void C_clientsLock(WrenVM* vm) {
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
}
|
||||
|
||||
void C_clientsUnlock(WrenVM* vm) {
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
}
|
||||
|
||||
void C_topicLock(WrenVM* vm) {
|
||||
pthread_mutex_lock(&topic_mutex);
|
||||
}
|
||||
|
||||
void C_topicUnlock(WrenVM* vm) {
|
||||
pthread_mutex_unlock(&topic_mutex);
|
||||
}
|
||||
|
||||
void C_printAddr(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
print_client_addr(clients[vmi]->addr);
|
||||
}
|
||||
|
||||
void C_topic(WrenVM* vm) {
|
||||
wrenSetSlotString(vm, 0, (const char *)topic);
|
||||
}
|
||||
|
||||
void C_setTopic(WrenVM* vm) {
|
||||
const char *t = wrenGetSlotString(vm, 1);
|
||||
strncpy(topic, t, sizeof(topic));
|
||||
topic[sizeof(topic)-1] = '\0';
|
||||
}
|
||||
|
||||
void C_bufferSize(WrenVM* vm) {
|
||||
wrenSetSlotDouble(vm, 0, (double)BUFFER_SZ);
|
||||
}
|
||||
|
||||
void C_write(WrenVM* vm) {
|
||||
int fd = (int)wrenGetSlotDouble(vm, 1);
|
||||
const void *buf = (const void *)wrenGetSlotString(vm, 2);
|
||||
size_t count = (size_t)wrenGetSlotDouble(vm, 3);
|
||||
ssize_t res = write(fd, buf, count);
|
||||
wrenSetSlotDouble(vm, 0, (double)res);
|
||||
}
|
||||
|
||||
void C_read(WrenVM* vm) {
|
||||
char buf[BUFFER_SZ / 2];
|
||||
int fd = (int)wrenGetSlotDouble(vm, 1);
|
||||
size_t count = (size_t)wrenGetSlotDouble(vm, 2);
|
||||
ssize_t rlen = read(fd, buf, count);
|
||||
buf[rlen] = '\0';
|
||||
wrenSetSlotString(vm, 0, (const char *)buf);
|
||||
}
|
||||
|
||||
void C_close(WrenVM* vm) {
|
||||
int connfd = (int)wrenGetSlotDouble(vm, 1);
|
||||
close(connfd);
|
||||
}
|
||||
|
||||
void C_delete(WrenVM* vm) {
|
||||
int vmi = (int)wrenGetSlotDouble(vm, 1);
|
||||
client_t *cli = clients[vmi];
|
||||
queue_delete(cli->uid);
|
||||
free(cli);
|
||||
cli_count--;
|
||||
pthread_detach(pthread_self());
|
||||
}
|
||||
|
||||
WrenForeignMethodFn bindForeignMethod(
|
||||
WrenVM* vm,
|
||||
const char* module,
|
||||
const char* className,
|
||||
bool isStatic,
|
||||
const char* signature) {
|
||||
if (strcmp(module, "main") == 0) {
|
||||
if (strcmp(className, "Clients") == 0) {
|
||||
if (isStatic && strcmp(signature, "max") == 0) return C_max;
|
||||
if (isStatic && strcmp(signature, "count") == 0) return C_count;
|
||||
if (isStatic && strcmp(signature, "isActive(_)") == 0) return C_isActive;
|
||||
if (isStatic && strcmp(signature, "connfd(_)") == 0) return C_connfd;
|
||||
if (isStatic && strcmp(signature, "uid(_)") == 0) return C_uid;
|
||||
if (isStatic && strcmp(signature, "name(_)") == 0) return C_name;
|
||||
if (isStatic && strcmp(signature, "setName(_,_)") == 0) return C_setName;
|
||||
if (isStatic && strcmp(signature, "printAddr(_)") == 0) return C_printAddr;
|
||||
if (isStatic && strcmp(signature, "delete(_)") == 0) return C_delete;
|
||||
} else if (strcmp(className, "Mutex") == 0) {
|
||||
if (isStatic && strcmp(signature, "clientsLock()") == 0) return C_clientsLock;
|
||||
if (isStatic && strcmp(signature, "clientsUnlock()") == 0) return C_clientsUnlock;
|
||||
if (isStatic && strcmp(signature, "topicLock()") == 0) return C_topicLock;
|
||||
if (isStatic && strcmp(signature, "topicUnlock()") == 0) return C_topicUnlock;
|
||||
} else if (strcmp(className, "Chat") == 0) {
|
||||
if (isStatic && strcmp(signature, "topic") == 0) return C_topic;
|
||||
if (isStatic && strcmp(signature, "topic=(_)") == 0) return C_setTopic;
|
||||
if (isStatic && strcmp(signature, "bufferSize") == 0) return C_bufferSize;
|
||||
if (isStatic && strcmp(signature, "write(_,_,_)") == 0) return C_write;
|
||||
if (isStatic && strcmp(signature, "read(_,_)") == 0) return C_read;
|
||||
if (isStatic && strcmp(signature, "close(_)") == 0) return C_close;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void writeFn(WrenVM* vm, const char* text) {
|
||||
printf("%s", text);
|
||||
}
|
||||
|
||||
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
|
||||
switch (errorType) {
|
||||
case WREN_ERROR_COMPILE:
|
||||
printf("[%s line %d] [Error] %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_STACK_TRACE:
|
||||
printf("[%s line %d] in %s\n", module, line, msg);
|
||||
break;
|
||||
case WREN_ERROR_RUNTIME:
|
||||
printf("[Runtime Error] %s\n", msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char *readFile(const char *fileName) {
|
||||
FILE *f = fopen(fileName, "r");
|
||||
fseek(f, 0, SEEK_END);
|
||||
long fsize = ftell(f);
|
||||
rewind(f);
|
||||
char *script = malloc(fsize + 1);
|
||||
fread(script, 1, fsize, f);
|
||||
fclose(f);
|
||||
script[fsize] = 0;
|
||||
return script;
|
||||
}
|
||||
|
||||
void catch_ctrl_c(int sig) {
|
||||
/* clean up and exit */
|
||||
for (int i = 0; i < MAX_CLIENTS; ++i) {
|
||||
wrenFreeVM(vms[i]);
|
||||
if (clients[i]) {
|
||||
close(clients[i]->connfd);
|
||||
free(clients[i]);
|
||||
}
|
||||
}
|
||||
close(listenfd);
|
||||
free(script);
|
||||
printf("\n<[ SERVER ENDED ]>\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
WrenConfiguration config;
|
||||
wrenInitConfiguration(&config);
|
||||
config.writeFn = &writeFn;
|
||||
config.errorFn = &errorFn;
|
||||
config.bindForeignMethodFn = &bindForeignMethod;
|
||||
const char* module = "main";
|
||||
const char* fileName = "chat_server.wren";
|
||||
script = readFile(fileName);
|
||||
|
||||
/* config the VMs and interpret the script */
|
||||
for (int i = 0; i < MAX_CLIENTS; ++i) {
|
||||
vms[i] = wrenNewVM(&config);
|
||||
wrenInterpret(vms[i], module, script);
|
||||
}
|
||||
|
||||
/* prepare to start the server */
|
||||
int connfd = 0;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct sockaddr_in cli_addr;
|
||||
pthread_t tid;
|
||||
|
||||
/* socket settings */
|
||||
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
serv_addr.sin_port = htons(5000);
|
||||
|
||||
/* ignore pipe signals */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* catch ctrl-c being pressed */
|
||||
signal(SIGINT, catch_ctrl_c);
|
||||
|
||||
/* bind */
|
||||
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
|
||||
perror("Socket binding failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* listen */
|
||||
if (listen(listenfd, 10) < 0) {
|
||||
perror("Socket listening failed");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("<[ SERVER STARTED ]>\n");
|
||||
|
||||
/* accept clients */
|
||||
while (1) {
|
||||
socklen_t clilen = sizeof(cli_addr);
|
||||
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
|
||||
|
||||
/* check if max clients is reached */
|
||||
if ((cli_count + 1) == MAX_CLIENTS) {
|
||||
printf("<< max clients reached\n");
|
||||
printf("<< reject ");
|
||||
print_client_addr(cli_addr);
|
||||
printf("\n");
|
||||
close(connfd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* client settings */
|
||||
client_t *cli = (client_t *)malloc(sizeof(client_t));
|
||||
cli->addr = cli_addr;
|
||||
cli->connfd = connfd;
|
||||
cli->uid = uid++;
|
||||
sprintf(cli->name, "%d", cli->uid);
|
||||
|
||||
/* add client to the queue and fork thread */
|
||||
queue_add(cli);
|
||||
pthread_create(&tid, NULL, &handle_client, (void*)cli);
|
||||
|
||||
/* reduce CPU usage */
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
49
Task/Chat-server/Zkl/chat-server.zkl
Normal file
49
Task/Chat-server/Zkl/chat-server.zkl
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
const PORT=23;
|
||||
|
||||
var users=Dictionary(); // ( handle:socket, ...)
|
||||
pipe:=Thread.Pipe(); // how server tells thread to connect to user
|
||||
|
||||
fcn accept(pipe){ // a thread waiting for the server to send a socket
|
||||
while(socket:=pipe.read()){
|
||||
println("Somebody is connecting ...");
|
||||
socket.read(); // telnet stuff
|
||||
while(True){ // get credentials
|
||||
reg name;
|
||||
socket.write("Your handle: "); // bottle neck
|
||||
try{ name = socket.read().text.strip() } catch(IOError){ continue }
|
||||
if(users.holds(name)) socket.write("Handle is already in use.\n");
|
||||
else if(name){
|
||||
users[name] = socket;
|
||||
chat.launch(name,socket); // thread
|
||||
broadcast(name, "+++ %s arrived +++".fmt(name));
|
||||
break; // wait for next connection
|
||||
}
|
||||
}//while
|
||||
}//while
|
||||
}.launch(pipe); // thread
|
||||
|
||||
fcn chat(name,socket){ // a thread, one per user
|
||||
try{
|
||||
socket.write("^D to disconnect\n");
|
||||
while(True){
|
||||
message:=socket.read().text.strip();
|
||||
if(message=="\xff\xec") break; // ^D to disconnect.
|
||||
broadcast(name, "%s> %s".fmt(name,message));
|
||||
}
|
||||
}catch{} // eg socket pukes
|
||||
users.del(name); socket.close();
|
||||
broadcast(name, "--- %s leaves ---".fmt(name));
|
||||
}
|
||||
|
||||
// Send a message to all users from the given name.
|
||||
fcn broadcast(name, message){ // called from user thread
|
||||
println(message); // log message to server console
|
||||
users.pump(Void,'wrap([(toName,socket)]){
|
||||
if(toName != name) try{ socket.write(message + "\n") } catch(IOError){}
|
||||
});
|
||||
}
|
||||
|
||||
// Set up the server socket.
|
||||
server:=Network.TCPServerSocket.open(PORT);
|
||||
println("Listening on %s:%s".fmt(server.hostname,server.port));
|
||||
server.listen(pipe); // Main event loop
|
||||
Loading…
Add table
Add a link
Reference in a new issue