Linguagem: C++ com cola lógica Lua.
O código foi testado para compilar e executar no Ubuntu x86, Ubuntu x86_64 e Gentoo x86_64, desde que a versão adequada do LuaJIT seja usada. Modificações na libjansson para remover a formatação forçada de floats com .0 após números inteiros foram feitas para suportar adequadamente "inteiros" e ainda ter conversão automática de Lua, que suporta apenas duplos.
Ele também compila no Ubuntu 12.04 LTS x86_64, visto que libjansson e google-glog são construídos manualmente.
LuaJIT
libev
evhttpclient
google-glog
google-perftools (tcmalloc) - Opcional com pequenas modificações na fonte e no makefile
libjansson
contratado
libicu - veja o gerenciador de pacotes local
curl - veja o gerenciador de pacotes local
boost - Opcional se você substituir os ponteiros intrusivos por algo de sua preferência.
Provavelmente serão necessárias modificações em src/Makefile para refletir suas pastas de instalação. Um sistema de construção mais robusto é bem-vindo, mas não era necessário no momento em que o projeto foi escrito. (CMake?)
Eu (@zwagoth) aprendi uma coisa aqui: Sempre faça comentários na hora de escrever. Para compensar isso documentarei a estrutura básica do programa para auxiliar na compreensão.
Desculpas pela bagunça de uma base de código. Este também foi um dos meus primeiros projetos C++ de qualquer escala e complexidade.
Contém quase toda a lógica principal para manipulação de mensagens de protocolo, mensagens RTB e vários retornos de chamada de eventos básicos, como conexão e desconexão.
O arquivo contém tabelas de funções anônimas nomeadas de acordo com os eventos que elas manipulam. Este arquivo não deve armazenar nenhum estado e é considerado apenas uma área de armazenamento lógico. O design básico deste arquivo é permitir a lógica de colagem sem forçar Lua a fazer qualquer trabalho pesado e minimizar a quantidade de dados que são transferidos para dentro e para fora de Lua ao custo de mais chamadas de função para C++.
Existem quatro tabelas injetadas no namespace de arquivo global com nomes curtos para facilitar a digitação:
u
: funções de conexão/caractere (usuário)
s
: funções de servidor/estado global
c
: funções de estado do canal
const
: ids de erro e valores constantes
As funções de retorno de chamada do protocolo aceitam dois parâmetros, a conexão à qual o comando está associado e uma cópia da tabela dos argumentos json fornecidos.
As conexões são números opacos e NÃO devem ser modificadas de forma alguma. Alterar o valor de uma conexão não é seguro. Você foi avisado.
Um arquivo lua de variáveis de configuração que são usadas durante a inicialização e operação do daemon de chat.
Um servidor de políticas flash minimalista. Se você precisa de suporte a Flash, é isso que você executa. Personalize a política embutida de acordo com suas necessidades.
Ponto de entrada do programa. Lida com a inicialização de threads de segundo plano e curl.
Faz muitas coisas. O fluxo de código começa em Server::run()
.
O fluxo de conexão é o seguinte:
listenCallback handshakeCallback connectionWriteCallback connectionReadCallback connectionwriteCallback
listenCallback
configura manipuladores de eventos por conexão e passa o fluxo para ...
handshakeCallback
, que lida com leituras para handshakes de websocket.
connectionWriteCallback
trata quando uma conexão está pronta para ser gravada e é habilitada quando itens estão na fila para serem gravados na conexão. Lida com buffer.
connectionReadCallback
lida com todos os eventos de leitura quando a fase de handshake termina. Toda a análise de protocolo acontece aqui e os comandos são despachados e executados de dentro desta função.
pingCallback
lida com o envio de eventos de ping aos clientes. Se o protocolo for alterado, esta deve ser uma das primeiras coisas a serem feitas.
connectionTimerCallback
é acionado periodicamente e verifica se a conexão está inoperante e a limpa.
runLuaEvent
é uma magia de salamandra. Também onde a mágica acontece para cada comando. É aqui que cada comando muda para o código Lua do código C++. Lida com todos os estados Lua e o retorno de chamada para garantir que Lua não seja pega em um loop infinito. Lida com erros de impressão de dentro de Lua.
Este arquivo armazena todos os dados de estado relacionados a canais, conexões, banimentos e moderação.
As conexões são divididas entre identificadas e não identificadas, pois os nomes dos caracteres não são conhecidos até que o servidor de login valide que eles existem e os mantenha fora do conjunto de caracteres que podem ser pesquisados por nome.
Lida com o salvamento e a restauração do estado no disco.
É executado como um thread em segundo plano que processa solicitações e respostas de login e as repassa ao thread principal.
Sistema de login serializado, usa fila de login global. Isso poderia ser melhorado um pouco.
A conversão para curl_multi seria boa, mas envolve alguma interação divertida com libev ou muitas pesquisas cegas. As filas devem ser bloqueadas antes de serem acessadas, devido ao encadeamento.
Classe básica de canal, mantém dados de estado sobre um canal durante sua vida útil. Todas as ações de baixo nível relacionadas aos canais acontecem neste arquivo através de ganchos em Lua. Geralmente envolvido em um ponteiro intrusivo para gerenciar o tempo de vida da instância.
É aqui que acontece a serialização e desserialização de canais do json.
Lida com todas as redes de conexão e depura estados Lua.
Mantém listas de torções, status, mensagem de status e gênero.
Mantém lista de ignorados e amigos.
Alças por aceleradores de conexão.
É aqui que ocorre o buffer dos dados de saída.
Geralmente transmitido usando ponteiros instrutivos para gerenciar o tempo de vida da instância.
Mantém uma lista interna de quais canais foram associados. Isso deve ser mantido sincronizado com a lista real de usuários do canal.
Este arquivo é reservado para algumas funções que exigem velocidade bruta em vez de serem personalizáveis. Lida com o comando de login ( IDN
). Lida com o comando de depuração ( ZZZ
). Lida com o comando de pesquisa ( FKS
).
Todos os comandos do wrapper Lua que se enquadram na categoria s
em arquivos Lua.
Todos os comandos do wrapper Lua que se enquadram na categoria u
em arquivos Lua.
Todos os comandos do wrapper Lua que se enquadram na categoria c
em arquivos Lua.
Todos os valores do wrapper Lua que se enquadram na categoria const
nos arquivos Lua.
Mensagens de erro e definições.
Use as macros definidas para verificação de erros e tipos! Esta é a única maneira de evitar falhas se o tipo incorreto for passado inesperadamente como dados leves para uma função.
Certifique-se de que sua pilha Lua esteja equilibrada. Esforcei-me muito para ter certeza de que isso era verdade, mas erros são fáceis de cometer.
Evite retornar tabelas para código Lua, elas são caras para construir e geralmente têm um curto período de uso. Use o bom senso para equilibrar o custo das chamadas de função e o custo da construção de tabelas.
Evite passar strings para Lua desnecessariamente. Pode ser caro devido às cópias de memória.
Abuse do fato de lua aceitar vários valores de retorno como um recurso nativo. Veja acima duas notas.
Lida com o thread redis somente push. É um pequeno wrapper em torno dos comandos redis e seus valores de retorno.
Usa uma fila de entrada para receber comandos. Os comandos são executados periodicamente e não têm garantia de confiabilidade. Pode ser desabilitado e ignora a entrada quando desabilitado.
gdb funciona bem para depurar este aplicativo. Desabilitar o tcmalloc e a seção JIT do LuaJIT deve ajudar muito na depuração de travamentos (o tcmalloc pode ocultar alguns pequenos danos no heap).
As ferramentas de perfil de memória no tcmalloc são muito boas. Consulte a documentação do tcmalloc para obter mais informações sobre como usá-lo.