O arquivo de configuração pss.json

A página descreve o formato do arquivo pss.json: como o documento é construído, o que o serviço aceita ao lê-lo e o que se perde ao gravá-lo. Ela é dirigida a quem edita o arquivo diretamente ou transfere as configurações para outro nó.

Uma edição do arquivo entra em vigor a partir da próxima inicialização. Para alterar a configuração de um serviço em funcionamento, use a interface web ou a API HTTP (Gerenciamento pela API HTTP) — só elas aplicam uma alteração imediatamente e informam o resultado.

Os procedimentos passo a passo de edição, verificação e transferência — Editar, verificar e transferir as configurações.

O que é este arquivo

pss.json é o arquivo de configuração em uso, no diretório /opt/pss/config. A ordem de carregamento, o recuo para pss_back.json e pss_default.json e o repositório de arquivos danificados no diretório bad/ estão descritos em Comportamento na inicialização e em erros de configuração.

Uma consequência dessa ordem precisa ser lembrada antes de abrir o arquivo em um editor: um único valor inaceitável custa todos os fluxos. O arquivo não é consertado por partes — ele é rejeitado por inteiro, e o recuo leva a pss_default.json, no qual não há fluxo nenhum. A cópia de segurança pss_back.json existe apenas onde as configurações foram restauradas ao menos uma vez pela interface web (Manutenção); o serviço não mantém uma cópia regular. É justamente por isso que o arquivo é verificado antes de o serviço lê-lo.

O arquivo não é uma descrição completa da configuração: nele ficam guardadas apenas as diferenças em relação aos valores com os quais o produto foi compilado. O que disso decorre está na seção seguinte; é o mais importante a entender antes de editar.

No mesmo diretório está o pss.properties — os parâmetros globais do processo (caminhos para os dados e para os logs e afins). É um arquivo «chave=valor» com sintaxe própria, não tem relação com JSON, e nada do que foi dito aqui se aplica a ele.

No arquivo estão apenas as diferenças em relação aos valores padrão

Ao gravar o arquivo, o serviço omite todo valor simples que coincida com o valor padrão. São salvas apenas as diferenças.

Disso decorrem três coisas, cada uma das quais ocorre na prática:

  • Pelo arquivo não dá para saber como o serviço está configurado. Uma chave ausente significa o valor padrão, e esse valor não está escrito em lugar nenhum do arquivo. Para ler a configuração vigente por inteiro, solicite-a ao serviço em funcionamento pela API HTTP: ali são devolvidas todas as chaves, inclusive as que ficaram no seu valor padrão.

  • Gravar uma chave com o seu valor padrão é inútil. Esse valor é aceito e, na próxima gravação do arquivo, desaparece.

  • Uma mudança do valor padrão entre versões altera o comportamento em silêncio. Se o nó nunca redefiniu essa chave, ela não está no arquivo — e após uma atualização ela passará a funcionar com o novo padrão desde a primeira inicialização, sem que o arquivo diga nada a respeito. Esse é o principal risco ao transferir configurações entre versões, e pelo próprio arquivo ele não é detectado. Só há uma maneira de ver essa mudança: ler a configuração vigente das duas versões pela API HTTP, onde também são devolvidos os valores padrão.

A omissão diz respeito apenas a valores isolados. As próprias seções e listas são sempre gravadas, mesmo quando nada resta dentro: "user-default": {} é uma seção cujas chaves estão todas nos seus valores padrão, e "accept-stream": [] é uma lista vazia gravada pela mesma regra. Colchetes vazios não dizem nem que a configuração foi definida, nem que foi omitida: atenha-se ao significado da chave em questão.

Estrutura do documento

O documento é um único objeto JSON. Os seus membros de primeiro nível são as seções de configurações:

Seção

Tipo

O que descreve

server

objeto

O nome e o papel do nó, o registro em log, a manutenção.

cluster

objeto

Meshwork: os endereços, nomes e segredos dos nós vizinhos.

user-default

objeto

Reservada, ainda não contém chaves.

user

array

As contas dos receptores de fluxos e dos parceiros.

