#ObjectScript

0 Seguidores · 104 Postagens

InterSystems ObjectScript é uma linguagem de script que opera com dados, usando qualquer modelo de dados da Plataforma de Dados InterSystems (Objetos, Relacionais, Chave-valor, Documentos, Globais) e, desenvolve a lógica de negócios para aplicações de servidor na Plataforma de Dados InterSystems.

Documentação.

Artigo ROBSON SERPA DA ROSA · Jun. 28, 2021 5m read

Uma VIEW em SQL é basicamente uma instrução SQL preparada.
Deve ser executado e montado como qualquer outra consulta SQL.
VIEW MATERIALIZADA significa que o conteúdo é coletado antes das mãos e pode ser recuperado com bastante rapidez.
Eu vi o conceito primeiro com meu concorrente favorito chamado O * e eles fizeram muito barulho sobre isso.

  { favorite: because I could win every benchmark against them devil }

0
0 117
Job Rogerio de Oliveira · Jun. 24, 2021

Pessoal,

Procuro perfil de analista de integração / Ensemble (freelance). Interessados, por favor enviar mensagem de WhatsApp (61) 98405-2981.

Local de trabalho: 100% Remoto

Habilidades:  Cache DB, Object Script, InterSystems, Ensemble

Conhecimentos Necessários:

0
0 125
Artigo Yuri Marx · jan 20, 2021 1m read

As vezes é necessário executar comandos do shell do sistema operacional host, onde se encontra seu programa ObjectScript, para acionar programas, serviços do sistema operacional, agendar crontasks, dentre outras atividades. Para isto, a linguagem possui um procedimento utilitário chamado $ZF(-100). Seu formato é:

$ZF(-100,flags,program,args)

Onde flags é o tipo de comando que você quer executar. No nosso caso, a flag é "/SHELL", para executar comandos shell no sistema operacional host.

Program é o nome do programa ou serviço a ser executado.

0
0 162
Pergunta Henrique Dias · jan 18, 2021

Boa noite pessoal, tudo bem?

Estou com uma dúvida, qual seria a melhor forma de ler todos os arquivos, por exemplo CSV, de um determinado diretório?

Para ler o arquivo CSV, utilizo o ClassMethod abaixo: 

ClassMethod readCSV() As %Status
{

   set file = ##class(%File).%New("/irisdev/dataImport/teste.csv")
   set sc = file.Open("R")
   if $$$ISERR(sc) quit
   
   set count = 0

   while 'file.AtEnd {
      set count = $INCREMENT(count)
      set line = file.ReadLine()
      quit:(line="")
      write line,!
   }
   do file.Close()
}

Agradeço qualquer sugestão de vocês. 

4
0 432
Artigo Yuri Marx · jan 16, 2021 3m read

Oi Comunidade InterSystems!

A linguagem ObjectScript do InterSystems IRIS possui a capacidade de estender classes utilizando um recurso muito interessante chamado XData.

Trata-se de uma seção em sua classe que pode ser utilizada para criar definições personalizadas a serem utilizadas dentro da própria classe e também externamente.

Para criar uma ou mais definições de XData para sua classe é muito fácil, veja o exemplo:

0
0 185
Artigo Lily Taub · Dez. 21, 2020 9m read

Introdução

A maior parte da comunicação servidor-cliente na web é baseada em uma estrutura de solicitação e resposta. O cliente envia uma solicitação ao servidor e o servidor responde a esta solicitação. O protocolo WebSocket fornece um canal bidirecional de comunicação entre um servidor e um cliente, permitindo que os servidores enviem mensagens aos clientes sem primeiro receber uma solicitação. Para obter mais informações sobre o protocolo WebSocket e sua implementação no InterSystems IRIS, consulte os links abaixo.

Este tutorial é uma atualização de "Asynchronous Websockets - um tutorial rápido" para Caché 2016.2+ e InterSystems IRIS 2018.1+.

Operação assíncrona vs síncrona

No InterSystems IRIS, uma conexão WebSocket pode ser implementada de forma síncrona ou assíncrona. O modo como a conexão WebSocket entre o cliente e o servidor opera é determinado pela propriedade “SharedConnection” da classe %CSP.WebSocket.

  • SharedConnection=1 : operação assíncrona

  • SharedConnection=0: operação síncrona

Uma conexão WebSocket entre um cliente e um servidor hospedado em uma instância do InterSystems IRIS inclui uma conexão entre a instância IRIS e o Web Gateway. Na operação síncrona de WebSocket, a conexão usa um canal privado. Na operação assíncrona de WebSocket, um grupo de clientes WebSocket compartilha um conjunto de conexões entre a instância IRIS e o Web Gateway. A vantagem de uma implementação assíncrona de WebSockets se destaca quando se tem muitos clientes se conectando ao mesmo servidor, pois esta implementação não exige que cada cliente seja tratado por uma conexão exclusiva entre o Web Gateway e a instância IRIS.

