Hard Code Golf: Crie uma sala de chat

13

Cue Storyline: É o início do século 21, e a maioria das coisas se tornou coisa do passado. Você e seus colegas jogadores de código de golfe, no entanto, estão em uma missão para reencenar os anos 90. Como parte desse desafio, você deve recriar uma sala de bate-papo minimalista.

O objetivo: criar uma sala de bate-papo com o mínimo de bytes possível. Os programas que você escreve devem funcionar como um servidor simples, que serve uma página da Web, que permite aos usuários postar texto na tela.

O objetivo real: Realmente hospedar uma sala de chat em funcionamento a partir do seu próprio computador. Você não precisa fazer isso, mas é muito mais divertido assim.

Requisitos:

  • Os usuários devem poder fornecer um nome de usuário que dure pela sessão
  • Os usuários devem poder digitar e enviar repetidamente texto, que será exibido para outros usuários
  • Cada usuário deve poder ver o texto que é enviado por todos os usuários, juntamente com os nomes de usuários dos remetentes, e as informações devem ser exibidas em ordem cronológica
  • A página também deve exibir o número de pessoas on-line e uma lista de seus nomes de usuário
  • Sua sala de bate-papo deve estar acessível a qualquer pessoa na internet que saiba onde encontrá-la (como saber o endereço IP).
  • Ele deve funcionar em navegadores modernos.

Tudo o resto é com você!

Submissões:

  • Deve incluir o código fonte ou um link para o código fonte
  • Deve incluir capturas de tela da sala de chat funcional
  • Deve incluir o tamanho total, em bytes, de todos os programas / arquivos que você escreveu, necessários para fazê-lo funcionar.

Esse desafio está na caixa de areia há um tempo, então, espero que todas as dobras tenham sido resolvidas.

PhiNotPi
fonte
1
seria permitido se forçássemos os participantes a digitar cada uma de suas respostas em nove segundos?
John Dvorak
Eu acho que 9 segundos provavelmente é muito curto. Algo como 99 segundos provavelmente poderia funcionar, no entanto. Eu nunca pensei em colocar limites de tempo nas conversas.
PhiNotPi 4/08/13
defina "online". Precisamos postar novamente antes da descarga, o tempo limite de 5s será suficiente ou podemos reivindicar que as pessoas nunca saiam?
John Dvorak
podemos permitir a injeção de HTML e outras coisas que podem quebrar a sala de bate-papo (desde que não danifiquemos nosso próprio computador)?
John Dvorak
Na verdade, você pode esclarecer "digite cada uma das respostas em nove segundos?" Por "online", eu significaria uma lista de pessoas que atualmente estão visualizando a sala de bate-papo, como abrir a sala de bate-papo em uma janela do navegador. Um tempo limite será bom.
PhiNotPi

Respostas:

18

PHP + JQuery + HTML + CSS, 1535 bytes

Esta é uma submissão que se inclina mais para o que o OP considerou como 'o objetivo real'. Ou seja, um servidor de bate-papo totalmente funcional, que pode ser hospedado em praticamente qualquer servidor Web em qualquer lugar.

A funcionalidade inclui:

  • Notificações quando os usuários entram ou saem da sala de bate-papo.
  • Notificações quando os usuários alteram seu alias.
  • Pesquisa em tempo real para novas mensagens, sem gerar excesso de tráfego ou carga no servidor.
  • Layout e usabilidade muito semelhantes aos clientes de bate-papo existentes, como o X-Chat.

Para ser uma sessão, insira um alias na caixa apropriada e pressione Tabou Enterpara enviar. Se o alias já estiver em uso, você será notificado. O envio de mensagens também é feito via Enter.

Para sua conveniência, um arquivo de todos os arquivos pode ser encontrado aqui: chat.zip (escolha Download no menu Arquivo). Para instalar, descompacte em um diretório da web em qualquer servidor executando o PHP 5.4 ou superior.

Ressalvas:

  • O IE 8 ou inferior girará em um loop infinito durante a pesquisa, porque, por algum motivo desconhecido para a humanidade, todas as solicitações do Ajax são armazenadas em cache por padrão. Também impede que você envie a mesma mensagem duas vezes e atualize a lista de usuários corretamente. Isso pode ser corrigido adicionando cache:falsea cada solicitação do Ajax.
  • Em todas as versões do IE, as mensagens não serão enviadas pressionando Enter, porque o changeevento não é acionado (pressionar Tab, no entanto, funciona). Isso poderia ser corrigido adicionando um onkeypressmanipulador, verificando se a chave era Enter e depois chamando $(v).blur().focus().

