Skip to content
Snippets Groups Projects
MarkController.php 5.92 KiB
<?php

namespace App\Http\Controllers;

use Cylab\Mark\Client;

class MarkController extends Controller
{
    private $server;

    private function server()
    {
        if ($this->server === null) {
            $mark_url = 'http://' . config("app.mark_host") . ':' . config('app.mark_port');
            $this->server = new Client($mark_url);

            // test we can connect to the server
            try {
                $this->server->test();
            } catch (\JsonRPC\Exception\ConnectionFailureException $ex) {
                session()->flash('error', 'Failed to connect to MARK server at ' . $mark_url);
                abort(redirect('app/error'));
            }
        }

        return $this->server;
    }

    public function error()
    {
        return view('app.error', ["message" => session()->pull('error')]);
    }

    public function status()
    {
        $status = $this->server()->status();
        $status_history = $this->server()->history();

        $history_memory = $this->extractPoints($status_history, "memory_used");
        $history_load = $this->extractPoints($status_history, "load");

        $history_jobs_executed = $this->extractPoints($status_history, "executor_jobs_executed");
        $history_jobs_execution_rate = $this->computeExecutionRate($history_jobs_executed);


        return view("app.status", [
            "status" => $status,
            "history_memory" => $history_memory,
            "history_load" => $history_load,
            "history_jobs_execution_rate" => $history_jobs_execution_rate]);
    }

    public function pause()
    {
        $this->server()->pause();
        return redirect(action('MarkController@status'));
    }

    public function resume()
    {
        $this->server()->resume();
        return redirect(action('MarkController@status'));
    }

    public function reload()
    {
        $this->server()->reload();
        return redirect(action('MarkController@status'));
    }
    public function ranking(string $label)
    {

        // find the detector corresponding to this label
        $detectors = $this->server()->activation();
        $detector = null;
        foreach ($detectors as $d) {
            if ($d["label"] == $label) {
                $detector = $d;
                break;
            }
        }

        $evidences = $this->server()->findEvidence($label);

        $now = \Carbon\Carbon::now();

        return view(
            "app.ranking",
            [
                    "label" => $label,
                    "evidences" => $evidences,
                    "detector" => $detector,
            "now" => $now]
        );
    }

    public function rankingHome()
    {
        $activation_graph_elements = [];
        $activation = $this->server()->activation();
        foreach ($activation as $agent) {
            // nodes
            $activation_graph_elements[] = ["data" => ["id" => $agent["label"]]];
            $activation_graph_elements[] = ["data" => ["id" => $agent["triggerLabel"]]];

            // edges
            $activation_graph_elements[] = ["data" => [
                "id" => rand(),
                "source" => $agent["triggerLabel"],
                "target" => $agent["label"]]];
        }

        return view("app.detectors", ["activation_graph_elements" => $activation_graph_elements]);
    }

    public function extractPoints(array $evidences, string $field) : array
    {
        $points = [];
        foreach ($evidences as $evidence) {
            // used by status history
            // this is dirty :-(
            // status history should return an array of objects
            if (is_array($evidence)) {
                $points[] = new \App\TimePoint(
                    $evidence["time"],
                    $evidence[$field]
                );
            } else {
                $points[] = new \App\TimePoint(
                    $evidence->time,
                    $evidence->$field
                );
            }
        }
        return $points;
    }

    public function evidence(string $id)
    {
        $time_window = 3600; // in seconds

        $ev = $this->server()->findEvidenceById($id);
        $since = $ev->time - $time_window * 1000;

        $references = [];
        foreach ($ev->references as $id) {
            $references[] = $this->server()->findEvidenceById($id);
        }

        $history = $this->server()->findEvidenceSince($ev->label, $ev->subject, $since);

        return view(
            'app.evidence',
            [
                    "evidence" => $ev,
                    "history" => $history,
                    "history_points" => $this->extractPoints($history, "score"),
            "references" => $references]
        );
    }

    public function evidenceData(string $id, $data_id)
    {
        $ev = $this->server()->findEvidenceById($id);
        $query = $ev->requests[$data_id];
        $data = $this->server->findData($query);

        return view('app.data', [
            "evidence" => $ev,
            "query" => $query,
            "data" => $data
        ]);
    }

    /**
     * Compute the number of jobs executed per minute.
     *
     * @param array $history_jobs_executed
     * @return array
     */
    private function computeExecutionRate(array $history_jobs_executed) : array
    {

        if (count($history_jobs_executed) < 2) {
            // not enough points to compute execution rate...
            return [];
        }

        $points = [];
        $last_point_time = $history_jobs_executed[0]->t;
        $last_point_value = $history_jobs_executed[0]->y;

        foreach ($history_jobs_executed as $point) {
            // this point is less than a minute after the last computed point
            if (($point->t - $last_point_time) < 60000) {
                continue;
            }

            $points[] = new \App\TimePoint($point->t, $point->y - $last_point_value);

            $last_point_time = $point->t;
            $last_point_value = $point->y;
        }

        return $points;
    }
}