Neste tutorial, implementaremos WebSockets de forma assíncrona. Portanto, todas as janelas de bate-papo abertas compartilham um conjunto de conexões entre o Web Gateway e a instância IRIS que hospeda a classe do servidor WebSocket.

Visão geral da aplicação de chat

O “hello world” do WebSockets é uma aplicação de chat em que um usuário pode enviar mensagens que são transmitidas a todos os usuários logados na aplicação. Neste tutorial, os componentes da aplicação de chat incluem:

  • Servidor: implementado em uma classe que estende %CSP.WebSocket

  • Cliente: implementado por uma página CSP

A implementação desta aplicação de chat irá realizar o seguinte:

  • Os usuários podem transmitir mensagens para todas as janelas do chat abertas

  • Os usuários on-line aparecerão na lista “Usuários on-line” de todas as janelas de chat abertas

  • Os usuários podem alterar seu nome de usuário compondo uma mensagem começando com a palavra-chave “alias” e esta mensagem não será transmitida, mas atualizará a lista de “Usuários On-line”

  • Quando os usuários fecham a janela de chat, eles são removidos da lista de “Usuários on-line”

Para ver o código fonte da aplicação de chat, visite este repositório no GitHub.

O Cliente

O lado do cliente da nossa aplicação de chat é implementado por uma página CSP contendo o estilo para a janela do chat, a declaração da conexão WebSocket, eventos do WebSocket e métodos que tratam da comunicação de e para o servidor, e funções auxiliares que empacotam mensagens enviadas para o servidor e processam as mensagens de entrada.

Primeiro, veremos como a aplicação inicia a conexão WebSocket usando uma biblioteca Javascript WebSocket.

    ws = new WebSocket(((window.location.protocol === "https:")? "wss:":"ws:")
                    + "//"+ window.location.host + "/csp/user/Chat.Server.cls");

new cria uma nova instância da classe WebSocket. Isso abre uma conexão WebSocket com o servidor usando o protocolo "wss" (indica o uso de TLS para o canal de comunicação WebSocket) ou "ws". O servidor é especificado pelo número da porta do servidor web e nome do host da instância que define a classe Chat.Server (essas informações estão contidas na variável window.location.host). O nome de nossa classe no servidor (Chat.Server.cls) está incluído no URI de abertura do WebSocket como uma solicitação GET para o recurso no servidor.

O evento ws.onopen é disparado quando a conexão WebSocket é estabelecida com êxito, fazendo a transição de um estado de conectando para um estado aberto.

    ws.onopen = function(event){
        document.getElementById("headline").innerHTML = "CHAT - CONNECTED";
    };

Este evento atualiza o cabeçalho da janela do chat para indicar que o cliente e o servidor estão conectados.

Enviando mensagens

A ação de um usuário enviando uma mensagem aciona a função de envio. Essa função atua como um invólucro em torno do método ws.send, que contém a mecânica de envio da mensagem do cliente ao servidor pela conexão WebSocket.

function send() {
    var line=$("#inputline").val();
    if (line.substr(0,5)=="alias"){
        alias=line.split(" ")[1];
        if (alias==""){
            alias="default";
        }
        var data = {}
        data.User = alias
        ws.send(JSON.stringify(data));
        } else {
        var msg=btoa(line);
        var data={};
        data.Message=msg;
        data.Author=alias;
        if (ws && msg!="") {
            ws.send(JSON.stringify(data));
        }
    }
    $("#inputline").val("");
}

send envia pacotes as informações a serem enviadas ao servidor em um objeto JSON, definindo pares de chave/valor de acordo com o tipo de informação que está sendo enviada (atualização de alias ou mensagem geral). btoa traduz o conteúdo de uma mensagem geral em uma string ASCII codificada em base 64.

Recebendo mensagens

Quando o cliente recebe uma mensagem do servidor, o evento ws.onmessage é acionado.

ws.onmessage = function(event) {
    var d=JSON.parse(event.data);
    if (d.Type=="Chat") {
        $("#chat").append(wrapmessage(d));
            $("#chatdiv").animate({ scrollTop: $('#chatdiv').prop("scrollHeight")}, 1000);
    } else if(d.Type=="userlist") {
        var ul = document.getElementById("userlist");
        while(ul.firstChild){ul.removeChild(ul.firstChild)};
        $("#userlist").append(wrapuser(d.Users));
    } else if(d.Type=="Status"){
        document.getElementById("headline").innerHTML = "CHAT - connected - "+d.WSID;
    }
};

Dependendo do tipo de mensagem que o cliente recebe (“Chat”, “userlist” ou “status”), o evento onmessage chama wrapmessage ou wrapuser para popular as seções apropriadas da janela de chat com os dados de entrada. Se a mensagem recebida for uma atualização de status, o cabeçalho de status da janela do chat é atualizado com o ID do WebSocket, que identifica a conexão WebSocket bidirecional associada à janela do chat.