web-server

objeto

A interface web e as suas contas.

http-server

objeto

A distribuição dos fluxos por HTTP.

epg-server

objeto

A distribuição do guia de programação.

cs

objeto

Servidores externos de gerenciamento de assinantes.

mosaic

objeto

Ativação do mosaico.

epg

objeto

A coleta do guia de programação e as suas fontes.

alerter

objeto

Os limiares dos alertas e os endereços de entrega.

acme

objeto

A obtenção automática de certificados.

dvb-adapter

array

Placas de recepção DVB.

dvr-storage-list

objeto

Armazenamentos do arquivo DVR.

stream

array

Fluxos.

stream-adaptive

array

Grupos de bitrate adaptativo.

Os arrays de primeiro nível sempre contêm objetos. Dentro das seções e das entradas também aparecem listas simples de valores — números e cadeias; sobre elas veja Os arrays pareados são correspondidos por posição. Os objetos dos arrays contêm, por sua vez, arrays aninhados de objetos, por isso a maior profundidade do documento é de três níveis:

stream[]  ->  input[]   ->  as chaves de uma entrada
          ->  output[]  ->  as chaves de uma saída

As chaves das seções simples são todas opcionais, e a ausência de uma seção inteira não é um erro.

As entradas de array são a exceção. Além de id, cada entrada precisa levar as suas chaves de ancoragem: um fluxo — stream-name; uma entrada e uma saída — type e o endereço ou caminho do transporte escolhido; uma placa de recepção — name; um armazenamento — name e dir-path; uma conta da interface web e do guia de programação — login e password; uma fonte do guia — name e source. Omitir qualquer uma delas descarta o arquivo inteiro. O esquema verifica essas chaves, portanto uma verificação antes da inicialização apanhará uma entrada assim.

A referência de cada chave — o tipo, a faixa e o valor padrão de cada uma — está no documento de referência da API HTTP (Documentos de referência). Aqui ela não é repetida de propósito: duas cópias de uma mesma referência divergem em uma única versão.

O que o serviço faz ao ler o arquivo

A leitura é deliberadamente desigual: em uns casos o serviço perdoa o erro, em outros rejeita o arquivo inteiro — a sua primeira tarefa é levantar o nó. É aí exatamente que está a diferença entre um erro de digitação que você vai perceber e um que não vai.

É aceito, mas não como pretendia quem editou

O que há no arquivo

O que o serviço faz

Chave desconhecida

É ignorada. No log é escrito um aviso com o nome da chave e da seção a que ela se dirige (para uma entrada de array é nomeado o array, e não a entrada em si). A configuração que você queria alterar simplesmente não muda, e um erro de digitação no nome de uma chave não aparece enquanto o log não for lido. Do arquivo a chave desaparece na próxima gravação da configuração, mas por si só não provoca uma gravação e pode ficar muito tempo no arquivo.

Falta uma chave

Vale o valor padrão. Não é um erro.

Falta uma seção

Todas as suas chaves assumem os valores padrão. Não é um erro.

A mesma chave duas vezes em uma seção

A última vence em silêncio. Nem erro nem aviso.

Um número, ou true e false, entre aspas

É aceito: o valor é lido como texto e analisado. O esquema, porém, rejeitará esse valor, por isso números e indicadores são escritos sem aspas.

Um número fora da faixa

É levado ao limite mais próximo, com um aviso no log que indica a chave, o valor lido e o limite aplicado. Após o carregamento, o serviço regrava o arquivo com o valor corrigido, por isso na próxima inicialização o aviso não se repete. O mesmo valor enviado pela API HTTP não é corrigido, e sim rejeitado com erro.

Um array onde se espera um valor único

É ignorado por completo, sem uma única linha no log. A configuração permanece no valor padrão e nenhum diagnóstico aparece.

Os erros de forma em torno das listas e uma chave repetida são os casos que passam em completo silêncio: o log não dirá nada sobre eles. São eles o principal argumento a favor de verificar o arquivo pelo esquema antes da inicialização.

Nota

