LanterECR / LAN-4GateLibraryCPP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Реализация кассового протокола LAN-4Gate

Сборка Linux Сборка macOS Сборка Windows

Release badge

Total alerts Language grade: C/C++

Список будущих изменений и расширения функционала

Содержание

  1. Описание
  2. Требования
    1. Стандарт
    2. CMake
    3. Компиляторы
    4. Зависимости
  3. Тесты
  4. Переменные CMake
    1. CMAKE_INSTALL_PREFIX
    2. CMAKE_BUILD_TYPE
    3. L4G_BUILD_STATIC
    4. L4G_BUILD_SHARED
    5. L4G_BUILD_MODULE
    6. L4G_BUILD_SWIG
    7. L4G_SWIG_TARGET_LANGUAGE
    8. ENV{HUNTER_ROOT}
  5. Сборка и установка
  6. Подключение к проекту
    1. Подключение к CMake
      1. Поддиректория проекта)
      2. Поиск пакета)
    2. Другие системы сборки
    3. Использование совместно с языками, отличными от C++
  7. Использование
    1. CPP
    2. CSHARP
    3. Java

Описание

Библиотека реализует протокол кассового взаимодействия LAN-4Gate компании ЛАНТЕР.

Для разрешения зависимостей используется пакетный менеджер Hunter версии 0.23.313

Подробная документация сгенерирована Doxygen. Доступна по ссылке и в шапке файла

Требования

Стандарт

Библиотека реализована на С++11. Для компиляции требуется поддержка данной версии.

CMake

Для генерации необходим CMake версии 3.10 и старше

Компиляторы

Требования к компиляторам соответствуют таковым у библиотеки GTest

Для компиляции требуются версии компиляторов не ниже следующих:

  • MSVC 2015
  • GCC 5
  • clang 5.0

Зависимости

Проект зависит от нижеперечисленных библиотек. Зависимости разрешаются пакетным менеджером Hunter.cmake

  • jsoncpp. Используется Object версия библиотеки
  • asio. Используется статическая версия библиотеки
  • GTest

Тесты

Работа библиотеки проверена на нижеперечисленных компиляторах. Работа с другими версиями не гарантируется

  • MSVC версий 2015, 2017 и 2019
  • GCC версий 5, 6, 7, 8 и 9
  • clang версий 5.0, 6.0, 7, 8, 9 и 10

Переменные CMake

Для управления сборкой используются следующие переменные CMake. Переменные могут быть опущены

CMAKE_INSTALL_PREFIX

Стандартная переменная CMake, указывающая путь установки библиотеки

По указанному пути будут установлены компоненты библиотеки при вызове команды установки

Без указания переменной установка будет выполнена в директорию по умолчанию.

CMAKE_BUILD_TYPE

Стандартная переменная CMake, указывающая тип сборки библиотек - Debug, Release, MinSizeRel, RelWithDebInfo

L4G_BUILD_STATIC

Включает или отключает сборку статической версии библиотеки. Включена опция fpic

Значение по умолчанию - ON

cmake -DL4G_BUILD_STATIC=[ON|OFF] [прочие опции...]

L4G_BUILD_SHARED

Включает или отключает сборку динамической версии библиотеки. Включена опция fpic

Значение по умолчанию - ON

cmake -DL4G_BUILD_SHARED=[ON|OFF] [прочие опции...]

L4G_BUILD_MODULE

Включает или отключает сборку динамической модульной библиотеки. Включена опция fpic

Значение по умолчанию - ON

L4G_BUILD_SWIG

Включает сборку библиотеки с использованием SWIG. Включение данной опции отключает остальные сборки L4G_BUILD_*. Будет собрана библиотека с интегрированным интерфейсом доступа из целевого языка и файл, содержащий API на целевом языке

Значение по умолчанию - OFF

cmake -DL4G_BUILD_SWIG=[ON|OFF] [прочие опции...]

L4G_SWIG_TARGET_LANGUAGE

Указывает целевой язык для генерации обертки с помощью SWIG. Имеет действие только при включенной опции L4G_BUILD_SWIG

