Passed
Push — master ( 96ef05...f81447 )
by Darko
09:59
created

TmuxLayoutBuilder   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 216
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 27
eloc 95
c 1
b 0
f 0
dl 0
loc 216
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A createIRCScraperWindow() 0 6 1
A __construct() 0 5 1
D createOptionalWindows() 0 59 16
A buildLayout() 0 6 1
A buildBasicLayout() 0 29 2
A commandExists() 0 6 2
A buildStrippedLayout() 0 23 2
A buildFullLayout() 0 37 2
1
<?php
2
3
namespace App\Services\Tmux;
4
5
use App\Models\Settings;
6
7
/**
8
 * Service for building tmux window layouts based on sequential mode
9
 */
10
class TmuxLayoutBuilder
11
{
12
    protected TmuxSessionManager $sessionManager;
13
14
    protected TmuxPaneManager $paneManager;
15
16
    protected string $sessionName;
17
18
    public function __construct(TmuxSessionManager $sessionManager)
19
    {
20
        $this->sessionManager = $sessionManager;
21
        $this->sessionName = $sessionManager->getSessionName();
22
        $this->paneManager = new TmuxPaneManager($this->sessionName);
23
    }
24
25
    /**
26
     * Build the appropriate layout based on sequential mode
27
     */
28
    public function buildLayout(int $sequentialMode): bool
29
    {
30
        return match ($sequentialMode) {
31
            1 => $this->buildBasicLayout(),
32
            2 => $this->buildStrippedLayout(),
33
            default => $this->buildFullLayout(),
34
        };
35
    }
36
37
    /**
38
     * Build full non-sequential layout (mode 0)
39
     */
40
    protected function buildFullLayout(): bool
41
    {
42
        // Window 0: Monitor + Binaries + Backfill + Releases
43
        if (! $this->sessionManager->createSession('Monitor')) {
44
            return false;
45
        }
46
47
        // Select pane 0.0, then split for binaries (right side, 67%)
48
        $this->paneManager->selectPane('0.0');
49
        $this->paneManager->splitHorizontal('0', '67%', 'update_binaries');
50
51
        // Select pane 0.1 (binaries), then split for backfill (bottom, 67%)
52
        $this->paneManager->selectPane('0.1');
53
        $this->paneManager->splitVertical('0', '67%', 'backfill');
54
55
        // Split again for releases (bottom, 50%)
56
        $this->paneManager->splitVertical('0', '50%', 'update_releases');
57
58
        // Window 1: Fix names + Remove crap
59
        $this->paneManager->createWindow(1, 'utils');
60
        $this->paneManager->setPaneTitle('1.0', 'fixReleaseNames');
61
        $this->paneManager->selectPane('1.0');
62
        $this->paneManager->splitHorizontal('1', '50%', 'removeCrapReleases');
63
64
        // Window 2: Postprocessing (Additional + Non-Amazon + Amazon)
65
        $this->paneManager->createWindow(2, 'post');
66
        $this->paneManager->setPaneTitle('2.0', 'postprocessing_additional');
67
        $this->paneManager->splitVertical('2', '67%', 'postprocessing_non_amazon');
68
        $this->paneManager->splitVertical('2', '50%', 'postprocessing_amazon');
69
70
        // Window 3: IRC Scraper
71
        $this->createIRCScraperWindow();
72
73
        // Additional windows (optional monitoring tools)
74
        $this->createOptionalWindows();
75
76
        return true;
77
    }
78
79
    /**
80
     * Build basic sequential layout (mode 1)
81
     */
82
    protected function buildBasicLayout(): bool
83
    {
84
        // Window 0: Monitor + Releases
85
        if (! $this->sessionManager->createSession('Monitor')) {
86
            return false;
87
        }
88
89
        // Select pane 0.0, then split for releases
90
        $this->paneManager->selectPane('0.0');
91
        $this->paneManager->splitHorizontal('0', '67%', 'update_releases');
92
93
        // Window 1: Utils (Fix names + Remove crap)
94
        $this->paneManager->createWindow(1, 'utils');
95
        $this->paneManager->setPaneTitle('1.0', 'fixReleaseNames');
96
        $this->paneManager->selectPane('1.0');
97
        $this->paneManager->splitHorizontal('1', '50%', 'removeCrapReleases');
98
99
        // Window 2: Postprocessing
100
        $this->paneManager->createWindow(2, 'post');
101
        $this->paneManager->setPaneTitle('2.0', 'postprocessing_additional');
102
        $this->paneManager->splitVertical('2', '67%', 'postprocessing_non_amazon');
103
        $this->paneManager->splitVertical('2', '50%', 'postprocessing_amazon');
104
105
        // Window 3: IRC Scraper
106
        $this->createIRCScraperWindow();
107
108
        $this->createOptionalWindows();
109
110
        return true;
111
    }
112
113
    /**
114
     * Build stripped sequential layout (mode 2)
115
     */
116
    protected function buildStrippedLayout(): bool
117
    {
118
        // Window 0: Monitor + Sequential
119
        if (! $this->sessionManager->createSession('Monitor')) {
120
            return false;
121
        }
122
123
        // Select pane 0.0, then split for sequential
124
        $this->paneManager->selectPane('0.0');
125
        $this->paneManager->splitHorizontal('0', '67%', 'sequential');
126
127
        // Window 1: Amazon postprocessing
128
        $this->paneManager->createWindow(1, 'utils');
129
        $this->paneManager->setPaneTitle('1.0', 'fixReleaseNames');
130
        $this->paneManager->selectPane('1.0');
131
        $this->paneManager->splitHorizontal('1', '50%', 'postprocessing_amazon');
132
133
        // Window 2: IRC Scraper
134
        $this->createIRCScraperWindow();
135
136
        $this->createOptionalWindows();
137
138
        return true;
139
    }
140
141
    /**
142
     * Create IRC scraper window
143
     */
144
    protected function createIRCScraperWindow(): bool
145
    {
146
        $this->paneManager->createWindow(3, 'IRCScraper');
147
        $this->paneManager->setPaneTitle('3.0', 'scrapeIRC');
148
149
        return true;
150
    }
151
152
    /**
153
     * Create optional monitoring windows based on settings
154
     */
155
    protected function createOptionalWindows(): void
156
    {
157
        $windowIndex = 4;
158
159
        // htop
160
        if ((int) Settings::settingValue('htop') === 1 && $this->commandExists('htop')) {
161
            $this->paneManager->createWindow($windowIndex, 'htop');
162
            $this->paneManager->respawnPane("{$windowIndex}.0", 'htop');
163
            $windowIndex++;
164
        }
165
166
        // nmon
167
        if ((int) Settings::settingValue('nmon') === 1 && $this->commandExists('nmon')) {
168
            $this->paneManager->createWindow($windowIndex, 'nmon');
169
            $this->paneManager->respawnPane("{$windowIndex}.0", 'nmon -t');
170
            $windowIndex++;
171
        }
172
173
        // vnstat
174
        if ((int) Settings::settingValue('vnstat') === 1 && $this->commandExists('vnstat')) {
175
            $vnstatArgs = Settings::settingValue('vnstat_args') ?? '';
176
            $this->paneManager->createWindow($windowIndex, 'vnstat');
177
            $this->paneManager->respawnPane("{$windowIndex}.0", "watch -n10 'vnstat {$vnstatArgs}'");
178
            $windowIndex++;
179
        }
180
181
        // tcptrack
182
        if ((int) Settings::settingValue('tcptrack') === 1 && $this->commandExists('tcptrack')) {
183
            $tcptrackArgs = Settings::settingValue('tcptrack_args') ?? '';
184
            $this->paneManager->createWindow($windowIndex, 'tcptrack');
185
            $this->paneManager->respawnPane("{$windowIndex}.0", "tcptrack {$tcptrackArgs}");
186
            $windowIndex++;
187
        }
188
189
        // bwm-ng
190
        if ((int) Settings::settingValue('bwmng') === 1 && $this->commandExists('bwm-ng')) {
191
            $this->paneManager->createWindow($windowIndex, 'bwm-ng');
192
            $this->paneManager->respawnPane("{$windowIndex}.0", 'bwm-ng');
193
            $windowIndex++;
194
        }
195
196
        // mytop
197
        if ((int) Settings::settingValue('mytop') === 1 && $this->commandExists('mytop')) {
198
            $this->paneManager->createWindow($windowIndex, 'mytop');
199
            $this->paneManager->respawnPane("{$windowIndex}.0", 'mytop -u');
200
            $windowIndex++;
201
        }
202
203
        // redis-stat
204
        if ((int) Settings::settingValue('redis') === 1 && $this->commandExists('redis-cli')) {
205
            $this->paneManager->createWindow($windowIndex, 'redis-stat');
206
            $this->paneManager->respawnPane("{$windowIndex}.0", 'redis-stat --verbose --server=63790');
207
            $windowIndex++;
208
        }
209
210
        // bash console
211
        if ((int) Settings::settingValue('console') === 1) {
212
            $this->paneManager->createWindow($windowIndex, 'bash');
213
            $this->paneManager->respawnPane("{$windowIndex}.0", 'bash -i');
214
        }
215
    }
216
217
    /**
218
     * Check if a command exists
219
     */
220
    protected function commandExists(string $command): bool
221
    {
222
        $result = \Illuminate\Support\Facades\Process::timeout(5)
223
            ->run("which {$command} 2>/dev/null");
224
225
        return $result->successful() && str_contains($result->output(), $command);
226
    }
227
}
228