trafficmonitor/app/Services/CollectorService.php

163 lines
6.6 KiB
PHP

<?php
namespace App\Services;
use App\DTOs\CollectorDTO;
use App\Entities\CollectorEntity;
use App\Entities\TrafficEntity;
use App\Forms\CollectorForm;
use App\Helpers\CollectorHelper;
use App\Libraries\SNMPLibrary;
use App\Models\CollectorModel;
use CodeIgniter\I18n\Time;
use RuntimeException;
class CollectorService extends CommonService
{
const OID_IF_IN_OCTETS = '1.3.6.1.2.1.31.1.1.1.6.';
const OID_IF_OUT_OCTETS = '1.3.6.1.2.1.31.1.1.1.10.';
private $_form = null;
private $_helper = null;
public function __construct(CollectorModel $model)
{
parent::__construct($model);
$this->addClassPaths('Collector');
}
public function createDTO(array $formDatas): CollectorDTO
{
return new CollectorDTO($formDatas);
}
public function getFormService(): CollectorForm
{
if ($this->_form === null) {
$this->_form = new CollectorForm();
$this->_form->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false),
]);
}
return $this->_form;
}
public function getHelper(): CollectorHelper
{
if ($this->_helper === null) {
$this->_helper = new CollectorHelper();
$this->_helper->setAttributes([
'pk_field' => $this->model->getPKField(),
'title_field' => $this->model->getTitleField(),
'table' => $this->model->getTable(),
'useAutoIncrement' => $this->model->useAutoIncrement(),
'class_path' => $this->getClassPaths(false),
]);
}
return $this->_helper;
}
//기본 기능부분
protected function getEntity_process(mixed $entity): CollectorEntity
{
return $entity;
}
protected function create_process(array $formDatas): CollectorEntity
{
return new CollectorEntity($formDatas);
}
public function create(object $dto): CollectorEntity
{
if (!$dto instanceof CollectorDTO) {
throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다.");
}
return parent::create($dto);
}
protected function modify_process($uid, array $formDatas): CollectorEntity
{
return parent::modify_process($uid, $formDatas);
}
public function modify($uid, object $dto): CollectorEntity
{
if (!$dto instanceof CollectorDTO) {
throw new RuntimeException(__METHOD__ . "에서 오류발생:" . get_class($dto) . "는 사용할수 없습니다.");
}
return parent::modify($uid, $dto);
}
//List 검색용
//FormFilter 조건절 처리
//검색어조건절처리
public function setSearchWord(string $word): void
{
$this->model->orLike($this->model->getTable() . "." . $this->model->getTitleField(), $word, 'both');
parent::setSearchWord($word);
}
//Chart용
public function getAggregateDatas(TrafficEntity $trafficEntity, string $startDate, string $endDate): array
{
$entities = [];
foreach ($this->getEntities(["trafficinfo_uid" => $trafficEntity->getPK(), "created_at >=" => $startDate, "created_at <=" => $endDate]) as $entity) {
$entities[] = ['in_kbits' => $entity->getIn(), 'out_kbits' => $entity->getOut(), 'created_at' => $entity->getCreatedAt()];
}
return $entities;
}
/**
* in_kbits과 out_kbits 두 값을 한꺼번에 구하는 함수
*/
public function get95PercentileBoth(TrafficEntity $trafficEntity, string $startDate, string $endDate): array
{
return [
'in_kbits' => $this->model->get95PercentileValue($trafficEntity, 'in', $startDate, $endDate),
'out_kbits' => $this->model->get95PercentileValue($trafficEntity, 'out', $startDate, $endDate)
];
}
public function getCalculatedData(TrafficEntity $trafficEntity): array
{
$snmp = new SNMPLibrary($trafficEntity->getIP(), $trafficEntity->getCommunity());
$currentInOctets = $snmp->get(self::OID_IF_IN_OCTETS . $trafficEntity->getInterface());
$currentOutOctets = $snmp->get(self::OID_IF_OUT_OCTETS . $trafficEntity->getInterface());
if ($currentInOctets === null || $currentOutOctets === null) {
$message = "트래픽 수집 실패: {$trafficEntity->getIP()} - IF{$trafficEntity->getInterface()} (UID: {$trafficEntity->getPK()})";
log_message('error', $message);
throw new \Exception($message);
}
// 이전 데이터를 조회하여 Rate 계산에 사용
$lastEntity = $this->model->getLastEntity($trafficEntity->getPK());
$inKbitsSec = 0.0;
$outKbitsSec = 0.0;
// 이전 데이터가 있어야만 Rate 계산 가능
if ($lastEntity !== null) {
$lastTime = Time::parse($lastEntity->getCreatedAt())->getTimestamp();
$deltaTime = Time::now()->getTimestamp() - $lastTime;
if ($deltaTime > 0) {
// DB에서 가져온 값도 BIGINT 타입으로 잘 처리되어야 합니다.
// PHP 64비트 환경이라면 자동으로 64비트 정수로 가져옵니다.
$lastIn = $lastEntity->getRawIn();
$lastOut = $lastEntity->getRawOut();
// 💡 1. IN/OUT바운드 Octets 차분 계산 64비트 카운터(BIGINT)를 사용하기 때문에 단순 뺄셈으로 처리합니다.
$deltaInOctets = $currentInOctets - $lastIn;
$deltaOutOctets = $currentOutOctets - $lastOut;
// Kbit/s 계산: (Delta_Octets * 8 bits) / Delta_Time_Seconds / 1000 (-> Kbit/s) 실수(float) 연산으로 정확도를 높입니다.
$inKbitsSec = ($deltaInOctets * 8.0) / $deltaTime / 1000.0;
$outKbitsSec = ($deltaOutOctets * 8.0) / $deltaTime / 1000.0;
} else {
log_message('error', "시간 차이 오류 발생: {$trafficEntity->getIP()} - {$deltaTime}초 (UID: {$trafficEntity->getPK()})");
}
}
return [
'trafficinfo_uid' => (int)$trafficEntity->getPK(),
'in' => (int)$inKbitsSec, // 정수형으로 반환
'out' => (int)$outKbitsSec, // 정수형으로 반환
'raw_in' => (int)$currentInOctets,
'raw_out' => (int)$currentOutOctets,
];
}
}