Version 6.3.4

This commit is contained in:
Chrystian Huot 2022-05-25 11:06:22 -04:00
parent 4d0dbd0e8e
commit 60fcf1e066
21 changed files with 345 additions and 280 deletions

View file

@ -28,6 +28,12 @@ _v6.3.3_
- Show the real IP address in the logs taking into account if behind a proxy. - Show the real IP address in the logs taking into account if behind a proxy.
- Fix panic when emitting a call to clients. - Fix panic when emitting a call to clients.
_v6.3.4_
- Fix ffmpeg audio filter not available on older version (issue #189).
- Improved logging when run as a service, Windows users can now see these logs in the events viewer.
- Dirwatch now catches panic errors and logs them.
## Version 6.2 ## Version 6.2
- New max clients options which is 200 by default. - New max clients options which is 200 by default.

View file

@ -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.3.zip rdio-scanner-darwin-amd64-v6.3.4.zip
rdio-scanner-darwin-arm64-v6.3.3.zip rdio-scanner-darwin-arm64-v6.3.4.zip
rdio-scanner-freebsd-amd64-v6.3.3.zip rdio-scanner-freebsd-amd64-v6.3.4.zip
rdio-scanner-linux-386-v6.3.3.zip rdio-scanner-linux-386-v6.3.4.zip
rdio-scanner-linux-amd64-v6.3.3.zip rdio-scanner-linux-amd64-v6.3.4.zip
rdio-scanner-linux-arm64-v6.3.3.zip rdio-scanner-linux-arm64-v6.3.4.zip
rdio-scanner-linux-arm-v6.3.3.zip rdio-scanner-linux-arm-v6.3.4.zip
rdio-scanner-windows-amd64-v6.3.3.zip rdio-scanner-windows-amd64-v6.3.4.zip
**Happy Rdio scanning !** **Happy Rdio scanning !**

View file

@ -16,8 +16,8 @@
################################################################################ ################################################################################
app := rdio-scanner app := rdio-scanner
date := 2022/05/24 date := 2022/05/25
ver := 6.3.3 ver := 6.3.4
client := $(wildcard client/*.json client/*.ts) client := $(wildcard client/*.json client/*.ts)
server := $(wildcard server/*.go) server := $(wildcard server/*.go)

View file

@ -1,12 +1,12 @@
{ {
"name": "rdio-scanner", "name": "rdio-scanner",
"version": "6.3.3", "version": "6.3.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "rdio-scanner", "name": "rdio-scanner",
"version": "6.3.3", "version": "6.3.4",
"license": "LICENSE", "license": "LICENSE",
"dependencies": { "dependencies": {
"@angular/animations": "^13.3.9", "@angular/animations": "^13.3.9",

View file

@ -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.3" "version": "6.3.4"
} }

View file

@ -272,7 +272,7 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
} else { } else {
this.rdioScannerService.replay() this.rdioScannerService.replay()
} }
} else { } else if (this.replayOffset < this.callHistory.length) {
this.rdioScannerService.play(this.callHistory[this.replayOffset]); this.rdioScannerService.play(this.callHistory[this.replayOffset]);
} }

View file

@ -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.3.zip > ~/Downloads/rdio-scanner-darwin-arm64-v6.3.4.zip
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.3.3.zip Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.3.4.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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:38:06 server started 2022/05/25 08:38:06 server started
2022/05/24 08:38:06 main interface at http://macos.local:3000 2022/05/25 08:38:06 main interface at http://macos.local:3000
2022/05/24 08:38:06 admin interface at http://macos.local:3000/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:48:03 server started 2022/05/25 08:48:03 server started
2022/05/24 08:48:03 main interface at http://macos.local 2022/05/25 08:48:03 main interface at http://macos.local
2022/05/24 08:48:03 admin interface at http://macos.local/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:50:58 server started 2022/05/25 08:50:58 server started
2022/05/24 08:50:58 main interface at http://macos.local 2022/05/25 08:50:58 main interface at http://macos.local
2022/05/24 08:50:58 main interface at https://macos.local 2022/05/25 08:50:58 main interface at https://macos.local
2022/05/24 08:50:58 admin interface at https://macos.local/admin 2022/05/25 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/24 08:52:24 rdio-scanner.ini file created 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:54:08 server started 2022/05/25 08:54:08 server started
2022/05/24 08:54:08 main interface at http://macos.local 2022/05/25 08:54:08 main interface at http://macos.local
2022/05/24 08:54:08 main interface at https://macos.local 2022/05/25 08:54:08 main interface at https://macos.local
2022/05/24 08:54:08 admin interface at https://macos.local/admin 2022/05/25 08:54:08 admin interface at https://macos.local/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -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.3.zip > ~/rdio-scanner-freebsd-amd64-v6.3.4.zip
Archive: ../rdio-scanner-freebsd-amd64-v6.3.3.zip Archive: ../rdio-scanner-freebsd-amd64-v6.3.4.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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:16:36 server started 2022/05/25 08:16:36 server started
2022/05/24 08:16:36 main interface at http://pc-freebsd:3000 2022/05/25 08:16:36 main interface at http://pc-freebsd:3000
2022/05/24 08:16:36 admin interface at http://pc-freebsd:3000/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 08:19:38 server started 2022/05/25 08:19:38 server started
2022/05/24 08:19:38 main interface at http://pc-freebsd 2022/05/25 08:19:38 main interface at http://pc-freebsd
2022/05/24 08:19:38 admin interface at http://pc-freebsd/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 10:34:29 server started 2022/05/25 10:34:29 server started
2022/05/24 10:34:29 main interface at http://pc-freebsd 2022/05/25 10:34:29 main interface at http://pc-freebsd
2022/05/24 10:34:29 main interface at https://pc-freebsd 2022/05/25 10:34:29 main interface at https://pc-freebsd
2022/05/24 10:34:29 admin interface at https://pc-freebsd/admin 2022/05/25 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/24 10:37:00 rdio-scanner.ini file created 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 10:38:28 server started 2022/05/25 10:38:28 server started
2022/05/24 10:38:29 main interface at http://pc-freebsd 2022/05/25 10:38:29 main interface at http://pc-freebsd
2022/05/24 10:38:29 main interface at https://pc-freebsd 2022/05/25 10:38:29 main interface at https://pc-freebsd
2022/05/24 10:38:29 admin interface at https://pc-freebsd/admin 2022/05/25 10:38:29 admin interface at https://pc-freebsd/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -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.3.zip > ~/Downloads/rdio-scanner-linux-amd64-v6.3.4.zip
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.3.3.zip Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.3.4.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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 09:11:48 server started 2022/05/25 09:11:48 server started
2022/05/24 09:11:48 main interface at http://pc-linux:3000 2022/05/25 09:11:48 main interface at http://pc-linux:3000
2022/05/24 09:11:48 admin interface at http://pc-linux:3000/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 09:14:00 server started 2022/05/25 09:14:00 server started
2022/05/24 09:14:00 main interface at http://pc-linux 2022/05/25 09:14:00 main interface at http://pc-linux
2022/05/24 09:14:00 admin interface at http://pc-linux/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 09:16:47 server started 2022/05/25 09:16:47 server started
2022/05/24 09:16:47 main interface at http://pc-linux 2022/05/25 09:16:47 main interface at http://pc-linux
2022/05/24 09:16:47 main interface at https://pc-linux 2022/05/25 09:16:47 main interface at https://pc-linux
2022/05/24 09:16:47 admin interface at https://pc-linux/admin 2022/05/25 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/24 09:19:29 rdio-scanner.ini file created 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 09:20:40 server started 2022/05/25 09:20:40 server started
2022/05/24 09:20:40 main interface at http://pc-linux 2022/05/25 09:20:40 main interface at http://pc-linux
2022/05/24 09:20:40 main interface at https://pc-linux 2022/05/25 09:20:40 main interface at https://pc-linux
2022/05/24 09:20:40 admin interface at https://pc-linux/admin 2022/05/25 09:20:40 admin interface at https://pc-linux/admin
## Install Rdio Scanner as a service ## Install Rdio Scanner as a service

View file

@ -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.3.zip ..\downloads\rdio-scanner-windows-amd64-v6.3.4.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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 13:48:48 server started 2022/05/25 13:48:48 server started
2022/05/24 13:48:48 main interface at http://pc-windows:3000 2022/05/25 13:48:48 main interface at http://pc-windows:3000
2022/05/24 13:48:48 admin interface at http://pc-windows:3000/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 10:53:31 server started 2022/05/25 10:53:31 server started
2022/05/24 10:53:31 main interface at http://pc-windows 2022/05/25 10:53:31 main interface at http://pc-windows
2022/05/24 10:53:31 admin interface at http://pc-windows/admin 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 11:05:43 server started 2022/05/25 11:05:43 server started
2022/05/24 11:05:43 main interface at http://pc-windows 2022/05/25 11:05:43 main interface at http://pc-windows
2022/05/24 11:05:43 main interface at https://pc-windows 2022/05/25 11:05:43 main interface at https://pc-windows
2022/05/24 11:05:43 admin interface at https://pc-windows/admin 2022/05/25 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/24 11:08:28 rdio-scanner.ini file created 2022/05/25 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.3 Rdio Scanner v6.3.4
---------------------------------- ----------------------------------
2022/05/24 11:11:28 server started 2022/05/25 11:11:28 server started
2022/05/24 11:11:28 main interface at http://pc-windows 2022/05/25 11:11:28 main interface at http://pc-windows
2022/05/24 11:11:28 main interface at https://pc-windows 2022/05/25 11:11:28 main interface at https://pc-windows
2022/05/24 11:11:28 admin interface at https://pc-windows/admin 2022/05/25 11:11:28 admin interface at https://pc-windows/admin
\pagebreak{} \pagebreak{}

View file

@ -105,7 +105,7 @@ func (admin *Admin) ChangePassword(currentPassword string, newPassword string) e
return err return err
} }
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelWarn, "admin password changed.") admin.Controller.Logs.LogEvent(LogLevelWarn, "admin password changed.")
return nil return nil
} }
@ -149,7 +149,7 @@ func (admin *Admin) ConfigHandler(w http.ResponseWriter, r *http.Request) {
}() }()
logError := func(err error) { logError := func(err error) {
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelError, fmt.Sprintf("admin.confighandler.put: %s", err.Error())) admin.Controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("admin.confighandler.put: %s", err.Error()))
} }
t := admin.GetAuthorization(r) t := admin.GetAuthorization(r)
@ -284,7 +284,7 @@ func (admin *Admin) ConfigHandler(w http.ResponseWriter, r *http.Request) {
admin.SendConfig(w) admin.SendConfig(w)
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelWarn, "configuration changed") admin.Controller.Logs.LogEvent(LogLevelWarn, "configuration changed")
default: default:
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
@ -394,11 +394,7 @@ func (admin *Admin) LoginHandler(w http.ResponseWriter, r *http.Request) {
if attempt.Count > admin.AttemptsMax || time.Since(attempt.Date) < admin.AttemptsMaxDelay { if attempt.Count > admin.AttemptsMax || time.Since(attempt.Date) < admin.AttemptsMaxDelay {
if attempt.Count == admin.AttemptsMax+1 { if attempt.Count == admin.AttemptsMax+1 {
admin.Controller.Logs.LogEvent( admin.Controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("too many login attempts for ip=\"%v\"", remoteAddr))
admin.Controller.Database,
LogLevelWarn,
fmt.Sprintf("too many login attempts for ip=\"%v\"", remoteAddr),
)
} }
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
@ -417,11 +413,7 @@ func (admin *Admin) LoginHandler(w http.ResponseWriter, r *http.Request) {
} }
if !ok { if !ok {
admin.Controller.Logs.LogEvent( admin.Controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("invalid login attempt for ip=%v", remoteAddr))
admin.Controller.Database,
LogLevelWarn,
fmt.Sprintf("invalid login attempt for ip=%v", remoteAddr),
)
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
return return
} }
@ -499,7 +491,7 @@ func (admin *Admin) PasswordHandler(w http.ResponseWriter, r *http.Request) {
) )
logError := func(err error) { logError := func(err error) {
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelError, fmt.Sprintf("admin.passwordhandler.post: %s", err.Error())) admin.Controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("admin.passwordhandler.post: %s", err.Error()))
} }
t := admin.GetAuthorization(r) t := admin.GetAuthorization(r)

View file

@ -51,6 +51,7 @@ type Config struct {
SslCertFile string SslCertFile string
SslKeyFile string SslKeyFile string
SslListen string SslListen string
daemon *Daemon
newAdminPassword string newAdminPassword string
} }
@ -179,7 +180,7 @@ func NewConfig() *Config {
} }
if *serviceAction != "" { if *serviceAction != "" {
NewDaemon().Control(*serviceAction) config.daemon = NewDaemon().Control(*serviceAction)
} }
return config return config

View file

@ -16,45 +16,40 @@
package main package main
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"log" "log"
"os" "os"
"os/exec"
"os/signal" "os/signal"
"path"
"strconv" "strconv"
"strings"
"sync" "sync"
"time" "time"
) )
type Controller struct { type Controller struct {
Admin *Admin Admin *Admin
Api *Api Api *Api
Calls *Calls Calls *Calls
Config *Config Config *Config
Database *Database Database *Database
Accesses *Accesses Accesses *Accesses
Apikeys *Apikeys Apikeys *Apikeys
Dirwatches *Dirwatches Dirwatches *Dirwatches
Downstreams *Downstreams Downstreams *Downstreams
Groups *Groups FFMpeg *FFMpeg
Logs *Logs Groups *Groups
Options *Options Logs *Logs
Scheduler *Scheduler Options *Options
Systems *Systems Scheduler *Scheduler
Tags *Tags Systems *Systems
Clients *Clients Tags *Tags
Register chan *Client Clients *Clients
Unregister chan *Client Register chan *Client
Ingest chan *Call Unregister chan *Client
ffmpeg bool Ingest chan *Call
ffmpegWarned bool ingestMutex sync.Mutex
ingestMutex sync.Mutex running bool
running bool
} }
func NewController(config *Config) *Controller { func NewController(config *Config) *Controller {
@ -65,6 +60,7 @@ func NewController(config *Config) *Controller {
Calls: NewCalls(), Calls: NewCalls(),
Dirwatches: NewDirwatches(), Dirwatches: NewDirwatches(),
Downstreams: NewDownstreams(), Downstreams: NewDownstreams(),
FFMpeg: NewFFMpeg(),
Groups: NewGroups(), Groups: NewGroups(),
Logs: NewLogs(), Logs: NewLogs(),
Options: NewOptions(), Options: NewOptions(),
@ -82,63 +78,12 @@ func NewController(config *Config) *Controller {
controller.Database = NewDatabase(config) controller.Database = NewDatabase(config)
controller.Scheduler = NewScheduler(controller) controller.Scheduler = NewScheduler(controller)
controller.Logs.setDaemon(config.daemon)
controller.Logs.setDatabase(controller.Database)
return controller return controller
} }
func (controller *Controller) ConvertAudio(call *Call) {
var (
args = []string{"-i", "-"}
err error
)
if !controller.ffmpeg {
if !controller.ffmpegWarned {
controller.ffmpegWarned = true
controller.Logs.LogEvent(controller.Database, LogLevelWarn, "ffmpeg is not available, no audio conversion will be performed.")
}
return
}
if system, ok := controller.Systems.GetSystem(call.System); ok {
if talkgroup, ok := system.Talkgroups.GetTalkgroup(call.Talkgroup); ok {
if tag, ok := controller.Tags.GetTag(talkgroup.TagId); ok {
args = append(args,
"-metadata", fmt.Sprintf("album=%v", talkgroup.Label),
"-metadata", fmt.Sprintf("artist=%v", system.Label),
"-metadata", fmt.Sprintf("date=%v", call.DateTime),
"-metadata", fmt.Sprintf("genre=%v", tag),
"-metadata", fmt.Sprintf("title=%v", talkgroup.Name),
)
}
}
}
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.Stdin = bytes.NewReader(call.Audio)
stdout := bytes.NewBuffer([]byte(nil))
cmd.Stdout = stdout
stderr := bytes.NewBuffer([]byte(nil))
cmd.Stderr = stderr
if err = cmd.Run(); err == nil {
call.Audio = stdout.Bytes()
call.AudioType = "audio/mp4"
switch v := call.AudioName.(type) {
case string:
call.AudioName = fmt.Sprintf("%v.m4a", strings.TrimSuffix(v, path.Ext((v))))
}
} else {
fmt.Println(stderr.String())
}
}
func (controller *Controller) EmitCall(call *Call) { func (controller *Controller) EmitCall(call *Call) {
controller.Clients.EmitCall(call, controller.Accesses.IsRestricted()) controller.Clients.EmitCall(call, controller.Accesses.IsRestricted())
controller.Downstreams.Send(controller, call) controller.Downstreams.Send(controller, call)
@ -169,15 +114,11 @@ func (controller *Controller) IngestCall(call *Call) {
defer controller.IngestUnlock() defer controller.IngestUnlock()
logCall := func(call *Call, level string, message string) { logCall := func(call *Call, level string, message string) {
controller.Logs.LogEvent( controller.Logs.LogEvent(level, fmt.Sprintf("newcall: system=%v talkgroup=%v file=%v %v", call.System, call.Talkgroup, call.AudioName, message))
controller.Database,
level,
fmt.Sprintf("newcall: system=%v talkgroup=%v file=%v %v", call.System, call.Talkgroup, call.AudioName, message),
)
} }
logError := func(err error) { logError := func(err error) {
controller.Logs.LogEvent(controller.Database, LogLevelError, fmt.Sprintf("controller.ingestcall: %v", err.Error())) controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("controller.ingestcall: %v", err.Error()))
} }
if system, ok = controller.Systems.GetSystem(call.System); ok { if system, ok = controller.Systems.GetSystem(call.System); ok {
@ -346,7 +287,9 @@ func (controller *Controller) IngestCall(call *Call) {
} }
if !controller.Options.DisableAudioConversion { if !controller.Options.DisableAudioConversion {
controller.ConvertAudio(call) if err := controller.FFMpeg.Convert(call, controller.Systems, controller.Tags); err != nil {
controller.Logs.LogEvent(LogLevelWarn, err.Error())
}
} }
if id, err = controller.Calls.WriteCall(call, controller.Database); err == nil { if id, err = controller.Calls.WriteCall(call, controller.Database); err == nil {
@ -385,11 +328,7 @@ func (controller *Controller) IngestUnlock() {
} }
func (controller *Controller) LogClientsCount() { func (controller *Controller) LogClientsCount() {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelInfo, fmt.Sprintf("listeners count is %v", controller.Clients.Count()))
controller.Database,
LogLevelInfo,
fmt.Sprintf("listeners count is %v", controller.Clients.Count()),
)
} }
func (controller *Controller) ProcessMessage(client *Client, message *Message) error { func (controller *Controller) ProcessMessage(client *Client, message *Message) error {
@ -494,31 +433,19 @@ func (controller *Controller) ProcessMessageCommandPin(client *Client, message *
if access, ok := controller.Accesses.GetAccess(code); ok { if access, ok := controller.Accesses.GetAccess(code); ok {
client.Access = access client.Access = access
} else { } else {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("invalid access code=\"%s\" address=\"%s\"", code, client.GetRemoteAddr()))
controller.Database,
LogLevelWarn,
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
} }
if client.AuthCount == maxAuthCount { if client.AuthCount == maxAuthCount {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("access ident=\"%s\" locked", client.Access.Ident))
controller.Database,
LogLevelWarn,
fmt.Sprintf("access ident=\"%s\" locked", client.Access.Ident),
)
client.Send <- &Message{Command: MessageCommandPin} client.Send <- &Message{Command: MessageCommandPin}
return nil return nil
} }
if client.Access.HasExpired() { if client.Access.HasExpired() {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("access ident=\"%s\" expired", client.Access.Ident))
controller.Database,
LogLevelWarn,
fmt.Sprintf("access ident=\"%s\" expired", client.Access.Ident),
)
client.Send <- &Message{Command: MessageCommandExpired} client.Send <- &Message{Command: MessageCommandExpired}
return nil return nil
} }
@ -526,11 +453,7 @@ func (controller *Controller) ProcessMessageCommandPin(client *Client, message *
switch v := client.Access.Limit.(type) { switch v := client.Access.Limit.(type) {
case uint: case uint:
if controller.Clients.AccessCount(client) > int(v) { if controller.Clients.AccessCount(client) > int(v) {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelWarn, fmt.Sprintf("access ident=\"%s\" too many concurrent connections, limit is %d", client.Access.Ident, client.Access.Limit))
controller.Database,
LogLevelWarn,
fmt.Sprintf("access ident=\"%s\" too many concurrent connections, limit is %d", client.Access.Ident, client.Access.Limit),
)
client.Send <- &Message{Command: MessageCommandMax} client.Send <- &Message{Command: MessageCommandMax}
return nil return nil
} }
@ -554,7 +477,7 @@ func (controller *Controller) Start() error {
controller.running = true controller.running = true
} }
controller.Logs.LogEvent(controller.Database, LogLevelWarn, "server started") controller.Logs.LogEvent(LogLevelWarn, "server started")
if len(controller.Config.BaseDir) > 0 { if len(controller.Config.BaseDir) > 0 {
log.Printf("base folder is %s\n", controller.Config.BaseDir) log.Printf("base folder is %s\n", controller.Config.BaseDir)
@ -592,14 +515,6 @@ func (controller *Controller) Start() error {
return err return err
} }
cmd := exec.Command("ffmpeg", "-version")
if err := cmd.Run(); err == nil {
controller.ffmpeg = true
} else {
controller.ffmpeg = false
}
go func() { go func() {
c := make(chan os.Signal) c := make(chan os.Signal)
signal.Notify(c, os.Interrupt) signal.Notify(c, os.Interrupt)

View file

@ -28,6 +28,7 @@ type Daemon struct {
Errors chan error Errors chan error
Interface service.Interface Interface service.Interface
Service service.Service Service service.Service
Logger service.Logger
} }
func NewDaemon() *Daemon { func NewDaemon() *Daemon {
@ -61,12 +62,20 @@ func NewDaemon() *Daemon {
log.Fatal(err) log.Fatal(err)
} }
if d.Logger, err = d.Service.Logger(nil); err != nil {
log.Fatal(err)
}
return &d return &d
} }
func (d *Daemon) Control(action string) *Daemon { func (d *Daemon) Control(action string) *Daemon {
if action == "run" { if action == "run" {
go d.Service.Run() go func() {
if err := d.Service.Run(); err != nil {
d.Logger.Error(err)
}
}()
} else if err := service.Control(d.Service, action); err == nil { } else if err := service.Control(d.Service, action); err == nil {
os.Exit(0) os.Exit(0)

View file

@ -142,11 +142,7 @@ func (dirwatch *Dirwatch) Ingest(p string) {
} }
if err != nil { if err != nil {
dirwatch.controller.Logs.LogEvent( dirwatch.controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatch.ingest: %v", err.Error()))
dirwatch.controller.Database,
LogLevelError,
fmt.Sprintf("dirwatch.ingest: %v", err.Error()),
)
} }
} }
@ -524,9 +520,8 @@ 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 {
@ -552,8 +547,10 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
} }
go func() { go func() {
var timers = map[string]*time.Timer{}
logError := func(err error) { logError := func(err error) {
controller.Logs.LogEvent(controller.Database, LogLevelError, fmt.Sprintf("dirwatch.watcher: %v", err.Error())) controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatch.watcher: %v", err.Error()))
} }
newTimer := func(eventName string) *time.Timer { newTimer := func(eventName string) *time.Timer {
@ -571,6 +568,11 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
timers[k].Stop() timers[k].Stop()
delete(timers, k) delete(timers, k)
} }
switch v := recover().(type) {
case error:
controller.Logs.LogEvent(LogLevelError, v.Error())
}
}() }()
for { for {
@ -625,6 +627,13 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
}() }()
go func() { go func() {
defer func() {
switch v := recover().(type) {
case error:
controller.Logs.LogEvent(LogLevelError, v.Error())
}
}()
time.Sleep(delay) time.Sleep(delay)
if err := fs.WalkDir(os.DirFS(dirwatch.Directory), ".", func(p string, d fs.DirEntry, err error) error { if err := fs.WalkDir(os.DirFS(dirwatch.Directory), ".", func(p string, d fs.DirEntry, err error) error {
@ -640,11 +649,7 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
return err return err
}); err != nil { }); err != nil {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatch.walkdir: %s", err.Error()))
controller.Database,
LogLevelError,
fmt.Sprintf("dirwatch.walkdir: %s", err.Error()),
)
} }
}() }()
@ -776,11 +781,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
func (dirwatches *Dirwatches) Start(controller *Controller) { func (dirwatches *Dirwatches) Start(controller *Controller) {
for i := range dirwatches.List { for i := range dirwatches.List {
if err := dirwatches.List[i].Start(controller); err != nil { if err := dirwatches.List[i].Start(controller); err != nil {
controller.Logs.LogEvent( controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("dirwatches.start: %s", err.Error()))
controller.Database,
LogLevelError,
fmt.Sprintf("dirwatches.start: %s", err.Error()),
)
} }
} }
} }

View file

@ -440,11 +440,7 @@ func (downstreams *Downstreams) Read(db *Database) error {
func (downstreams *Downstreams) Send(controller *Controller, call *Call) { func (downstreams *Downstreams) Send(controller *Controller, call *Call) {
for _, downstream := range downstreams.List { for _, downstream := range downstreams.List {
logEvent := func(logLevel string, message string) { logEvent := func(logLevel string, message string) {
controller.Logs.LogEvent( controller.Logs.LogEvent(logLevel, fmt.Sprintf("downstream: system=%v talkgroup=%v file=%v to %v %v", call.System, call.Talkgroup, call.AudioName, downstream.Url, message))
controller.Database,
logLevel,
fmt.Sprintf("downstream: system=%v talkgroup=%v file=%v to %v %v", call.System, call.Talkgroup, call.AudioName, downstream.Url, message),
)
} }
if downstream.HasAccess(call) { if downstream.HasAccess(call) {

122
server/ffmpeg.go Normal file
View file

@ -0,0 +1,122 @@
// Copyright (C) 2019-2022 Chrystian Huot <chrystian.huot@saubeo.solutions>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>
package main
import (
"bytes"
"errors"
"fmt"
"os/exec"
"path"
"regexp"
"strconv"
"strings"
)
type FFMpeg struct {
available bool
version43 bool
warned bool
}
func NewFFMpeg() *FFMpeg {
ffmpeg := &FFMpeg{}
stdout := bytes.NewBuffer([]byte(nil))
cmd := exec.Command("ffmpeg", "-version")
cmd.Stdout = stdout
if err := cmd.Run(); err == nil {
ffmpeg.available = true
if l, err := stdout.ReadString('\n'); err == nil {
s := regexp.MustCompile(`.*ffmpeg version .{0,1}([0-9])\.([0-9])\.[0-9].*`).ReplaceAllString(strings.TrimSuffix(l, "\n"), "$1.$2")
v := strings.Split(s, ".")
if len(v) > 1 {
if major, err := strconv.Atoi(v[0]); err == nil {
if minor, err := strconv.Atoi(v[1]); err == nil {
if major >= 4 || (major == 4 && minor >= 3) {
ffmpeg.version43 = true
}
}
}
}
}
}
return ffmpeg
}
func (ffmpeg *FFMpeg) Convert(call *Call, systems *Systems, tags *Tags) error {
var (
args = []string{"-i", "-"}
err error
)
if !ffmpeg.available {
if !ffmpeg.warned {
ffmpeg.warned = true
return errors.New("ffmpeg is not available, no audio conversion will be performed.")
}
return nil
}
if system, ok := systems.GetSystem(call.System); ok {
if talkgroup, ok := system.Talkgroups.GetTalkgroup(call.Talkgroup); ok {
if tag, ok := tags.GetTag(talkgroup.TagId); ok {
args = append(args,
"-metadata", fmt.Sprintf("album=%v", talkgroup.Label),
"-metadata", fmt.Sprintf("artist=%v", system.Label),
"-metadata", fmt.Sprintf("date=%v", call.DateTime),
"-metadata", fmt.Sprintf("genre=%v", tag),
"-metadata", fmt.Sprintf("title=%v", talkgroup.Name),
)
}
}
}
if ffmpeg.version43 {
args = append(args, "-af", "apad=whole_dur=3s,loudnorm=I=-16:TP=-1.5:LRA=11")
}
args = append(args, "-c:a", "aac", "-b:a", "32k", "-movflags", "frag_keyframe+empty_moov", "-f", "ipod", "-")
cmd := exec.Command("ffmpeg", args...)
cmd.Stdin = bytes.NewReader(call.Audio)
stdout := bytes.NewBuffer([]byte(nil))
cmd.Stdout = stdout
stderr := bytes.NewBuffer([]byte(nil))
cmd.Stderr = stderr
if err = cmd.Run(); err == nil {
call.Audio = stdout.Bytes()
call.AudioType = "audio/mp4"
switch v := call.AudioName.(type) {
case string:
call.AudioName = fmt.Sprintf("%v.m4a", strings.TrimSuffix(v, path.Ext((v))))
}
} else {
fmt.Println(stderr.String())
}
return nil
}

View file

@ -38,7 +38,9 @@ type Log struct {
} }
type Logs struct { type Logs struct {
mutex sync.Mutex database *Database
mutex sync.Mutex
daemon *Daemon
} }
func NewLogs() *Logs { func NewLogs() *Logs {
@ -47,20 +49,34 @@ func NewLogs() *Logs {
} }
} }
func (logs *Logs) LogEvent(db *Database, level string, message string) error { func (logs *Logs) LogEvent(level string, message string) error {
logs.mutex.Lock() logs.mutex.Lock()
defer logs.mutex.Unlock() defer logs.mutex.Unlock()
log.Println(message) if logs.daemon != nil {
switch level {
case LogLevelError:
logs.daemon.Logger.Error(message)
case LogLevelWarn:
logs.daemon.Logger.Warning(message)
case LogLevelInfo:
logs.daemon.Logger.Info(message)
}
l := Log{ } else {
DateTime: time.Now().UTC(), log.Println(message)
Level: level,
Message: message,
} }
if _, err := db.Sql.Exec("insert into `rdioScannerLogs` (`dateTime`, `level`, `message`) values (?, ?, ?)", l.DateTime, l.Level, l.Message); err != nil { if logs.database != nil {
return fmt.Errorf("logs.logevent: %v", err) l := Log{
DateTime: time.Now().UTC(),
Level: level,
Message: message,
}
if _, err := logs.database.Sql.Exec("insert into `rdioScannerLogs` (`dateTime`, `level`, `message`) values (?, ?, ?)", l.DateTime, l.Level, l.Message); err != nil {
return fmt.Errorf("logs.logevent: %v", err)
}
} }
return nil return nil
@ -219,6 +235,14 @@ func (logs *Logs) Search(searchOptions *LogsSearchOptions, db *Database) (*LogsS
return logResults, nil return logResults, nil
} }
func (logs *Logs) setDaemon(d *Daemon) {
logs.daemon = d
}
func (logs *Logs) setDatabase(d *Database) {
logs.database = d
}
type LogsSearchOptions struct { type LogsSearchOptions struct {
Date interface{} `json:"date,omitempty"` Date interface{} `json:"date,omitempty"`
Level interface{} `json:"level,omitempty"` Level interface{} `json:"level,omitempty"`

View file

@ -24,6 +24,7 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"regexp"
"strings" "strings"
"time" "time"
@ -60,7 +61,7 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
controller.Logs.LogEvent(controller.Database, LogLevelInfo, "admin password changed.") controller.Logs.LogEvent(LogLevelInfo, "admin password changed.")
os.Exit(0) os.Exit(0)
@ -247,14 +248,16 @@ func main() {
} }
func GetRemoteAddr(r *http.Request) string { func GetRemoteAddr(r *http.Request) string {
re := regexp.MustCompile(`(\[[^\]]+\]|[^:]+):.*`)
for _, addr := range strings.Split(r.Header.Get("X-Forwarded-For"), ",") { for _, addr := range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {
if ip := strings.Split(addr, ":"); len(ip[0]) > 0 { if ip := re.ReplaceAllString(addr, "$1"); len(ip) > 0 {
return ip[0] return ip
} }
} }
if ip := strings.Split(r.RemoteAddr, ":"); len(ip[0]) > 0 { if ip := re.ReplaceAllString(r.RemoteAddr, "$1"); len(ip) > 0 {
return ip[0] return ip
} }
return "unknown" return "unknown"

View file

@ -45,7 +45,7 @@ func (scheduler *Scheduler) pruneDatabase() error {
scheduler.Controller.IngestLock() scheduler.Controller.IngestLock()
defer scheduler.Controller.IngestUnlock() defer scheduler.Controller.IngestUnlock()
scheduler.Controller.Logs.LogEvent(scheduler.Controller.Database, LogLevelInfo, "database pruning") scheduler.Controller.Logs.LogEvent(LogLevelInfo, "database pruning")
if err := scheduler.Controller.Calls.Prune(scheduler.Controller.Database, scheduler.Controller.Options.PruneDays); err != nil { if err := scheduler.Controller.Calls.Prune(scheduler.Controller.Database, scheduler.Controller.Options.PruneDays); err != nil {
return err return err
@ -63,11 +63,7 @@ func (scheduler *Scheduler) run() {
defer scheduler.mutex.Unlock() defer scheduler.mutex.Unlock()
logError := func(err error) { logError := func(err error) {
scheduler.Controller.Logs.LogEvent( scheduler.Controller.Logs.LogEvent(LogLevelError, fmt.Sprintf("scheduler.run: %s", err.Error()))
scheduler.Controller.Database,
LogLevelError,
fmt.Sprintf("scheduler.run: %s", err.Error()),
)
} }
if err := scheduler.pruneDatabase(); err != nil { if err := scheduler.pruneDatabase(); err != nil {

View file

@ -15,4 +15,4 @@
package main package main
const Version = "6.3.3" const Version = "6.3.4"