Também é desconhecida uma chave que esta compilação não suporta. Em um nó cuja compilação não sabe receber DVB, a seção dvb-adapter de um arquivo transferido torna-se desconhecida por inteiro: um aviso no log — e na próxima gravação ela desaparece do arquivo.

É rejeitado junto com todo o arquivo

Cada um desses casos interrompe o carregamento. O arquivo é movido para o diretório bad/ e o serviço passa ao arquivo seguinte na ordem (Comportamento na inicialização e em erros de configuração).

O que há no arquivo

Explicação

Um erro de sintaxe JSON

Qualquer um.

Um valor null

Em qualquer lugar e para qualquer chave. null nunca é aceito: para devolver uma configuração ao seu valor padrão, apaga-se a chave.

Uma forma de valor incorreta

Um objeto onde se espera um valor único; um valor único onde se espera um objeto ou uma lista de objetos.

Um número ou outra palavra em lugar de um indicador

As chaves lógicas só aceitam true e false — entre aspas ou sem. Nem 1 e 0, nem "yes" e "no" são aceitos.

Uma cadeia mais longa que o permitido

Os limites de comprimento, ao contrário das faixas numéricas, nunca são truncados.

Um número fracionário onde é preciso um inteiro

O valor não é analisado como inteiro e o carregamento é interrompido. O mesmo para uma cadeia que não é lida como número.

Uma entrada de array sem chave de ancoragem

Além de id, uma entrada precisa levar as suas próprias chaves obrigatórias (Estrutura do documento).

Uma entrada de array sem id

O identificador é obrigatório. A exceção é o array stream: ali um id ausente é lido como 0, e esse é um valor admissível, por isso só a segunda entrada sem identificador será rejeitada, como repetição.

Um id repetido

Duas entradas de um mesmo array com o mesmo identificador.

A repetição de um valor declarado único

Vários arrays exigem que uma chave seja única entre as suas entradas: nomes de contas, nomes e caminhos dos armazenamentos, nomes de fluxos, endereços das fontes e outros.

Um valor vazio onde é preciso texto

Dentro das entradas de array essa exigência é estrita; nas seções simples ela não é observada em toda parte, e não convém confiar nessa tolerância.

Um valor que não passou na verificação da seção

Algumas seções verificam os seus valores como um todo, e essa verificação também interrompe o carregamento: caracteres não admitidos ou excesso de comprimento no nome do nó e no nome do domínio, um nível de log desconhecido, um domínio adicional mal escrito, um número divergente de entradas nos arrays pareados do Meshwork, um comprimento divergente das listas de nomes e de valores das variáveis de ambiente.

O log faz parte do procedimento

Os erros da primeira tabela não impedem a inicialização; os da segunda a interrompem. O único lugar onde os primeiros são visíveis é o log após a primeira inicialização. Qualquer linha sobre uma chave ignorada ou um valor levado ao limite significa que o arquivo diz outra coisa que não o que você escreveu nele.

Regras que não se veem no arquivo

São propriedades da leitura, não da sintaxe. O arquivo pode ser um JSON impecável, passar por todas as verificações da seção anterior e, ainda assim, significar algo diferente do que aparenta.

A ordem das chaves dentro de um objeto importa

As chaves são aplicadas na ordem em que estão escritas. Em vários lugares uma chave determina que chaves existem adiante na mesma entrada e, por isso, precisa vir antes delas. Uma chave escrita acima da sua chave determinante ainda não está reconhecida no momento da leitura e é descartada como desconhecida — com um aviso no log e sem erro de carregamento.

É assim que funcionam:

  • type em uma entrada de entrada ou de saída — escolhe o transporte e tudo o que lhe diz respeito;

  • mpts e stream-name em uma entrada de fluxo. O mpts escolhe o tipo de fluxo e precisa preceder, entre outras coisas, os arrays input e output, enquanto o stream-name abre os parâmetros de OTT, do arquivo e do multiplex se a chave mpts não estiver na entrada. O valor padrão da chave enable-mosaic, herdado de mpts, é definido em definitivo no momento em que mpts é lido (e, na sua ausência, stream-name): um enable-mosaic definido explicitamente acima desse ponto é sobrescrito por esse valor, abaixo é mantido;

  • type e mode em uma entrada de placa DVB — juntos determinam o conjunto de parâmetros de configuração, e ambos precisam vir antes da chave name.

