Jump to content

dev botao

Problemas ao utlizar acbr multithread com servidor web


Recommended Posts

  • Membros Pro

Bom dia.

Estamos desenvolvendo uma API golang utilizando o ACBrLib para emissão de MDFe.
Para isso funcionar precisamos desenvolver uma interface em golang para chamar as funções da so (Estamos usando linux).
Já é possivel chamar as funções do ACBrLib e transmissões, porém temos um problema.
Ao tentar usar a biblioteca multithread fazendo multiplas requisições (simuladas com a AB), a aplicação quebra de forma intermitente. Todas as vezes que ela quebra está relacionado a falha de segmentação que vem da lib.
A estrutura de canais para controlar o multhread desenvolvida no golang está funcional, iniciamos a biblioteca e usamos a função desejada.
Existe alguma limitação para o uso da biblioteca multithread?
Existe alguma coisa que esquecemos de usar ao chamar as funções do ACBrLib?
Alguém já teve essa experiencia de usar o ACBrLib para desenvolver uma API multithread para emissão de algum documento fiscal?
Abaixo segue um trecho do código desenvolvido para a aplicação.

 


func (p poolLib) Status() string {
	return p.seletor()
}

func (p *poolLib) seletor() string {

	var lib uintptr

	lib = <-liver

	usando <- lib

	status := p.acbr.Status(lib)

	lib = <-usando

	liver <- lib

	return status
}

func NewPool(libacbr Dominio.IEnviar) Poollib {

	chLivre := make(chan uintptr, 4)

	chUsado := make(chan uintptr, 4)

	for i := 0; i < 4; i++ {

		var ptr uintptr

		libacbr.Init(&ptr)

		chLivre <- ptr
	}

	liver = chLivre

	usando = chUsado

	return &poolLib{

		acbr: libacbr,
	}
}

Chamada a função delegada da lib

func (m MDFe) callStatus(uintptr2 uintptr) string {

	bytes := m.bufferNew()
	
	versao := m.versao(uintptr2, bytes, &m.tamanho)
	
	return strconv.Itoa(versao)
}

Estamos usando a função versão para teste a comunicação com lib para evitar chamadas desnecessárias a sefaz

Link to comment
Share on other sites

  • Consultores
6 minutos atrás, Dev Comercial disse:

Bom dia.

Estamos desenvolvendo uma API golang utilizando o ACBrLib para emissão de MDFe.
Para isso funcionar precisamos desenvolver uma interface em golang para chamar as funções da so (Estamos usando linux).
Já é possivel chamar as funções do ACBrLib e transmissões, porém temos um problema.
Ao tentar usar a biblioteca multithread fazendo multiplas requisições (simuladas com a AB), a aplicação quebra de forma intermitente. Todas as vezes que ela quebra está relacionado a falha de segmentação que vem da lib.
A estrutura de canais para controlar o multhread desenvolvida no golang está funcional, iniciamos a biblioteca e usamos a função desejada.
Existe alguma limitação para o uso da biblioteca multithread?
Existe alguma coisa que esquecemos de usar ao chamar as funções do ACBrLib?
Alguém já teve essa experiencia de usar o ACBrLib para desenvolver uma API multithread para emissão de algum documento fiscal?
Abaixo segue um trecho do código desenvolvido para a aplicação.

 


func (p poolLib) Status() string {
	return p.seletor()
}

func (p *poolLib) seletor() string {

	var lib uintptr

	lib = <-liver

	usando <- lib

	status := p.acbr.Status(lib)

	lib = <-usando

	liver <- lib

	return status
}

func NewPool(libacbr Dominio.IEnviar) Poollib {

	chLivre := make(chan uintptr, 4)

	chUsado := make(chan uintptr, 4)

	for i := 0; i < 4; i++ {

		var ptr uintptr

		libacbr.Init(&ptr)

		chLivre <- ptr
	}

	liver = chLivre

	usando = chUsado

	return &poolLib{

		acbr: libacbr,
	}
}