В текущей версии поддерживается генерация оберток для C# и Java

  • -DL4G_SWIG_TARGET_LANGUAGE=csharp - генерация обертки для C#
  • -DL4G_SWIG_TARGET_LANGUAGE=java - генерация обертки для Java

Значение по умолчанию - csharp

cmake -L4G_BUILD_SWIG=ON -DL4G_SWIG_TARGET_LANGUAGE=csharp [прочие опции...]

L4G_TESTS

Включает или отключает сборку unit-тестов с помощью GTest

Значение по умолчанию - OFF

cmake -DL4G_TESTS=[ON|OFF] [прочие опции...]

ENV{HUNTER_ROOT}

Переменная окружения, указывающая путь расположения Hunter. Если не задана, то Hunter будет скачан и развернут внутри сборочной директории

Сборка и установка

Для сборки необходимо клонировать репозиторий, выполнить генерацию, сборку и установку

git clone https://github.com/LanterECR/LAN-4GateLibraryCPP.git

Для сборки библиотеки необходимо выполнить одно из нижеперечисленных действий

Без указания опции -G будет использован системный генератор. Сборка и установка с параметрами по умолчанию.

cd LAN-4GateLibraryCPP
mkdir build
cd build
cmake ..
cmake --build . --target install

В директории установки будет создана нижеприведенная иерархия папок.

Папка bin будет создана только на Windows. В ней находится dll.

Иерархия соответствует ОС Windows.

Список библиотек Windows

  • l4g_module.dll - динамическая библиотека
  • l4g_shared.dll - динамическая библиотека
  • l4g_shared.lib - статическая библиотека для линовки динамической
  • l4g_static.lib - статическая библиотека

ВНИМАНИЕ: Для библиотек Windows в сборке Debug добавляется суффикс d перед точкой.

В папке share находятся модули cmake, используемые командой find_package()

Install_dir  
│
└───bin
│   │ l4g_shared.dll
│   
└───include
│   │ Lanter
│     └─── ...    
│
└───lib
|   | l4g_shared.lib
|   | l4g_static.lib
|
└───share
    | LAN_4GateLib
      └───cmake
          | LAN_4GateLibConfig.cmake
          | LAN_4GateLibConfig-release.cmake
          | LAN_4GateLibConfigVersion.cmake

В случае сборки SWIG будет сгенерирована библиотека Lan4Gate.dll. Используется совместно с интерфейсным файлом для целевого языка. В случае Debug сборки необходимо удалить суффикс d.

