mirror of
https://github.com/skot/ESP-Miner.git
synced 2025-04-09 20:39:14 +02:00
realtime logs
This commit is contained in:
parent
0ceb4532a4
commit
bac6da555a
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -11,7 +11,11 @@
|
||||
"esp_netif.h": "c",
|
||||
"esp_http_server.h": "c",
|
||||
"esp_chip_info.h": "c",
|
||||
"xtensa_context.h": "c"
|
||||
"xtensa_context.h": "c",
|
||||
"sys.h": "c",
|
||||
"array": "c",
|
||||
"string": "c",
|
||||
"string_view": "c"
|
||||
},
|
||||
"editor.formatOnSave": true
|
||||
}
|
6
main/http_server/axe-os/package-lock.json
generated
6
main/http_server/axe-os/package-lock.json
generated
@ -19,6 +19,7 @@
|
||||
"ngx-toastr": "^17.0.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"xterm": "^5.2.1",
|
||||
"zone.js": "~0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -13163,6 +13164,11 @@
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/xterm": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/xterm/-/xterm-5.2.1.tgz",
|
||||
"integrity": "sha512-cs5Y1fFevgcdoh2hJROMVIWwoBHD80P1fIP79gopLHJIE4kTzzblanoivxTiQ4+92YM9IxS36H1q0MxIJXQBcA=="
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
@ -22,6 +22,7 @@
|
||||
"ngx-toastr": "^17.0.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"xterm": "^5.2.1",
|
||||
"zone.js": "~0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -12,6 +12,7 @@ import { EditComponent } from './components/edit/edit.component';
|
||||
import { HeaderComponent } from './components/header/header.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { LoadingComponent } from './components/loading/loading.component';
|
||||
import { ANSIPipe } from './pipes/ansi.pipe';
|
||||
|
||||
const components = [
|
||||
AppComponent,
|
||||
@ -23,7 +24,8 @@ const components = [
|
||||
...components,
|
||||
EditComponent,
|
||||
HomeComponent,
|
||||
LoadingComponent
|
||||
LoadingComponent,
|
||||
ANSIPipe
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -89,15 +89,19 @@ export class EditComponent {
|
||||
}
|
||||
|
||||
this.systemService.performWWWOTAUpdate(file)
|
||||
.pipe(this.loadingService.lockUIUntilComplete())
|
||||
.subscribe({
|
||||
.pipe(
|
||||
this.loadingService.lockUIUntilComplete(),
|
||||
).subscribe({
|
||||
next: (event) => {
|
||||
if (event.type === HttpEventType.UploadProgress) {
|
||||
this.websiteUpdateProgress = Math.round((event.loaded / (event.total as number)) * 100);
|
||||
} else if (event.type === HttpEventType.Response) {
|
||||
if (event.ok) {
|
||||
this.toastrService.success('Website updated', 'Success!');
|
||||
window.location.reload();
|
||||
setTimeout(() => {
|
||||
this.toastrService.success('Website updated', 'Success!');
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
|
||||
} else {
|
||||
this.toastrService.error(event.statusText, 'Error');
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.header-text {
|
||||
|
@ -113,4 +113,11 @@
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card mt-2">
|
||||
<h2>Realtime Logs</h2>
|
||||
<div id="logs" #scrollContainer>
|
||||
<div *ngFor="let log of logs">₿ {{log | ANSI}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
@ -36,4 +36,18 @@ table>tr>td {
|
||||
.button-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#logs {
|
||||
height: 500px;
|
||||
font-family: monospace;
|
||||
border: 1px solid #304562;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
|
||||
>div {
|
||||
max-width: 100%;
|
||||
line-break: anywhere;
|
||||
|
||||
}
|
||||
}
|
@ -1,27 +1,47 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AfterViewChecked, Component, ElementRef, ViewChild } from '@angular/core';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { Observable } from 'rxjs';
|
||||
import { LoadingService } from 'src/app/services/loading.service';
|
||||
import { SystemService } from 'src/app/services/system.service';
|
||||
import { WebsocketService } from 'src/app/services/web-socket.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent {
|
||||
export class HomeComponent implements AfterViewChecked {
|
||||
@ViewChild('scrollContainer') private scrollContainer!: ElementRef;
|
||||
|
||||
public info$: Observable<any>;
|
||||
|
||||
public logs: string[] = [];
|
||||
|
||||
constructor(
|
||||
private systemService: SystemService,
|
||||
private toastr: ToastrService,
|
||||
private loadingService: LoadingService
|
||||
private loadingService: LoadingService,
|
||||
private websocketService: WebsocketService
|
||||
) {
|
||||
this.info$ = this.systemService.getInfo().pipe(
|
||||
this.loadingService.lockUIUntilComplete()
|
||||
)
|
||||
|
||||
this.websocketService.ws$.subscribe({
|
||||
next: (val) => {
|
||||
this.logs.push(val);
|
||||
if (this.logs.length > 100) {
|
||||
this.logs.shift();
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
ngAfterViewChecked(): void {
|
||||
if (this.scrollContainer?.nativeElement != null) {
|
||||
this.scrollContainer.nativeElement.scrollTo({ left: 0, top: this.scrollContainer.nativeElement.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
}
|
||||
|
||||
public restart() {
|
||||
@ -31,3 +51,4 @@ export class HomeComponent {
|
||||
this.toastr.success('Success!', 'Bitaxe restarted');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
#loading {
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: fixed;
|
||||
z-index: 999;
|
||||
z-index: 99999999999999999999;
|
||||
}
|
||||
|
||||
#loading-text {
|
||||
|
8
main/http_server/axe-os/src/app/pipes/ansi.pipe.spec.ts
Normal file
8
main/http_server/axe-os/src/app/pipes/ansi.pipe.spec.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ANSIPipe } from './ansi.pipe';
|
||||
|
||||
describe('ANSIPipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new ANSIPipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
13
main/http_server/axe-os/src/app/pipes/ansi.pipe.ts
Normal file
13
main/http_server/axe-os/src/app/pipes/ansi.pipe.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'ANSI',
|
||||
pure: true
|
||||
})
|
||||
export class ANSIPipe implements PipeTransform {
|
||||
|
||||
transform(value: string): string {
|
||||
return value.slice(9, value.length - 5);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { WebSocketService } from './web-socket.service';
|
||||
|
||||
describe('WebSocketService', () => {
|
||||
let service: WebSocketService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(WebSocketService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WebsocketService {
|
||||
|
||||
public ws$: WebSocketSubject<string>;
|
||||
|
||||
constructor() {
|
||||
this.ws$ = webSocket({
|
||||
url: `ws://${window.location.host}/api/ws`,
|
||||
deserializer: (e: MessageEvent) => { return e.data }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -32,6 +32,9 @@
|
||||
static const char *TAG = "http_server";
|
||||
|
||||
static GlobalState *GLOBAL_STATE;
|
||||
static httpd_handle_t server = NULL;
|
||||
|
||||
static int fd = -1;
|
||||
|
||||
#define REST_CHECK(a, str, goto_tag, ...) \
|
||||
do \
|
||||
@ -377,6 +380,40 @@ esp_err_t POST_OTA_update(httpd_req_t *req)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void log_to_websocket(const char *format, va_list args)
|
||||
{
|
||||
char log_buffer[1000];
|
||||
vsnprintf(log_buffer, sizeof(log_buffer), format, args);
|
||||
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
ws_pkt.payload = (uint8_t *)log_buffer;
|
||||
ws_pkt.len = strlen(log_buffer);
|
||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
vprintf(format, args);
|
||||
if (httpd_ws_send_frame_async(server, fd, &ws_pkt) != ESP_OK)
|
||||
{
|
||||
esp_log_set_vprintf(vprintf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This handler echos back the received ws data
|
||||
* and triggers an async send if certain message received
|
||||
*/
|
||||
esp_err_t echo_handler(httpd_req_t *req)
|
||||
{
|
||||
|
||||
if (req->method == HTTP_GET)
|
||||
{
|
||||
ESP_LOGI(TAG, "Handshake done, the new connection was opened");
|
||||
fd = httpd_req_to_sockfd(req);
|
||||
esp_log_set_vprintf(log_to_websocket);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
esp_err_t start_rest_server(void *pvParameters)
|
||||
{
|
||||
GLOBAL_STATE = (GlobalState *)pvParameters;
|
||||
@ -389,7 +426,6 @@ esp_err_t start_rest_server(void *pvParameters)
|
||||
REST_CHECK(rest_context, "No memory for rest context", err);
|
||||
strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));
|
||||
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.uri_match_fn = httpd_uri_match_wildcard;
|
||||
|
||||
@ -432,6 +468,14 @@ esp_err_t start_rest_server(void *pvParameters)
|
||||
.user_ctx = NULL};
|
||||
httpd_register_uri_handler(server, &update_post_ota_www);
|
||||
|
||||
httpd_uri_t ws = {
|
||||
.uri = "/api/ws",
|
||||
.method = HTTP_GET,
|
||||
.handler = echo_handler,
|
||||
.user_ctx = NULL,
|
||||
.is_websocket = true};
|
||||
httpd_register_uri_handler(server, &ws);
|
||||
|
||||
/* URI handler for getting web server files */
|
||||
httpd_uri_t common_get_uri = {
|
||||
.uri = "/*",
|
||||
|
@ -5,4 +5,5 @@ CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
CONFIG_ESP_MAXIMUM_RETRY=3
|
||||
CONFIG_ESP_MAXIMUM_RETRY=3
|
||||
CONFIG_HTTPD_WS_SUPPORT=y
|
Loading…
x
Reference in New Issue
Block a user