Chamada a função delegada da lib

func (m MDFe) callStatus(uintptr2 uintptr) string {

	bytes := m.bufferNew()
	
	versao := m.versao(uintptr2, bytes, &m.tamanho)
	
	return strconv.Itoa(versao)
}

Estamos usando a função versão para teste a comunicação com lib para evitar chamadas desnecessárias a sefaz

Consegue saber o método que quebra? Tem algum retorno quando inicializa? 

Link to comment
Share on other sites

  • Membros Pro

 A aplicação consegue inicializar e funcionar corretamente.  De forma intermitente ao chamar o método versão da lib a aplicação quebra somente com status 255 ou com esse log

SIGSEGV: segmentation violation
PC=0x7f25a3646cc9 m=3 sigcode=128 addr=0x0
signal arrived during cgo execution

goroutine 442 gp=0xc000582700 m=3 mp=0xc000069008 [syscall]:
runtime.cgocall(0x4e8be0, 0xc00047ea90)
        /home/julionovaes/sdk/go1.22.2/src/runtime/cgocall.go:157 +0x4b fp=0xc000308a60 sp=0xc000308a28 pc=0x4073ab
github.com/ebitengine/purego.RegisterFunc.func1({0xc00017ac80?, 0x3?, 0x3?})
        /home/julionovaes/go/pkg/mod/github.com/ebitengine/[email protected]/func.go:302 +0xc85 fp=0xc000308ee0 sp=0xc000308a60 pc=0x4e62c5
reflect.callReflect(0xc000421890, 0xc000309438, 0xc000309310, 0xc000309318)
        /home/julionovaes/sdk/go1.22.2/src/reflect/value.go:782 +0x549 fp=0xc0003092c0 sp=0xc000308ee0 pc=0x4c7d69
reflect.callReflect(0xc000421890, 0xc000309438, 0xc000309310, 0xc000309318)
        <autogenerated>:1 +0x45 fp=0xc0003092f0 sp=0xc0003092c0 pc=0x4d3865
reflect.makeFuncStub()
        /home/julionovaes/sdk/go1.22.2/src/reflect/asm_amd64.s:47 +0x6e fp=0xc000309438 sp=0xc0003092f0 pc=0x4d2f4e
