Desenvolvendo um Atualizador de arquivos.

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (6)  (0)

Desenvolvendo um atualizador de arquivos por versão via protocolo TCP, com componentes nativos.

Bom, como todos sabem, um atualizador cai muito bem para quem desenvolve programas empresariais, pela sua praticidade de atualização.

Bom, vamos começar fazendo o servidor, que é a parte mais simples!

Vamos precisar de:
1* Pagecontrol
1* Memo
1* TidTCPServer
1* TidAntiFreeze
1* TGroupBox
2* TEdits

Altere a propriedade name do formulário para: "FormPrincipalServer".
Altere a propriedade name de um edit para: "edtVersoes"e coloque o caption dele de: "Versoes.txt"
Altere a propriedade name de outro edit para: "edt1" e coloque o caption dele de: "C:\ServerAtualizador"
Altere a propriedade name do idTCPServer1 para: "Servidor"
Altere a propriedade DefaultPort do Servidor para: 34005
Altere a propriedade Bindings do Servidor para: ":34005"
Altere a propriedade Active do Servidor para: True
Crie duas TABS no PageControl, e uma chame de LOG e coloque o memo dentro dela com a propriedade align= alClient
A outra, chame de Configuração, e coloque os dois edits lá.

Crie uma pasta no seu diretório C:\ chamada "ServerAtualizador"
Crie um arquivo nesta pasta chamado versoes.txt contendo o arquivo que você desja atualizar e a versão dele ao lado EX: "Modulo1.exe=1.0.0.1"


Desta forma:
server1.JPGserver2.JPG

Agora vá no Servidor no evento OnExecute e coloque:

var
  Comando, Parametro, Linha, IP: string;
  Stream: TMemoryStream;
