mirror of
https://github.com/chuot/rdio-scanner.git
synced 2026-08-13 16:33:01 -06:00
Version 6.0.4
This commit is contained in:
parent
04fda4558e
commit
b76567ec19
|
|
@ -37,6 +37,13 @@ _v6.0.3_
|
|||
- Fix strconv.Atoi: invalid syntax for dirwatch type sdrtrunk.
|
||||
- Fix the new version available dialog opening more than once.
|
||||
|
||||
_v6.0.4_
|
||||
|
||||
- Fix wrong time calculation in prune scheduler.
|
||||
- More fix on the SQL_BUSY error (issue #67).
|
||||
- Support files (certs, db, ini) are now created in the same folder as the executable, if the folder is writable, or under a `Rdio Scanner` folder in the user's home folder.
|
||||
- Some code refactoring.
|
||||
|
||||
## Version 5.2
|
||||
|
||||
- Change to how the server reports version.
|
||||
|
|
|
|||
35
COMPILING.md
Normal file
35
COMPILING.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# How to compile
|
||||
|
||||
The official version of [Rdio Scanner](https://github.com/chuot/rdio-scanner) is compiled on a PC using the current version of Fedora Workstation. You should have no problem building on another platform as long as the prerequisites are available and installed.
|
||||
|
||||
## Install the prerequisites
|
||||
|
||||
Your os distribution may have all of the following prerequisites available in its own package repository. Make sure, however, that they are at the latest version. This is especially not the case with Ubuntu and its Node.js.
|
||||
|
||||
- latest version of git ([here](https://git-scm.com/downloads))
|
||||
- latest version of gnu make ([here](https://www.gnu.org/software/make/))
|
||||
- latest long-term support version of Node.js ([here](https://nodejs.org/en/))
|
||||
- latest version of Go ([here](https://go.dev/dl/))
|
||||
- latest version of Pandoc with pandoc-pdf ([here](https://pandoc.org/installing.html))
|
||||
- latest version of Info-Zip ([here](http://infozip.sourceforge.net/))
|
||||
|
||||
## Compile the app
|
||||
|
||||
Clone the official repository on your computer and start the build process.
|
||||
|
||||
git clone https://github.com/chuot/rdio-scanner.git
|
||||
cd rdio-scanner
|
||||
make
|
||||
|
||||
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
|
||||
|
||||
rdio-scanner-darwin-amd64-v6.0.4.zip
|
||||
rdio-scanner-darwin-arm64-v6.0.4.zip
|
||||
rdio-scanner-freebsd-amd64-v6.0.4.zip
|
||||
rdio-scanner-linux-386-v6.0.4.zip
|
||||
rdio-scanner-linux-amd64-v6.0.4.zip
|
||||
rdio-scanner-linux-arm64-v6.0.4.zip
|
||||
rdio-scanner-linux-arm-v6.0.4.zip
|
||||
rdio-scanner-windows-amd64-v6.0.4.zip
|
||||
|
||||
**Happy Rdio scanning !**
|
||||
14
Makefile
14
Makefile
|
|
@ -16,7 +16,8 @@
|
|||
################################################################################
|
||||
|
||||
app := rdio-scanner
|
||||
ver := 6.0.3
|
||||
date := 2021/12/08
|
||||
ver := 6.0.4
|
||||
|
||||
client := $(wildcard client/*.json client/*.ts)
|
||||
server := $(wildcard server/*.go)
|
||||
|
|
@ -25,7 +26,7 @@ build = @cd server && GOOS=$(1) GOARCH=$(2) go build -o ../dist/$(1)-$(2)/$(3)
|
|||
pandoc = @test -d dist/$(1)-$(2) || mkdir -p dist/$(1)-$(2) && pandoc -f markdown -o dist/$(1)-$(2)/$(3) --resource-path docs:docs/platforms $(4) docs/webapp.md CHANGELOG.md
|
||||
zip = @cd dist/$(1)-$(2) && zip -q ../$(app)-$(1)-$(2)-v$(ver).zip * && cd .. && rm -fr $(1)-$(2)
|
||||
|
||||
.PHONY: all clean dist setver
|
||||
.PHONY: all clean dist sed
|
||||
.PHONY: darwin darwin-amd64 darwin-arm64
|
||||
.PHONY: freebsd freebsd-amd64
|
||||
.PHONY: linux linux-386 linux-amd64 linux-arm linux-arm64
|
||||
|
|
@ -38,10 +39,11 @@ clean:
|
|||
|
||||
dist: darwin freebsd linux windows
|
||||
|
||||
setver:
|
||||
@sed -i -re "s/^(\s*\"version\":).*$$/\1 \"$(ver)\"/" client/package.json
|
||||
@sed -i -re "s/^(const\s+Version\s+=).*$$/\1 \"$(ver)\"/" server/version.go
|
||||
@sed -i -re "s/v[0-9]\.[0-9]\.[0-9]/v$(ver)/" docs/platforms/*.md
|
||||
sed:
|
||||
@sed -i -re "s|^(\s*\"version\":).*$$|\1 \"$(ver)\"|" client/package.json
|
||||
@sed -i -re "s|^(const\s+Version\s+=).*$$|\1 \"$(ver)\"|" server/version.go
|
||||
@sed -i -re "s|v[0-9]\.[0-9]\.[0-9]|v$(ver)|" COMPILING.md docs/platforms/*.md
|
||||
@sed -i -re "s|[0-9]{4}/[0-9]{2}/[0-9]{2}|$(date)|" docs/platforms/*.md
|
||||
|
||||
webapp: server/webapp/index.html
|
||||
|
||||
|
|
|
|||
834
client/package-lock.json
generated
834
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,31 +1,31 @@
|
|||
{
|
||||
"author": "Chrystian Huot <chrystian.huot@saubeo.solutions>",
|
||||
"dependencies": {
|
||||
"@angular/animations": "^13.0.2",
|
||||
"@angular/cdk": "^13.0.2",
|
||||
"@angular/common": "~13.0.2",
|
||||
"@angular/compiler": "~13.0.2",
|
||||
"@angular/core": "~13.0.2",
|
||||
"@angular/forms": "~13.0.2",
|
||||
"@angular/material": "^13.0.2",
|
||||
"@angular/platform-browser": "~13.0.2",
|
||||
"@angular/platform-browser-dynamic": "~13.0.2",
|
||||
"@angular/router": "^13.0.2",
|
||||
"@angular/service-worker": "^13.0.2",
|
||||
"@angular/animations": "^13.0.3",
|
||||
"@angular/cdk": "^13.0.3",
|
||||
"@angular/common": "~13.0.3",
|
||||
"@angular/compiler": "~13.0.3",
|
||||
"@angular/core": "~13.0.3",
|
||||
"@angular/forms": "~13.0.3",
|
||||
"@angular/material": "^13.0.3",
|
||||
"@angular/platform-browser": "~13.0.3",
|
||||
"@angular/platform-browser-dynamic": "~13.0.3",
|
||||
"@angular/router": "^13.0.3",
|
||||
"@angular/service-worker": "^13.0.3",
|
||||
"rxjs": "~7.4.0",
|
||||
"tslib": "^2.3.1",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~13.0.3",
|
||||
"@angular/cli": "^13.0.3",
|
||||
"@angular/compiler-cli": "~13.0.2",
|
||||
"@types/node": "~16.11.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
||||
"@typescript-eslint/parser": "^5.5.0",
|
||||
"@angular-devkit/build-angular": "~13.0.4",
|
||||
"@angular/cli": "^13.0.4",
|
||||
"@angular/compiler-cli": "~13.0.3",
|
||||
"@types/node": "~16.11.12",
|
||||
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
||||
"@typescript-eslint/parser": "^5.6.0",
|
||||
"ajv-keywords": "^5.1.0",
|
||||
"eslint": "^8.3.0",
|
||||
"npm-check-updates": "^12.0.2",
|
||||
"eslint": "^8.4.1",
|
||||
"npm-check-updates": "^12.0.3",
|
||||
"ts-node": "~10.4.0",
|
||||
"typescript": "~4.4.4"
|
||||
},
|
||||
|
|
@ -39,5 +39,5 @@
|
|||
"build": "ng build --base-href ./ --configuration production",
|
||||
"start": "ng serve"
|
||||
},
|
||||
"version": "6.0.3"
|
||||
"version": "6.0.4"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -757,8 +757,6 @@ export class RdioScannerService implements OnDestroy {
|
|||
}
|
||||
};
|
||||
|
||||
this.websocket.onerror = () => this.event.emit({ linked: false });
|
||||
|
||||
this.websocket.onopen = () => {
|
||||
this.event.emit({ linked: true });
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
|
|||
|
||||
You can enjoy your [Rdio Scanner](https://github.com/chuot/rdio-scanner) on the go on your mobile device with the native app.
|
||||
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
|
||||
\pagebreak{}
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
rdio@macos ~ % mkdir rdio-scanner
|
||||
rdio@macos ~ % cd rdio-scanner
|
||||
rdio@macos rdio-scanner % unzip \
|
||||
> ~/Downloads/rdio-scanner-darwin-arm64-v6.0.3.zip
|
||||
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.0.3.zip
|
||||
> ~/Downloads/rdio-scanner-darwin-arm64-v6.0.4.zip
|
||||
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.0.4.zip
|
||||
inflating: rdio-scanner
|
||||
inflating: rdio-scanner.pdf
|
||||
|
||||
|
|
@ -50,11 +50,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
|
||||
rdio@macos rdio-scanner % ./rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 08:38:06 server started
|
||||
2021/11/29 08:38:06 main interface at http://macos.local:3000
|
||||
2021/11/29 08:38:06 admin interface at http://macos.local:3000/admin
|
||||
2021/12/08 08:38:06 server started
|
||||
2021/12/08 08:38:06 main interface at http://macos.local:3000
|
||||
2021/12/08 08:38:06 admin interface at http://macos.local:3000/admin
|
||||
|
||||
4. Access the administrative dashboard to finalize the configuration.
|
||||
|
||||
|
|
@ -76,11 +76,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
|||
|
||||
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 08:48:03 server started
|
||||
2021/11/29 08:48:03 main interface at http://macos.local
|
||||
2021/11/29 08:48:03 admin interface at http://macos.local/admin
|
||||
2021/12/08 08:48:03 server started
|
||||
2021/12/08 08:48:03 main interface at http://macos.local
|
||||
2021/12/08 08:48:03 admin interface at http://macos.local/admin
|
||||
|
||||
## Listening with SSL with self-signed certificates
|
||||
|
||||
|
|
@ -89,8 +89,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
|
|||
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
|
||||
|
||||
rdio@macos rdio-scanner % ./rdio-scanner -ssl_create
|
||||
2021/11/29 08:49:16 generating ssl certificate files
|
||||
2021/11/29 08:49:17 ssl files created
|
||||
2021/12/08 08:49:16 generating ssl certificate files
|
||||
2021/12/08 08:49:17 ssl files created
|
||||
|
||||
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
|
||||
|
||||
|
|
@ -107,12 +107,12 @@ Now we use the self-signed server certificate to run our instance.
|
|||
> -ssl_key_file server.key \
|
||||
> -ssl_listen :443
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 08:50:58 server started
|
||||
2021/11/29 08:50:58 main interface at http://macos.local
|
||||
2021/11/29 08:50:58 main interface at https://macos.local
|
||||
2021/11/29 08:50:58 admin interface at https://macos.local/admin
|
||||
2021/12/08 08:50:58 server started
|
||||
2021/12/08 08:50:58 main interface at http://macos.local
|
||||
2021/12/08 08:50:58 main interface at https://macos.local
|
||||
2021/12/08 08:50:58 admin interface at https://macos.local/admin
|
||||
|
||||
## Save your advanced configuration to a config file
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
|||
> -ssl_key_file server.key \
|
||||
> -ssl_listen :443 \
|
||||
> -config_save
|
||||
2021/11/29 08:52:24 rdio-scanner.ini file created
|
||||
2021/12/08 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.
|
||||
|
||||
|
|
@ -139,12 +139,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
|||
|
||||
rdio@macos rdio-scanner % ./rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 08:54:08 server started
|
||||
2021/11/29 08:54:08 main interface at http://macos.local
|
||||
2021/11/29 08:54:08 main interface at https://macos.local
|
||||
2021/11/29 08:54:08 admin interface at https://macos.local/admin
|
||||
2021/12/08 08:54:08 server started
|
||||
2021/12/08 08:54:08 main interface at http://macos.local
|
||||
2021/12/08 08:54:08 main interface at https://macos.local
|
||||
2021/12/08 08:54:08 admin interface at https://macos.local/admin
|
||||
|
||||
## Install Rdio Scanner as a service
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
|
|||
|
||||
You can enjoy your [Rdio Scanner](https://github.com/chuot/rdio-scanner) on the go on your mobile device with the native app.
|
||||
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
|
||||
\pagebreak{}
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
rdio@pc-freebsd:~ $ mkdir rdio-scanner
|
||||
rdio@pc-freebsd:~ $ cd rdio-scanner
|
||||
rdio@pc-freebsd:~/rdio-scanner $ unzip \
|
||||
> ~/rdio-scanner-freebsd-amd64-v6.0.3.zip
|
||||
Archive: ../rdio-scanner-freebsd-amd64-v6.0.3.zip
|
||||
> ~/rdio-scanner-freebsd-amd64-v6.0.4.zip
|
||||
Archive: ../rdio-scanner-freebsd-amd64-v6.0.4.zip
|
||||
extracting: rdio-scanner
|
||||
extracting: rdio-scanner.pdf
|
||||
|
||||
|
|
@ -50,11 +50,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
|
||||
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/28 08:16:36 server started
|
||||
2021/11/28 08:16:36 main interface at http://pc-freebsd:3000
|
||||
2021/11/28 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
||||
2021/12/08 08:16:36 server started
|
||||
2021/12/08 08:16:36 main interface at http://pc-freebsd:3000
|
||||
2021/12/08 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
||||
|
||||
4. Access the administrative dashboard to finalize the configuration.
|
||||
|
||||
|
|
@ -80,11 +80,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
|||
Password:
|
||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/28 08:19:38 server started
|
||||
2021/11/28 08:19:38 main interface at http://pc-freebsd
|
||||
2021/11/28 08:19:38 admin interface at http://pc-freebsd/admin
|
||||
2021/12/08 08:19:38 server started
|
||||
2021/12/08 08:19:38 main interface at http://pc-freebsd
|
||||
2021/12/08 08:19:38 admin interface at http://pc-freebsd/admin
|
||||
|
||||
## Listening with SSL with self-signed certificates
|
||||
|
||||
|
|
@ -93,8 +93,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
|
|||
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
|
||||
|
||||
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner -ssl_create
|
||||
2021/11/28 10:32:17 generating ssl certificate files
|
||||
2021/11/28 10:32:19 ssl files created
|
||||
2021/12/08 10:32:17 generating ssl certificate files
|
||||
2021/12/08 10:32:19 ssl files created
|
||||
|
||||
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
|
||||
|
||||
|
|
@ -113,12 +113,12 @@ Now we use the self-signed server certificate to run our instance.
|
|||
> -ssl_key_file server.key \
|
||||
> -ssl_listen :443
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/28 10:34:29 server started
|
||||
2021/11/28 10:34:29 main interface at http://pc-freebsd
|
||||
2021/11/28 10:34:29 main interface at https://pc-freebsd
|
||||
2021/11/28 10:34:29 admin interface at https://pc-freebsd/admin
|
||||
2021/12/08 10:34:29 server started
|
||||
2021/12/08 10:34:29 main interface at http://pc-freebsd
|
||||
2021/12/08 10:34:29 main interface at https://pc-freebsd
|
||||
2021/12/08 10:34:29 admin interface at https://pc-freebsd/admin
|
||||
|
||||
## Save your advanced configuration to a config file
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
|||
> -ssl_key_file server.key \
|
||||
> -ssl_listen :443 \
|
||||
> -config_save
|
||||
2021/11/28 10:37:00 rdio-scanner.ini file created
|
||||
2021/12/08 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.
|
||||
|
||||
|
|
@ -147,12 +147,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
|||
Password:
|
||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/28 10:38:28 server started
|
||||
2021/11/28 10:38:29 main interface at http://pc-freebsd
|
||||
2021/11/28 10:38:29 main interface at https://pc-freebsd
|
||||
2021/11/28 10:38:29 admin interface at https://pc-freebsd/admin
|
||||
2021/12/08 10:38:28 server started
|
||||
2021/12/08 10:38:29 main interface at http://pc-freebsd
|
||||
2021/12/08 10:38:29 main interface at https://pc-freebsd
|
||||
2021/12/08 10:38:29 admin interface at https://pc-freebsd/admin
|
||||
|
||||
## Install Rdio Scanner as a service
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
|
|||
|
||||
You can enjoy your [Rdio Scanner](https://github.com/chuot/rdio-scanner) on the go on your mobile device with the native app.
|
||||
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
|
||||
\pagebreak{}
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
[rdio@pc-linux ~]$ mkdir rdio-scanner
|
||||
[rdio@pc-linux ~]$ cd rdio-scanner
|
||||
[rdio@pc-linux rdio-scanner]$ unzip \
|
||||
> ~/Downloads/rdio-scanner-linux-amd64-v6.0.3.zip
|
||||
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.0.3.zip
|
||||
> ~/Downloads/rdio-scanner-linux-amd64-v6.0.4.zip
|
||||
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.0.4.zip
|
||||
inflating: rdio-scanner
|
||||
inflating: rdio-scanner.pdf
|
||||
|
||||
|
|
@ -50,11 +50,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
|
||||
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 09:11:48 server started
|
||||
2021/11/29 09:11:48 main interface at http://pc-linux:3000
|
||||
2021/11/29 09:11:48 admin interface at http://pc-linux:3000/admin
|
||||
2021/12/08 09:11:48 server started
|
||||
2021/12/08 09:11:48 main interface at http://pc-linux:3000
|
||||
2021/12/08 09:11:48 admin interface at http://pc-linux:3000/admin
|
||||
|
||||
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@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
||||
[sudo] password for rdio:
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 09:14:00 server started
|
||||
2021/11/29 09:14:00 main interface at http://pc-linux
|
||||
2021/11/29 09:14:00 admin interface at http://pc-linux/admin
|
||||
2021/12/08 09:14:00 server started
|
||||
2021/12/08 09:14:00 main interface at http://pc-linux
|
||||
2021/12/08 09:14:00 admin interface at http://pc-linux/admin
|
||||
|
||||
## Listening with SSL with self-signed certificates
|
||||
|
||||
|
|
@ -90,8 +90,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
|
|||
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
|
||||
|
||||
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner -ssl_create
|
||||
2021/11/29 09:15:03 generating ssl certificate files
|
||||
2021/11/29 09:15:05 ssl files created
|
||||
2021/12/08 09:15:03 generating ssl certificate files
|
||||
2021/12/08 09:15:05 ssl files created
|
||||
|
||||
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
|
||||
|
||||
|
|
@ -109,12 +109,12 @@ Now we use the self-signed server certificate to run our instance.
|
|||
> -ssl_listen :443
|
||||
[sudo] password for rdio:
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 09:16:47 server started
|
||||
2021/11/29 09:16:47 main interface at http://pc-linux
|
||||
2021/11/29 09:16:47 main interface at https://pc-linux
|
||||
2021/11/29 09:16:47 admin interface at https://pc-linux/admin
|
||||
2021/12/08 09:16:47 server started
|
||||
2021/12/08 09:16:47 main interface at http://pc-linux
|
||||
2021/12/08 09:16:47 main interface at https://pc-linux
|
||||
2021/12/08 09:16:47 admin interface at https://pc-linux/admin
|
||||
|
||||
## Save your advanced configuration to a config file
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
|||
> -ssl_key_file server.key \
|
||||
> -ssl_listen :443 \
|
||||
> -config_save
|
||||
2021/11/29 09:19:29 rdio-scanner.ini file created
|
||||
2021/12/08 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.
|
||||
|
||||
|
|
@ -142,12 +142,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
|||
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
|
||||
[sudo] Mot de passe de rdio :
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/29 09:20:40 server started
|
||||
2021/11/29 09:20:40 main interface at http://pc-linux
|
||||
2021/11/29 09:20:40 main interface at https://pc-linux
|
||||
2021/11/29 09:20:40 admin interface at https://pc-linux/admin
|
||||
2021/12/08 09:20:40 server started
|
||||
2021/12/08 09:20:40 main interface at http://pc-linux
|
||||
2021/12/08 09:20:40 main interface at https://pc-linux
|
||||
2021/12/08 09:20:40 admin interface at https://pc-linux/admin
|
||||
|
||||
## Install Rdio Scanner as a service
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ Here is a list of recorders known to work with [Rdio Scanner](https://github.com
|
|||
|
||||
You can enjoy your [Rdio Scanner](https://github.com/chuot/rdio-scanner) on the go on your mobile device with the native app.
|
||||
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
[](https://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||
|
||||
\pagebreak{}
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
C:\Users\rdio> cd rdio-scanner
|
||||
|
||||
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
||||
..\downloads\rdio-scanner-windows-amd64-v6.0.3.zip
|
||||
..\downloads\rdio-scanner-windows-amd64-v6.0.4.zip
|
||||
x rdio-scanner.exe
|
||||
x rdio-scanner.pdf
|
||||
|
||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
|||
|
||||
C:\Users\rdio\rdio-scanner>rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/25 13:48:48 server started
|
||||
2021/11/25 13:48:48 main interface at http://pc-windows:3000
|
||||
2021/11/25 13:48:48 admin interface at http://pc-windows:3000/admin
|
||||
2021/12/08 13:48:48 server started
|
||||
2021/12/08 13:48:48 main interface at http://pc-windows:3000
|
||||
2021/12/08 13:48:48 admin interface at http://pc-windows:3000/admin
|
||||
|
||||
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
|
|||
|
||||
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/26 10:53:31 server started
|
||||
2021/11/26 10:53:31 main interface at http://pc-windows
|
||||
2021/11/26 10:53:31 admin interface at http://pc-windows/admin
|
||||
2021/12/08 10:53:31 server started
|
||||
2021/12/08 10:53:31 main interface at http://pc-windows
|
||||
2021/12/08 10:53:31 admin interface at http://pc-windows/admin
|
||||
|
||||
## Listening with SSL with self-signed certificates
|
||||
|
||||
|
|
@ -90,8 +90,8 @@ It is advised to share your [Rdio Scanner](https://github.com/chuot/rdio-scanner
|
|||
We can create such self-signed certificates by running [Rdio Scanner](https://github.com/chuot/rdio-scanner) with the **-ssl_create** argument.
|
||||
|
||||
C:\Users\rdio\rdio-scanner>rdio-scanner -ssl_create
|
||||
2021/11/26 10:58:51 generating ssl certificate files
|
||||
2021/11/26 10:58:54 ssl files created
|
||||
2021/12/08 10:58:51 generating ssl certificate files
|
||||
2021/12/08 10:58:54 ssl files created
|
||||
|
||||
This has generated these files in the same folder as your [Rdio Scanner](https://github.com/chuot/rdio-scanner) executable.
|
||||
|
||||
|
|
@ -108,12 +108,12 @@ Now we use the self-signed server certificate to run our instance.
|
|||
-ssl_key_file server.key ^
|
||||
-ssl_listen :443
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/26 11:05:43 server started
|
||||
2021/11/26 11:05:43 main interface at http://pc-windows
|
||||
2021/11/26 11:05:43 main interface at https://pc-windows
|
||||
2021/11/26 11:05:43 admin interface at https://pc-windows/admin
|
||||
2021/12/08 11:05:43 server started
|
||||
2021/12/08 11:05:43 main interface at http://pc-windows
|
||||
2021/12/08 11:05:43 main interface at https://pc-windows
|
||||
2021/12/08 11:05:43 admin interface at https://pc-windows/admin
|
||||
|
||||
## Save your advanced configuration to a config file
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ You don't want to have to type everytime a long list of arguments. No problem, y
|
|||
-ssl_key_file server.key ^
|
||||
-ssl_listen :443 ^
|
||||
-config_save
|
||||
2021/11/26 11:08:28 rdio-scanner.ini file created
|
||||
2021/12/08 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.
|
||||
|
||||
|
|
@ -140,12 +140,12 @@ Then simply run [Rdio Scanner](https://github.com/chuot/rdio-scanner) without an
|
|||
|
||||
C:\Users\rdio\rdio-scanner>rdio-scanner
|
||||
|
||||
Rdio Scanner v6.0.3
|
||||
Rdio Scanner v6.0.4
|
||||
----------------------------------
|
||||
2021/11/26 11:11:28 server started
|
||||
2021/11/26 11:11:28 main interface at http://pc-windows
|
||||
2021/11/26 11:11:28 main interface at https://pc-windows
|
||||
2021/11/26 11:11:28 admin interface at https://pc-windows/admin
|
||||
2021/12/08 11:11:28 server started
|
||||
2021/12/08 11:11:28 main interface at http://pc-windows
|
||||
2021/12/08 11:11:28 main interface at https://pc-windows
|
||||
2021/12/08 11:11:28 admin interface at https://pc-windows/admin
|
||||
|
||||
\pagebreak{}
|
||||
|
||||
|
|
|
|||
|
|
@ -202,11 +202,9 @@ func (accesses *Accesses) Read(db *Database) error {
|
|||
*accesses = append(*accesses, access)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -270,12 +268,9 @@ func (accesses *Accesses) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ const (
|
|||
)
|
||||
|
||||
type Admin struct {
|
||||
initialized bool
|
||||
Attempts AdminLoginAttempts
|
||||
AttemptsMax uint
|
||||
AttemptsMaxDelay time.Duration
|
||||
|
|
@ -47,6 +46,7 @@ type Admin struct {
|
|||
Register chan *websocket.Conn
|
||||
Tokens []string
|
||||
Unregister chan *websocket.Conn
|
||||
running bool
|
||||
}
|
||||
|
||||
type AdminLoginAttempt struct {
|
||||
|
|
@ -56,6 +56,20 @@ type AdminLoginAttempt struct {
|
|||
|
||||
type AdminLoginAttempts map[string]*AdminLoginAttempt
|
||||
|
||||
func NewAdmin(controller *Controller) *Admin {
|
||||
return &Admin{
|
||||
Attempts: AdminLoginAttempts{},
|
||||
AttemptsMax: uint(3),
|
||||
AttemptsMaxDelay: time.Duration(time.Duration.Minutes(10)),
|
||||
Broadcast: make(chan *[]byte, 100),
|
||||
Conns: make(map[*websocket.Conn]bool),
|
||||
Controller: controller,
|
||||
Register: make(chan *websocket.Conn, 100),
|
||||
Tokens: []string{},
|
||||
Unregister: make(chan *websocket.Conn, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (admin *Admin) BroadcastConfig() {
|
||||
|
||||
if b, err := json.Marshal(admin.GetConfig()); err == nil {
|
||||
|
|
@ -298,52 +312,6 @@ func (admin *Admin) GetConfig() map[string]interface{} {
|
|||
}
|
||||
}
|
||||
|
||||
func (admin *Admin) Init(controller *Controller) error {
|
||||
if admin.initialized {
|
||||
return errors.New("admin already initialized")
|
||||
}
|
||||
|
||||
admin.initialized = true
|
||||
admin.Attempts = AdminLoginAttempts{}
|
||||
admin.AttemptsMax = uint(3)
|
||||
admin.AttemptsMaxDelay = time.Duration(time.Duration.Minutes(10))
|
||||
admin.Broadcast = make(chan *[]byte, 100)
|
||||
admin.Conns = make(map[*websocket.Conn]bool)
|
||||
admin.Controller = controller
|
||||
admin.Register = make(chan *websocket.Conn, 100)
|
||||
admin.Tokens = []string{}
|
||||
admin.Unregister = make(chan *websocket.Conn, 100)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case data, ok := <-admin.Broadcast:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for conn := range admin.Conns {
|
||||
err := conn.WriteMessage(websocket.TextMessage, *data)
|
||||
if err != nil {
|
||||
admin.Unregister <- conn
|
||||
}
|
||||
}
|
||||
|
||||
case conn := <-admin.Register:
|
||||
admin.Conns[conn] = true
|
||||
|
||||
case conn := <-admin.Unregister:
|
||||
if _, ok := admin.Conns[conn]; ok {
|
||||
delete(admin.Conns, conn)
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (admin *Admin) LogsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
t := admin.GetAuthorization(r)
|
||||
if !admin.ValidateToken(t) {
|
||||
|
|
@ -570,6 +538,43 @@ func (admin *Admin) SendConfig(w http.ResponseWriter) {
|
|||
}
|
||||
}
|
||||
|
||||
func (admin *Admin) Start() error {
|
||||
if admin.running {
|
||||
return errors.New("admin already running")
|
||||
} else {
|
||||
admin.running = true
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case data, ok := <-admin.Broadcast:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
for conn := range admin.Conns {
|
||||
err := conn.WriteMessage(websocket.TextMessage, *data)
|
||||
if err != nil {
|
||||
admin.Unregister <- conn
|
||||
}
|
||||
}
|
||||
|
||||
case conn := <-admin.Register:
|
||||
admin.Conns[conn] = true
|
||||
|
||||
case conn := <-admin.Unregister:
|
||||
if _, ok := admin.Conns[conn]; ok {
|
||||
delete(admin.Conns, conn)
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (admin *Admin) ValidateToken(sToken string) bool {
|
||||
found := false
|
||||
for _, t := range admin.Tokens {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
|
|
@ -35,18 +34,11 @@ const (
|
|||
)
|
||||
|
||||
type Api struct {
|
||||
initialized bool
|
||||
Controller *Controller
|
||||
}
|
||||
|
||||
func (api *Api) Init(controller *Controller) error {
|
||||
if api.initialized {
|
||||
return errors.New("api already initialized")
|
||||
}
|
||||
|
||||
api.Controller = controller
|
||||
|
||||
return nil
|
||||
func NewApi(controller *Controller) *Api {
|
||||
return &Api{Controller: controller}
|
||||
}
|
||||
|
||||
func (api *Api) CallUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
|||
|
|
@ -174,10 +174,10 @@ func (apikeys *Apikeys) Read(db *Database) error {
|
|||
rows.Close()
|
||||
|
||||
if err != nil {
|
||||
err = formatError(err)
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (apikeys *Apikeys) Write(db *Database) error {
|
||||
|
|
@ -239,12 +239,9 @@ func (apikeys *Apikeys) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ func (client *Client) Init(controller *Controller, conn *websocket.Conn) error {
|
|||
client.Access = &Access{}
|
||||
client.Controller = controller
|
||||
client.Conn = conn
|
||||
client.Send = make(chan *Message, 100)
|
||||
client.Send = make(chan *Message, 8)
|
||||
client.LivefeedMap = LivefeedMap{}
|
||||
|
||||
controller.Register <- client
|
||||
|
|
|
|||
126
server/config.go
126
server/config.go
|
|
@ -35,6 +35,7 @@ const (
|
|||
)
|
||||
|
||||
type Config struct {
|
||||
BaseDir string
|
||||
ConfigFile string
|
||||
DbType string
|
||||
DbFile string
|
||||
|
|
@ -53,43 +54,7 @@ type Config struct {
|
|||
newAdminPassword string
|
||||
}
|
||||
|
||||
func (config *Config) GetConfigFilePath() string {
|
||||
return config.GetPath(config.ConfigFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetDbFilePath() string {
|
||||
return config.GetPath(config.DbFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetPath(p string) string {
|
||||
if !path.IsAbs(p) {
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
if !regexp.MustCompile(`go-build[0-9]+`).Match([]byte(exe)) {
|
||||
return path.Join(filepath.Dir(exe), p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCaCertFilePath() string {
|
||||
return config.GetPath(config.SslCaCertFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCaKeyFilePath() string {
|
||||
return config.GetPath(config.SslCaKeyFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCertFilePath() string {
|
||||
return config.GetPath(config.SslCertFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslKeyFilePath() string {
|
||||
return config.GetPath(config.SslKeyFile)
|
||||
}
|
||||
|
||||
func (config *Config) Init() (ok bool, error error) {
|
||||
func NewConfig() *Config {
|
||||
const (
|
||||
defaultAdminUrl = "/admin"
|
||||
defaultConfigFile = "rdio-scanner.ini"
|
||||
|
|
@ -101,6 +66,7 @@ func (config *Config) Init() (ok bool, error error) {
|
|||
)
|
||||
|
||||
var (
|
||||
config = &Config{}
|
||||
configSave = flag.Bool("config_save", false, fmt.Sprintf("save configuration to %s", defaultConfigFile))
|
||||
serviceAction = flag.String("service", "", "service command, one of start, stop, restart, install, uninstall")
|
||||
sslCreate = flag.Bool("ssl_create", false, "create self-signed certificates")
|
||||
|
|
@ -121,33 +87,50 @@ func (config *Config) Init() (ok bool, error error) {
|
|||
flag.StringVar(&config.SslKeyFile, "ssl_key_file", "", "ssl PEM formated key")
|
||||
flag.StringVar(&config.SslListen, "ssl_listen", "", "listening address for ssl")
|
||||
flag.StringVar(&config.newAdminPassword, "admin_password", "", "change admin password")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if exe, err := os.Executable(); err == nil {
|
||||
if !regexp.MustCompile(`go-build[0-9]+`).Match([]byte(exe)) {
|
||||
config.BaseDir = filepath.Dir(exe)
|
||||
if !config.isBaseDirWritable() {
|
||||
if h, err := os.UserHomeDir(); err == nil {
|
||||
config.BaseDir = filepath.Join(h, "Rdio Scanner")
|
||||
if _, err := os.Stat(config.BaseDir); os.IsNotExist(err) {
|
||||
os.MkdirAll(config.BaseDir, 0770)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !config.isBaseDirWritable() {
|
||||
log.Fatalf("no write permissions in %s", config.BaseDir)
|
||||
}
|
||||
|
||||
switch {
|
||||
case *configSave:
|
||||
if err := config.saveConfig(); err == nil {
|
||||
log.Printf("%s file created", config.ConfigFile)
|
||||
return false, nil
|
||||
|
||||
fmt.Printf("%s file created\n", config.ConfigFile)
|
||||
os.Exit(0)
|
||||
} else {
|
||||
return false, err
|
||||
fmt.Printf("error: %s\n", err.Error())
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
case *sslCreate:
|
||||
log.Print("generating ssl certificate files")
|
||||
fmt.Println("generating ssl certificate files")
|
||||
|
||||
if err := CreateSelfSignedCert(config); err == nil {
|
||||
log.Print("ssl files created")
|
||||
return false, nil
|
||||
|
||||
fmt.Println("ssl files created")
|
||||
os.Exit(0)
|
||||
} else {
|
||||
return false, err
|
||||
fmt.Printf("error: %s", err.Error())
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
case *version:
|
||||
fmt.Println(Version)
|
||||
return false, nil
|
||||
os.Exit(0)
|
||||
|
||||
default:
|
||||
if cfg, err := ini.Load(config.GetConfigFilePath()); err == nil {
|
||||
|
|
@ -201,15 +184,56 @@ func (config *Config) Init() (ok bool, error error) {
|
|||
}
|
||||
|
||||
if !(config.DbType == DbTypeMariadb || config.DbType == DbTypeMysql || config.DbType == DbTypeSqlite) {
|
||||
return false, fmt.Errorf("unknown database type %s", config.DbType)
|
||||
fmt.Printf("unknown database type %s\n", config.DbType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if *serviceAction != "" {
|
||||
return NewDaemon().Control(*serviceAction)
|
||||
NewDaemon().Control(*serviceAction)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
return config
|
||||
}
|
||||
|
||||
func (config *Config) GetConfigFilePath() string {
|
||||
return config.GetPath(config.ConfigFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetDbFilePath() string {
|
||||
return config.GetPath(config.DbFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetPath(p string) string {
|
||||
if path.IsAbs(p) {
|
||||
return p
|
||||
}
|
||||
return path.Join(config.BaseDir, p)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCaCertFilePath() string {
|
||||
return config.GetPath(config.SslCaCertFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCaKeyFilePath() string {
|
||||
return config.GetPath(config.SslCaKeyFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslCertFilePath() string {
|
||||
return config.GetPath(config.SslCertFile)
|
||||
}
|
||||
|
||||
func (config *Config) GetSslKeyFilePath() string {
|
||||
return config.GetPath(config.SslKeyFile)
|
||||
}
|
||||
|
||||
func (config *Config) isBaseDirWritable() bool {
|
||||
if f, err := os.CreateTemp(config.BaseDir, ".tmp*"); err == nil {
|
||||
f.Close()
|
||||
os.Remove(f.Name())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (config *Config) saveConfig() error {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,34 @@ type Controller struct {
|
|||
Register chan *Client
|
||||
Unregister chan *Client
|
||||
Ingest chan *Call
|
||||
initialized bool
|
||||
ffmpeg bool
|
||||
ffmpegWarned bool
|
||||
running bool
|
||||
}
|
||||
|
||||
func NewController(config *Config) *Controller {
|
||||
controller := &Controller{
|
||||
Config: config,
|
||||
Accesses: &Accesses{},
|
||||
Apikeys: &Apikeys{},
|
||||
Dirwatches: &Dirwatches{},
|
||||
Downstreams: &Downstreams{},
|
||||
Groups: &Groups{},
|
||||
Options: &Options{},
|
||||
Systems: &Systems{},
|
||||
Tags: &Tags{},
|
||||
Clients: make(map[*Client]bool),
|
||||
Register: make(chan *Client, 64),
|
||||
Unregister: make(chan *Client, 64),
|
||||
Ingest: make(chan *Call, 64),
|
||||
}
|
||||
|
||||
controller.Admin = NewAdmin(controller)
|
||||
controller.Api = NewApi(controller)
|
||||
controller.Database = NewDatabase(config)
|
||||
controller.Scheduler = NewScheduler(controller)
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
func (controller *Controller) CheckDuplicate(call *Call) bool {
|
||||
|
|
@ -68,7 +93,7 @@ func (controller *Controller) CheckDuplicate(call *Call) bool {
|
|||
return count > 0
|
||||
}
|
||||
|
||||
func (controller *Controller) ConvertAudio(call *Call) error {
|
||||
func (controller *Controller) ConvertAudio(call *Call) {
|
||||
var (
|
||||
args = []string{"-i", "-"}
|
||||
err error
|
||||
|
|
@ -80,8 +105,7 @@ func (controller *Controller) ConvertAudio(call *Call) error {
|
|||
|
||||
LogEvent(controller.Database, LogLevelWarn, "ffmpeg is not accessible, no audio conversion will be performed.")
|
||||
}
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
if system, ok := controller.Systems.GetSystem(call.System); ok {
|
||||
|
|
@ -106,6 +130,9 @@ func (controller *Controller) ConvertAudio(call *Call) error {
|
|||
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"
|
||||
|
|
@ -114,9 +141,10 @@ func (controller *Controller) ConvertAudio(call *Call) error {
|
|||
case string:
|
||||
call.AudioName = fmt.Sprintf("%v.m4a", strings.TrimSuffix(v, path.Ext((v))))
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
} else {
|
||||
fmt.Println(stderr.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (controller *Controller) EmitCall(call *Call) {
|
||||
|
|
@ -323,10 +351,7 @@ func (controller *Controller) IngestCall(call *Call) {
|
|||
}
|
||||
|
||||
if !controller.Options.DisableAudioConversion {
|
||||
if err = controller.ConvertAudio(call); err != nil {
|
||||
logError(fmt.Errorf("convertaudio: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
controller.ConvertAudio(call)
|
||||
}
|
||||
|
||||
if id, err = call.Write(controller.Database); err == nil {
|
||||
|
|
@ -339,111 +364,6 @@ func (controller *Controller) IngestCall(call *Call) {
|
|||
}
|
||||
}
|
||||
|
||||
func (controller *Controller) Init(config *Config, database *Database) error {
|
||||
if controller.initialized {
|
||||
return errors.New("controller already initialized")
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
controller.initialized = true
|
||||
controller.Admin = &Admin{}
|
||||
controller.Api = &Api{}
|
||||
controller.Config = config
|
||||
controller.Database = database
|
||||
controller.Accesses = &Accesses{}
|
||||
controller.Apikeys = &Apikeys{}
|
||||
controller.Dirwatches = &Dirwatches{}
|
||||
controller.Downstreams = &Downstreams{}
|
||||
controller.Groups = &Groups{}
|
||||
controller.Options = &Options{}
|
||||
controller.Scheduler = &Scheduler{}
|
||||
controller.Systems = &Systems{}
|
||||
controller.Tags = &Tags{}
|
||||
controller.Clients = make(map[*Client]bool)
|
||||
controller.Register = make(chan *Client, 64)
|
||||
controller.Unregister = make(chan *Client, 64)
|
||||
controller.Ingest = make(chan *Call, 64)
|
||||
|
||||
if err = controller.Accesses.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Apikeys.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Dirwatches.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Downstreams.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Groups.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Options.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Systems.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Tags.Read(database); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = controller.Admin.Init(controller); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Api.Init(controller); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Scheduler.Init(controller); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("ffmpeg", "-version")
|
||||
if err := cmd.Run(); err == nil {
|
||||
controller.ffmpeg = true
|
||||
|
||||
} else {
|
||||
controller.ffmpeg = false
|
||||
}
|
||||
|
||||
if err = controller.Scheduler.Start(); err != nil {
|
||||
log.Printf("scheduler: %s", err.Error())
|
||||
}
|
||||
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
<-c
|
||||
controller.Terminate()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case call := <-controller.Ingest:
|
||||
controller.IngestCall(call)
|
||||
|
||||
case client := <-controller.Register:
|
||||
controller.Clients[client] = true
|
||||
controller.LogClientsCount()
|
||||
|
||||
case client := <-controller.Unregister:
|
||||
if _, ok := controller.Clients[client]; ok {
|
||||
delete(controller.Clients, client)
|
||||
close(client.Send)
|
||||
controller.LogClientsCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
controller.Dirwatches.Start(controller)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (controller *Controller) LogClientsCount() {
|
||||
LogEvent(
|
||||
controller.Database,
|
||||
|
|
@ -629,6 +549,93 @@ func (controller *Controller) SendClientConfig(client *Client) {
|
|||
}
|
||||
}
|
||||
|
||||
func (controller *Controller) Start() error {
|
||||
var err error
|
||||
|
||||
if controller.running {
|
||||
return errors.New("controller already running")
|
||||
} else {
|
||||
controller.running = true
|
||||
}
|
||||
|
||||
LogEvent(controller.Database, LogLevelWarn, "server started")
|
||||
|
||||
if len(controller.Config.BaseDir) > 0 {
|
||||
LogEvent(controller.Database, LogLevelWarn, fmt.Sprintf("base folder is %s", controller.Config.BaseDir))
|
||||
}
|
||||
|
||||
if err = controller.Accesses.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Apikeys.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Dirwatches.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Downstreams.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Groups.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Options.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Systems.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Tags.Read(controller.Database); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = controller.Admin.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = controller.Scheduler.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command("ffmpeg", "-version")
|
||||
if err := cmd.Run(); err == nil {
|
||||
controller.ffmpeg = true
|
||||
|
||||
} else {
|
||||
controller.ffmpeg = false
|
||||
}
|
||||
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt)
|
||||
<-c
|
||||
controller.Terminate()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case call := <-controller.Ingest:
|
||||
controller.IngestCall(call)
|
||||
|
||||
case client := <-controller.Register:
|
||||
controller.Clients[client] = true
|
||||
controller.LogClientsCount()
|
||||
|
||||
case client := <-controller.Unregister:
|
||||
if _, ok := controller.Clients[client]; ok {
|
||||
delete(controller.Clients, client)
|
||||
close(client.Send)
|
||||
controller.LogClientsCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
controller.Dirwatches.Start(controller)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (controller *Controller) Terminate() {
|
||||
if err := controller.Database.Sql.Close(); err != nil {
|
||||
log.Println(err)
|
||||
|
|
@ -636,6 +643,10 @@ func (controller *Controller) Terminate() {
|
|||
|
||||
controller.Dirwatches.Stop()
|
||||
|
||||
for c := range controller.Clients {
|
||||
c.Conn.Close()
|
||||
}
|
||||
|
||||
log.Println("terminated")
|
||||
|
||||
os.Exit(0)
|
||||
|
|
|
|||
|
|
@ -62,14 +62,16 @@ func NewDaemon() *Daemon {
|
|||
return &d
|
||||
}
|
||||
|
||||
func (d *Daemon) Control(action string) (bool, error) {
|
||||
func (d *Daemon) Control(action string) {
|
||||
if action == "run" {
|
||||
go d.Service.Run()
|
||||
|
||||
return true, nil
|
||||
}
|
||||
} else if err := service.Control(d.Service, action); err == nil {
|
||||
os.Exit(0)
|
||||
|
||||
return false, service.Control(d.Service, action)
|
||||
} else {
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
type DaemonInterface struct{}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ package main
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
|
@ -27,59 +26,52 @@ import (
|
|||
)
|
||||
|
||||
type Database struct {
|
||||
initialized bool
|
||||
Config *Config
|
||||
DateTimeFormat string
|
||||
Sql *sql.DB
|
||||
}
|
||||
|
||||
func (db *Database) Init(config *Config) error {
|
||||
func NewDatabase(config *Config) *Database {
|
||||
var err error
|
||||
|
||||
if db.initialized {
|
||||
return errors.New("database already initialized")
|
||||
}
|
||||
database := &Database{Config: config}
|
||||
|
||||
db.initialized = true
|
||||
|
||||
db.Config = config
|
||||
|
||||
switch db.Config.DbType {
|
||||
switch config.DbType {
|
||||
case DbTypeSqlite:
|
||||
db.DateTimeFormat = "2006-01-02 15:04:05.000 -07:00"
|
||||
database.DateTimeFormat = "2006-01-02 15:04:05.000 -07:00"
|
||||
|
||||
dsn := fmt.Sprintf("file:%s", db.Config.GetDbFilePath())
|
||||
dsn := fmt.Sprintf("file:%s", config.GetDbFilePath())
|
||||
|
||||
if db.Sql, err = sql.Open("sqlite", dsn); err != nil {
|
||||
return err
|
||||
if database.Sql, err = sql.Open("sqlite", dsn); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
case DbTypeMariadb, DbTypeMysql:
|
||||
db.DateTimeFormat = "2006-01-02 15:04:05"
|
||||
database.DateTimeFormat = "2006-01-02 15:04:05"
|
||||
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", db.Config.DbUsername, db.Config.DbPassword, db.Config.DbHost, db.Config.DbPort, db.Config.DbName)
|
||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", config.DbUsername, config.DbPassword, config.DbHost, config.DbPort, config.DbName)
|
||||
|
||||
if db.Sql, err = sql.Open("mysql", dsn); err != nil {
|
||||
return err
|
||||
if database.Sql, err = sql.Open("mysql", dsn); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unknown database type %s", db.Config.DbType)
|
||||
log.Fatalf("unknown database type %s\n", config.DbType)
|
||||
}
|
||||
|
||||
db.Sql.SetConnMaxLifetime(0)
|
||||
db.Sql.SetMaxIdleConns(10)
|
||||
db.Sql.SetMaxOpenConns(10)
|
||||
database.Sql.SetConnMaxLifetime(0)
|
||||
database.Sql.SetMaxIdleConns(10)
|
||||
database.Sql.SetMaxOpenConns(10)
|
||||
|
||||
if err = db.migrate(); err != nil {
|
||||
return err
|
||||
if err = database.migrate(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err = db.seed(); err != nil {
|
||||
return err
|
||||
if err = database.seed(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return database
|
||||
}
|
||||
|
||||
func (db *Database) ParseDateTime(f interface{}) (time.Time, error) {
|
||||
|
|
@ -102,7 +94,7 @@ func (db *Database) Prune(controller *Controller) error {
|
|||
|
||||
LogEvent(controller.Database, LogLevelInfo, "database pruning")
|
||||
|
||||
date := time.Now().Truncate(time.Duration(controller.Options.PruneDays*24) * time.Hour).Format(db.DateTimeFormat)
|
||||
date := time.Now().Add(-24 * time.Hour * time.Duration(controller.Options.PruneDays)).Format(db.DateTimeFormat)
|
||||
|
||||
if _, err := controller.Database.Sql.Exec("delete from `rdioScannerCalls` where `dateTime` < ?", date); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ func (dirwatch *Dirwatch) ingestTrunkRecorder(p string) error {
|
|||
}
|
||||
|
||||
if call.Audio, err = ioutil.ReadFile(audioName); err != nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
if b, err = ioutil.ReadFile(p); err != nil {
|
||||
|
|
@ -494,9 +494,10 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
|||
}
|
||||
}()
|
||||
|
||||
fileSystem := os.DirFS(dirwatch.Directory)
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
return fs.WalkDir(fileSystem, ".", func(p string, d fs.DirEntry, err error) error {
|
||||
fs.WalkDir(os.DirFS(dirwatch.Directory), ".", func(p string, d fs.DirEntry, err error) error {
|
||||
fp := path.Join(dirwatch.Directory, p)
|
||||
|
||||
if dirwatch.isDir(fp) {
|
||||
|
|
@ -508,6 +509,9 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
|||
}
|
||||
return err
|
||||
})
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dirwatch *Dirwatch) Stop() {
|
||||
|
|
@ -582,11 +586,9 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
|
|||
*dirwatches = append(*dirwatches, dirwatch)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -641,8 +643,7 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
|||
return formatError(err)
|
||||
}
|
||||
|
||||
rows, err = db.Sql.Query("select `_id` from `rdioScannerDirWatches`")
|
||||
if err != nil {
|
||||
if rows, err = db.Sql.Query("select `_id` from `rdioScannerDirWatches`"); err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -661,12 +662,9 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -674,28 +672,13 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
|||
}
|
||||
|
||||
func (dirwatch *Dirwatch) isDir(d string) bool {
|
||||
var isDir bool
|
||||
|
||||
logError := func(err error) {
|
||||
LogEvent(dirwatch.controller.Database, LogLevelError, fmt.Sprintf("dirwatch.isDir: %s", err.Error()))
|
||||
}
|
||||
|
||||
if f, err := os.Open(d); err == nil {
|
||||
if fi, err := f.Stat(); err == nil {
|
||||
if fi, err := os.Stat(d); err == nil {
|
||||
if fi.IsDir() {
|
||||
isDir = true
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
logError(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
logError(err)
|
||||
}
|
||||
} else {
|
||||
logError(err)
|
||||
}
|
||||
|
||||
return isDir
|
||||
return false
|
||||
}
|
||||
|
||||
func (dirwatch *Dirwatch) walkDir(d string) error {
|
||||
|
|
|
|||
|
|
@ -337,23 +337,24 @@ func (downstreams *Downstreams) FromMap(f []interface{}) {
|
|||
|
||||
func (downstreams *Downstreams) Read(db *Database) error {
|
||||
var (
|
||||
apikey interface{}
|
||||
err error
|
||||
id uint
|
||||
rows *sql.Rows
|
||||
systems interface{}
|
||||
)
|
||||
|
||||
*downstreams = Downstreams{}
|
||||
|
||||
formatError := func(err error) error {
|
||||
return fmt.Errorf("downstreams.read: %v", err)
|
||||
}
|
||||
|
||||
if rows, err = db.Sql.Query("select `_id`, `apiKey`, `disabled`, `order`, `systems`, `url` from `rdioScannerDownstreams`"); err != nil {
|
||||
return err
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var (
|
||||
apikey interface{}
|
||||
id uint
|
||||
systems interface{}
|
||||
)
|
||||
|
||||
downstream := Downstream{}
|
||||
if err = rows.Scan(&id, &apikey, &downstream.Disabled, &downstream.Order, &systems, &downstream.Url); err != nil {
|
||||
break
|
||||
|
|
@ -383,12 +384,10 @@ func (downstreams *Downstreams) Read(db *Database) error {
|
|||
*downstreams = append(*downstreams, downstream)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
return err
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
@ -473,12 +472,9 @@ func (downstreams *Downstreams) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,15 +21,15 @@ require (
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c // indirect
|
||||
golang.org/x/sys v0.0.0-20211204120058-94396e421777 // indirect
|
||||
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.8 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
lukechampine.com/uint128 v1.1.1 // indirect
|
||||
modernc.org/cc/v3 v3.35.18 // indirect
|
||||
modernc.org/ccgo/v3 v3.12.86 // indirect
|
||||
modernc.org/libc v1.11.88 // indirect
|
||||
modernc.org/ccgo/v3 v3.12.87 // indirect
|
||||
modernc.org/libc v1.11.89 // indirect
|
||||
modernc.org/mathutil v1.4.1 // indirect
|
||||
modernc.org/memory v1.0.5 // indirect
|
||||
modernc.org/opt v0.1.1 // indirect
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c h1:7SfqwP5fxEtl/P02w5IhKc86ziJ+A25yFrkVgoy2FT8=
|
||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b h1:MWaHNqZy3KTpuTMAGvv+Kw+ylsEpmyJZizz1dqxnu28=
|
||||
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -65,8 +65,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211204120058-94396e421777 h1:QAkhGVjOxMa+n4mlsAWeAU+BMZmimQAaNiMu+iUi94E=
|
||||
golang.org/x/sys v0.0.0-20211204120058-94396e421777/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
|
|
@ -141,8 +141,9 @@ modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3
|
|||
modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
|
||||
modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
||||
modernc.org/ccgo/v3 v3.12.84/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
||||
modernc.org/ccgo/v3 v3.12.86 h1:zN0MkWIf1a2SgP6w9V3EG5r30CSrpRunyzJ5wcYRLFM=
|
||||
modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTSrU=
|
||||
modernc.org/ccgo/v3 v3.12.87 h1:d8IVZadjkPWICHmMWEaPAL37zBrZ7rE7/+Plegf0cyw=
|
||||
modernc.org/ccgo/v3 v3.12.87/go.mod h1:55tmwIw8bqNbqYCZ2DIXGqB1I0goRe6tq2qHqr1FaQU=
|
||||
modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
|
||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
|
|
@ -182,8 +183,9 @@ modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0=
|
|||
modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
|
||||
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
|
||||
modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY=
|
||||
modernc.org/libc v1.11.88 h1:ibbHksDVITfJtBTSCENSXRt/pL4P/QJP+EzJUimW268=
|
||||
modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ=
|
||||
modernc.org/libc v1.11.89 h1:41X0GhYT3+0WbXvsOMDguwnmfY6692gXkSlOuSaO9jc=
|
||||
modernc.org/libc v1.11.89/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c=
|
||||
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
|
|
|
|||
|
|
@ -166,11 +166,9 @@ func (groups *Groups) Read(db *Database) error {
|
|||
*groups = append(*groups, group)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -228,12 +226,9 @@ func (groups *Groups) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -229,12 +229,10 @@ func NewLogResults(logOptions *LogOptions, db *Database) (*LogResults, error) {
|
|||
logResults.Logs = append(logResults.Logs, log)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return logResults, formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
return logResults, formatError(err)
|
||||
if err != nil {
|
||||
return nil, formatError(err)
|
||||
}
|
||||
|
||||
return logResults, nil
|
||||
|
|
|
|||
|
|
@ -40,27 +40,16 @@ func main() {
|
|||
sslPort string
|
||||
)
|
||||
|
||||
config := &Config{}
|
||||
ok, err := config.Init()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if !ok {
|
||||
os.Exit(0)
|
||||
}
|
||||
config := NewConfig()
|
||||
|
||||
database := &Database{}
|
||||
if err = database.Init(config); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
controller := &Controller{}
|
||||
if err = controller.Init(config, database); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
controller := NewController(config)
|
||||
|
||||
if config.newAdminPassword != "" {
|
||||
if hash, err := bcrypt.GenerateFromPassword([]byte(config.newAdminPassword), bcrypt.DefaultCost); err == nil {
|
||||
if err := controller.Options.Read(controller.Database); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
controller.Options.adminPassword = string(hash)
|
||||
controller.Options.adminPasswordNeedChange = config.newAdminPassword == defaults.adminPassword
|
||||
|
||||
|
|
@ -68,10 +57,6 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := controller.Options.Read(controller.Database); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
LogEvent(controller.Database, LogLevelInfo, "admin password changed.")
|
||||
|
||||
os.Exit(0)
|
||||
|
|
@ -84,7 +69,9 @@ func main() {
|
|||
fmt.Printf("\nRdio Scanner v%s\n", Version)
|
||||
fmt.Printf("----------------------------------\n")
|
||||
|
||||
LogEvent(controller.Database, LogLevelWarn, "server started")
|
||||
if err := controller.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if h, err := os.Hostname(); err == nil {
|
||||
hostname = h
|
||||
|
|
|
|||
|
|
@ -22,22 +22,17 @@ import (
|
|||
)
|
||||
|
||||
type Scheduler struct {
|
||||
initialized bool
|
||||
cancel chan interface{}
|
||||
Controller *Controller
|
||||
Ticker *time.Ticker
|
||||
cancel chan interface{}
|
||||
running bool
|
||||
}
|
||||
|
||||
func (scheduler *Scheduler) Init(controller *Controller) error {
|
||||
if scheduler.initialized {
|
||||
return errors.New("scheduler already initialized")
|
||||
func NewScheduler(controller *Controller) *Scheduler {
|
||||
return &Scheduler{
|
||||
Controller: controller,
|
||||
cancel: make(chan interface{}),
|
||||
}
|
||||
|
||||
scheduler.Controller = controller
|
||||
scheduler.cancel = make(chan interface{})
|
||||
scheduler.initialized = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (scheduler *Scheduler) run() {
|
||||
|
|
@ -55,14 +50,10 @@ func (scheduler *Scheduler) run() {
|
|||
}
|
||||
|
||||
func (scheduler *Scheduler) Start() error {
|
||||
if !scheduler.initialized {
|
||||
return errors.New("scheduler not initialized")
|
||||
}
|
||||
|
||||
if scheduler.Ticker != nil {
|
||||
if err := scheduler.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
if scheduler.running {
|
||||
return errors.New("scheduler already running")
|
||||
} else {
|
||||
scheduler.running = true
|
||||
}
|
||||
|
||||
scheduler.Ticker = time.NewTicker(time.Hour)
|
||||
|
|
@ -83,12 +74,13 @@ func (scheduler *Scheduler) Start() error {
|
|||
}
|
||||
|
||||
func (scheduler *Scheduler) Stop() error {
|
||||
if !scheduler.initialized {
|
||||
return errors.New("scheduler not initialized")
|
||||
if !scheduler.running {
|
||||
return errors.New("scheduler not running")
|
||||
}
|
||||
|
||||
scheduler.Ticker.Stop()
|
||||
scheduler.Ticker = nil
|
||||
scheduler.running = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,8 +283,10 @@ func NewSearchResults(searchOptions *SearchOptions, client *Client) (*SearchResu
|
|||
searchResults.Results = append(searchResults.Results, searchResult)
|
||||
}
|
||||
|
||||
rows.Close()
|
||||
|
||||
if err != nil {
|
||||
err = formatError(err)
|
||||
return nil, formatError(err)
|
||||
}
|
||||
|
||||
return searchResults, err
|
||||
|
|
|
|||
|
|
@ -358,11 +358,9 @@ func (systems *Systems) Read(db *Database) error {
|
|||
*systems = append(*systems, system)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -437,12 +435,9 @@ func (systems *Systems) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,11 +166,9 @@ func (tags *Tags) Read(db *Database) error {
|
|||
*tags = append(*tags, tag)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
@ -227,12 +225,9 @@ func (tags *Tags) Write(db *Database) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rows.Close()
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
if err = rows.Close(); err != nil {
|
||||
if err != nil {
|
||||
return formatError(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@
|
|||
|
||||
package main
|
||||
|
||||
const Version = "6.0.3"
|
||||
const Version = "6.0.4"
|
||||
|
|
|
|||
Loading…
Reference in a new issue