MDFe/mdfe.MDFe.callStatus({{0x9ef7c0, 0xc0004ac2c0}, 0x0, 0xc0004217d0, 0xc000421890, 0xc0004218f0, 0xc0004219b0, 0xc000421a10, 0xc000421ad0, 0xc000421b90, ...}, ...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/MDFeLib.go:49 +0x155 fp=0xc0003094e8 sp=0xc000309438 pc=0x512d75
MDFe/mdfe.MDFe.Status(...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/MDFeLib.go:42
MDFe/mdfe.(*MDFe).Status(0x4d7e3f?, 0x0?)
        <autogenerated>:1 +0x85 fp=0xc0003095b0 sp=0xc0003094e8 pc=0x513785
MDFe/mdfe.(*poolLib).seletor(0xc0003095f8)
        /home/julionovaes/GolandProjects/MDFe/mdfe/testePoolMDFe.go:31 +0x65 fp=0xc0003095f0 sp=0xc0003095b0 pc=0x513225
MDFe/mdfe.poolLib.Status(...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/testePoolMDFe.go:20
MDFe/mdfe.(*poolLib).Status(0x9ef780?)
        <autogenerated>:1 +0x45 fp=0xc000309630 sp=0xc0003095f0 pc=0x513825
main.main.func1(0xc000146000)
        /home/julionovaes/GolandProjects/MDFe/main.go:75 +0x77 fp=0xc000309698 sp=0xc000309630 pc=0x83ec37
github.com/gin-gonic/gin.(*Context).Next(...)

 

Link to comment
Share on other sites

  • Consultores
1 minuto atrás, Dev Comercial disse:

 A aplicação consegue inicializar e funcionar corretamente.  De forma intermitente ao chamar o método versão da lib a aplicação quebra somente com status 255 ou com esse log

SIGSEGV: segmentation violation
PC=0x7f25a3646cc9 m=3 sigcode=128 addr=0x0
signal arrived during cgo execution

goroutine 442 gp=0xc000582700 m=3 mp=0xc000069008 [syscall]:
runtime.cgocall(0x4e8be0, 0xc00047ea90)
        /home/julionovaes/sdk/go1.22.2/src/runtime/cgocall.go:157 +0x4b fp=0xc000308a60 sp=0xc000308a28 pc=0x4073ab
github.com/ebitengine/purego.RegisterFunc.func1({0xc00017ac80?, 0x3?, 0x3?})
        /home/julionovaes/go/pkg/mod/github.com/ebitengine/[email protected]/func.go:302 +0xc85 fp=0xc000308ee0 sp=0xc000308a60 pc=0x4e62c5
reflect.callReflect(0xc000421890, 0xc000309438, 0xc000309310, 0xc000309318)
        /home/julionovaes/sdk/go1.22.2/src/reflect/value.go:782 +0x549 fp=0xc0003092c0 sp=0xc000308ee0 pc=0x4c7d69
reflect.callReflect(0xc000421890, 0xc000309438, 0xc000309310, 0xc000309318)
        <autogenerated>:1 +0x45 fp=0xc0003092f0 sp=0xc0003092c0 pc=0x4d3865
reflect.makeFuncStub()
        /home/julionovaes/sdk/go1.22.2/src/reflect/asm_amd64.s:47 +0x6e fp=0xc000309438 sp=0xc0003092f0 pc=0x4d2f4e
MDFe/mdfe.MDFe.callStatus({{0x9ef7c0, 0xc0004ac2c0}, 0x0, 0xc0004217d0, 0xc000421890, 0xc0004218f0, 0xc0004219b0, 0xc000421a10, 0xc000421ad0, 0xc000421b90, ...}, ...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/MDFeLib.go:49 +0x155 fp=0xc0003094e8 sp=0xc000309438 pc=0x512d75
MDFe/mdfe.MDFe.Status(...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/MDFeLib.go:42
MDFe/mdfe.(*MDFe).Status(0x4d7e3f?, 0x0?)
        <autogenerated>:1 +0x85 fp=0xc0003095b0 sp=0xc0003094e8 pc=0x513785
MDFe/mdfe.(*poolLib).seletor(0xc0003095f8)
        /home/julionovaes/GolandProjects/MDFe/mdfe/testePoolMDFe.go:31 +0x65 fp=0xc0003095f0 sp=0xc0003095b0 pc=0x513225
MDFe/mdfe.poolLib.Status(...)
        /home/julionovaes/GolandProjects/MDFe/mdfe/testePoolMDFe.go:20
MDFe/mdfe.(*poolLib).Status(0x9ef780?)
        <autogenerated>:1 +0x45 fp=0xc000309630 sp=0xc0003095f0 pc=0x513825
main.main.func1(0xc000146000)
        /home/julionovaes/GolandProjects/MDFe/main.go:75 +0x77 fp=0xc000309698 sp=0xc000309630 pc=0x83ec37
github.com/gin-gonic/gin.(*Context).Next(...)

 

Tu disse que é intermitente, ela quebra e é recarregada novamente? 

Link to comment
Share on other sites

  • Consultores
Agora, Dev Comercial disse:

Quando quebra a aplicação finaliza e não tenho como recarregar a lib

Então o que tu quis dizer com o intermitente é que ocorre algumas vezes, mas não sempre?

1 minuto atrás, Dev Comercial disse:

Quando quebra a aplicação finaliza e não tenho como recarregar a lib

Estou olhando a sua implementação, verifique as possibilidades de um ponteiro nulo.

  • Like 1
Link to comment
Share on other sites

  • Consultores
19 minutos atrás, Dev Comercial disse:

xiste algum exemplo trabalhando com as libs do acbr em alguma api com multithread ?

existe alguns exemplos como java, c#, python
https://svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Demos/

Qual versão da sua lib, pode anexar o log configurado paranoico aqui para nós

Consultor SAC ACBr

Daniel de Morais (Infocotidiano)
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Link to comment
Share on other sites

  • Membros Pro

Bom dia.

Fiz um teste com a lib nfe, com esta o multithread funciona corretamente tanto usando varias instancias do ponteiro quanto utilizando uma instancia só. segue um exemplo do código.

Porém eu preciso usar a libmdfe.

 

package main

import (
	"fmt"
	"github.com/ebitengine/purego"
	"log"
	"regexp"
)

var ultimoRetorno func(uintptr, []byte, *int) int
var versao func(uintptr, []byte, *int) int
var inicializar func(*uintptr, string, string) int
var tamanho = 255

func main() {

	var lib = "NFe"

	if lib == "NFe" {
		lib := carregarLib("/home/julionovaes/mega/NFe/libacbrnfe64.so")
		purego.RegisterLibFunc(&versao, lib, "NFE_Versao")
		purego.RegisterLibFunc(&ultimoRetorno, lib, "NFE_UltimoRetorno")
		purego.RegisterLibFunc(&inicializar, lib, "NFE_Inicializar")
	} else {
		lib := carregarLib("/home/julionovaes/documentos/libacbrmdfe64.so")
		purego.RegisterLibFunc(&inicializar, lib, "MDFE_Inicializar")
		purego.RegisterLibFunc(&versao, lib, "MDFE_Versao")
		purego.RegisterLibFunc(&ultimoRetorno, lib, "MDFE_UltimoRetorno")
	}

	var listPtr []uintptr

	for i := 0; i < 6; i++ {

		var pt uintptr

		inicializar(&pt, "", "")

		listPtr = append(listPtr, pt)

	}

	go func() {
		callVersao(listPtr[0])
	}()
	go func() {
		callVersao(listPtr[1])
	}()

	go func() {
		callVersao(listPtr[0])
	}()
	go func() {
		callVersao(listPtr[1])
	}()
	go func() {
		callVersao(listPtr[0])
	}()
	go func() {
		callVersao(listPtr[1])
	}()

	go func() {
		callVersao(listPtr[0])
	}()
	go func() {
		callVersao(listPtr[1])
	}()

	fmt.Println("Processamento concluído!")

}


func callVersao(uintptr2 uintptr) string {

	bytes := bufferNew()

	var versaor int

	if &uintptr2 != nil {

		fmt.Println("<<<<<<<<<<<<<<<<<<<< pointer ", uintptr2, ">>>>>>>>>>>>>>>>>>>>>>>>>>")

		versaor = versao(uintptr2, bytes, &tamanho)

		fmt.Println("<<<<<<<<<<<<<<<<<<<< Quebrou ? ", uintptr2, ">>>>>>>>>>>>>>>>>>>>>>>>>>")

	}

	return string(versaor)
}

 

Link to comment
Share on other sites

  • Consultores
4 horas atrás, Dev Comercial disse:

Porém eu preciso usar a libmdfe.

O principio é o mesmo de todas as Libs. So abstrair o nome da lib e metodos q pode ter nomes diferentes.
Mas o uso do ponteiro é igual para todas as libs.

 

Consultor SAC ACBr

Daniel de Morais (Infocotidiano)
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Link to comment
Share on other sites

  • Membros Pro

Sabemos disso, porem o processo multithread na mdfe não funciona como na libnfe por exemplo. Fizemos o teste para verificar justamente isso. a libmdfe apresenta um comportamento diferente falhando com múltiplas chamadas enquanto a libnfe não tem esse mesmo comportamento.

O código é um só para exemplificar.

 

Link to comment
Share on other sites

  • Consultores
1 minuto atrás, Dev Comercial disse:

O código é um só para exemplificar.

anexe o log por favor;
apenas confirmando a lib utilizada na MDFE é MT ? (pergundo, pois como ST e MT tem o mesmo nome, as vezes pode confundir)
 

Consultor SAC ACBr

Daniel de Morais (Infocotidiano)
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Link to comment
Share on other sites

  • Membros Pro

Na inicialização da lib ST teria dado erro por conta o ponteiro lib handle 

Segue o log da lib MDFe MT. Não apresenta mensagem de erro apenas para de funcionar 

17/09/24 10:27:15:797 - TLibMDFeConfig.AplicarConfiguracoes: /home/julionovaes/downloads/AcbrLibConfig.ini
17/09/24 10:27:15:797 - Travar
17/09/24 10:27:15:798 - TLibMDFeConfig.AplicarConfiguracoes - Feito
17/09/24 10:27:15:798 - Destravar
17/09/24 10:27:15:798 - TLibMDFeConfig.Ler - Feito
17/09/24 10:27:15:798 - Destravar
17/09/24 10:27:15:798 -    SetRetorno(0, )
17/09/24 10:27:33:597 - LIB_Versao
17/09/24 10:27:33:597 -    MoverStringParaPChar. StrLen:9, BufLen:0
17/09/24 10:27:33:597 - LIB_Versao
7/09/24 10:27:33:597 -    Versao:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------, len:9
17/09/24 10:27:33:597 -    MoverStringParaPChar. StrLen:9, BufLen:0
7/09/24 10:27:33:597 -    SetRetorno(0, 1.2.2.266)
17/09/24 10:27:33:597 -    Versao:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------, len:9
17/09/24 10:40:02:958 - TLibMDFeConfig.AplicarConfiguracoes: /home/julionovaes/downloads/AcbrLibConfig.ini
17/09/24 10:40:02:958 - Travar
17/09/24 10:40:02:958 - TLibMDFeConfig.AplicarConfiguracoes - Feito
17/09/24 10:40:02:958 - Destravar
17/09/24 10:40:02:958 - TLibMDFeConfig.Ler - Feito
17/09/24 10:40:02:958 - Destravar
17/09/24 10:40:02:958 -    SetRetorno(0, )
17/09/24 10:45:19:715 - TLibMDFeConfig.AplicarConfiguracoes: /home/julionovaes/downloads/AcbrLibConfig.ini
17/09/24 10:45:19:715 - Travar
17/09/24 10:45:19:715 - TLibMDFeConfig.AplicarConfiguracoes - Feito
17/09/24 10:45:19:715 - Destravar
17/09/24 10:45:19:715 - TLibMDFeConfig.Ler - Feito
17/09/24 10:45:19:715 - Destravar
17/09/24 10:45:19:715 -    SetRetorno(0, )

 

Link to comment
Share on other sites

  • Membros Pro

Estou usando o debian bookworm e a OpenSSL 3.0.14 porém com  OpenSSL Legacy Provider habilitado por conta da  compatibilidade com a biblioteca. a versão 1.1 não pode ser instalada nas distribuições como debian devido a vulnerabilidades o Legacy Provider garante a compatibilidade e tanto que consigo fazer alguns envios.

Link to comment
Share on other sites

  • Consultores

Bom dia @Dev Comercial
Criei uma VM com o Debian 12 (bookworm), esta está com OpenSSL 3.0.14 em Modo Legacy observe o comando

openssl list -providers


criado o link simbólico conforme manual

ln -s /usr/lib/x86_64-linux-gnu/libxml2.so.2 /usr/lib/x86_64-linux-gnu/libxml2.so


Screenshot_418.png

Criei uma aplicação Exemplo em Python para utilizar a lib multithread
Defino os paths, exemplo:

PATH_ACBRLIB_INI = '/home/acbr/Python/MDFe/ACBrLib.INI'
PATH_SCHEMAS = '/home/acbr/Python/MDFe/Schemas/MDFe'
PATH_INIServico = '/home/acbr/Python/MDFe/ACBrMDFeServicos.ini"


Inicializo a biblioteca

LRetorno = acbr_lib.MDFE_Inicializar(byref(ponteiro), PATH_ACBRLIB_INI,"")


Se LRetorno == 0, biblioteca inicializada com sucesso

Configurei o meu ambiente utilizando o metodo MDFE_ConfigGravarValor

#configurando log
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "Principal", "LogNivel", "4")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "Principal", "LogPath", PATH_LOG)      
#configurando certificado e ambiente
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "SSLCryptLib", "1")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "SSLHttpLib", "3")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "SSLXmlSignLib", "4")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "UF", 'SP')
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "ArquivoPFX", ARQ_PFX)
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "DFe", "Senha", SENHA_PFX)
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "MDFe", "Ambiente", "1")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "MDFe", "SSLType", "5")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "MDFe", "PathSchemas", PATH_SCHEMAS)
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "MDFe", "VersaoDF", "1")
acbr_lib.MDFE_ConfigGravarValor(ponteiro, "MDFe", "IniServicos", PATH_INIServico)