begin
  //Procesando os comandos
  Linha:= AThread.Connection.ReadLn; //Lê a linha enviada.
  IP:= AThread.Connection.Binding.PeerIP;
  Parametro:= Copy(Linha, Pos(` `,Linha)+1, length(Linha) );
  Comando:= LowerCase(copy(Linha, 1, pos( ,Linha)-1));

  if Comando = `arquivoversoes` then begin
    //Envia para o cliente, o aquivo de versões
    try
      mmo1.Lines.Add(IP + ` :: Requisição de arquivo de versões`);
      Stream:= TMemoryStream.Create;
      Stream.LoadFromFile(edt1.Text + `\` + edtVersoes.Text);
      AThread.Connection.WriteLn(inttostr(Stream.Size)); //Envia o tamanho do arquivo
      AThread.Connection.WriteStream(Stream);
    finally
      Stream.Free;
    end;
  end else

  if Comando = `get` then begin
    //Envia para o cliente, o aquivo que ele pediu.
    try
      mmo1.Lines.Add(IP + ` :: Requisição de arquivo "` + Parametro + `"`);
      Stream:= TMemoryStream.Create;
      Stream.LoadFromFile(edt1.Text + `\` + Parametro);
      AThread.Connection.WriteLn(inttostr(Stream.Size)); //Envia o tamanho do arquivo
      AThread.Connection.WriteStream(Stream);
    finally
      Stream.Free;
    end;
  end;

No OnConnect coloque:
  mmo1.Lines.Add(AThread.Connection.Binding.PeerIP + ` Conectado`);
  AThread.Connection.WriteLn(`[Servidor]Você está conectado ao servidor de atualização`);

Agora, Declare uma variável Global Chamada: "Local" do tipo string e antes do End. coloque isto:

initialization
  Local:=ExtractFilePath(Application.ExeName);

finalization


O Servidor Já está pronto, salve, compile-o e mantenha-o aberto.

-----------

O Cliente...
O Cliente é a chave fundamental para a atualização, é ele quem verifica e faz o pedido do que tem que ser atualizado de acordo com a versão do arquivo.

Para o Cliente, utilizaremos os seguintes componentes:
2* Panels
1* Memo
1* Button
1* TidTCPClient
1* TidAntiFreeze

Agora, esta é a parte mais trabalhosa, pois há bastante código.

*Defina o nome do formulário de: "FormPrincipalAtualizador"

*Crie duas Variáveis Globais (Elas servirão para armazenar o local do executavel e se já foi atualizado ou não.):

  Atualizado: Boolean;
  Local: String;
 

*Altere a propriedade name do Memo1 para: "mmo1" coloque-o dentro de um panel, com a propriedade align do panel como alClient

*Defina o caption do Button1 para "Atualizar", coloque-o dentro de um panel. com a propriedade align do panel para alBottom

*Defina a propriedade name do idTCPClient1 para "Cliente", e também troque a propriedade Port para 34005

**Ambos os panels separados dentro do form... e não um dentro do outro.

O formulário tera de ficar mais ou menos assim:


---
Para que consigamos a versão do executável, temos que utilizar uma função; Coloque esta função em baixo do {$R *.DFM}

function GetVersion(Arquivo:String): string;
var
  VerInfoSize: DWORD;
  VerInfo: Pointer;
  VerValueSize: DWORD;
  VerValue: PVSFixedFileInfo;
  Dummy: DWORD;
begin
  Result := ``;
  VerInfoSize := GetFileVersionInfoSize(PChar(Arquivo), Dummy);
  if VerInfoSize = 0 then Exit;
  GetMem(VerInfo, VerInfoSize);
  GetFileVersionInfo(PChar(Arquivo), 0, VerInfoSize, VerInfo);
  VerQueryValue(VerInfo, `\`, Pointer(VerValue), VerValueSize);
  with VerValue^ do
  begin

    Result := IntToStr(dwFileVersionMS shr 16);
    Result := Result + `.` + IntToStr(dwFileVersionMS and $FFFF);
    Result := Result + `.` + IntToStr(dwFileVersionLS shr 16);
    Result := Result + `.` + IntToStr(dwFileVersionLS and $FFFF);
  end;
  FreeMem(VerInfo, VerInfoSize);
end;

Esta função retorna a versão de um arquivo no formato X.X.X.X... EX: 1.0.0.1
Será de muita importância para a atualização correta dos arquivos.

Adicione estas funções extras na seção Private

Procedure TFormPrincipalAtualizador.AdicionaLog(Linha:String);
Begin
  mmo1.Lines.add( DateToStr(now)+` `+ TimeToStr(Now) + ` :: ` + Linha );
  Application.ProcessMessages;
end;

Function TFormPrincipalAtualizador.VerificaVersao(Internet, Local:String):Boolean;
var
  Buffer : String;
  I : Integer;
  NET : array [1..4] of integer;
  LOC : array [1..4] of integer;
Begin
  Buffer:= Internet+`.`;//Define a variavel para a versao da internet
  for I:=1 to 4 do begin
    NET[I]:= StrToInt( Copy(Buffer, 1, pos(`.`,Buffer)-1 ) ); //copia o  numero até o ponto
    Delete(Buffer, 1, pos(`.`,Buffer)); //excui até o ponto para pegar o próximo
  end;
  Buffer:= Local+`.`;//Define a variavel para a versao Local
  for I:=1 to 4 do begin
    LOC[I]:= StrToInt( Copy(Buffer, 1, pos(`.`,Buffer)-1 ) ); //copia o numero até o ponto
    Delete(Buffer, 1, pos(`.`,Buffer)); //excui até o ponto para pegar o próximo
  end;
  Result:= (NET[1] > LOC[1]) or (NET[2] > LOC[2]) or (NET[3] > LOC[3]) or (NET[4] > LOC[4]);
end;

Esta função testa se há alguma versão maior... e retorna True caso haja ou False caso contrário.

Agora, vá na ação OnClick do Button1 e coloque o seguinte código:

if
Atualizado then begin
  Cliente.Disconnect;
  Close;
end else begin
  Button1.Enabled:=False;
  InicializarAtualizacao;
  Button1.Caption:=`Fechar`;
end;

Isto fará com que a atualização seja iniciada e após ela libere o botão e faça sair.

Na ação OnWorkBegin do Cliente coloque o seguinte código:

AdicionaLog(`Baixando arquivo. Tamanho`+inttostr(AWorkCountMax div 1024)+`KB`);

---
Agora, antes do End., coloque este código, ele fará com que a variável "Local" guarde o local do aplicativo.

initialization
  Local:=ExtractFilePath(Application.ExeName);

finalization

---
OK! Agora falta a mais importante de todas!!!
O Procedimento que atualiza.
Declare ele na seção Private.

Procedure TFormPrincipalAtualizador.InicializarAtualizacao;
  procedure HabilitaCampos;
  Begin
    Atualizado:=True;
    Button1.Enabled:=True;
  end;
var

  Stream : TMemoryStream;
  Versoes : TStrings;
  I : Integer;
  Arquivo, Versao: String;
begin
  AdicionaLog(`Iniciando Atualização`);
  try
    AdicionaLog(`Tentando Conexão com:`+Cliente.Host);
    Cliente.Connect; //Tenta se conectar
    AdicionaLog(Cliente.ReadLn);
    AdicionaLog(`Conexão estabelecida com sucesso`);
  except
    on
e: Exception do begin
      AdicionaLog(`Falha ao se conectar com o servidor de atualização.`);
      AdicionaLog(`ERRO: "`+e.Message+`"`);
      HabilitaCampos;
      Exit;
    end;
  end;


  //A conexão obteve sucesso.
  AdicionaLog(`Pedindo Arquivo de versões...`);
  with Cliente do begin
    Versoes:= TStringList.Create;
    Stream:= TMemoryStream.Create;
    WriteLn(`arquivoversoes `); //manda o comando para o servidor. (deixe um espaço após o texto.)

    Stream.size:=StrToInt( ReadLn ); //Lê o tamanho que o servidor enviou.
    ReadStream(Stream, Stream.size, False); //Lê a stream que o servidor enviou.
    Stream.Position:=0; //manda a memória do Stream para o início

    If Stream.Memory = nil then begin //se estiver zerado deu erro.
      AdicionaLog(`Falha ao transferir a lista de versões.`);
      HabilitaCampos;
      Exit;
    end;

    Versoes.LoadFromStream(Stream); //Faz as linhas de versões lerem
    AdicionaLog(`Lista de versões transferida com sucesso.`);
  end;
  AdicionaLog(`Verificando Versões...`);

  For I:= 0 to Versoes.Count-1 do begin
    Arquivo:= copy(Versoes.Strings[I], 1, pos(`=`,Versoes.Strings[I])-1);
    Versao:= copy(Versoes.Strings[I], pos(`=`,Versoes.Strings[I])+1, length(Versoes.Strings[I]));
    if FileExists(Local + Arquivo) then
      if VerificaVersao(Versao, GetVersion(Local + Arquivo)) then begin
        AdicionaLog(`Versão `+GetVersion(Local + Arquivo)+` do Arquivo:"`+extractfilename(Arquivo)+`"`+` será atualizada para: `+versao);
        AdicionaLog(`Requisitando arquivo ao servidor...`);

        with Cliente do begin
          WriteLn(`get `+Arquivo);
          Stream.size:=StrToInt( ReadLn ); //Lê o tamanho que o servidor enviou.
          ReadStream(Stream, Stream.size, False); //Lê a stream que o servidor enviou.
          Stream.Position:=0; //manda a memória do Stream para o início
          Stream.SaveToFile(Local + Arquivo);
          AdicionaLog(`Download do arquivo: `+Arquivo+` Concluído.`);
        end;
      end;//if verifica....

 
AdicionaLog(`Atualização Terminada.`);
  end;
  HabilitaCampos;
end;

Este procedimento, manda um comando de requisição de versões para o servidor, após receber, ele percorre a lista de versões e verifica os seus respectivos arquivos e suas versões, caso sejam inferior, ele requisita um novo arquivo para o servidor.
Também, caso o arquivo não exista no diretório onde está o atualizador, ele não executa nada.

Pronto!
Agora uma imagem dos dois funcionando.


Está concluído o nosso Atualizador!

Um forte abraço, até a próxima!

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?