Uma exceção à regra geral: se os arrays input e output estiverem acima de mpts, as entradas e saídas são construídas como para um fluxo de um único programa, e um tipo admissível apenas para um fluxo de vários programas leva à rejeição de todo o arquivo, e não a um aviso.

Um arquivo escrito pelo próprio serviço sempre satisfaz essas regras: o serviço emite as chaves em uma ordem fixa e segura. Só é vulnerável um arquivo cuja ordem foi alterada manualmente. O JSON Schema não tem noção de ordem, portanto o esquema não verifica isso. A regra prática é simples: não mova nada — mantenha a ordem em que o serviço gravou o arquivo.

Os identificadores são atribuídos manualmente

Cada entrada de cada array tem uma chave id. Os identificadores são atribuídos automaticamente apenas ao criar uma entrada pela API HTTP; na leitura do arquivo ninguém os atribui.

Por isso uma entrada acrescentada manualmente precisa levar um id explícito:

  • ele é obrigatório em qualquer array — sem ele todo o arquivo é rejeitado;

  • ele precisa ser único dentro do seu array;

  • o menor valor admissível é 1 em todo lugar, exceto no array stream, onde 0 também é admissível.

Para o array stream daí decorre uma armadilha: um id ausente é lido ali como 0, ou seja, como um identificador de verdade. A primeira entrada sem id passará; a segunda colidirá com ela e descartará todo o arquivo. Pela mesma razão, um fluxo com id 0 é gravado no arquivo sem nenhuma linha id — não é um erro de gravação, e sim consequência de zero ser aqui justamente o valor padrão.

A unicidade dos identificadores não é exprimível em JSON Schema, portanto essa é uma das poucas regras que o esquema não verificará por você. Um comando pronto para encontrar repetições está em As verificações que o esquema não faz.

A ordem das entradas em um array não é preservada

O serviço ordena as listas grandes a cada leitura, cada uma pela sua própria chave: os fluxos pelo nome exibido, as entradas e saídas de um fluxo pela chave de ordem, as contas pelo login, os armazenamentos e as placas de recepção pelo nome. Em qualquer ordem que você escreva tais entradas, o arquivo salvo será diferente. Não atribua sentido à ordem delas: onde a sequência importa, existe uma chave própria para isso.

A regra não é universal, e vale a pena notar duas exceções:

  • algumas listas mantêm a ordem do arquivo — em particular os grupos de bitrate adaptativo e os servidores de gerenciamento de assinantes;

  • as listas simples de valores nunca são reordenadas. Isso é essencial: é justamente na ordem delas que se apoiam os arrays pareados (Os arrays pareados são correspondidos por posição).

Os arrays pareados são correspondidos por posição

Várias configurações são expressas por arrays paralelos correspondidos por número: a entrada N de um array refere-se à entrada N dos demais. É assim que funcionam os endereços, nomes e segredos dos nós Meshwork vizinhos, os nomes e valores das variáveis de ambiente e as listas «antes — depois» na reatribuição de identificadores. Apagar uma entrada de um array sem apagar a entrada correspondente dos demais desloca tudo o que vem em seguida.

O esquema verificará que cada array contém elementos do tipo correto, mas não que os comprimentos dos arrays coincidam. Isso o próprio serviço verifica e descarta todo o arquivo quando os comprimentos divergem nos peers Meshwork, nas variáveis de ambiente, nas listas «antes — depois» da reatribuição de PID (mpegts-pid-old e mpegts-pid-new), nas listas de troca de idioma (mpegts-lang-set-pid e mpegts-lang-set) e nas chaves de desembaralhamento (biss-pnr e biss-key). No quarteto de endereços RIST (rist-addr-*) uma divergência de comprimento não interrompe o carregamento, mas a entrada não abre e o motivo é escrito no log. Um comando de conferência pronto está em O comprimento igual dos arrays pareados.