Apos configurar utilizo o metodo MDFE_ConfigGravar para salvar no INI as configurações

acbr_lib.MDFE_ConfigGravar(ponteiro, PATH_ACBRLIB_INI.encode("utf-8"))

Por fim , após tudo configurado se eu executar o metodo para consultar status do serviço, obtenho a reposta normalmente:
Abaixo no meu exemplo qdo executo o script do python, verifico onde esta a pasta de schemas, e se existe os arquivos.
Lembrando que o acbrlib.ini se nao existir ele vai criar.
Tem que configurar o path do arquivo ACBrMDFeServicos.INI (na seção [MDFe], "IniServicos", pathServicos igual configurei acima)

Screenshot_421.png

Ele vai criar o arquivo Log, vou anexar aqui: ACBrLibMDFe-20240926.log

Em resumo a lib na VM esta funcionando como esperado.
Por favor veja se estas configurações passada acima estão sendo feitas no seu ambiente.
 

  • Like 1
Consultor SAC ACBr

Daniel de Morais (Infocotidiano)
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Link to comment
Share on other sites

  • Membros Pro

Realmente dessa forma que mostrou, o problema não ocorre. O problema acontece com um múltiplas requisições simultâneas. no caso você pode constatar o problema gerando varias thread manualmente como no exemplo go ou transformando  aplicação em servidor por exemplo com flask e utilizar o comando ab para simular varias requests.