Em suma, o IE não é suportado.


Cliente

O posicionamento dos elementos pode ser um pouco mais robusto, mas deve ficar bem com um tamanho mínimo de janela 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

Peço desculpas pelo servidor estar dividido em tantos pequenos pedaços. A alternativa seria usar um protocolo de mensagem adequado (via JSON codificar / decodificar) ou ter um grande de if ... elseif ...acordo com o qual as variáveis ​​de postagem estão presentes. Criando scripts separados, basta solicitar o que você precisa é muito mais curto e talvez mais simples que os dois.

o.php (119 bytes) O canetas como conexão com o 'banco de dados'

<?$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 alterações no 'banco de dados'

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

p.php (151 bytes) P olls para novas mensagens

<?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 uma mensagem para o servidor

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

u.php (222 bytes) L registo Ser ou mudança 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 a lista de utilizador n ames

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

l.php (98 bytes) Usuário l eft (fechou o navegador)

<?include('o.php');$m[]=[$t,"<i><b>$l</b> has left the chat.</i>"];
unset($u[$l]);include('c.php');
primo
fonte
Eu acho que você pode ficar onchange=usem os parênteses. Você não terá um contexto consistente, no entanto, mas não precisará disso.
John Dvorak
Você pode tornar o tutorial um pouco mais detalhado? Eu quero configurar isso em um Mac.
haykam
@ Amendoim, digitei algumas instruções: codepad.org/UKGwb4g2 . Estou trabalhando às cegas, mas isso provavelmente funcionará.
Primo
13

Python, 230

Isso é mínimo, mas parece estar dentro das especificações. Os usuários são contados como "visualizando a página" se tiverem conversado nos ú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)

Isso usa um dos meus truques favoritos em python: os valores padrão são apenas referências ao que você passou. Se é um objeto mutável, ele apenas aparece.

Outro que eu não uso com frequência - curry!

Executando o servidor:

Execute o script de bate-papo a partir de python (por exemplo python chat.py) e aponte o navegador http://localhost:8080para ver algo como

captura de tela

Python, 442

Este é realmente bom de usar. Isso é golfe, então considero isso uma solução menos satisfatória. Agora, eu abusei de um iframe e de um formulário com manipulação de teclas ... e uma meta atualização para pesquisar novos conteúdos.

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())

versão 2

boothby
fonte
2
Eu duvido que eu posso apontar meu navegador no http://localhost:8080/c e acessar o servidor HTTP
John Dvorak
1
@JanDvorak Foi por isso que não fiz disso um link.
usar o seguinte código
1
Para aqueles que já possuem um serviço em execução na porta 8080, você pode acrescentar o seguinte para usar uma porta diferente:S.config.update({'server.socket_port':8090})
primo
Quão difícil seria atualizar a janela de bate-papo quando alguém envia uma nova mensagem, e não apenas o usuário? (Na sua forma atual, a fim de verificar se existem novas mensagens, você precisa enviar uma mensagem em branco antes de sua janela é atualizada.)
primo
1
@primo Right! É assim que você verifica se as pessoas disseram alguma coisa. O problema dizia reencenar os anos 90. E naquela época, esperar que seus usuários aceitassem a interface sugerida pelo código mais simples ainda era legal. A HP nos deu RPN e gostamos . Pensando como um 201 * -er você obtém 1280 caracteres de inchaço.
usar o seguinte comando
5

Meteoro: 575 caracteres

Eu me diverti muito com este! O aplicativo está disponível em 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
fonte
Link agora está morto.
programmer5000
5

Javascript do nó / meteoro + html + css + websocket: 1.105 bytes

Aqui está um usando node.js / meteor . Obviamente escrito em js, em tempo real e usando websockets. Usa os pacotes internos padrão do meteoro.

Poderia ser muito menor. Também é persistente por meio do mongo incluído (não que isso seja uma coisa boa).

Uma captura de tela de trabalho:

insira a descrição da imagem aqui

Para executar, instale o meteoro.

Linux:

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

Windows: win.meteor.com

Clone meu repositório e execute o meteoro:

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

aponte seu navegador para 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
fonte
1
Bem-vindo ao codegolf! Esse arquivo chat.htmlparece ter apenas 254 bytes. Observe que os navegadores não são muito exigentes - não me preocupo em fechar as tags e você definitivamente não precisa da barra no final das tags (a menos que o nó exija isso). Além disso, mate mais espaço em branco! Eu vejo um par no javascript, e muito no html.
Boothby