Os comentários são lidos, mas não preservados

A leitura admite comentários de bloco na forma /* ... */ — são cômodos durante o trabalho no arquivo. Somente essa forma: o comentário de linha // não é suportado e torna o arquivo sintaticamente incorreto, ou seja, o descarta por inteiro. Pela mesma razão, não escreva a sequência /* dentro de um valor de texto — ela será tomada como início de comentário.

Os comentários não sobrevivem a uma gravação: o serviço monta o documento de novo a cada vez a partir do que mantém na memória, por isso a primeira gravação apaga todos eles. Considere-os anotações pelo tempo da edição, e escreva o que deve permanecer na chave note, que a maioria das seções e entradas possui.

As ferramentas JSON estritas — inclusive o validador de Editar, verificar e transferir as configurações — não analisarão um arquivo com comentários. Antes da verificação, os comentários são removidos.

Conjuntos condicionais de chaves

Duas chaves funcionam como interruptores que determinam quais chaves são admissíveis ao lado delas:

  • Nas entradas de entrada e de saída o type escolhe o transporte. Cada transporte tem o seu próprio conjunto de chaves; uma chave de outro transporte não é reconhecida.

  • Nas entradas de placa DVB o type escolhe o sistema de radiodifusão e o mode, o modo de operação. Juntos determinam o conjunto de chaves de configuração, inclusive se existem chaves do conversor.

O esquema reproduz essas condições e rejeitará uma chave que não pertença à variante escolhida. O único caso que ele não consegue exprimir é o de uma chave cuja forma depende de um interruptor no objeto que a envolve: em um fluxo de vários programas a chave de desembaralhamento (biss-key) é escrita como lista, e em um fluxo de um único programa, como valor único. O esquema aceita ambas as formas onde quer que essa chave apareça; a correta só o serviço escolhe.

Valores que não devem ser repassados

O arquivo guarda senhas e chaves em texto claro. Antes de entregar a configuração a quem quer que seja — a um colega, a um chamado de suporte, a um sistema de tíquetes, a um repositório público — substitua os valores de:

  • as senhas das contas nas seções da interface web, do guia de programação e dos receptores de fluxos, a senha do servidor de gerenciamento de assinantes, e o login e a senha da fonte do guia;

  • o segredo próprio do nó e os segredos dos nós Meshwork vizinhos;

  • as frases secretas dos transportes e as senhas de cliente das entradas PS1 e SRT, a senha da entrada RTSP, o login e a senha da entrada HLS/HTTP;

  • as chaves e os identificadores de chave da proteção de conteúdo e os segredos compartilhados;

  • as chaves de desembaralhamento;

  • o token do bot do serviço de mensagens e a senha da conta de e-mail;

  • a chave de vinculação da autoridade certificadora.

Duas chaves não têm nome de segredo, mas regularmente os contêm: o endereço de publicação de uma saída para uma plataforma externa e o endereço de origem de uma entrada, se as credenciais estiverem escritas diretamente no link.

A lista cresce a cada novo transporte, portanto não a tome como exaustiva: antes de enviar o arquivo, procure nele por password, secret, key, token e passphrase, e examine cada link.

O arquivo não é a única via para esses valores: pela API HTTP eles são legíveis por qualquer conta do nó, inclusive um papel somente de leitura (Acesso).

Aviso

Substituir um segredo por uma cadeia vazia nem sempre é seguro: parte dessas chaves não aceita valor vazio, e o arquivo será rejeitado por inteiro. Coloque uma substituição evidente, de comprimento verossímil.

Verificação pelo JSON Schema

Junto com a documentação é publicada uma descrição legível por máquina do arquivo de configuração em formato JSON Schema. Ela apanha toda uma classe de erros que o próprio serviço engole em silêncio — sobretudo um erro de digitação no nome de uma chave e um array escrito em lugar de um valor único.

Dois arquivos de esquema

Arquivo

Finalidade

pss.schema.json

Estrito. Cada chave precisa estar entre as declaradas pelo produto. É usado para um arquivo destinado à versão indicada no cabeçalho do esquema.