Componentes adicionais do cliente

Um erro na comunicação entre o cliente e o servidor aciona o método WebSocket onerror, que emite um alerta que nos notifica do erro e atualiza o cabeçalho de status da página.

ws.onerror = function(event) {
    document.GetElementById("headline").innerHTML = "CHAT - error";
    alert("Received error"); 
};

O método onclose é disparado quando a conexão WebSocket entre o cliente e o servidor é fechada, e atualiza o cabeçalho de status.

ws.onclose = function(event) {
    ws = null;
    document.getElementById("headline").innerHTML = "CHAT - disconnected";
}

O servidor

O lado do servidor da aplicação de chat é implementado pela classe Chat.Server, que estende de %CSP.WebSocket. Nossa classe de servidor herda várias propriedades e métodos de %CSP.WebSocket, alguns dos quais discutirei abaixo. Chat.Server também implementa métodos personalizados para processar mensagens de entrada e transmitir mensagens para o(s) cliente(s).

Antes de iniciar o servidor

OnPreServer() é executado antes de o servidor WebSocket ser criado e é herdado da classe %CSP.WebSocket.

Method OnPreServer() As %Status
{
    set ..SharedConnection=1
    if (..WebSocketID '= ""){ 
        set ^Chat.WebSocketConnections(..WebSocketID)=""
    } else {
        set ^Chat.Errors($INCREMENT(^Chat.Errors),"no websocketid defined")=$HOROLOG 
    }
    Quit $$$OK
}

Este método define o parâmetro da classe SharedConnection em 1, indicando que nossa conexão WebSocket será assíncrona e suportada por vários processos que definem conexões entre a instância InterSystems IRIS e o Web Gateway. O parâmetro SharedConnection só pode ser alterado em OnPreServer(). O OnPreServer() também armazena o ID WebSocket associado ao cliente no ^Chat.WebSocketConnections global.

O método do servidor

O corpo principal da lógica executada pelo servidor está contido no método Server().