Иерархия каталога установки будет следующей (на примере генерации интерфейса для C#):

Install_dir  
│
└───bin
│   │ Lan4Gate.dll
│   
└───csharp
    | Lan4gateInterface.cs

Цели сборки

После генерации кэша, создаются следующие цели сборки:

  • l4g_shared - сборка динамической библиотеки
  • l4g_static - сборка статической библиотеки
  • install - сборка всех целей и установка в директорию из CMAKE_INSTALL_PREFIX

Подключение к проекту

Подключение к CMake

Для линковки используются следующие интерфейсные библиотеки:

  1. L4G::l4g_shared - подключит динамическую библиотеку
  2. L4G::l4g_static - подключит статическую библиотеку

Линковка выполняется аналогично примеру:

...
add_executable(SomeAwesomeProgram source1.cpp source2.cpp)

target_link_libraries(SomeAwesomeProgram L4G::l4g_shared)
# or
target_link_libraries(SomeAwesomeProgram L4G::l4g_static)
...

Интерфейсные библиотеки содержат путь к заголовочным файлам, соответствующим библиотекам и зависимостям.

Вся информация будет автоматически доступна после добавление к линковке

Поддиректория проекта

Проект может быть подключен как поддиректория проекта, например git submodule

В таком случае предварительная сборка библиотеки не требуется и будет выполнена автоматически вместе с проектом.

Для корректного использования требуется подключение менеджера Hunter ПЕРЕД директивой project. Возможность отключения Hunter появится в следующих версиях.

Пример для следующей иерархии директорий

Project
│
└───3rdparty
│   │ LAN-4GateLibraryCPP
|
| CMakeLists.txt
| source.cpp
set(HUNTER_GATE_PATH ${CMAKE_BINARY_DIR}/cmake/HunterGate.cmake)

if(NOT EXISTS ${HUNTER_GATE_PATH})
   file(DOWNLOAD
           https://raw.githubusercontent.com/cpp-pm/gate/master/cmake/HunterGate.cmake
           ${HUNTER_GATE_PATH})
endif()
include(${HUNTER_GATE_PATH})

HunterGate(
        URL "https://github.com/cpp-pm/hunter/archive/v0.23.313.tar.gz"
        SHA1 "6c369e5aab2749a616917df3b23511535f413604"
)

project(Example)

add_subdirectory(3rdparty/LAN-4GateLibraryCPP)

add_executable(Example source.cpp)

target_link_libraries(Example L4G::l4g_shared)

Поиск пакета

Используется при предварительно скомпилированной библиотеке. Поисковые модули из директории shared должны быть доступны в переменной CMAKE_MODULE_PATH, переменной LAN-4GateLib_ROOT или через PATH

project(Example)

find_package(LAN-4GateLib)

add_executable(Example source.cpp)

target_link_libraries(Example L4G::l4g_shared)

Другие системы сборки

Для подключения к системам сборки, отличным от CMake необходимо указать путь к заголовочным файлам и конкретной версии библиотеки

При работе под Windows линковаться должна статическая библиотека l4g_shared.lib

Использование совместно с языками, отличными от C++

При сборке библиотеки с включённой опцией L4G_BUILD_SWIG будет сгенерирован интерфейсный файл, содержащий API доступа к библиотеке с помощью целевого языка. Данный файл необходимо подключить к проекту согласно правилам используемого языка

Использование

CPP

Для использования функционала библиотеки с языком C++ необходимо подключить заголовочный файл Lanter/Lan4GateInclude.h

Данный файл подключает фабрику соединений, фабрику менеджера ILan4Gate и функцию получения версии библиотеки.

В следующем примере создается менеджер ILan4Gate с логическим идентификатором 1. Ему передается TCP сервер, обслуживающий единственное соединение, который слушает порт по умолчанию - 20501.

В качестве колбеков передаются реализации интерфейсов из пространства имен Lanter::Manager::Callback;

Менеджер запускает отдельный поток.

После ожидается ввод пользователя. Если введен символ "q", то происходит выход. В остальных случаях отправляется Sale на 1 рубль

#include <iostream>

#include "Lanter/Lan4GateIncude.h"

class ConnectionCallback : public Lanter::Manager::Callback::IConnectionCallback {
public:
    ~ConnectionCallback() override = default;

    void newState(bool state) override {
        if(state) {
            std::cout << "==== Gate connected ====" << std::endl;
        } else {
            std::cout << "==== Gate disconnected ====" << std::endl;
        }
    }
};

class RequestCallback : public Lanter::Manager::Callback::IRequestCallback {
public:
    ~RequestCallback() override = default;

    void newData(std::shared_ptr<Lanter::Message::Request::IRequestData> data) override {
        std::cout << std::endl << "===== REQUEST ====" << std::endl;
    }
};

class ResponseCallback : public Lanter::Manager::Callback::IResponseCallback {
public:
    ~ResponseCallback() override = default;

    void newData(std::shared_ptr<Lanter::Message::Response::IResponseData> data) override {
        std::cout << std::endl << "===== RESPONSE ====" << std::endl;
    }
};

class NotificationCallback : public Lanter::Manager::Callback::INotificationCallback{
public:
    ~NotificationCallback() override = default;

    void newData(std::shared_ptr<Lanter::Message::Notification::INotificationData> data) override {
        std::cout << std::endl << "===== NOTIFICATION ====" << std::endl;
    }
};


int main(int argc, char* argv[])
{

    std::cout << " +++++ Lan4Gate library version is " << Lanter::Utils::Version::getVersion() << " +++++" << std::endl;
    auto manager = Lanter::Manager::Lan4GateFactory::getLan4Gate(1, Lanter::Communication::CommunicationFactory::getSingleTcpServer());


    ConnectionCallback connectionCallback;
    manager->addConnectionCallback(connectionCallback);

    RequestCallback requestCallback;
    manager->addRequestCallback(requestCallback);

    ResponseCallback responseCallback;
    manager->addResponseCallback(responseCallback);

    NotificationCallback notificationCallback;
    manager->addNotificationCallback(notificationCallback);

    if(manager->runOnThread() ==Lanter::Manager::ILan4Gate::Status::Success) {
        std::cout << "+++++ Gate started +++++" << std::endl;
    }

    std::string str;
    while(true) {
        std::cin >> str;
        if(str == "q") {
            break;
        }
        auto sale = manager->getPreparedRequest(Lanter::Message::OperationCode::Sale);
        
        sale->setAmount(100); //1 рубль
        sale->setCurrencyCode(643); //Российский рубль
        sale->setEcrMerchantNumber(1);//Логический номер мерчанта
        
        manager->sendMessage(sale);
    }
    return 0;
}

CSHARP

Для использования функционала библиотеки с языком C# необходимо подключить файл Lan4gateInterface.cs, содержащий интерфейс доступа, к проекту, а библиотеку Lan4Gate.dll добавить в зависимости проекта. Библиотека должна находиться в одном каталоге с исполняемым файлом

Интерфейс доступа находится в пространстве имен Lanter.Lan4Gate;

ВНИМАНИЕ: SWIG не генерирует interface для C#. Вместо interface генерируются полноценные классы. Анонимная реализация или множественная имплементация невозможна.

В следующем примере создается менеджер ILan4Gate с логическим идентификатором 1. Ему передается TCP сервер, обслуживающий единственное соединение, который слушает порт по умолчанию - 20501.

В качестве колбеков передаются реализации интерфейсов из пространства имен Lanter.Lan4Gate;

Менеджер запускает отдельный поток.

После ожидается ввод пользователя. Если введен символ "q", то происходит выход. В остальных случаях отправляется FinalizeTransaction

using System;

namespace Lan4GateExample
{
    class ConnectionCallback : Lanter.Lan4Gate.IConnectionCallback
    {
        public override void newState(bool state)
        {
            if (state)
            {
                Console.WriteLine("==== Gate connected ====");
            }
            else
            {
                Console.WriteLine("==== Gate disconnected ====");
            }
        }
    }

    class RequestCallback : Lanter.Lan4Gate.IRequestCallback
    {
        public override void newData(Lanter.Lan4Gate.IRequestData data)
        {
            Console.WriteLine("===== REQUEST ====");
        }
    }

    class ResponseCallback : Lanter.Lan4Gate.IResponseCallback
    {
        public override void newData(Lanter.Lan4Gate.IResponseData data)
        {
            Console.WriteLine("===== RESPONSE ====");
        }
    }

    class NotificationCallback : Lanter.Lan4Gate.INotificationCallback
    {
        public override void newData(Lanter.Lan4Gate.INotificationData data)
        {
            Console.WriteLine("===== NOTIFICATION ====");
        }
    } 

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(" +++++ Lan4Gate library version is " + Lanter.Lan4Gate.Version.getVersion() + " +++++");

            var manager = Lanter.Lan4Gate.Lan4GateFactory.getLan4Gate(1, Lanter.Lan4Gate.CommunicationFactory.getSingleTcpServer());

            manager.addConnectionCallback(new ConnectionCallback());

            manager.addRequestCallback(new RequestCallback());

            manager.addResponseCallback(new ResponseCallback());

            manager.addNotificationCallback(new NotificationCallback());

            if (manager.runOnThread() == Lanter.Lan4Gate.ILan4Gate.Status.Success)
            {
                Console.WriteLine("+++++ Gate started +++++");
            }

            while(true)
            {
                string str = Console.ReadLine();

                if(str == "q")
                {
                    break;
                }

                manager.sendMessage(manager.getPreparedRequest(Lanter.Lan4Gate.OperationCode.FinalizeTransaction));
            }
        }
    }
}

