mirror of
https://github.com/chuot/rdio-scanner.git
synced 2026-08-13 08:33:00 -06:00
Version 6.3.3
This commit is contained in:
parent
6beae3869b
commit
4d0dbd0e8e
|
|
@ -19,6 +19,15 @@ _v6.3.2_
|
||||||
- Fix `semacquire` lockup in Clients (issue #177, #181, #182).
|
- Fix `semacquire` lockup in Clients (issue #177, #181, #182).
|
||||||
- Replay button now replays from history if pressed multiple times quickly (issue #186).
|
- Replay button now replays from history if pressed multiple times quickly (issue #186).
|
||||||
|
|
||||||
|
_v6.3.3_
|
||||||
|
|
||||||
|
- Fix concurrent map writes fatal error in dirwatch (issue #187).
|
||||||
|
- Brighter LED colors and new orange color.
|
||||||
|
- Fix call id when retrieved from a MySQL database.
|
||||||
|
- Add loudnorm audio filter to the ffmpeg audio conversion.
|
||||||
|
- Show the real IP address in the logs taking into account if behind a proxy.
|
||||||
|
- Fix panic when emitting a call to clients.
|
||||||
|
|
||||||
## Version 6.2
|
## Version 6.2
|
||||||
|
|
||||||
- New max clients options which is 200 by default.
|
- New max clients options which is 200 by default.
|
||||||
|
|
|
||||||
16
COMPILING.md
16
COMPILING.md
|
|
@ -27,13 +27,13 @@ Clone the official repository on your computer and start the build process.
|
||||||
|
|
||||||
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
|
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
|
||||||
|
|
||||||
rdio-scanner-darwin-amd64-v6.3.2.zip
|
rdio-scanner-darwin-amd64-v6.3.3.zip
|
||||||
rdio-scanner-darwin-arm64-v6.3.2.zip
|
rdio-scanner-darwin-arm64-v6.3.3.zip
|
||||||
rdio-scanner-freebsd-amd64-v6.3.2.zip
|
rdio-scanner-freebsd-amd64-v6.3.3.zip
|
||||||
rdio-scanner-linux-386-v6.3.2.zip
|
rdio-scanner-linux-386-v6.3.3.zip
|
||||||
rdio-scanner-linux-amd64-v6.3.2.zip
|
rdio-scanner-linux-amd64-v6.3.3.zip
|
||||||
rdio-scanner-linux-arm64-v6.3.2.zip
|
rdio-scanner-linux-arm64-v6.3.3.zip
|
||||||
rdio-scanner-linux-arm-v6.3.2.zip
|
rdio-scanner-linux-arm-v6.3.3.zip
|
||||||
rdio-scanner-windows-amd64-v6.3.2.zip
|
rdio-scanner-windows-amd64-v6.3.3.zip
|
||||||
|
|
||||||
**Happy Rdio scanning !**
|
**Happy Rdio scanning !**
|
||||||
4
Makefile
4
Makefile
|
|
@ -16,8 +16,8 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
app := rdio-scanner
|
app := rdio-scanner
|
||||||
date := 2022/05/21
|
date := 2022/05/24
|
||||||
ver := 6.3.2
|
ver := 6.3.3
|
||||||
|
|
||||||
client := $(wildcard client/*.json client/*.ts)
|
client := $(wildcard client/*.json client/*.ts)
|
||||||
server := $(wildcard server/*.go)
|
server := $(wildcard server/*.go)
|
||||||
|
|
|
||||||
4
client/package-lock.json
generated
4
client/package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "rdio-scanner",
|
"name": "rdio-scanner",
|
||||||
"version": "6.3.2",
|
"version": "6.3.3",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rdio-scanner",
|
"name": "rdio-scanner",
|
||||||
"version": "6.3.2",
|
"version": "6.3.3",
|
||||||
"license": "LICENSE",
|
"license": "LICENSE",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^13.3.9",
|
"@angular/animations": "^13.3.9",
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,5 @@
|
||||||
"build": "ng build --base-href ./ --configuration production",
|
"build": "ng build --base-href ./ --configuration production",
|
||||||
"start": "ng serve"
|
"start": "ng serve"
|
||||||
},
|
},
|
||||||
"version": "6.3.2"
|
"version": "6.3.3"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ export class RdioScannerAdminService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
getLeds(): string[] {
|
getLeds(): string[] {
|
||||||
return ['blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow'];
|
return ['blue', 'cyan', 'green', 'magenta', 'orage', 'red', 'white', 'yellow'];
|
||||||
}
|
}
|
||||||
|
|
||||||
async getLogs(options: LogsQueryOptions): Promise<LogsQuery | undefined> {
|
async getLogs(options: LogsQueryOptions): Promise<LogsQuery | undefined> {
|
||||||
|
|
|
||||||
|
|
@ -44,21 +44,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.off::after {
|
&.off::after {
|
||||||
background: #e63232;
|
background: rgb(255, 23, 68);
|
||||||
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
||||||
0 0 3px 1px rgb(230, 50, 50);
|
0 0 3px 1px rgb(255, 23, 68);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.on::after {
|
&.on::after {
|
||||||
background: rgb(100, 230, 50);
|
background: rgb(0, 230, 118);;
|
||||||
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
||||||
0 0 3px 1px rgb(100, 230, 50);
|
0 0 3px 1px rgb(0, 230, 118);;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.partial::after {
|
&.partial::after {
|
||||||
background: rgb(230, 165, 50);
|
background: rgb(255, 234, 0);
|
||||||
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
box-shadow: 1px 1px 1px rgba(255, 255, 255, 0.7) inset,
|
||||||
0 0 3px 1px rgb(230, 165, 50);
|
0 0 3px 1px rgb(255, 234, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,42 +175,47 @@
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
|
||||||
&.on {
|
&.on {
|
||||||
background: rgb(100, 230, 50);
|
background: rgb(0, 230, 118);
|
||||||
box-shadow: 0 0 6px 3px rgb(100, 230, 50);
|
box-shadow: 0 0 6px 3px rgb(0, 230, 118);
|
||||||
|
|
||||||
&.blue {
|
&.blue {
|
||||||
background: rgb(50, 50, 230);
|
background: rgb(41, 121, 255);
|
||||||
box-shadow: 0 0 6px 3px rgb(50, 50, 230);
|
box-shadow: 0 0 6px 3px rgb(41, 121, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cyan {
|
&.cyan {
|
||||||
background: rgb(50, 230, 230);
|
background: rgb(0, 229, 255);
|
||||||
box-shadow: 0 0 6px 3px rgb(50, 230, 230);
|
box-shadow: 0 0 6px 3px rgb(0, 229, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.green {
|
&.green {
|
||||||
background: rgb(100, 230, 50);
|
background: rgb(0, 230, 118);
|
||||||
box-shadow: 0 0 6px 3px rgb(100, 230, 50);
|
box-shadow: 0 0 6px 3px rgb(0, 230, 118);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.magenta {
|
&.magenta {
|
||||||
background: rgb(230, 50, 230);
|
background: rgb(213, 0, 249);
|
||||||
box-shadow: 0 0 6px 3px rgb(230, 50, 230);
|
box-shadow: 0 0 6px 3px rgb(213, 0, 249);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.orange {
|
||||||
|
background: rgb(255, 145, 0);
|
||||||
|
box-shadow: 0 0 6px 3px rgb(255, 145, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.red {
|
&.red {
|
||||||
background: rgb(230, 50, 50);
|
background: rgb(255, 23, 68);
|
||||||
box-shadow: 0 0 6px 3px rgb(230, 50, 50);
|
box-shadow: 0 0 6px 3px rgb(255, 23, 68);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.white {
|
&.white {
|
||||||
background: rgb(230, 230, 230);
|
background: rgb(255, 255, 255);
|
||||||
box-shadow: 0 0 6px 3px rgb(230, 230, 230);
|
box-shadow: 0 0 6px 3px rgb(255, 255, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.yellow {
|
&.yellow {
|
||||||
background: rgb(230, 230, 50);
|
background: rgb(255, 234, 0);
|
||||||
box-shadow: 0 0 6px 3px rgb(230, 230, 50);
|
box-shadow: 0 0 6px 3px rgb(255, 234, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
call: RdioScannerCall | undefined;
|
call: RdioScannerCall | undefined;
|
||||||
callError = '0';
|
callError = '0';
|
||||||
callFrequency: string = this.formatFrequency(0);
|
callFrequency: string = this.formatFrequency(0);
|
||||||
callHistory: RdioScannerCall[] | undefined;
|
callHistory: RdioScannerCall[] = new Array<RdioScannerCall>(5);
|
||||||
callPrevious: RdioScannerCall | undefined;
|
callPrevious: RdioScannerCall | undefined;
|
||||||
callProgress = new Date(0, 0, 0, 0, 0, 0);
|
callProgress = new Date(0, 0, 0, 0, 0, 0);
|
||||||
callQueue = 0;
|
callQueue = 0;
|
||||||
|
|
@ -101,6 +101,9 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
playbackMode = false;
|
playbackMode = false;
|
||||||
|
|
||||||
|
replayOffset = 0;
|
||||||
|
replayTimer: Subscription | undefined;
|
||||||
|
|
||||||
get showListenersCount(): boolean {
|
get showListenersCount(): boolean {
|
||||||
return this.config?.showListenersCount || false;
|
return this.config?.showListenersCount || false;
|
||||||
}
|
}
|
||||||
|
|
@ -125,9 +128,7 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
private rdioScannerService: RdioScannerService,
|
private rdioScannerService: RdioScannerService,
|
||||||
private ngChangeDetectorRef: ChangeDetectorRef,
|
private ngChangeDetectorRef: ChangeDetectorRef,
|
||||||
private ngFormBuilder: FormBuilder,
|
private ngFormBuilder: FormBuilder,
|
||||||
) {
|
) { }
|
||||||
this.callHistory = this.rdioScannerService.getHistory();
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticate(password = this.authForm.value.password): void {
|
authenticate(password = this.authForm.value.password): void {
|
||||||
this.authForm.disable();
|
this.authForm.disable();
|
||||||
|
|
@ -253,7 +254,27 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
if (!this.livefeedPaused && (this.call || this.callPrevious)) {
|
if (!this.livefeedPaused && (this.call || this.callPrevious)) {
|
||||||
this.rdioScannerService.beep(RdioScannerBeepStyle.Activate);
|
this.rdioScannerService.beep(RdioScannerBeepStyle.Activate);
|
||||||
|
|
||||||
this.rdioScannerService.replay();
|
if (this.replayTimer instanceof Subscription) {
|
||||||
|
this.replayTimer.unsubscribe();
|
||||||
|
this.replayOffset = Math.min(this.callHistory.length, this.replayOffset + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.replayTimer = timer(750).subscribe(() => {
|
||||||
|
this.replayTimer = undefined;
|
||||||
|
this.replayOffset = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.call && !this.replayOffset) {
|
||||||
|
this.rdioScannerService.replay()
|
||||||
|
} else if (this.callPrevious !== this.callHistory[0]) {
|
||||||
|
if (this.replayOffset) {
|
||||||
|
this.rdioScannerService.play(this.callHistory[this.replayOffset - 1]);
|
||||||
|
} else {
|
||||||
|
this.rdioScannerService.replay()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.rdioScannerService.play(this.callHistory[this.replayOffset]);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.rdioScannerService.beep(RdioScannerBeepStyle.Denied);
|
this.rdioScannerService.beep(RdioScannerBeepStyle.Denied);
|
||||||
|
|
@ -376,10 +397,6 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
this.authForm.get('password')?.setErrors({ expired: true });
|
this.authForm.get('password')?.setErrors({ expired: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('history' in event) {
|
|
||||||
this.callHistory = event.history || [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('holdSys' in event) {
|
if ('holdSys' in event) {
|
||||||
this.holdSys = event.holdSys || false;
|
this.holdSys = event.holdSys || false;
|
||||||
}
|
}
|
||||||
|
|
@ -530,6 +547,16 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
this.callUnit = typeof this.call.source === 'number' ? `${this.call.source}` : '';
|
this.callUnit = typeof this.call.source === 'number' ? `${this.call.source}` : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.callPrevious &&
|
||||||
|
this.callPrevious.id !== this.call.id &&
|
||||||
|
!this.callHistory.find((call: RdioScannerCall) => call?.id === this.callPrevious?.id)
|
||||||
|
) {
|
||||||
|
this.callHistory.pop();
|
||||||
|
|
||||||
|
this.callHistory.unshift(this.callPrevious);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const call = this.call || this.callPrevious;
|
const call = this.call || this.callPrevious;
|
||||||
|
|
@ -544,7 +571,7 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const colors = ['blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow'];
|
const colors = ['blue', 'cyan', 'green', 'magenta', 'orange', 'red', 'white', 'yellow'];
|
||||||
|
|
||||||
this.ledStyle = this.call && this.livefeedPaused ? 'on paused' : this.call ? 'on' : 'off';
|
this.ledStyle = this.call && this.livefeedPaused ? 'on paused' : this.call ? 'on' : 'off';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
private beepContext: AudioContext | undefined;
|
private beepContext: AudioContext | undefined;
|
||||||
|
|
||||||
private call: RdioScannerCall | undefined;
|
private call: RdioScannerCall | undefined;
|
||||||
private callHistory: RdioScannerCall[] = new Array<RdioScannerCall>(5);
|
private callPrevious: RdioScannerCall | undefined;
|
||||||
private callQueue: RdioScannerCall[] = [];
|
private callQueue: RdioScannerCall[] = [];
|
||||||
|
|
||||||
private categories: RdioScannerCategory[] = [];
|
private categories: RdioScannerCategory[] = [];
|
||||||
|
|
@ -99,7 +99,6 @@ export class RdioScannerService implements OnDestroy {
|
||||||
private playbackRefreshing = false;
|
private playbackRefreshing = false;
|
||||||
|
|
||||||
private replayDelay: Subscription | undefined;
|
private replayDelay: Subscription | undefined;
|
||||||
private replayOffset = 0;
|
|
||||||
|
|
||||||
private skipDelay: Subscription | undefined;
|
private skipDelay: Subscription | undefined;
|
||||||
|
|
||||||
|
|
@ -156,7 +155,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
const call = this.call || this.callHistory[0];
|
const call = this.call || this.callPrevious;
|
||||||
|
|
||||||
if (call) {
|
if (call) {
|
||||||
const sys = call.system;
|
const sys = call.system;
|
||||||
|
|
@ -225,12 +224,8 @@ export class RdioScannerService implements OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getHistory(): RdioScannerCall[] {
|
|
||||||
return this.callHistory;
|
|
||||||
}
|
|
||||||
|
|
||||||
holdSystem(options?: { resubscribe?: boolean }): void {
|
holdSystem(options?: { resubscribe?: boolean }): void {
|
||||||
const call = this.call || this.callHistory[0];
|
const call = this.call || this.callPrevious;
|
||||||
|
|
||||||
if (call && this.livefeedMap) {
|
if (call && this.livefeedMap) {
|
||||||
if (this.livefeedMapPriorToHoldSystem) {
|
if (this.livefeedMapPriorToHoldSystem) {
|
||||||
|
|
@ -284,7 +279,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
holdTalkgroup(options?: { resubscribe?: boolean }): void {
|
holdTalkgroup(options?: { resubscribe?: boolean }): void {
|
||||||
const call = this.call || this.callHistory[0];
|
const call = this.call || this.callPrevious;
|
||||||
|
|
||||||
if (call && this.livefeedMap) {
|
if (call && this.livefeedMap) {
|
||||||
if (this.livefeedMapPriorToHoldTalkgroup) {
|
if (this.livefeedMapPriorToHoldTalkgroup) {
|
||||||
|
|
@ -508,17 +503,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
replay(): void {
|
replay(): void {
|
||||||
if (this.replayDelay instanceof Subscription) {
|
this.play(this.call || this.callPrevious);
|
||||||
this.replayDelay.unsubscribe();
|
|
||||||
this.replayOffset = Math.min(this.callHistory.length - 1, this.replayOffset + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.replayDelay = timer(750).subscribe(() => {
|
|
||||||
this.replayDelay = undefined;
|
|
||||||
this.replayOffset = 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.play(this.replayOffset > 0 ? this.callHistory[this.replayOffset] : this.call || this.callHistory[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
searchCalls(options: RdioScannerSearchOptions): void {
|
searchCalls(options: RdioScannerSearchOptions): void {
|
||||||
|
|
@ -573,11 +558,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.call) {
|
if (this.call) {
|
||||||
if (!this.callHistory.find((call: RdioScannerCall) => call?.id === this.call?.id)) {
|
this.callPrevious = this.call;
|
||||||
this.callHistory.pop();
|
|
||||||
this.callHistory.unshift(this.call);
|
|
||||||
this.event.emit({ history: this.callHistory });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.call = undefined;
|
this.call = undefined;
|
||||||
}
|
}
|
||||||
|
|
@ -771,7 +752,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
this.sendtoWebsocket(WebsocketCommand.Call, `${id}`, flags);
|
this.sendtoWebsocket(WebsocketCommand.Call, `${id}`, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPlaybackQueueCount(id = this.call?.id || this.callHistory[0]?.id): number {
|
private getPlaybackQueueCount(id = this.call?.id || this.callPrevious?.id): number {
|
||||||
let queueCount = 0;
|
let queueCount = 0;
|
||||||
|
|
||||||
if (id && this.playbackList) {
|
if (id && this.playbackList) {
|
||||||
|
|
@ -922,7 +903,7 @@ export class RdioScannerService implements OnDestroy {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = this.playbackList.results.findIndex((call) => call.id === this.callHistory[0]?.id);
|
const index = this.playbackList.results.findIndex((call) => call.id === this.callPrevious?.id);
|
||||||
|
|
||||||
if (this.playbackList.options.sort === -1) {
|
if (this.playbackList.options.sort === -1) {
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,6 @@ export interface RdioScannerEvent {
|
||||||
call?: RdioScannerCall;
|
call?: RdioScannerCall;
|
||||||
config?: RdioScannerConfig;
|
config?: RdioScannerConfig;
|
||||||
expired?: boolean;
|
expired?: boolean;
|
||||||
history?: RdioScannerCall[];
|
|
||||||
holdSys?: boolean;
|
holdSys?: boolean;
|
||||||
holdTg?: boolean;
|
holdTg?: boolean;
|
||||||
linked?: boolean;
|
linked?: boolean;
|
||||||
|
|
@ -160,7 +159,7 @@ export interface RdioScannerSearchOptions {
|
||||||
export interface RdioScannerSystem {
|
export interface RdioScannerSystem {
|
||||||
id: number;
|
id: number;
|
||||||
label: string;
|
label: string;
|
||||||
led?: 'blue' | 'cyan' | 'green' | 'magenta' | 'red' | 'white' | 'yellow';
|
led?: 'blue' | 'cyan' | 'green' | 'magenta' | 'orange' | 'red' | 'white' | 'yellow';
|
||||||
order?: number;
|
order?: number;
|
||||||
talkgroups: RdioScannerTalkgroup[];
|
talkgroups: RdioScannerTalkgroup[];
|
||||||
units: RdioScannerUnit[];
|
units: RdioScannerUnit[];
|
||||||
|
|
@ -171,7 +170,7 @@ export interface RdioScannerTalkgroup {
|
||||||
group: string;
|
group: string;
|
||||||
id: number;
|
id: number;
|
||||||
label: string;
|
label: string;
|
||||||
led?: 'blue' | 'cyan' | 'green' | 'magenta' | 'red' | 'white' | 'yellow';
|
led?: 'blue' | 'cyan' | 'green' | 'magenta' | 'orange' | 'red' | 'white' | 'yellow';
|
||||||
name: string;
|
name: string;
|
||||||
tag: string;
|
tag: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
rdio@macos ~ % mkdir rdio-scanner
|
rdio@macos ~ % mkdir rdio-scanner
|
||||||
rdio@macos ~ % cd rdio-scanner
|
rdio@macos ~ % cd rdio-scanner
|
||||||
rdio@macos rdio-scanner % unzip \
|
rdio@macos rdio-scanner % unzip \
|
||||||
> ~/Downloads/rdio-scanner-darwin-arm64-v6.3.2.zip
|
> ~/Downloads/rdio-scanner-darwin-arm64-v6.3.3.zip
|
||||||
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.3.2.zip
|
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.3.3.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
inflating: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
rdio@macos rdio-scanner % ./rdio-scanner
|
rdio@macos rdio-scanner % ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:38:06 server started
|
2022/05/24 08:38:06 server started
|
||||||
2022/05/21 08:38:06 main interface at http://macos.local:3000
|
2022/05/24 08:38:06 main interface at http://macos.local:3000
|
||||||
2022/05/21 08:38:06 admin interface at http://macos.local:3000/admin
|
2022/05/24 08:38:06 admin interface at http://macos.local:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -77,11 +77,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
|
|
||||||
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
|
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:48:03 server started
|
2022/05/24 08:48:03 server started
|
||||||
2022/05/21 08:48:03 main interface at http://macos.local
|
2022/05/24 08:48:03 main interface at http://macos.local
|
||||||
2022/05/21 08:48:03 admin interface at http://macos.local/admin
|
2022/05/24 08:48:03 admin interface at http://macos.local/admin
|
||||||
|
|
||||||
## Listening on a SSL port
|
## Listening on a SSL port
|
||||||
|
|
||||||
|
|
@ -95,12 +95,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
|
||||||
> -ssl_key_file mykey.key \
|
> -ssl_key_file mykey.key \
|
||||||
> -ssl_listen :443
|
> -ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:50:58 server started
|
2022/05/24 08:50:58 server started
|
||||||
2022/05/21 08:50:58 main interface at http://macos.local
|
2022/05/24 08:50:58 main interface at http://macos.local
|
||||||
2022/05/21 08:50:58 main interface at https://macos.local
|
2022/05/24 08:50:58 main interface at https://macos.local
|
||||||
2022/05/21 08:50:58 admin interface at https://macos.local/admin
|
2022/05/24 08:50:58 admin interface at https://macos.local/admin
|
||||||
|
|
||||||
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
||||||
|
|
||||||
|
|
@ -118,7 +118,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
||||||
> -ssl_auto_cert mydomain.com \
|
> -ssl_auto_cert mydomain.com \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -config_save
|
||||||
2022/05/21 08:52:24 rdio-scanner.ini file created
|
2022/05/24 08:52:24 rdio-scanner.ini file created
|
||||||
|
|
||||||
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
||||||
|
|
||||||
|
|
@ -132,12 +132,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
||||||
|
|
||||||
rdio@macos rdio-scanner % ./rdio-scanner
|
rdio@macos rdio-scanner % ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:54:08 server started
|
2022/05/24 08:54:08 server started
|
||||||
2022/05/21 08:54:08 main interface at http://macos.local
|
2022/05/24 08:54:08 main interface at http://macos.local
|
||||||
2022/05/21 08:54:08 main interface at https://macos.local
|
2022/05/24 08:54:08 main interface at https://macos.local
|
||||||
2022/05/21 08:54:08 admin interface at https://macos.local/admin
|
2022/05/24 08:54:08 admin interface at https://macos.local/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
rdio@pc-freebsd:~ $ mkdir rdio-scanner
|
rdio@pc-freebsd:~ $ mkdir rdio-scanner
|
||||||
rdio@pc-freebsd:~ $ cd rdio-scanner
|
rdio@pc-freebsd:~ $ cd rdio-scanner
|
||||||
rdio@pc-freebsd:~/rdio-scanner $ unzip \
|
rdio@pc-freebsd:~/rdio-scanner $ unzip \
|
||||||
> ~/rdio-scanner-freebsd-amd64-v6.3.2.zip
|
> ~/rdio-scanner-freebsd-amd64-v6.3.3.zip
|
||||||
Archive: ../rdio-scanner-freebsd-amd64-v6.3.2.zip
|
Archive: ../rdio-scanner-freebsd-amd64-v6.3.3.zip
|
||||||
extracting: rdio-scanner
|
extracting: rdio-scanner
|
||||||
extracting: rdio-scanner.pdf
|
extracting: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
|
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:16:36 server started
|
2022/05/24 08:16:36 server started
|
||||||
2022/05/21 08:16:36 main interface at http://pc-freebsd:3000
|
2022/05/24 08:16:36 main interface at http://pc-freebsd:3000
|
||||||
2022/05/21 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
2022/05/24 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -81,11 +81,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
Password:
|
Password:
|
||||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
|
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 08:19:38 server started
|
2022/05/24 08:19:38 server started
|
||||||
2022/05/21 08:19:38 main interface at http://pc-freebsd
|
2022/05/24 08:19:38 main interface at http://pc-freebsd
|
||||||
2022/05/21 08:19:38 admin interface at http://pc-freebsd/admin
|
2022/05/24 08:19:38 admin interface at http://pc-freebsd/admin
|
||||||
|
|
||||||
## Listening on a SSL port
|
## Listening on a SSL port
|
||||||
|
|
||||||
|
|
@ -101,12 +101,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
|
||||||
> -ssl_key_file mykey.key \
|
> -ssl_key_file mykey.key \
|
||||||
> -ssl_listen :443
|
> -ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 10:34:29 server started
|
2022/05/24 10:34:29 server started
|
||||||
2022/05/21 10:34:29 main interface at http://pc-freebsd
|
2022/05/24 10:34:29 main interface at http://pc-freebsd
|
||||||
2022/05/21 10:34:29 main interface at https://pc-freebsd
|
2022/05/24 10:34:29 main interface at https://pc-freebsd
|
||||||
2022/05/21 10:34:29 admin interface at https://pc-freebsd/admin
|
2022/05/24 10:34:29 admin interface at https://pc-freebsd/admin
|
||||||
|
|
||||||
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
||||||
|
|
||||||
|
|
@ -126,7 +126,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
||||||
> -ssl_auto_cert mydomain.com \
|
> -ssl_auto_cert mydomain.com \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -config_save
|
||||||
2022/05/21 10:37:00 rdio-scanner.ini file created
|
2022/05/24 10:37:00 rdio-scanner.ini file created
|
||||||
|
|
||||||
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
||||||
|
|
||||||
|
|
@ -142,12 +142,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
||||||
Password:
|
Password:
|
||||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
|
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 10:38:28 server started
|
2022/05/24 10:38:28 server started
|
||||||
2022/05/21 10:38:29 main interface at http://pc-freebsd
|
2022/05/24 10:38:29 main interface at http://pc-freebsd
|
||||||
2022/05/21 10:38:29 main interface at https://pc-freebsd
|
2022/05/24 10:38:29 main interface at https://pc-freebsd
|
||||||
2022/05/21 10:38:29 admin interface at https://pc-freebsd/admin
|
2022/05/24 10:38:29 admin interface at https://pc-freebsd/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
[rdio@pc-linux ~]$ mkdir rdio-scanner
|
[rdio@pc-linux ~]$ mkdir rdio-scanner
|
||||||
[rdio@pc-linux ~]$ cd rdio-scanner
|
[rdio@pc-linux ~]$ cd rdio-scanner
|
||||||
[rdio@pc-linux rdio-scanner]$ unzip \
|
[rdio@pc-linux rdio-scanner]$ unzip \
|
||||||
> ~/Downloads/rdio-scanner-linux-amd64-v6.3.2.zip
|
> ~/Downloads/rdio-scanner-linux-amd64-v6.3.3.zip
|
||||||
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.3.2.zip
|
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.3.3.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
inflating: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
|
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 09:11:48 server started
|
2022/05/24 09:11:48 server started
|
||||||
2022/05/21 09:11:48 main interface at http://pc-linux:3000
|
2022/05/24 09:11:48 main interface at http://pc-linux:3000
|
||||||
2022/05/21 09:11:48 admin interface at http://pc-linux:3000/admin
|
2022/05/24 09:11:48 admin interface at http://pc-linux:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
||||||
[sudo] password for rdio:
|
[sudo] password for rdio:
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 09:14:00 server started
|
2022/05/24 09:14:00 server started
|
||||||
2022/05/21 09:14:00 main interface at http://pc-linux
|
2022/05/24 09:14:00 main interface at http://pc-linux
|
||||||
2022/05/21 09:14:00 admin interface at http://pc-linux/admin
|
2022/05/24 09:14:00 admin interface at http://pc-linux/admin
|
||||||
|
|
||||||
## Listening on a SSL port
|
## Listening on a SSL port
|
||||||
|
|
||||||
|
|
@ -97,12 +97,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
|
||||||
> -ssl_listen :443
|
> -ssl_listen :443
|
||||||
[sudo] password for rdio:
|
[sudo] password for rdio:
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 09:16:47 server started
|
2022/05/24 09:16:47 server started
|
||||||
2022/05/21 09:16:47 main interface at http://pc-linux
|
2022/05/24 09:16:47 main interface at http://pc-linux
|
||||||
2022/05/21 09:16:47 main interface at https://pc-linux
|
2022/05/24 09:16:47 main interface at https://pc-linux
|
||||||
2022/05/21 09:16:47 admin interface at https://pc-linux/admin
|
2022/05/24 09:16:47 admin interface at https://pc-linux/admin
|
||||||
|
|
||||||
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
||||||
|
|
||||||
|
|
@ -120,7 +120,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
||||||
> -ssl_auto_cert mydomain.com \
|
> -ssl_auto_cert mydomain.com \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -config_save
|
||||||
2022/05/21 09:19:29 rdio-scanner.ini file created
|
2022/05/24 09:19:29 rdio-scanner.ini file created
|
||||||
|
|
||||||
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
||||||
|
|
||||||
|
|
@ -135,12 +135,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
||||||
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
|
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
|
||||||
[sudo] Mot de passe de rdio :
|
[sudo] Mot de passe de rdio :
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 09:20:40 server started
|
2022/05/24 09:20:40 server started
|
||||||
2022/05/21 09:20:40 main interface at http://pc-linux
|
2022/05/24 09:20:40 main interface at http://pc-linux
|
||||||
2022/05/21 09:20:40 main interface at https://pc-linux
|
2022/05/24 09:20:40 main interface at https://pc-linux
|
||||||
2022/05/21 09:20:40 admin interface at https://pc-linux/admin
|
2022/05/24 09:20:40 admin interface at https://pc-linux/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
C:\Users\rdio> cd rdio-scanner
|
C:\Users\rdio> cd rdio-scanner
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
||||||
..\downloads\rdio-scanner-windows-amd64-v6.3.2.zip
|
..\downloads\rdio-scanner-windows-amd64-v6.3.3.zip
|
||||||
x rdio-scanner.exe
|
x rdio-scanner.exe
|
||||||
x rdio-scanner.pdf
|
x rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -52,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner>rdio-scanner
|
C:\Users\rdio\rdio-scanner>rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 13:48:48 server started
|
2022/05/24 13:48:48 server started
|
||||||
2022/05/21 13:48:48 main interface at http://pc-windows:3000
|
2022/05/24 13:48:48 main interface at http://pc-windows:3000
|
||||||
2022/05/21 13:48:48 admin interface at http://pc-windows:3000/admin
|
2022/05/24 13:48:48 admin interface at http://pc-windows:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
|
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 10:53:31 server started
|
2022/05/24 10:53:31 server started
|
||||||
2022/05/21 10:53:31 main interface at http://pc-windows
|
2022/05/24 10:53:31 main interface at http://pc-windows
|
||||||
2022/05/21 10:53:31 admin interface at http://pc-windows/admin
|
2022/05/24 10:53:31 admin interface at http://pc-windows/admin
|
||||||
|
|
||||||
## Listening on a SSL port
|
## Listening on a SSL port
|
||||||
|
|
||||||
|
|
@ -96,12 +96,12 @@ You can use your own SSL certificates that match your domain name with `-ssl_cer
|
||||||
-ssl_key_file meykey.key ^
|
-ssl_key_file meykey.key ^
|
||||||
-ssl_listen :443
|
-ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 11:05:43 server started
|
2022/05/24 11:05:43 server started
|
||||||
2022/05/21 11:05:43 main interface at http://pc-windows
|
2022/05/24 11:05:43 main interface at http://pc-windows
|
||||||
2022/05/21 11:05:43 main interface at https://pc-windows
|
2022/05/24 11:05:43 main interface at https://pc-windows
|
||||||
2022/05/21 11:05:43 admin interface at https://pc-windows/admin
|
2022/05/24 11:05:43 admin interface at https://pc-windows/admin
|
||||||
|
|
||||||
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
If you don't want to worry about SSL certificates, you can use the built-in Let's Encrypt auto-cert feature. This requires that you have both port 80 (HTTP) and port 443 (HTTPS) open to the world. Also, your domain name should point to your IP address where [Rdio Scanner](https://github.com/chuot/rdio-scanner/) is running. The advantage of this approach is that everything is done automatically, no certificate request, no certificate renewal.
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
||||||
-ssl_auto_cert mydomain.com ^
|
-ssl_auto_cert mydomain.com ^
|
||||||
-ssl_listen :443 ^
|
-ssl_listen :443 ^
|
||||||
-config_save
|
-config_save
|
||||||
2022/05/21 11:08:28 rdio-scanner.ini file created
|
2022/05/24 11:08:28 rdio-scanner.ini file created
|
||||||
|
|
||||||
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
All of your parameters passed as arguments to [Rdio Scanner](https://github.com/chuot/rdio-scanner) have been saved to an INI file which has the same arguments/values list.
|
||||||
|
|
||||||
|
|
@ -133,12 +133,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner>rdio-scanner
|
C:\Users\rdio\rdio-scanner>rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.3.2
|
Rdio Scanner v6.3.3
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/05/21 11:11:28 server started
|
2022/05/24 11:11:28 server started
|
||||||
2022/05/21 11:11:28 main interface at http://pc-windows
|
2022/05/24 11:11:28 main interface at http://pc-windows
|
||||||
2022/05/21 11:11:28 main interface at https://pc-windows
|
2022/05/24 11:11:28 main interface at https://pc-windows
|
||||||
2022/05/21 11:11:28 admin interface at https://pc-windows/admin
|
2022/05/24 11:11:28 admin interface at https://pc-windows/admin
|
||||||
|
|
||||||
\pagebreak{}
|
\pagebreak{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ The color is _green_ by default, but can be customized by the system or by the t
|
||||||
|  | When active, incoming audio will be played according to the active systems/talkgroups on the **SELECT TG** panel. The LED can also be _yellow_ if playing audio from the archive while **LIVE FEED** is inactive, this is called **playback mode**. Disabling **LIVE FEED** will also stop any playing audio and will clear the listening queue. |
|
|  | When active, incoming audio will be played according to the active systems/talkgroups on the **SELECT TG** panel. The LED can also be _yellow_ if playing audio from the archive while **LIVE FEED** is inactive, this is called **playback mode**. Disabling **LIVE FEED** will also stop any playing audio and will clear the listening queue. |
|
||||||
|  | Temporarily maintain the current system in live feed mode. |
|
|  | Temporarily maintain the current system in live feed mode. |
|
||||||
|  | Temporarily maintain the current talkgroup in live feed mode. |
|
|  | Temporarily maintain the current talkgroup in live feed mode. |
|
||||||
|  | Replay the current audio from the beginning or the previous one if there is none active. |
|
|  | Replay the current audio from the beginning or the previous one if there is none active. Press repeatedly to replay items displayed in the history section. For example, press three times to replay the third history item. |
|
||||||
|  | Stop the audio currently playing and play the next one in the listening queue. This is useful when playing boring or encrypted sound. |
|
|  | Stop the audio currently playing and play the next one in the listening queue. This is useful when playing boring or encrypted sound. |
|
||||||
|  | Activate and deactivate the talkgroup from the current or previous audio. |
|
|  | Activate and deactivate the talkgroup from the current or previous audio. |
|
||||||
|  | Display the archived audio panel. |
|
|  | Display the archived audio panel. |
|
||||||
|
|
|
||||||
|
|
@ -371,20 +371,22 @@ func (admin *Admin) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
err := json.NewDecoder(r.Body).Decode(&m)
|
|
||||||
if err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&m); err != nil {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
attempt := admin.Attempts[r.RemoteAddr]
|
remoteAddr := GetRemoteAddr(r)
|
||||||
|
|
||||||
|
attempt := admin.Attempts[remoteAddr]
|
||||||
|
|
||||||
if attempt == nil {
|
if attempt == nil {
|
||||||
admin.Attempts[r.RemoteAddr] = &AdminLoginAttempt{
|
admin.Attempts[remoteAddr] = &AdminLoginAttempt{
|
||||||
Count: 1,
|
Count: 1,
|
||||||
Date: time.Now(),
|
Date: time.Now(),
|
||||||
}
|
}
|
||||||
attempt = admin.Attempts[r.RemoteAddr]
|
attempt = admin.Attempts[remoteAddr]
|
||||||
} else {
|
} else {
|
||||||
attempt.Count++
|
attempt.Count++
|
||||||
attempt.Date = time.Now()
|
attempt.Date = time.Now()
|
||||||
|
|
@ -395,7 +397,7 @@ func (admin *Admin) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
admin.Controller.Logs.LogEvent(
|
admin.Controller.Logs.LogEvent(
|
||||||
admin.Controller.Database,
|
admin.Controller.Database,
|
||||||
LogLevelWarn,
|
LogLevelWarn,
|
||||||
fmt.Sprintf("too many login attempts for ip=\"%v\"", r.RemoteAddr),
|
fmt.Sprintf("too many login attempts for ip=\"%v\"", remoteAddr),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -418,7 +420,7 @@ func (admin *Admin) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
admin.Controller.Logs.LogEvent(
|
admin.Controller.Logs.LogEvent(
|
||||||
admin.Controller.Database,
|
admin.Controller.Database,
|
||||||
LogLevelWarn,
|
LogLevelWarn,
|
||||||
fmt.Sprintf("invalid login attempt for ip=%v", r.RemoteAddr),
|
fmt.Sprintf("invalid login attempt for ip=%v", remoteAddr),
|
||||||
)
|
)
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,10 @@ func (calls *Calls) GetCall(id uint, db *Database) (*Call, error) {
|
||||||
calls.mutex.Lock()
|
calls.mutex.Lock()
|
||||||
defer calls.mutex.Unlock()
|
defer calls.mutex.Unlock()
|
||||||
|
|
||||||
call := Call{}
|
call := Call{Id: id}
|
||||||
|
|
||||||
query := fmt.Sprintf("select `id`, `audio`, `audioName`, `audioType`, `DateTime`, `frequencies`, `frequency`, `patches`, `source`, `sources`, `system`, `talkgroup` from `rdioScannerCalls` where `id` = %v", id)
|
query := fmt.Sprintf("select `audio`, `audioName`, `audioType`, `DateTime`, `frequencies`, `frequency`, `patches`, `source`, `sources`, `system`, `talkgroup` from `rdioScannerCalls` where `id` = %v", id)
|
||||||
err := db.Sql.QueryRow(query).Scan(&call.Id, &call.Audio, &call.AudioName, &call.AudioType, &dateTime, &frequencies, &call.Frequency, &patches, &call.Source, &sources, &call.System, &call.Talkgroup)
|
err := db.Sql.QueryRow(query).Scan(&call.Audio, &call.AudioName, &call.AudioType, &dateTime, &frequencies, &call.Frequency, &patches, &call.Source, &sources, &call.System, &call.Talkgroup)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return nil, fmt.Errorf("getcall: %v, %v", err, query)
|
return nil, fmt.Errorf("getcall: %v, %v", err, query)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -36,9 +37,10 @@ type Client struct {
|
||||||
TagsMap TagsMap
|
TagsMap TagsMap
|
||||||
Livefeed *Livefeed
|
Livefeed *Livefeed
|
||||||
SystemsMap SystemsMap
|
SystemsMap SystemsMap
|
||||||
|
request *http.Request
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Init(controller *Controller, conn *websocket.Conn) error {
|
func (client *Client) Init(controller *Controller, request *http.Request, conn *websocket.Conn) error {
|
||||||
const (
|
const (
|
||||||
pongWait = 60 * time.Second
|
pongWait = 60 * time.Second
|
||||||
pingPeriod = pongWait / 10 * 9
|
pingPeriod = pongWait / 10 * 9
|
||||||
|
|
@ -57,8 +59,9 @@ func (client *Client) Init(controller *Controller, conn *websocket.Conn) error {
|
||||||
client.Access = &Access{}
|
client.Access = &Access{}
|
||||||
client.Controller = controller
|
client.Controller = controller
|
||||||
client.Conn = conn
|
client.Conn = conn
|
||||||
client.Send = make(chan *Message)
|
|
||||||
client.Livefeed = NewLivefeed()
|
client.Livefeed = NewLivefeed()
|
||||||
|
client.Send = make(chan *Message)
|
||||||
|
client.request = request
|
||||||
|
|
||||||
controller.Register <- client
|
controller.Register <- client
|
||||||
|
|
||||||
|
|
@ -148,7 +151,15 @@ func (client *Client) Init(controller *Controller, conn *websocket.Conn) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) GetRemoteAddr() string {
|
||||||
|
return GetRemoteAddr(client.request)
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) SendConfig(groups *Groups, options *Options, systems *Systems, tags *Tags) {
|
func (client *Client) SendConfig(groups *Groups, options *Options, systems *Systems, tags *Tags) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
client.SystemsMap = systems.GetScopedSystems(client, groups, tags, options.SortTalkgroups)
|
client.SystemsMap = systems.GetScopedSystems(client, groups, tags, options.SortTalkgroups)
|
||||||
client.GroupsMap = groups.GetGroupsMap(&client.SystemsMap)
|
client.GroupsMap = groups.GetGroupsMap(&client.SystemsMap)
|
||||||
client.TagsMap = tags.GetTagsMap(&client.SystemsMap)
|
client.TagsMap = tags.GetTagsMap(&client.SystemsMap)
|
||||||
|
|
@ -171,6 +182,10 @@ func (client *Client) SendConfig(groups *Groups, options *Options, systems *Syst
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) SendListenersCount(count int) {
|
func (client *Client) SendListenersCount(count int) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
client.Send <- &Message{
|
client.Send <- &Message{
|
||||||
Command: MessagecommandListenersCount,
|
Command: MessagecommandListenersCount,
|
||||||
Payload: count,
|
Payload: count,
|
||||||
|
|
@ -218,6 +233,10 @@ func (clients *Clients) Count() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clients *Clients) EmitCall(call *Call, restricted bool) {
|
func (clients *Clients) EmitCall(call *Call, restricted bool) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
clients.Map.Range(func(k interface{}, _ interface{}) bool {
|
clients.Map.Range(func(k interface{}, _ interface{}) bool {
|
||||||
switch c := k.(type) {
|
switch c := k.(type) {
|
||||||
case *Client:
|
case *Client:
|
||||||
|
|
@ -231,6 +250,10 @@ func (clients *Clients) EmitCall(call *Call, restricted bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clients *Clients) EmitConfig(groups *Groups, options *Options, systems *Systems, tags *Tags, restricted bool) {
|
func (clients *Clients) EmitConfig(groups *Groups, options *Options, systems *Systems, tags *Tags, restricted bool) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
count := clients.Count()
|
count := clients.Count()
|
||||||
|
|
||||||
clients.Map.Range(func(k interface{}, _ interface{}) bool {
|
clients.Map.Range(func(k interface{}, _ interface{}) bool {
|
||||||
|
|
@ -265,6 +288,10 @@ func (clients *Clients) EmitListenersCount() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (clients *Clients) Remove(client *Client) {
|
func (clients *Clients) Remove(client *Client) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
|
||||||
clients.Map.Delete(client)
|
clients.Map.Delete(client)
|
||||||
|
|
||||||
close(client.Send)
|
close(client.Send)
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ func (controller *Controller) ConvertAudio(call *Call) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "-c:a", "aac", "-b:a", "32k", "-movflags", "frag_keyframe+empty_moov", "-f", "ipod", "-")
|
args = append(args, "-af", "apad=whole_dur=3s,loudnorm=I=-16:TP=-1.5:LRA=11", "-c:a", "aac", "-b:a", "32k", "-movflags", "frag_keyframe+empty_moov", "-f", "ipod", "-")
|
||||||
|
|
||||||
cmd := exec.Command("ffmpeg", args...)
|
cmd := exec.Command("ffmpeg", args...)
|
||||||
cmd.Stdin = bytes.NewReader(call.Audio)
|
cmd.Stdin = bytes.NewReader(call.Audio)
|
||||||
|
|
@ -497,7 +497,7 @@ func (controller *Controller) ProcessMessageCommandPin(client *Client, message *
|
||||||
controller.Logs.LogEvent(
|
controller.Logs.LogEvent(
|
||||||
controller.Database,
|
controller.Database,
|
||||||
LogLevelWarn,
|
LogLevelWarn,
|
||||||
fmt.Sprintf("invalid access code=\"%s\" address=\"%s\"", code, client.Conn.RemoteAddr().String()),
|
fmt.Sprintf("invalid access code=\"%s\" address=\"%s\"", code, client.GetRemoteAddr()),
|
||||||
)
|
)
|
||||||
client.Send <- &Message{Command: MessageCommandPin}
|
client.Send <- &Message{Command: MessageCommandPin}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ type Dirwatch struct {
|
||||||
UsePolling bool `json:"usePolling"`
|
UsePolling bool `json:"usePolling"`
|
||||||
controller *Controller
|
controller *Controller
|
||||||
dirs map[string]bool
|
dirs map[string]bool
|
||||||
pending map[string]*time.Timer
|
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -525,8 +524,9 @@ func (dirwatch *Dirwatch) parseMask(call *Call) {
|
||||||
|
|
||||||
func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
var (
|
var (
|
||||||
delay time.Duration
|
delay time.Duration
|
||||||
err error
|
err error
|
||||||
|
timers = map[string]*time.Timer{}
|
||||||
)
|
)
|
||||||
|
|
||||||
if dirwatch.Disabled {
|
if dirwatch.Disabled {
|
||||||
|
|
@ -558,7 +558,7 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
|
|
||||||
newTimer := func(eventName string) *time.Timer {
|
newTimer := func(eventName string) *time.Timer {
|
||||||
return time.AfterFunc(delay, func() {
|
return time.AfterFunc(delay, func() {
|
||||||
delete(dirwatch.pending, eventName)
|
delete(timers, eventName)
|
||||||
|
|
||||||
if _, err := os.Stat(eventName); err == nil {
|
if _, err := os.Stat(eventName); err == nil {
|
||||||
dirwatch.Ingest(eventName)
|
dirwatch.Ingest(eventName)
|
||||||
|
|
@ -566,6 +566,13 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
for k := range timers {
|
||||||
|
timers[k].Stop()
|
||||||
|
delete(timers, k)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if dirwatch.watcher == nil {
|
if dirwatch.watcher == nil {
|
||||||
break
|
break
|
||||||
|
|
@ -582,10 +589,10 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if dirwatch.pending[event.Name] != nil {
|
if timers[event.Name] != nil {
|
||||||
dirwatch.pending[event.Name].Stop()
|
timers[event.Name].Stop()
|
||||||
}
|
}
|
||||||
dirwatch.pending[event.Name] = newTimer(event.Name)
|
timers[event.Name] = newTimer(event.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
case fsnotify.Remove:
|
case fsnotify.Remove:
|
||||||
|
|
@ -598,11 +605,11 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
case fsnotify.Write:
|
case fsnotify.Write:
|
||||||
if dirwatch.pending[event.Name] != nil {
|
if timers[event.Name] != nil {
|
||||||
if dirwatch.pending[event.Name] != nil {
|
if timers[event.Name] != nil {
|
||||||
dirwatch.pending[event.Name].Stop()
|
timers[event.Name].Stop()
|
||||||
}
|
}
|
||||||
dirwatch.pending[event.Name] = newTimer(event.Name)
|
timers[event.Name] = newTimer(event.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -610,6 +617,8 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
case err, ok := <-dirwatch.watcher.Errors:
|
case err, ok := <-dirwatch.watcher.Errors:
|
||||||
if ok {
|
if ok {
|
||||||
logError(err)
|
logError(err)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -647,11 +656,6 @@ func (dirwatch *Dirwatch) Stop() {
|
||||||
dirwatch.watcher.Close()
|
dirwatch.watcher.Close()
|
||||||
dirwatch.watcher = nil
|
dirwatch.watcher = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for k := range dirwatch.pending {
|
|
||||||
dirwatch.pending[k].Stop()
|
|
||||||
delete(dirwatch.pending, k)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dirwatches struct {
|
type Dirwatches struct {
|
||||||
|
|
@ -715,7 +719,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
dirwatch := &Dirwatch{pending: map[string]*time.Timer{}}
|
dirwatch := &Dirwatch{}
|
||||||
|
|
||||||
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
|
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &Client{}
|
client := &Client{}
|
||||||
if err = client.Init(controller, conn); err != nil {
|
if err = client.Init(controller, r, conn); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,3 +245,17 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRemoteAddr(r *http.Request) string {
|
||||||
|
for _, addr := range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {
|
||||||
|
if ip := strings.Split(addr, ":"); len(ip[0]) > 0 {
|
||||||
|
return ip[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ip := strings.Split(r.RemoteAddr, ":"); len(ip[0]) > 0 {
|
||||||
|
return ip[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,4 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
const Version = "6.3.2"
|
const Version = "6.3.3"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue