Hard Code Golf: crea una sala de chat

13

Cue Storyline: es a principios del siglo XXI, y la mayoría de las cosas se han convertido en cosa del pasado. Sin embargo, usted y sus compañeros de código-golf-eteers están en una búsqueda para recrear la década de 1990. Como parte de este desafío, debes recrear una sala de chat minimalista.

El objetivo: crear una sala de chat con el menor número de bytes posible. El programa (s) que escriba funcionará como un servidor simple, que sirve una página web, que permite a los usuarios publicar texto en la pantalla.

El objetivo real: alojar una sala de chat que funcione desde su propia computadora. No tiene que hacer esto, pero es mucho más divertido de esta manera.

Requisitos:

  • Los usuarios deberían poder darse un nombre de usuario que dure la sesión
  • Los usuarios deben poder escribir y enviar texto repetidamente, que se mostrará a otros usuarios
  • Cada usuario debe poder ver el texto enviado por todos los usuarios, junto con los nombres de usuario de los remitentes, y la información debe mostrarse en orden cronológico.
  • La página también debe mostrar el número de personas en línea y una lista de sus nombres de usuario
  • Su sala de chat debe ser accesible para cualquier persona en Internet que sepa dónde encontrarla (como conocer la dirección IP).
  • Debería funcionar en los navegadores web modernos.

¡Todo lo demás depende de ti!

Presentaciones:

  • Debe incluir el código fuente o un enlace al código fuente
  • Debe incluir capturas de pantalla de la sala de chat funcional
  • Debe incluir el tamaño total, en bytes, de todos los programas / archivos que ha escrito que son necesarios para que funcione.

Este desafío ha estado en la caja de arena por un tiempo, así que espero que todos los problemas hayan sido resueltos.

PhiNotPi
fuente
1
¿sería permisible si obligáramos a los usuarios a escribir cada una de sus respuestas en nueve segundos?
John Dvorak
Creo que 9 segundos es probablemente demasiado corto. Sin embargo, algo así como 99 segundos probablemente podría funcionar. Nunca pensé en poner límites de tiempo a los chateadores.
PhiNotPi
definir "en línea". ¿Necesitamos volver a publicar antes de la descarga, el tiempo de espera de 5 segundos será suficiente, o incluso se nos permite reclamar que las personas nunca cierren sesión?
John Dvorak
¿podemos permitir la inyección de HTML y otras cosas que podrían romper la sala de chat (siempre y cuando no dañemos nuestra propia computadora)?
John Dvorak el
En realidad, ¿puedes aclarar "escribe cada una de sus respuestas en nueve segundos?" Por "en línea", me refiero a una lista de personas que actualmente están viendo la sala de chat, como abrir la sala de chat en una ventana del navegador. Un tiempo de espera estará bien.
PhiNotPi

Respuestas:

18

PHP + JQuery + HTML + CSS, 1535 bytes

Esta es una presentación que se inclina más hacia lo que el OP consideró como 'el objetivo real'. Es decir, un servidor de chat totalmente funcional, que puede alojarse en casi cualquier servidor web en cualquier lugar.

La funcionalidad incluye:

  • Notificaciones cuando los usuarios entran o salen de la sala de chat.
  • Notificaciones cuando los usuarios cambian su alias.
  • Sondeo en tiempo real para mensajes nuevos, sin generar tráfico excesivo del servidor o carga del servidor.
  • Diseño y usabilidad muy parecidos a los clientes de chat existentes, como X-Chat.

Para ser una sesión, ingrese un alias en el cuadro correspondiente y presione Tabo Enterpara enviar. Si el alias ya está en uso, se le notificará. El envío de mensajes también se realiza a través de Enter.

Para su comodidad, puede encontrar un archivo de todos los archivos aquí: chat.zip (elija Descargar en el menú Archivo). Para instalar, descomprima en un directorio web en cualquier servidor que ejecute PHP 5.4 o superior.

Advertencias:

  • IE 8 o inferior girará en un bucle infinito durante el sondeo, porque por alguna razón desconocida para la humanidad, todas las solicitudes de Ajax se almacenan en caché de forma predeterminada. También le impide enviar el mismo mensaje dos veces y actualizar la lista de usuarios correctamente. Esto podría solucionarse agregando cache:falsea cada solicitud de Ajax.
  • En todas las versiones de IE, los mensajes no se enviarán presionando Intro, porque el changeevento no se activa (sin embargo, presionar Tabulador funciona). Esto podría solucionarse agregando un onkeypresscontrolador, verificando si la clave era Enter y luego llamando $(v).blur().focus().

En resumen, IE no es compatible.


Cliente

El posicionamiento de los elementos podría ser un poco más robusto, pero debería verse bien con un tamaño mínimo de ventana de aproximadamente ~ 800x600.

chat.htm (190 bytes)

<script src=jquery.min.js></script>
<script src=c.js></script>
<link rel=stylesheet href=c.css>
<select id=u multiple></select><pre id=o></pre>
<input id=n onchange=u()><input id=v onchange=s()>

c.css (136 bytes)

i{color:#999}
#u{float:right;height:100%;width:200px;margin-left:10px}
#o{border:1px solid #999;height:93%;overflow-y:scroll}
#v{width:54%}

c.js (435 bytes)

var l
(function p(){
  $.ajax({url:'p.php',data:{n:$('#n').val()},success:function(d){
    $('#o').html(d).scrollTop(1e4);$('#u').load('n.php');
  },complete:p,timeout:2e4})
})()
function s(){
  $.get('s.php',{n:$(n).val(),v:$(v).val()})
  $(v).val('')
}
function u(){
  $.get('u.php',{l:i=l,n:l=$(n).val()}).fail(function(){
    alert("This name is already in use!")
    $(n).val(l=i)
  })
}
$(window).on('unload',function(){$.ajax({url:'l.php',data:{l:l},async:false})})

Servidor

Pido disculpas por el servidor dividido en tantos trozos pequeños. La alternativa sería utilizar un protocolo de mensaje adecuado (a través de codificación / decodificación JSON), o tener un if ... elseif ...mensaje grande de acuerdo con las variables de publicación presentes. Al hacer scripts por separado, un simple pedido del que necesita es mucho más corto y quizás más simple que ambos.

o.php (119 bytes) O pen como conexión a la 'base de datos'

<?$m=array_slice(unserialize(file_get_contents(m)),-300);
$u=unserialize(file_get_contents(u));$t=time();extract($_GET);

c.php (57 bytes) C omite cambios en la 'base de datos'

<?foreach([u,m]as$c)file_put_contents($c,serialize($$c));

p.php (151 bytes) P olls para mensajes nuevos

<?for($t=time();@filemtime(m)<$t;usleep(1e3))clearstatcache();include('o.php');
foreach($m as$v)if($n&&$v[0]>=$u[$n])echo@date("[H:i]",$v[0])."$v[1]\n";

s.php (62 bytes) S finaliza un mensaje al servidor

<?include('o.php');$m[]=[$t,"<b>$n</b>: $v"];include('c.php');

u.php (222 bytes) T inscripción Ser o cambio de alias

<?include('o.php');if(!trim($n)||$u[$n])exit(header('HTTP/1.1 418'));
$m[]=[$t,$u[$l]?
"<i><b>$l</b> is now known as <b>$n</b>.</i>":
"<i><b>$n</b> has entered the chat.</i>"];
$u[$n]=$u[$l]?:$t;unset($u[$l]);include('c.php');

n.php (65 bytes) recupera la lista de usuario n Ames

<?include('o.php');foreach($u as$k=>$v)echo"<option>$k</option>";

l.php (98 bytes) El usuario tiene l eft (cerró su navegador)

<?include('o.php');$m[]=[$t,"<i><b>$l</b> has left the chat.</i>"];
unset($u[$l]);include('c.php');
primo
fuente
Creo que puedes onchange=uprescindir de los paréntesis. Sin embargo, no obtendrá un contexto coherente, pero de todos modos no lo necesita.
John Dvorak el
¿Puedes hacer el tutorial un poco más detallado? Quiero configurar esto en una Mac.
haykam
@ Maní Escribí algunas instrucciones: codepad.org/UKGwb4g2 . Estoy trabajando a ciegas, pero esto probablemente funcionará.
primo
13

Python, 230

Esto es bastante mínimo, pero parece estar a la altura. Los usuarios se cuentan como "viendo la página" si han chateado en los últimos 99 segundos.

import cherrypy as S,time
@S.quickstart
@S.expose
def _(n='',p='',l=["<form%sn value='%s'%sp%s'' type=submit>"],u={},t="><input name="):u[n]=time.time();l+=p and[n+':'+p];return'<br>'.join([k*(u[n]-99<u[k])for k in u]+l)%(t,n,t,t)

Utiliza uno de mis trucos favoritos en Python: los valores predeterminados son solo referencias a lo que haya pasado. Si se trata de un objeto mutable, simplemente aparece para el viaje.

Otro que no uso con frecuencia: ¡curry!

Ejecutando el servidor:

Ejecute el script de chat desde python (por ejemplo python chat.py) y luego apunte su navegador http://localhost:8080para ver algo como

captura de pantalla

Python, 442

Este es realmente agradable de usar. Esto es golf, así que considero que es una solución menos satisfactoria. Ahora, abuso de un iframe y un formulario con manejo de teclas ... y una meta actualización para sondear el contenido nuevo.

import time,cherrypy as S
class C:
 c=S.expose(lambda s:"<form action=w target=t method=post><input name=n><input name=p onkeyup='if(event.keyCode==13){this.form.submit();this.value=\"\"}'><br><iframe name=t width=640>")
 @S.expose
 def w(s,n='',p='',l=[],u={}):u[n]=time.time();l+=p and[n+':'+p];return'<meta http-equiv=refresh content="1;url=w?n=%s">'%n+','.join(k for k in u if(u[n]-9<u[k])*k)+'<hr>'+'<br>'.join(l[::-1])
S.quickstart(C())

versión 2

boothby
fuente
2
Dudo que pueda apuntar mi navegador http://localhost:8080/c y acceder a su servidor HTTP
John Dvorak
1
@ JanDvorak Es por eso que no hice ese enlace.
stand
1
Para aquellos que ya tienen un servicio que se ejecuta en el puerto 8080, puede anteponer lo siguiente para usar un puerto diferente:S.config.update({'server.socket_port':8090})
primo
¿Qué tan difícil sería actualizar la ventana de chat cuando alguien envía un nuevo mensaje, y no solo el usuario? (En su forma actual, para verificar si hay mensajes nuevos, debe enviar un mensaje en blanco antes de que se actualice su ventana.)
primo
1
@primo ¡Correcto! Así es como se verifica si la gente ha dicho algo. El problema dice que recrea los años 90. Y en aquel entonces, esperar que sus usuarios aceptaran la interfaz sugerida por el código más simple todavía era genial. HP nos dio RPN, y nos gustó . Pensar como un 201 * -er te da 1280 caracteres de hinchazón.
stand
5

Meteorito: 575 caracteres

¡Me divertí mucho con este! La aplicación está en vivo en http://cgchat.meteor.com/ .

chat.html: 171 caracteres

<body>{{>b}}</body><template name="b">{{#if l}}Online: {{#each u}}{{n}}, {{/each}}<hr>{{#each m}}{{n}}: {{t}}<p>{{/each}}<hr><input>{{else}}Name: <input>{{/if}}</template>

lib / chat.js: 45 caracteres

c=Meteor.Collection;u=new c('u');m=new c('m')

client / client.js: 359 caracteres

j=$.now;s=Session;t=Template.b;t.events({'change input':function(){v=$('input').val();s.get('u')?(m.insert({n:s.get('u'),t:v}),u.update(u.findOne({n:s.get('u')})._id,{$set:{l:j()}})):(s.set('u',v),u.insert({n:v,l:j()}))}});t.l=function(){return !!s.get('u')};t.u=function(){return u.find({l:{$gt:(j()-20000)}}).fetch()};t.m=function(){return m.find().fetch()}
Pieter Bos
fuente
Link ahora está muerto.
programmer5000
5

Nodo / Meteor javascript + html + css + websocket: 1,105 bytes

Aquí hay uno usando node.js / meteor . Obviamente escrito en js, en tiempo real, y usando websockets. Utiliza los paquetes integrados predeterminados de meteor.

Podría ser mucho más pequeño. También es persistente a través del mongo incluido (no es que eso sea algo bueno).

Una captura de pantalla de trabajo:

ingrese la descripción de la imagen aquí

Para ejecutar, instala meteorito.

Linux:

curl https://install.meteor.com | /bin/sh`

Windows: win.meteor.com

Clona mi repositorio y ejecuta meteorito:

git clone http://github.com/bradgearon/meteor-chat
cd meteor-chat
meteor

apunte su navegador a localhost: 3000

chat.js: 703 bytes (cliente / servidor):

l='subscribe',d=[],n='n',i='i',b='b',c='click #',r='return ',u='u',y=0
f=Function,m=Meteor,o=m.Collection,p=new o(b),t=new o(u)
w=f('t.remove({i:d.pop()})'),g=f('_(d.length).times(w)')
m.isClient&&(h=Template.h,e=h.events={},m[l](b),m[l](u),s=Session,
w=f(r+'s.get(i)'),h.p=f(r+'p.find()'),h.t=f(r+'t.find()'),a=f('a','a','y=$("#3").val(),s.set(i,1)'),
e[c+'2']=f('p.insert({c:(y||"?")+": "+$("#l").val()})'),
e[c + '4'] = f('w()||m.call("x",$("#3").val(),t._connection._lastSessionId,a)')
)||(
m.startup(f('t.remove({}),p.remove({}),m.setInterval(g,100)')),j=f('h=this.id;h&&d.push(h)'),
m.methods({x:f('k','d','s=m.default_server.sessions[d].socket,s.on("close",j),t.insert({n:k,i:s.id})')}))

chat.css: 132 bytes

g{display:block;overflow-y:scroll;margin:10px;}
n{float:right;width:40%;min-height:100%;}
d{float:left;width:60%;min-height:100%;}

chat.html: 270 bytes

<body>
    {{> h}}
</body>
<template name="h">
<d>
<g>{{#each p}}{{c}}<br />{{/each}}</g>
<input id=l>{{this.k}}</input>
<input type=submit id=2 />
</d>
<n>
<g>{{#each t}}{{n}}<br />{{/each}}</g>
<input id=3 />
<input type=submit id=4 />
</n>
</template>
beeradg
fuente
1
Bienvenido a codegolf! Ese archivo chat.htmlparece tener solo 254 bytes. Tenga en cuenta que los navegadores no son terriblemente exigentes: no me molesto en cerrar las etiquetas y definitivamente no necesita la barra al final de las etiquetas (a menos que el nodo lo requiera). ¡Además, mata más espacios en blanco! Veo un par en el javascript, y demasiado en el html.
stand