Skip to content

Commit

Permalink
added log search feature
Browse files Browse the repository at this point in the history
  • Loading branch information
mariotaku committed Apr 25, 2024
1 parent e8c4592 commit 8b6708d
Show file tree
Hide file tree
Showing 19 changed files with 557 additions and 1,124 deletions.
469 changes: 144 additions & 325 deletions Cargo.lock

Large diffs are not rendered by default.

607 changes: 43 additions & 564 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions package.json
Expand Up @@ -40,10 +40,15 @@
"@tauri-apps/plugin-fs": "2.0.0-beta.2",
"@tauri-apps/plugin-shell": "2.0.0-beta.2",
"@tauri-apps/plugin-upload": "2.0.0-beta.2",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-search": "0.15.0",
"@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^5.5.0",
"bootstrap": "^5.3.2",
"bootstrap-icons": "^1.11.2",
"buffer": "^6.0.3",
"chalk": "5.3.0",
"crypto-browserify": "3.12.0",
"filesize": "^10.1.0",
"find-matching-bracket": "1.0.3",
"lodash-es": "^4.17.21",
Expand All @@ -53,16 +58,16 @@
"ng-let": "^16.0.2",
"ngx-autosize": "2.0.4",
"path-browserify": "^1.0.1",
"process": "0.11.10",
"rxjs": "^7.4.0",
"semver": "^7.5.4",
"stream-browserify": "3.0.0",
"tslib": "^2.6.2",
"@xterm/xterm": "^5.3.0",
"@xterm/addon-fit": "^0.9.0",
"@xterm/addon-web-links": "^0.10.0",
"vm-browserify": "1.1.2",
"zone.js": "~0.14.2"
},
"devDependencies": {
"@angular-builders/custom-webpack": "^17.0.1",
"@angular-builders/custom-webpack": "^17.0.2",
"@angular-devkit/build-angular": "^17.3.2",
"@angular-eslint/builder": "17.3.0",
"@angular-eslint/eslint-plugin": "17.3.0",
Expand All @@ -88,9 +93,8 @@
"karma-coverage": "^2.2.1",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"node-polyfill-webpack-plugin": "^2.0.1",
"typescript": "^5.2.2",
"webpack": "^5.88.2"
"webpack": "^5.91.0"
},
"browserslist": [
"chrome >= 91",
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/conn_pool/connection.rs
Expand Up @@ -165,6 +165,7 @@ impl DeviceConnectionUserInfo {
if exit_code != 0 {
return Err(Error::Message {
message: format!("id command failed with exit code {}", exit_code),
unhandled: false,
});
}
return Ok(DeviceConnectionUserInfo::parse(&buf));
Expand Down
14 changes: 8 additions & 6 deletions src-tauri/src/conn_pool/pool.rs
Expand Up @@ -31,12 +31,14 @@ impl DeviceConnectionPool {
c.reset_last_ok();
Ok(c)
}
Err(_) => Err(self
.last_error
.lock()
.unwrap()
.take()
.unwrap_or(Error::Timeout)),
Err(e) => {
return Err(self.last_error.lock().unwrap().take().unwrap_or_else(|| {
Error::Message {
message: format!("Unknown error getting connection from pool: {e:?}"),
unhandled: true,
}
}));
}
};
}
}
Expand Down
16 changes: 14 additions & 2 deletions src-tauri/src/error.rs
Expand Up @@ -32,6 +32,7 @@ pub enum Error {
},
Message {
message: String,
unhandled: bool,
},
PassphraseRequired,
NotFound,
Expand All @@ -43,11 +44,13 @@ impl Error {
pub fn new<S: Into<String>>(message: S) -> Error {
return Error::Message {
message: message.into(),
unhandled: false,
};
}
pub fn bad_config() -> Error {
return Error::Message {
message: String::from("Bad configuration"),
unhandled: false,
};
}
pub fn io(kind: ErrorKind) -> Error {
Expand Down Expand Up @@ -90,6 +93,7 @@ impl From<serde_json::Error> for Error {
fn from(value: serde_json::Error) -> Self {
return Error::Message {
message: format!("JSON Error: {:?}", value),
unhandled: false,
};
}
}
Expand Down Expand Up @@ -134,6 +138,7 @@ impl From<SshError> for Error {
return match value {
SshError::RequestDenied(s) => Error::Message {
message: format!("SSH Error: {s}"),
unhandled: false,
},
SshError::TryAgain => Error::IO {
code: ErrorKind::WouldBlock,
Expand Down Expand Up @@ -164,6 +169,7 @@ impl From<SshError> for Error {
}
Error::Message {
message: format!("SSH Error: {s}"),
unhandled: false,
}
}
SshError::Sftp(e) => e.into(),
Expand All @@ -180,7 +186,10 @@ impl From<SftpError> for Error {
{
return from_sftp_error_code(code, message);
}
return Error::Message { message };
return Error::Message {
message,
unhandled: false,
};
}
}

Expand All @@ -205,7 +214,10 @@ fn from_sftp_error_code(code: u32, message: String) -> Error {
message: String::from("SSH_FX_WRITE_PROTECT"),
unhandled: true,
},
_ => Error::Message { message },
_ => Error::Message {
message,
unhandled: false,
},
};
}

Expand Down
9 changes: 6 additions & 3 deletions src-tauri/src/lib.rs
Expand Up @@ -8,6 +8,7 @@ use log::LevelFilter;
#[cfg(feature = "mobile")]
use native_dialog::{MessageDialog, MessageType};
use tauri::{AppHandle, Manager, RunEvent, Runtime};
use tauri::webview::PageLoadEvent;

use crate::app_dirs::{GetConfDir, GetSshDir, SetConfDir, SetSshDir};
use crate::device_manager::DeviceManager;
Expand Down Expand Up @@ -56,9 +57,11 @@ pub fn run() {
.manage(SessionManager::default())
.manage(SpawnManager::default())
.manage(ShellManager::default())
.on_page_load(|wnd, _payload| {
let spawns = wnd.state::<SpawnManager>();
spawns.clear();
.on_page_load(|wnd, payload| {
if payload.event() == PageLoadEvent::Started {
let spawns = wnd.state::<SpawnManager>();
spawns.clear();
}
})
.build(tauri::generate_context!())
.and_then(|app| {
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/spawn_manager/manager.rs
Expand Up @@ -20,6 +20,7 @@ impl SpawnManager {
for x in old_items {
if let Some(proc) = x.upgrade() {
log::debug!("Terminating {proc:?}");
proc.interrupt();
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/app/core/services/remote-log.service.ts
Expand Up @@ -33,6 +33,10 @@ export class RemoteLogService {
await this.cmd.exec(device, 'echo > /var/log/messages', 'utf-8');
}

async dmesgClear(device: DeviceLike): Promise<void> {
await this.cmd.exec(device, 'dmesg -c', 'utf-8');
}

private parsePmLog(line: string): LogMessage | null {
line = line.trim();
if (!line) {
Expand Down
17 changes: 15 additions & 2 deletions src/app/debug/dmesg/dmesg.component.html
@@ -1,3 +1,16 @@
<div class="h-100">
<app-log-reader [source]="logs"></app-log-reader>
<div class="w-100 h-100 d-flex flex-row">
<div class="h-100 d-flex flex-column p-2">
<button class="btn btn-sm btn-secondary mt-2" ngbTooltip="Search" (click)="logReader.toggleSearchBar()">
<i class="bi bi-search"></i>
</button>
<hr>
<button class="btn btn-sm btn-secondary mb-2" ngbTooltip="Clear" (click)="clearBuffer()">
<i class="bi bi-trash"></i>
</button>
<button class="btn btn-sm btn-secondary mb-2" ngbTooltip="Scroll to bottom"
[disabled]="logReader.reachedBottom" (click)="logReader.scrollToBottom()">
<i class="bi bi-chevron-bar-down"></i>
</button>
</div>
<app-log-reader class="flex-fill" [source]="logs" #logReader></app-log-reader>
</div>
49 changes: 29 additions & 20 deletions src/app/debug/dmesg/dmesg.component.ts
Expand Up @@ -5,35 +5,44 @@ import {from, identity, mergeMap, Observable} from "rxjs";
import {LogMessage, RemoteLogService} from "../../core/services/remote-log.service";

@Component({
selector: 'app-dmesg',
templateUrl: './dmesg.component.html',
styleUrls: ['./dmesg.component.scss']
selector: 'app-dmesg',
templateUrl: './dmesg.component.html',
styleUrls: ['./dmesg.component.scss']
})
export class DmesgComponent {

logs?: Observable<LogMessage>;
logs?: Observable<LogMessage>;

private deviceField: Device | null = null;
private deviceField: Device | null = null;

constructor(private cmd: RemoteCommandService, private log: RemoteLogService) {
}
constructor(private cmd: RemoteCommandService, private log: RemoteLogService) {
}


get device(): Device | null {
return this.deviceField;
}
get device(): Device | null {
return this.deviceField;
}

@Input()
set device(device: Device | null) {
this.deviceField = device;
this.logs = undefined;
if (device) {
this.reload(device);
@Input()
set device(device: Device | null) {
this.deviceField = device;
this.logs = undefined;
if (device) {
this.reload(device);
}
}
}

private reload(device: Device) {
this.logs = from(this.log.dmesg(device)).pipe(mergeMap(identity));
}
async clearBuffer(): Promise<void> {
const device = this.device;
if (!device) {
return;
}
await this.log.dmesgClear(device);
this.reload(device);
}

private reload(device: Device) {
this.logs = from(this.log.dmesg(device)).pipe(mergeMap(identity));
}

}
17 changes: 17 additions & 0 deletions src/app/debug/log-reader/log-reader.component.html
Expand Up @@ -5,4 +5,21 @@
</div>
<div class="position-absolute w-100 h-100 terminal-container" #termwin>
</div>
<div
class="position-absolute d-flex align-items-center flex-row bg-panel border-start border-end border-bottom terminal-search-bar p-2 me-5"
*ngIf="showSearchBar">
<input type="text" class="form-control form-control-sm me-2" (input)="searchTextChange.next(searchInput.value)"
#searchInput>
<small class="text-nowrap" *ngIf="matchesStatus as match">{{ match.resultIndex + 1 }}
/ {{ match.resultCount }}</small>
<button class="btn btn-sm" (click)="searchPrevious()"
[disabled]="!matchesStatus || matchesStatus.resultIndex <= 0 || matchesStatus.resultIndex >= matchesStatus.resultCount">
<i class="bi bi-arrow-up"></i>
</button>
<button class="btn btn-sm" (click)="searchNext()"
[disabled]="!matchesStatus || matchesStatus.resultIndex + 1 >= matchesStatus.resultCount">
<i class="bi bi-arrow-down"></i>
</button>
<button class="btn btn-sm" (click)="closeSearchBar()"><i class="bi bi-x-lg"></i></button>
</div>
</div>

0 comments on commit 8b6708d

Please sign in to comment.