Link to comment
Share on other sites

  • Consultores

Apenas confirmando:


A cada requisição da API vc cria um novoPonteiro / Handle

Inicializa LIb com o novo Ponteiro, se a API permitir varios CNPJ, uma dica é  criar acbrini.ini em uma pasta com CNPJ da empresa requisitada pela api
Isso vai evitar de 2 cnpjs diferentes acessem o mesmo INI
 

MDFE_Inicializar(ponteiro, '/home/MDFe/11222333444455/acbrlib.ini',"")

Configura utilizando o mesmo ponteiro

MDFE_ConfigGravarValor(ponteiro, "Principal", "TipoResposta", "2")

Persisto  a gravacao do INI com o mesmo ponteiro na pasta do CNPJ requisitado

MDFE_ConfigGravar(ponteiro, '/home/MDFe/11222333444455/acbrlib.ini',);

Executa o metodo com o mesmo ponteiro de consulta

MDFE_StatusServico(ponteiro, sResposta, ctypes.byref(esTamanho))

Finalizo a lib, tbm informando o ponteiro (Método usado para remover o componente ACBrMDFe e suas classes da memoria.)

MDFE_Finalizar(ponteiro)

Obviamente se o ponteiro 1001 estiver em uso, nao pode ser usado em outra requisição. cada requisição recebe um ponteiro novo (q nao esteja em uso)
 

  • Like 1
Consultor SAC ACBr

Daniel de Morais (Infocotidiano)
Ajude o Projeto ACBr crescer - Assine o SAC

Projeto ACBr     Telefone:(15) 2105-0750 WhatsApp(15)99790-2976.  Discord

Link to comment
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.