Method Server() As %Status
{
    do ..StatusUpdate(..WebSocketID)
    for {       
        set data=..Read(.size,.sc,1) 
        if ($$$ISERR(sc)){
            if ($$$GETERRORCODE(sc)=$$$CSPWebSocketTimeout) {
                //$$$DEBUG("no data")
            }
            if ($$$GETERRORCODE(sc)=$$$CSPWebSocketClosed){
                kill ^Chat.WebSocketConnections(..WebSocketID)
                do ..RemoveUser($g(^Chat.Users(..WebSocketID))) 
                kill ^Chat.Users(..WebSocketID)
                quit  // Client closed WebSocket
            }
        } else{
            if data["User"{
                do ..AddUser(data,..WebSocketID)
            } else {
                set mid=$INCREMENT(^Chat.Messages)
                set ^Chat.Messages(mid)=data
                do ..ProcessMessage(mid)
            }
        }
    }
    Quit $$$OK
}

Este método lê as mensagens recebidas do cliente (usando o método Read da classe %CSP.WebSockets), adiciona os objetos JSON recebidos ao ^Chat.Messages global e chama o ProcessMessage() para encaminhar a mensagem a todos os outros clientes de chat conectados. Quando um usuário fecha sua janela de chat (encerrando assim a conexão WebSocket com o servidor), a chamada do método Server() para Read retorna um código de erro que avalia a macro $$$CSPWebSocketClosed e o método prossegue para tratar o encerramento de acordo.

Processamento e distribuição de mensagens

ProcessMessage() adiciona metadados à mensagem de chat recebida e chama o SendData(), passando a mensagem como um parâmetro.

ClassMethod ProcessMessage(mid As %String)
{
    set msg = ##class(%DynamicObject).%FromJSON($GET(^Chat.Messages(mid)))
    set msg.Type="Chat"
    set msg.Sent=$ZDATETIME($HOROLOG,3)
    do ..SendData(msg)
}

ProcessMessage() recupera a mensagem formatada em JSON do ^Chat.Messages global e a converte em um objeto do InterSystems IRIS usando a classe %DynamicObject e o método '%FromJSON. Isso nos permite editar facilmente os dados antes de encaminharmos a mensagem para todos os clientes de chat conectados. Adicionamos um atributo Type com o valor “Chat”, que o cliente usa para determinar como lidar com a mensagem recebida. SendData() envia a mensagem para todos os outros clientes de chat conectados.

ClassMethod SendData(data As %DynamicObject)
{
    set c = ""
    for {
        set c = $order(^Chat.WebSocketConnections(c))
        if c="" Quit
        set ws = ..%New()
        set sc = ws.OpenServer(c)
        if $$$ISERR(sc) { do ..HandleError(c,"open") } 
        set sc = ws.Write(data.%ToJSON())
        if $$$ISERR(sc) { do ..HandleError(c,"write") }
    }
}

SendData() converte o objeto do InterSystems IRIS de volta em uma string JSON (data.%ToJSON()) e envia a mensagem para todos os clientes de chat. SendData() obtém o ID WebSocket associado a cada conexão cliente-servidor do ^Chat.WebSocketConnections global e usa o ID para abrir uma conexão WebSocket por meio do método OpenServer da classe %CSP.WebSocket. Podemos usar o método OpenServer para fazer isso porque nossas conexões WebSocket são assíncronas - extraímos do pool existente de processos do IRIS-Web Gateway e atribuímos um ID WebSocket que identifica a conexão do servidor a um cliente de chat específico. Por fim, o método Write()%CSP.WebSocket envia a representação da string JSON da mensagem para o cliente.

Conclusão

Esta aplicação de chat demonstra como estabelecer conexões WebSocket entre um cliente e um servidor hospedado pelo InterSystems IRIS. Para continuar lendo sobre o protocolo e sua implementação no InterSystems IRIS, dê uma olhada nos links na introdução.

0
0 1264
Anúncio Angelo Bruno Braga · Nov. 30, 2020

Olá Desenvolvedores,

Vocês estão preparados para participar de nossa competição anual de Dezembro ?

Junte-se ao concurso o Advento do Código 2020 da InterSystems, participe em nosso concurso de ObjectScript e ganhe prêmios !!!

 

<--break->🏆 Nosso Placar 🏆

Aqui você consegue ver os participantes do ano passado.

👉🏼 Junte-se ao placar privado de ObjectScript com o código 130669-ab1f69bf.

Nota: Você precisa se inscrever para o Advento de Código (ex.: com uma conta GitHub / Google / Twitter / Reddit ) para ver o placar e participar no concurso.

Prêmios: 

🥇 1° lugar - US$3,000 

🥈 2° lugar - US$2,000 

0
0 96
Pergunta Arian Botine · Nov. 15, 2020

Caché: 2017.2.1.801.0

Fala pessoal, tenho uma dúvida relacionada um problema especifico que eu estou tentando entender, onde ainda não tenho muitas informações, porém estou tentando criar uma forma de levantar dados precisos para expor mais detalhes aqui na comunidade ou até mesmo consultar o suporte da IS, a questão é muito simples:

Precisava saber através de código/rotina a seletividade de uma propriedade de tabela, atualmente consigo realizar um SET utilizando o comando:

SYSTEM.SQL.SetFieldSelectivity("#PACOTE","#TABELA","#PROPRIEDADE","#SELETIVIDADE","")
3
0 213
Artigo Evgeny Shvarov · Out. 26, 2020 5m read

Olá, desenvolvedores!

"objectscript.conn" :{
      "ns": "IRISAPP",
      "active": true,
      "docker-compose": {
        "service": "iris",
        "internalPort": 52773
      }

Quero compartilhar com vocês um novo recurso bem maneiro que descobri no novo lançamento 0.8 do plugin VSCode ObjectScript de @Dmitry Maslennikov e CaretDev.

O lançamento traz uma nova configuração "docker-compose", que resolve o problema com as portas necessárias para fazer o VSCode Editor se conectar à IRIS. Não era muito conveniente se você tivesse mais de um contêiner Docker com a IRIS em execução na mesma máquina. Agora, esse problema foi resolvido!

Veja abaixo como funciona.

O conceito de usar o Docker localmente para desenvolvimento com a IRIS  pressupõe que você tem o dockerfile e o docker-compose.yml no repositório usado para compilar o ambiente do projeto e carregar todo o código ObjectScript no contêiner IRIS obtido pelo Docker Hub. Além disso, você tem o arquivo .vscode/settings.json do VSCode no repositório ao qual você aponta a porta de conexão do servidor web IRIS (junto com outras configurações de conexão, como URL, Namespace e credenciais de login).

A pergunta é: qual é a porta à qual o VSCode deve se conectar?

Você pode usar a porta 52773, que é a porta IRIS padrão para servidores web. Mas, se você tentar iniciar o segundo contêiner do Docker, haverá uma falha, pois você não pode executar dois contêineres do Docker na mesma máquina que esperam conexões pela mesma porta. Mas você pode expor uma porta externa para o contêiner do Docker, e isso pode ser configurado por um arquivo docker-compose.yml. Veja um exemplo (a porta mapeada está em negrito):

version: '3.6'
services:
  iris:
    build: .
    restart: always
    ports:
      - 52791:52773
    volumes:
      - ~/iris.key:/usr/irissys/mgr/iris.key
      - ./:/irisdev/app

No docker-compose, você deve inserir a mesma porta em .vscode/settings.json:

Mas qual é o problema?

O problema é que, quando você expõe seu projeto como uma biblioteca ou demonstração e convida pessoas a executar e editar o código com o VSCode, você não quer que elas configurem a porta manualmente e quer que elas clonem o repositório, executem o Docker e tenham a opção de colaborar imediatamente. Eis a pergunta: no docker-compose, a que você deve mapear seu projeto para que não haja conflito com o ambiente de outra pessoa?

Mesmo se você não o expuser a ninguém exceto você mesmo, que porta deve colocar nas configurações de conexão do .vscode/settings.json?

A resposta é: quando você inicia um novo Docker com a IRIS, é exibida a mensagem de erro dizendo que a porta já está sendo usada e que você deve interromper os outros contêineres ou inventar uma nova porta que provavelmente não esteja em uso e tentar usá-la no docker-compose e settings.json.

Que chatice! É uma operação inútil que gasta tempo demais. Ninguém gosta de fazer isso.

O mesmo ocorre se você expuser a biblioteca.

O alívio chegou com o novo lançamento 0.8 do VSCode ObjectScript, em que você pode incluir uma seção docker-compose, que resolve o problema para sempre:

"objectscript.conn" :{
      "ns": "IRISAPP",
      "active": true,
      "docker-compose": {
        "service": "iris",
        "internalPort": 52773
      }

A seção contém os parâmetros "service" e "internalPort", que informam ao VSCode que, para encontrar a porta de conexão, deve-se verificar o arquivo docker-compose.yml que temos no mesmo repositório, encontrar "iris" na seção "service" e obter a porta, mapeada para a porta interna 52773.

Viva!

O mais maneiro é que agora o Docker tem o modo para docker-compose.yml em que você pode não configurar nenhuma porta no Docker. Você pode deixar o símbolo "-" na porta mapeada, e o Docker usará uma porta disponível aleatoriamente. 

iris:
    build: 
      context: .
      dockerfile: Dockerfile-zpm
    restart: always
    ports: 
      - 51773
      - 52773
      - 53773
    volumes:
      - ~/iris.key:/usr/irissys/mgr/iris.key
      - ./:/irisdev/app

Viva de novo! Agora, você tem uma opção para não se preocupar mais com as portas do servidor web da IRIS às quais o VSCode se conecta.

Como funciona nesse caso: executamos o docker-compose.yml, o Docker escolhe uma porta aleatória do servidor web e executa a IRIS com ela, o VSCode obtém essa porta pelo Docker e conecta-se à IRIS por ela, e você pode editar e compilar o código imediatamente. Sem nenhuma configuração adicional.

Não tem nada melhor que isso!

E você pode fazer o mesmo com o seguinte modelo que enviei recentemente de acordo com o novo recurso do VSCode ObjectScript 0.8, que atualizou o settings.json e o docker-compose.yml. Para testar o modelo, execute os comandos abaixo no terminal (testados no Mac). Você também precisa do git e do Docker Desktop instalados. 

$ git clone https://github.com/intersystems-community/objectscript-docker-template.git

$ cd objectscript-docker-template

$ docker-compose up -d

Abra essa pasta no VSCode (é preciso ter o plugin VScode ObjectScript instalado):

Verifique se o VSCode está conectado – clique na linha de status do VSCode:

Reconecte o VSCode, se necessário.

Você pode abrir o IRIS Terminal no VSCode, se necessário, com o menu ObjectScript.

Concluído! Agora, você pode executar, compilar e depurar o código!

Viva a programação!

0
0 171
Artigo Evgeny Shvarov · Out. 6, 2020 13m read

Olá, desenvolvedores!

Muitos de vocês publicam suas bibliotecas InterSystems ObjectScript no Open Exchange e GitHub.

Mas o que você faz para facilitar o uso e a colaboração do seu projeto por desenvolvedores?

Neste artigo, quero apresentar uma maneira fácil de iniciar e contribuir com qualquer projeto ObjectScript apenas copiando um conjunto padrão de arquivos para o seu repositório.

Vamos lá!

Copie esses arquivos deste repositório para o seu repositório:

Dockerfile

docker-compose.yml

Installer.cls

iris.script

settings.json{#9f423fcac90bf80939d78b509e9c2dd2-d165a4a3719c56158cd42a4899e791c99338ce73}

.dockerignore{#f7c5b4068637e2def526f9bbc7200c4e-c292b730421792d809e51f096c25eb859f53b637}
.gitattributes{#fc723d30b02a4cca7a534518111c1a66-051218936162e5338d54836895e0b651e57973e1}
.gitignore{#a084b794bc0759e7a6b77810e01874f2-e6aff5167df2097c253736b40468e7b21e577eeb}

E você agora possui uma maneira padrão de lançar e colaborar com seu projeto. Abaixo está o longo artigo sobre como e por que isso funciona.

OBS.: Neste artigo, consideraremos projetos que podem ser executados no InterSystems IRIS 2019.1 e versões mais recentes.

Escolhendo o ambiente de lançamento para projetos do InterSystems IRIS

Normalmente, queremos que um desenvolvedor teste o projeto/biblioteca e tenha certeza de que será um exercício rápido e seguro.

Na minha humilde opinião, a abordagem ideal para lançar qualquer coisa nova de forma rápida e segura é através da utilização do contêiner Docker, que dá ao desenvolvedor uma garantia de que tudo o que ele/ela inicia, importa, compila e calcula é seguro para a máquina host e de que nenhum sistema ou código será destruído ou deteriorado. Se algo der errado, basta parar e remover o contêiner. Se a aplicação ocupa uma quantidade enorme de espaço em disco, você a limpa com o contêiner e seu espaço estará de volta. Se uma aplicação deteriora a configuração do banco de dados, você exclui apenas o contêiner com configuração deteriorada. É assim, simples e seguro.

O contêiner Docker oferece segurança e padronização.

A maneira mais simples de executar o contêiner Docker do InterSystems IRIS é executar uma imagem do IRIS Community Edition:

  1. Instale o Docker desktop 

  2. Execute no terminal do sistema operacional o seguinte:

docker run --rm -p 52773:52773 --init --name my-iris store/intersystems/iris-community:2020.1.0.199.0
  1. Em seguida, abra o Portal de Administração do IRIS em seu navegador host em:

http://localhost:52773/csp/sys/UtilHome.csp

  1. Ou abra uma sessão no terminal:

    docker exec -it my-iris iris session IRIS

  2. Pare o contêiner IRIS quando não precisar mais dele:

    docker stop my-iris

OK! Executamos o IRIS em um contêiner docker. Mas você deseja que um desenvolvedor instale seu código no IRIS e talvez faça algumas configurações. Isso é o que discutiremos a seguir.

Importando arquivos ObjectScript

O projeto InterSystems ObjectScript mais simples pode conter um conjunto de arquivos ObjectScript como classes, rotinas, macro e globais. Verifique o artigo sobre nomenclatura e estrutura de pastas proposta.

A questão é: como importar todo esse código para um contêiner IRIS?

Aqui é o momento em que o Dockerfile nos ajuda pois podemos usá-lo para pegar o contêiner IRIS padrão, importar todo o código de um repositório para o IRIS e fazer algumas configurações com o IRIS, se necessário. Precisamos adicionar um Dockerfile no repositório.

Vamos examinar o Dockerfile do repositório de modelos ObjectScript:

ARG IMAGE=store/intersystems/irishealth:2019.3.0.308.0-community
ARG IMAGE=store/intersystems/iris-community:2019.3.0.309.0
ARG IMAGE=store/intersystems/iris-community:2019.4.0.379.0
ARG IMAGE=store/intersystems/iris-community:2020.1.0.199.0
FROM $IMAGE

USER root

WORKDIR /opt/irisapp
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp

USER irisowner

COPY  Installer.cls .
COPY  src src
COPY iris.script /tmp/iris.script # run iris and initial 

RUN iris start IRIS \
    && iris session IRIS < /tmp/iris.script

 

As primeiras linhas ARG definem a variável $IMAGE - que usaremos então em FROM. Isso é adequado para testar/executar o código em diferentes versões do IRIS, trocando-os apenas pelo que é a última linha antes do FROM para alterar a variável $IMAGE. 

Aqui temos: 

ARG IMAGE=store/intersystems/iris-community:2020.1.0.199.0

FROM $IMAGE

Isso significa que estamos pegando o IRIS 2020 Community Edition versão 199.

Queremos importar o código do repositório - isso significa que precisamos copiar os arquivos de um repositório para um contêiner do docker. As linhas abaixo ajudam a fazer isso:

USER root

WORKDIR /opt/irisapp
RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp

USER irisowner

COPY  Installer.cls .
COPY  src src

USER root - aqui, mudamos o usuário para root para criar uma pasta e copiar arquivos no docker.

WORKDIR  /opt/irisapp - nesta linha configuramos o diretório de trabalho no qual copiaremos os arquivos.

RUN chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/irisapp   -  aqui, damos os direitos ao usuário e grupo irisowner que executam o IRIS.

USER irisowner - trocando usuário de root para irisowner

COPY Installer.cls .  - copiando o Installer.cls para a raiz do workdir. Não esqueça aqui do ponto.

COPY src src - copia os arquivos de origem da pasta src no repo para a pasta src no workdir no docker.

No próximo bloco, executamos o script inicial, onde chamamos o instalador e o código ObjectScript:

COPY iris.script /tmp/iris.script # executar o iris e iniciar 
RUN iris start IRIS \
    && iris session IRIS < /tmp/iris.script

COPY iris.script / - copiamos iris.script para o diretório raiz. Ele contém o ObjectScript que desejamos chamar para configurar o contêiner.

RUN iris start IRIS</span>  - inicia o IRIS

&& iris session IRIS < /tmp/iris.script - inicia o terminal IRIS e insere o ObjectScript inicial nele.

Ótimo! Temos o Dockerfile, que importa arquivos no docker. Mas nos deparamos com outros dois arquivos: installer.cls e iris.script. Vamos examiná-los.

Installer.cls

Class App.Installer
{

XData setup
{
<Manifest>
  <Default Name="SourceDir" Value="#{$system.Process.CurrentDirectory()}src"/>
  <Default Name="Namespace" Value="IRISAPP"/>
  <Default Name="app" Value="irisapp" />

  <Namespace Name="${Namespace}" Code="${Namespace}" Data="${Namespace}" Create="yes" Ensemble="no">

    <Configuration>
      <Database Name="${Namespace}" Dir="/opt/${app}/data" Create="yes" Resource="%DB_${Namespace}"/>

      <Import File="${SourceDir}" Flags="ck" Recurse="1"/>
    </Configuration>
    <CSPApplication Url="/csp/${app}" Directory="${cspdir}${app}"  ServeFiles="1" Recurse="1" MatchRoles=":%DB_${Namespace}" AuthenticationMethods="32"
       
    />
  </Namespace>

</Manifest>
}

ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 3, pInstaller As %Installer.Installer, pLogger As %Installer.AbstractLogger) As %Status [ CodeMode = objectgenerator, Internal ]
{
  #; Deixe o documento XGL gerar código para este método. 
  Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "setup")
}

}

Francamente, não precisamos do Installer.cls para importar arquivos. Isso pode ser feito com uma linha. Mas frequentemente, além de importar o código, precisamos configurar a aplicação CSP, introduzir configurações de segurança, criar bancos de dados e namespaces.

Neste Installer.cls, criamos um novo banco de dados, namespace com o nome IRISAPP e criamos a aplicação /csp/irisapp padrão para este namespace.

Tudo isso realizamos no elemento <Namespace>:

<Namespace Name="${Namespace}" Code="${Namespace}" Data="${Namespace}" Create="yes" Ensemble="no">

    <Configuration>
      <Database Name="${Namespace}" Dir="/opt/${app}/data" Create="yes" Resource="%DB_${Namespace}"/>

      <Import File="${SourceDir}" Flags="ck" Recurse="1"/>
    </Configuration>
    <CSPApplication Url="/csp/${app}" Directory="${cspdir}${app}"  ServeFiles="1" Recurse="1" MatchRoles=":%DB_${Namespace}" AuthenticationMethods="32"
       
    />
  </Namespace>

E importamos todos os arquivos do SourceDir com a tag Import:

<Import File="${SourceDir}" Flags="ck" Recurse="1"/>

SourceDir aqui é uma variável, que é definida para o diretório/pasta src atual:

<Default Name="SourceDir" Value="#{$system.Process.CurrentDirectory()}src"/>

Uma classe Installer.cls com essas configurações nos dá a confiança de que criamos um novo banco de dados IRISAPP limpo, no qual importamos código ObjectScript arbitrário da pasta src.

iris.script

Aqui, você é bem-vindo para fornecer qualquer código de configuração ObjectScript inicial que deseja para iniciar seu contêiner IRIS.

Ex. Aqui carregamos e executamos o installer.cls e então criamos o UserPasswords sem expiração, apenas para evitar a primeira solicitação de alteração da senha, pois não precisamos desse prompt para o desenvolvimento.

; run installer to create namespace
do $SYSTEM.OBJ.Load("/opt/irisapp/Installer.cls", "ck")
set sc = ##class(App.Installer).setup()  zn "%SYS"
Do ##class(Security.Users).UnExpireUserPasswords("*") ; call your initial methods here
halt

docker-compose.yml

Por que precisamos de docker-compose.yml ? Não poderíamos simplesmente construir e executar a imagem apenas com Dockerfile? Sim, poderíamos. Mas docker-compose.yml simplifica a vida.

Normalmente, docker-compose.yml é usado para iniciar várias imagens docker conectadas a uma rede.

docker-compose.yml também pode ser usado para tornar a inicialização de uma imagem docker mais fácil quando lidamos com muitos parâmetros. Você pode usá-lo para passar parâmetros para o docker, como mapeamento de portas, volumes, parâmetros de conexão VSCode.

version: '3.6' 
services:
  iris:
    build: 
      context: .
      dockerfile: Dockerfile
    restart: always
    ports: 
      - 51773
      - 52773
      - 53773
    volumes:
      - ~/iris.key:/usr/irissys/mgr/iris.key
      - ./:/irisdev/app

Aqui, declaramos o serviço iris, que usa o arquivo docker Dockerfile e expõe as seguintes portas do IRIS: 51773, 52773, 53773. Além disso, este serviço mapeia dois volumes: iris.key do diretório inicial da máquina host para a pasta IRIS onde é esperado, e ele mapeia a pasta raiz do código-fonte para a pasta /irisdev/app.

Docker-compose nos oferece o comando mais curto e unificado para construir e executar a imagem, quaisquer que sejam os parâmetros que você configurar no docker compose.

em qualquer caso, o comando para construir e lançar a imagem é:

$ docker-compose up -d

 e para abrir o terminal IRIS:

$ docker-compose exec iris iris session iris

Node: 05a09e256d6b, Instance: IRIS

USER>

Além disso, docker-compose.yml ajuda a configurar a conexão para o plugin VSCode ObjectScript.

.vscode/settings.json

A parte relacionada às configurações de conexão da extensão ObjectScript é esta:

{
    "objectscript.conn" :{
      "ns": "IRISAPP",
      "active": true,
      "docker-compose": {
        "service": "iris",
        "internalPort": 52773
      }
    }     

}

Aqui vemos as configurações, que são diferentes das configurações padrão do plugin VSCode ObjectScript.

Aqui, dizemos que queremos nos conectar ao namespace IRISAPP (que criamos com Installer.cls):

"ns": "IRISAPP",

e há uma configuração docker-compose, que informa que, no arquivo docker-compose dentro do serviço "iris", o VSCode se conectará à porta, para a qual 52773 está mapeado:

"docker-compose": {
        "service": "iris",
        "internalPort": 52773
      }

Se verificarmos o que temos para 52773, veremos que esta é a porta mapeada não definida para 52773:

ports: 
      - 51773
      - 52773
      - 53773

Isso significa que uma porta aleatória disponível em uma máquina host será obtida e o VSCode se conectará a este IRIS no docker via porta aleatória automaticamente.

Este é um recurso muito útil, pois oferece a opção de executar qualquer quantidade de imagens do docker com IRIS em portas aleatórias e ter VSCode conectado a elas automaticamente.

E quanto a outros arquivos?

Nos também temos:

.dockerignore  - arquivo que você pode usar para filtrar os arquivos da máquina host que você não deseja que sejam copiados para a imagem docker que você construir. Normalmente .git e .DS_Store são linhas obrigatórias.

.gitattributes - atributos para git, que unificam terminações de linha para arquivos ObjectScript em fontes. Isso é muito útil se o repositório for colaborado por proprietários de Windows e Mac/Ubuntu.

.gitignore - arquivos, os quais você não deseja que o git rastreie o histórico de alterações. Normalmente, alguns arquivos ocultos no nível do sistema operacional, como .DS_Store.

Ótimo!

Como tornar seu repositório executável em docker e amigável para colaboração?

  1. Clone este repositório.

  2. Copie todos esses arquivos:

Dockerfile

docker-compose.yml

Installer.cls

iris.script

settings.json{#9f423fcac90bf80939d78b509e9c2dd2-d165a4a3719c56158cd42a4899e791c99338ce73}

.dockerignore{#f7c5b4068637e2def526f9bbc7200c4e-c292b730421792d809e51f096c25eb859f53b637}
.gitattributes{#fc723d30b02a4cca7a534518111c1a66-051218936162e5338d54836895e0b651e57973e1}
.gitignore{#a084b794bc0759e7a6b77810e01874f2-e6aff5167df2097c253736b40468e7b21e577eeb}

para o seu repositório.

Altere esta linha no Dockerfile para corresponder ao diretório com ObjectScript no repositório que você deseja importar para o IRIS (ou não altere se estiver na pasta /src).

É isso. E todos (e você também) terão seu código importado para o IRIS em um novo namespace IRISAPP.

Como as pessoas irão iniciar o seu projeto

o algoritmo para executar qualquer projeto ObjectScript no IRIS pode ser:

  1. Clone o projeto Git localmente

  2. Execute o projeto:

$ docker-compose up -d
$ docker-compose exec iris iris session iris

Node: 05a09e256d6b, Instance: IRIS

USER>zn "IRISAPP"

**Como qualquer desenvolvedor pode contribuir para o seu projeto **

  1. Bifurque o repositório e clone o repositório git bifurcado localmente

  2. Abra a pasta no VSCode (eles também precisam que as extensões Docker e ObjectScript estejam instaladas no VSCode)

  3. Clique com o botão direito em docker-compose.yml->Reiniciar - VSCode ObjectScript irá conectar-se automaticamente e estará pronto para editar/compilar/depurar

  4. Commit, Push e Pull as mudanças solicitadas em seu repositório

Aqui está um pequeno gif sobre como isso funciona:

É isso! Viva a programação!

0
0 490