Java

Для использования функционала библиотеки с языком Java необходимо подключить файл Lan4gateInterface.jar, содержащий интерфейс доступа, к проекту, а библиотеку Lan4Gate.dll добавить в зависимости проекта.

Интерфейс доступа находится в пакете org.lanter.lan4gate

ВНИМАНИЕ: SWIG не генерирует interface для Java. Вместо interface генерируются полноценные классы.

В следующем примере создается менеджер ILan4Gate с логическим идентификатором 1. Ему передается TCP клиент на 127.0.0.1, который стучится на порт 20501.

Менеджер запускает отдельный поток.

import org.lanter.lan4gate.CommunicationFactory;
import org.lanter.lan4gate.IConnectionCallback;
import org.lanter.lan4gate.IRequestCallback;
import org.lanter.lan4gate.IRequestData;
import org.lanter.lan4gate.RequestField;
import org.lanter.lan4gate.ILan4Gate;
import org.lanter.lan4gate.Lan4GateFactory;

public class Main {
static {
System.loadLibrary("Lan4Gate");
}
public static void main(String[] args) {
try {

        } catch (UnsatisfiedLinkError ex) {
            System.out.println(ex.getMessage());
        }
        short num = 1;
        ILan4Gate gate = Lan4GateFactory.getLan4Gate(num, CommunicationFactory.getTcpClient(20501));

        gate.addConnectionCallback(new IConnectionCallback(){
            public void newState(boolean state) {
                System.out.println("New state " + state);
            }
        });

        gate.addRequestCallback(new IRequestCallback(){
            public void newData(IRequestData data) {
                System.out.println("=======REQUEST========");
                for(RequestField field : data.getFieldsSet()) {
                    System.out.print("\t-" + field + ": ");

                    switch (field) {

                        case EcrNumber:
                            System.out.println(data.getEcrNumber());
                            break;
                        case EcrMerchantNumber:
                            System.out.println(data.getEcrMerchantNumber());
                            break;
                        case OperationCode:
                            System.out.println(data.getOperationCode());
                            break;
                        case Amount:
                            System.out.println(data.getAmount());
                            break;
                        case PartialAmount:
                            System.out.println(data.getPartialAmount());
                            break;
                        case TipsAmount:
                            System.out.println(data.getTipsAmount());
                            break;
                        case CashbackAmount:
                            System.out.println(data.getCashbackAmount());
                            break;
                        case CurrencyCode:
                            System.out.println(data.getCurrencyCode());
                            break;
                        case RRN:
                            System.out.println(data.getRRN());
                            break;
                        case AuthCode:
                            System.out.println(data.getAuthCode());
                            break;
                        case ReceiptReference:
                            System.out.println(data.getReceiptReference());
                            break;
                        case TransactionID:
                            System.out.println(data.getTransactionID());
                            break;
                        case CardDataEnc:
                            System.out.println(data.getCardDataEnc());
                            break;
                        case OpenTags:
                            System.out.println(data.getOpenTags());
                            break;
                        case EncTags:
                            System.out.println(data.getEncTags());
                            break;
                        case ProviderCode:
                            System.out.println(data.getProviderCode());
                            break;
                        case AdditionalInfo:
                            System.out.println(data.getAdditionalInfo());
                            break;
                        case BonusBalance:
                            System.out.println(data.getBonusBalance());
                            break;
                        case BonusAmount:
                            System.out.println(data.getBonusAmount());
                            break;
                        case HashCardTrack2:
                            System.out.println(data.getHashCardTrack2());
                            break;
                        case PaymentProviderCode:
                            System.out.println(data.getPaymentProviderCode());
                            break;
                        case PaymentParam1:
                            System.out.println(data.getPaymentParam1());
                            break;
                        case PaymentParam2:
                            System.out.println(data.getPaymentParam2());
                            break;
                        case PaymentParam3:
                            System.out.println(data.getPaymentParam3());
                            break;
                    }
                }
                System.out.println();
            }});

        gate.runOnThread();

        while(true);
    }
}

About


Languages

Language:C++ 94.4%Language:C 4.3%Language:CMake 1.0%Language:SWIG 0.3%