pss.compat.schema.json

Permissivo. Tipos, faixas, enumerações e chaves obrigatórias continuam sendo verificados, mas as chaves que o produto não conhece são ignoradas. É a primeira passagem ao transferir configurações de outra versão, onde chaves desconhecidas são esperadas e não suspeitas.

Ambos os esquemas trazem a versão do produto para a qual foram gerados. Uma configuração só é verificada com sentido pelo esquema da versão que a lerá. Verificar pelo esquema de outra versão dá uma resposta confiante e errada.

Aviso

O esquema permissivo ignora mais do que as chaves desconhecidas. A pertença de uma chave à variante escolhida (Conjuntos condicionais de chaves) apoia-se no esquema no mesmo mecanismo, por isso numa verificação permissiva também passa uma chave autêntica escrita no tipo de entrada errado, no modo de placa errado ou no tipo de fluxo errado — e com ela a sua própria faixa também fica sem verificação. O esquema permissivo é apenas a primeira passagem; a última palavra é sempre do estrito.

Nota

Os esquemas fazem parte do conjunto da documentação, e não do produto: no diretório de configurações de um nó em funcionamento não há cópia alguma, e ela não é necessária lá. Eles são publicados no site da documentação — https://doc2.pstreamer.tv/schema/, um diretório por versão. Pegue o esquema da sua versão e mantenha-o na máquina onde você edita o arquivo.

O endereço escrito dentro do próprio esquema, na chave $id, é o seu identificador e não uma instrução para baixar algo: a verificação de um arquivo funciona também sem acesso à rede.

O que o esquema verifica

  • os nomes das chaves — um erro de digitação vira um erro em vez de uma omissão silenciosa;

  • os tipos dos valores, inclusive um array escrito em lugar de um valor único;

  • as faixas numéricas e os limites de comprimento do texto;

  • os conjuntos fechados de valores admissíveis;

  • a presença das chaves obrigatórias, sobretudo id e type;

  • a pertença a uma variante — uma chave de outro transporte ou de outro sistema de radiodifusão será apontada.

O que o esquema não verifica

Tudo o que foi listado é verificado pelo próprio serviço ao ler o arquivo, e a maior parte interrompe o carregamento. O esquema reduz a lacuna, mas não a fecha: uma verificação bem-sucedida significa que o arquivo está correto e verossímil, não que o serviço o aceitará.

Nota

A API HTTP contém uma família de requisições /schema que devolvem listas de valores admissíveis e do equipamento detectado — os tipos de entrada e de saída suportados por esta compilação, os idiomas, as placas encontradas, os dispositivos de transcodificação. Não têm relação com o arquivo pss.schema.json, e um não substitui o outro. A coincidência nos nomes é apenas uma coincidência.

Compatibilidade entre versões

Aviso

A compatibilidade retroativa não é garantida. Uma atualização pode alterar igualmente o arquivo de configuração, o esquema e a API HTTP: a composição e os nomes das chaves, as faixas de valores, a forma das requisições e das respostas. Uma atualização não transfere as configurações nem avisa sobre divergências. Verifique o arquivo novamente após cada atualização, e os scripts que trabalham com a API HTTP — também após cada atualização.

Entre versões, chaves isoladas são acrescentadas, renomeadas e removidas, e as faixas admissíveis se estreitam. Uma chave removida torna-se desconhecida e é ignorada, de modo que a configuração simplesmente deixa de atuar; uma chave nova atua no padrão enquanto não for gravada; um valor que saiu de uma faixa estreitada é levado ao limite. O serviço não informa nenhum dos três.

No arquivo não há marca de versão. Nada dentro dele aponta a versão que o gravou, e o serviço não realiza conversão alguma ao ler um arquivo de uma compilação mais antiga ou mais nova. Junto com a esparsidade do arquivo, isso significa que um arquivo transferido é aplicado como está.

O esquema é, portanto, a única via prática para saber quais chaves de um arquivo existente esta versão já não entende. Verifique o arquivo novamente após cada atualização; o procedimento é Transferir as configurações para outra versão.