<?php

namespace App\Helpers\Tunnel;

use Symfony\Component\Process\Process;
use App\Helpers\Utility\SanityChecker;
use Illuminate\Support\Facades\Log;

class Generic {
  protected $name, $local, $remote;
  
  function __construct($_name = null, $_local = null, $_remote = null) {
    $this->name = $_name;
    $this->local = $_local;
    $this->remote = $_remote;
  }

  /**
   * Add a speed limit to a given tunnel.
   */
  function add_speed($_speed) {
    $result = false;

    if(SanityChecker::speed($_speed)) {
      // Add our 20% overheads to speed. We don't want to deal with floats so round up and cast.
      $_speed = (int) ceil($_speed * 1.2) . 'mbit';

      $command = new Process([
        'tc', 'qdisc', 'add', 'dev', $this->name, 'root', 'tbf', 'rate', $_speed, 'limit', $_speed, 'burst', '4000'
      ]);

      $command->run();

      $result = $command->isSuccessful();
    }

    return $result;
  }

  /**
   * Check a speed limit for a given tunnel.
   */
  function edit_speed($_speed) {
    $result = false;

    if(SanityChecker::speed($_speed)) {
      // Add our 20% overheads to speed. We don't want to deal with floats so round up and cast.
      $_speed = (int) ceil($_speed * 1.2) . 'mbit';

      $command = new Process([
        'tc', 'qdisc', 'change', 'dev', $this->name, 'root', 'tbf', 'rate', $_speed, 'limit', $_speed, 'burst', '4000'
      ]);

      $command->run();

      $result = $command->isSuccessful();
    }

    return $result;
  }

  /**
   * Check speed limit for a given tunnel.
   */
  function check_speed($_speed) {
    $callback_return = false;
    if(SanityChecker::speed($_speed)) {
      $process = Process::fromShellCommandline('tc qdisc show | grep "$NAME"');

      // Run the command, with the feedback being fed into the callback which puts input into the pointer callback return.
      $process->run(function ($type, $buffer) use(&$callback_return, $_speed) {
        $callback_return = str_contains($buffer, (int) ceil($_speed * 1.2) . 'mbit');
      }, [
          'NAME' => $this->name,
      ]);
    }

    return $callback_return;
  }

  /**
   * Check if a tunnel is up.
   */
  function verify() {
    $result = false;
    
    if(SanityChecker::name($this->name)) {
      $command = new Process([ 'ip', 'a', 'show', $this->name ]);

      $command->run();
      
      if($command->isSuccessful()) {
        if(str_contains($command->getOutput(), ',UP,')) {
          $result = true;
        }
      }
    }

    return $result;
  }

}

?>