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 strconv.Atoi: invalid syntax for dirwatch type sdrtrunk.
|
||||||
- Fix the new version available dialog opening more than once.
|
- 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
|
## Version 5.2
|
||||||
|
|
||||||
- Change to how the server reports version.
|
- 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
|
app := rdio-scanner
|
||||||
ver := 6.0.3
|
date := 2021/12/08
|
||||||
|
ver := 6.0.4
|
||||||
|
|
||||||
client := $(wildcard client/*.json client/*.ts)
|
client := $(wildcard client/*.json client/*.ts)
|
||||||
server := $(wildcard server/*.go)
|
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
|
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)
|
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: darwin darwin-amd64 darwin-arm64
|
||||||
.PHONY: freebsd freebsd-amd64
|
.PHONY: freebsd freebsd-amd64
|
||||||
.PHONY: linux linux-386 linux-amd64 linux-arm linux-arm64
|
.PHONY: linux linux-386 linux-amd64 linux-arm linux-arm64
|
||||||
|
|
@ -38,10 +39,11 @@ clean:
|
||||||
|
|
||||||
dist: darwin freebsd linux windows
|
dist: darwin freebsd linux windows
|
||||||
|
|
||||||
setver:
|
sed:
|
||||||
@sed -i -re "s/^(\s*\"version\":).*$$/\1 \"$(ver)\"/" client/package.json
|
@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|^(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 -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
|
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>",
|
"author": "Chrystian Huot <chrystian.huot@saubeo.solutions>",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^13.0.2",
|
"@angular/animations": "^13.0.3",
|
||||||
"@angular/cdk": "^13.0.2",
|
"@angular/cdk": "^13.0.3",
|
||||||
"@angular/common": "~13.0.2",
|
"@angular/common": "~13.0.3",
|
||||||
"@angular/compiler": "~13.0.2",
|
"@angular/compiler": "~13.0.3",
|
||||||
"@angular/core": "~13.0.2",
|
"@angular/core": "~13.0.3",
|
||||||
"@angular/forms": "~13.0.2",
|
"@angular/forms": "~13.0.3",
|
||||||
"@angular/material": "^13.0.2",
|
"@angular/material": "^13.0.3",
|
||||||
"@angular/platform-browser": "~13.0.2",
|
"@angular/platform-browser": "~13.0.3",
|
||||||
"@angular/platform-browser-dynamic": "~13.0.2",
|
"@angular/platform-browser-dynamic": "~13.0.3",
|
||||||
"@angular/router": "^13.0.2",
|
"@angular/router": "^13.0.3",
|
||||||
"@angular/service-worker": "^13.0.2",
|
"@angular/service-worker": "^13.0.3",
|
||||||
"rxjs": "~7.4.0",
|
"rxjs": "~7.4.0",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "~13.0.3",
|
"@angular-devkit/build-angular": "~13.0.4",
|
||||||
"@angular/cli": "^13.0.3",
|
"@angular/cli": "^13.0.4",
|
||||||
"@angular/compiler-cli": "~13.0.2",
|
"@angular/compiler-cli": "~13.0.3",
|
||||||
"@types/node": "~16.11.11",
|
"@types/node": "~16.11.12",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.5.0",
|
"@typescript-eslint/eslint-plugin": "^5.6.0",
|
||||||
"@typescript-eslint/parser": "^5.5.0",
|
"@typescript-eslint/parser": "^5.6.0",
|
||||||
"ajv-keywords": "^5.1.0",
|
"ajv-keywords": "^5.1.0",
|
||||||
"eslint": "^8.3.0",
|
"eslint": "^8.4.1",
|
||||||
"npm-check-updates": "^12.0.2",
|
"npm-check-updates": "^12.0.3",
|
||||||
"ts-node": "~10.4.0",
|
"ts-node": "~10.4.0",
|
||||||
"typescript": "~4.4.4"
|
"typescript": "~4.4.4"
|
||||||
},
|
},
|
||||||
|
|
@ -39,5 +39,5 @@
|
||||||
"build": "ng build --base-href ./ --configuration production",
|
"build": "ng build --base-href ./ --configuration production",
|
||||||
"start": "ng serve"
|
"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.websocket.onopen = () => {
|
||||||
this.event.emit({ linked: true });
|
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.
|
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://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||||
|
|
||||||
\pagebreak{}
|
\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 ~ % 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.0.3.zip
|
> ~/Downloads/rdio-scanner-darwin-arm64-v6.0.4.zip
|
||||||
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.0.3.zip
|
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.0.4.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
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@macos rdio-scanner % ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/29 08:38:06 server started
|
2021/12/08 08:38:06 server started
|
||||||
2021/11/29 08:38:06 main interface at http://macos.local:3000
|
2021/12/08 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 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.
|
||||||
|
|
||||||
|
|
@ -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@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/12/08 08:48:03 server started
|
||||||
2021/11/29 08:48:03 main interface at http://macos.local
|
2021/12/08 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 admin interface at http://macos.local/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## 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.
|
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
|
rdio@macos rdio-scanner % ./rdio-scanner -ssl_create
|
||||||
2021/11/29 08:49:16 generating ssl certificate files
|
2021/12/08 08:49:16 generating ssl certificate files
|
||||||
2021/11/29 08:49:17 ssl files created
|
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.
|
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_key_file server.key \
|
||||||
> -ssl_listen :443
|
> -ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/29 08:50:58 server started
|
2021/12/08 08:50:58 server started
|
||||||
2021/11/29 08:50:58 main interface at http://macos.local
|
2021/12/08 08:50:58 main interface at http://macos.local
|
||||||
2021/11/29 08:50:58 main interface at https://macos.local
|
2021/12/08 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 admin interface at https://macos.local/admin
|
||||||
|
|
||||||
## Save your advanced configuration to a config file
|
## 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_key_file server.key \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -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.
|
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@macos rdio-scanner % ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/29 08:54:08 server started
|
2021/12/08 08:54:08 server started
|
||||||
2021/11/29 08:54:08 main interface at http://macos.local
|
2021/12/08 08:54:08 main interface at http://macos.local
|
||||||
2021/11/29 08:54:08 main interface at https://macos.local
|
2021/12/08 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 admin interface at https://macos.local/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## 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.
|
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://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||||
|
|
||||||
\pagebreak{}
|
\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:~ $ 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.0.3.zip
|
> ~/rdio-scanner-freebsd-amd64-v6.0.4.zip
|
||||||
Archive: ../rdio-scanner-freebsd-amd64-v6.0.3.zip
|
Archive: ../rdio-scanner-freebsd-amd64-v6.0.4.zip
|
||||||
extracting: rdio-scanner
|
extracting: rdio-scanner
|
||||||
extracting: rdio-scanner.pdf
|
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@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/12/08 08:16:36 server started
|
||||||
2021/11/28 08:16:36 main interface at http://pc-freebsd:3000
|
2021/12/08 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 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.
|
||||||
|
|
||||||
|
|
@ -80,11 +80,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.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/28 08:19:38 server started
|
2021/12/08 08:19:38 server started
|
||||||
2021/11/28 08:19:38 main interface at http://pc-freebsd
|
2021/12/08 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 admin interface at http://pc-freebsd/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## 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.
|
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
|
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner -ssl_create
|
||||||
2021/11/28 10:32:17 generating ssl certificate files
|
2021/12/08 10:32:17 generating ssl certificate files
|
||||||
2021/11/28 10:32:19 ssl files created
|
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.
|
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_key_file server.key \
|
||||||
> -ssl_listen :443
|
> -ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/28 10:34:29 server started
|
2021/12/08 10:34:29 server started
|
||||||
2021/11/28 10:34:29 main interface at http://pc-freebsd
|
2021/12/08 10:34:29 main interface at http://pc-freebsd
|
||||||
2021/11/28 10:34:29 main interface at https://pc-freebsd
|
2021/12/08 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 admin interface at https://pc-freebsd/admin
|
||||||
|
|
||||||
## Save your advanced configuration to a config file
|
## 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_key_file server.key \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -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.
|
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:
|
Password:
|
||||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner
|
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/12/08 10:38:28 server started
|
||||||
2021/11/28 10:38:29 main interface at http://pc-freebsd
|
2021/12/08 10:38:29 main interface at http://pc-freebsd
|
||||||
2021/11/28 10:38:29 main interface at https://pc-freebsd
|
2021/12/08 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:29 admin interface at https://pc-freebsd/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## 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.
|
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://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||||
|
|
||||||
\pagebreak{}
|
\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 ~]$ 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.0.3.zip
|
> ~/Downloads/rdio-scanner-linux-amd64-v6.0.4.zip
|
||||||
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.0.3.zip
|
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.0.4.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
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@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/12/08 09:11:48 server started
|
||||||
2021/11/29 09:11:48 main interface at http://pc-linux:3000
|
2021/12/08 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 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.
|
||||||
|
|
||||||
|
|
@ -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
|
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
||||||
[sudo] password for rdio:
|
[sudo] password for rdio:
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/29 09:14:00 server started
|
2021/12/08 09:14:00 server started
|
||||||
2021/11/29 09:14:00 main interface at http://pc-linux
|
2021/12/08 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 admin interface at http://pc-linux/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## 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.
|
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
|
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner -ssl_create
|
||||||
2021/11/29 09:15:03 generating ssl certificate files
|
2021/12/08 09:15:03 generating ssl certificate files
|
||||||
2021/11/29 09:15:05 ssl files created
|
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.
|
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
|
> -ssl_listen :443
|
||||||
[sudo] password for rdio:
|
[sudo] password for rdio:
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/29 09:16:47 server started
|
2021/12/08 09:16:47 server started
|
||||||
2021/11/29 09:16:47 main interface at http://pc-linux
|
2021/12/08 09:16:47 main interface at http://pc-linux
|
||||||
2021/11/29 09:16:47 main interface at https://pc-linux
|
2021/12/08 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 admin interface at https://pc-linux/admin
|
||||||
|
|
||||||
## Save your advanced configuration to a config file
|
## 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_key_file server.key \
|
||||||
> -ssl_listen :443 \
|
> -ssl_listen :443 \
|
||||||
> -config_save
|
> -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.
|
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
|
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner
|
||||||
[sudo] Mot de passe de rdio :
|
[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/12/08 09:20:40 server started
|
||||||
2021/11/29 09:20:40 main interface at http://pc-linux
|
2021/12/08 09:20:40 main interface at http://pc-linux
|
||||||
2021/11/29 09:20:40 main interface at https://pc-linux
|
2021/12/08 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 admin interface at https://pc-linux/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## 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.
|
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://apps.apple.com/us/app/rdio-scanner/id1563065667#?platform=iphone)
|
||||||
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
[](https://play.google.com/store/apps/details?id=solutions.saubeo.rdioScanner)
|
||||||
|
|
||||||
\pagebreak{}
|
\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> cd rdio-scanner
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
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.exe
|
||||||
x rdio-scanner.pdf
|
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
|
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/12/08 13:48:48 server started
|
||||||
2021/11/25 13:48:48 main interface at http://pc-windows:3000
|
2021/12/08 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 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.
|
||||||
|
|
||||||
|
|
@ -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
|
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/12/08 10:53:31 server started
|
||||||
2021/11/26 10:53:31 main interface at http://pc-windows
|
2021/12/08 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 admin interface at http://pc-windows/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## 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.
|
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
|
C:\Users\rdio\rdio-scanner>rdio-scanner -ssl_create
|
||||||
2021/11/26 10:58:51 generating ssl certificate files
|
2021/12/08 10:58:51 generating ssl certificate files
|
||||||
2021/11/26 10:58:54 ssl files created
|
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.
|
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_key_file server.key ^
|
||||||
-ssl_listen :443
|
-ssl_listen :443
|
||||||
|
|
||||||
Rdio Scanner v6.0.3
|
Rdio Scanner v6.0.4
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2021/11/26 11:05:43 server started
|
2021/12/08 11:05:43 server started
|
||||||
2021/11/26 11:05:43 main interface at http://pc-windows
|
2021/12/08 11:05:43 main interface at http://pc-windows
|
||||||
2021/11/26 11:05:43 main interface at https://pc-windows
|
2021/12/08 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 admin interface at https://pc-windows/admin
|
||||||
|
|
||||||
## Save your advanced configuration to a config file
|
## 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_key_file server.key ^
|
||||||
-ssl_listen :443 ^
|
-ssl_listen :443 ^
|
||||||
-config_save
|
-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.
|
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
|
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/12/08 11:11:28 server started
|
||||||
2021/11/26 11:11:28 main interface at http://pc-windows
|
2021/12/08 11:11:28 main interface at http://pc-windows
|
||||||
2021/11/26 11:11:28 main interface at https://pc-windows
|
2021/12/08 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 admin interface at https://pc-windows/admin
|
||||||
|
|
||||||
\pagebreak{}
|
\pagebreak{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,11 +202,9 @@ func (accesses *Accesses) Read(db *Database) error {
|
||||||
*accesses = append(*accesses, access)
|
*accesses = append(*accesses, access)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,12 +268,9 @@ func (accesses *Accesses) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Admin struct {
|
type Admin struct {
|
||||||
initialized bool
|
|
||||||
Attempts AdminLoginAttempts
|
Attempts AdminLoginAttempts
|
||||||
AttemptsMax uint
|
AttemptsMax uint
|
||||||
AttemptsMaxDelay time.Duration
|
AttemptsMaxDelay time.Duration
|
||||||
|
|
@ -47,6 +46,7 @@ type Admin struct {
|
||||||
Register chan *websocket.Conn
|
Register chan *websocket.Conn
|
||||||
Tokens []string
|
Tokens []string
|
||||||
Unregister chan *websocket.Conn
|
Unregister chan *websocket.Conn
|
||||||
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type AdminLoginAttempt struct {
|
type AdminLoginAttempt struct {
|
||||||
|
|
@ -56,6 +56,20 @@ type AdminLoginAttempt struct {
|
||||||
|
|
||||||
type AdminLoginAttempts map[string]*AdminLoginAttempt
|
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() {
|
func (admin *Admin) BroadcastConfig() {
|
||||||
|
|
||||||
if b, err := json.Marshal(admin.GetConfig()); err == nil {
|
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) {
|
func (admin *Admin) LogsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
t := admin.GetAuthorization(r)
|
t := admin.GetAuthorization(r)
|
||||||
if !admin.ValidateToken(t) {
|
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 {
|
func (admin *Admin) ValidateToken(sToken string) bool {
|
||||||
found := false
|
found := false
|
||||||
for _, t := range admin.Tokens {
|
for _, t := range admin.Tokens {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
|
|
@ -35,18 +34,11 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Api struct {
|
type Api struct {
|
||||||
initialized bool
|
|
||||||
Controller *Controller
|
Controller *Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Api) Init(controller *Controller) error {
|
func NewApi(controller *Controller) *Api {
|
||||||
if api.initialized {
|
return &Api{Controller: controller}
|
||||||
return errors.New("api already initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
api.Controller = controller
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Api) CallUploadHandler(w http.ResponseWriter, r *http.Request) {
|
func (api *Api) CallUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
||||||
|
|
@ -174,10 +174,10 @@ func (apikeys *Apikeys) Read(db *Database) error {
|
||||||
rows.Close()
|
rows.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apikeys *Apikeys) Write(db *Database) error {
|
func (apikeys *Apikeys) Write(db *Database) error {
|
||||||
|
|
@ -239,12 +239,9 @@ func (apikeys *Apikeys) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ func (client *Client) Init(controller *Controller, conn *websocket.Conn) error {
|
||||||
client.Access = &Access{}
|
client.Access = &Access{}
|
||||||
client.Controller = controller
|
client.Controller = controller
|
||||||
client.Conn = conn
|
client.Conn = conn
|
||||||
client.Send = make(chan *Message, 100)
|
client.Send = make(chan *Message, 8)
|
||||||
client.LivefeedMap = LivefeedMap{}
|
client.LivefeedMap = LivefeedMap{}
|
||||||
|
|
||||||
controller.Register <- client
|
controller.Register <- client
|
||||||
|
|
|
||||||
126
server/config.go
126
server/config.go
|
|
@ -35,6 +35,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
BaseDir string
|
||||||
ConfigFile string
|
ConfigFile string
|
||||||
DbType string
|
DbType string
|
||||||
DbFile string
|
DbFile string
|
||||||
|
|
@ -53,43 +54,7 @@ type Config struct {
|
||||||
newAdminPassword string
|
newAdminPassword string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) GetConfigFilePath() string {
|
func NewConfig() *Config {
|
||||||
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) {
|
|
||||||
const (
|
const (
|
||||||
defaultAdminUrl = "/admin"
|
defaultAdminUrl = "/admin"
|
||||||
defaultConfigFile = "rdio-scanner.ini"
|
defaultConfigFile = "rdio-scanner.ini"
|
||||||
|
|
@ -101,6 +66,7 @@ func (config *Config) Init() (ok bool, error error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
config = &Config{}
|
||||||
configSave = flag.Bool("config_save", false, fmt.Sprintf("save configuration to %s", defaultConfigFile))
|
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")
|
serviceAction = flag.String("service", "", "service command, one of start, stop, restart, install, uninstall")
|
||||||
sslCreate = flag.Bool("ssl_create", false, "create self-signed certificates")
|
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.SslKeyFile, "ssl_key_file", "", "ssl PEM formated key")
|
||||||
flag.StringVar(&config.SslListen, "ssl_listen", "", "listening address for ssl")
|
flag.StringVar(&config.SslListen, "ssl_listen", "", "listening address for ssl")
|
||||||
flag.StringVar(&config.newAdminPassword, "admin_password", "", "change admin password")
|
flag.StringVar(&config.newAdminPassword, "admin_password", "", "change admin password")
|
||||||
|
|
||||||
flag.Parse()
|
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 {
|
switch {
|
||||||
case *configSave:
|
case *configSave:
|
||||||
if err := config.saveConfig(); err == nil {
|
if err := config.saveConfig(); err == nil {
|
||||||
log.Printf("%s file created", config.ConfigFile)
|
fmt.Printf("%s file created\n", config.ConfigFile)
|
||||||
return false, nil
|
os.Exit(0)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false, err
|
fmt.Printf("error: %s\n", err.Error())
|
||||||
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *sslCreate:
|
case *sslCreate:
|
||||||
log.Print("generating ssl certificate files")
|
fmt.Println("generating ssl certificate files")
|
||||||
|
|
||||||
if err := CreateSelfSignedCert(config); err == nil {
|
if err := CreateSelfSignedCert(config); err == nil {
|
||||||
log.Print("ssl files created")
|
fmt.Println("ssl files created")
|
||||||
return false, nil
|
os.Exit(0)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false, err
|
fmt.Printf("error: %s", err.Error())
|
||||||
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *version:
|
case *version:
|
||||||
fmt.Println(Version)
|
fmt.Println(Version)
|
||||||
return false, nil
|
os.Exit(0)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if cfg, err := ini.Load(config.GetConfigFilePath()); err == nil {
|
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) {
|
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 != "" {
|
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 {
|
func (config *Config) saveConfig() error {
|
||||||
|
|
|
||||||
|
|
@ -48,9 +48,34 @@ type Controller struct {
|
||||||
Register chan *Client
|
Register chan *Client
|
||||||
Unregister chan *Client
|
Unregister chan *Client
|
||||||
Ingest chan *Call
|
Ingest chan *Call
|
||||||
initialized bool
|
|
||||||
ffmpeg bool
|
ffmpeg bool
|
||||||
ffmpegWarned 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 {
|
func (controller *Controller) CheckDuplicate(call *Call) bool {
|
||||||
|
|
@ -68,7 +93,7 @@ func (controller *Controller) CheckDuplicate(call *Call) bool {
|
||||||
return count > 0
|
return count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controller *Controller) ConvertAudio(call *Call) error {
|
func (controller *Controller) ConvertAudio(call *Call) {
|
||||||
var (
|
var (
|
||||||
args = []string{"-i", "-"}
|
args = []string{"-i", "-"}
|
||||||
err error
|
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.")
|
LogEvent(controller.Database, LogLevelWarn, "ffmpeg is not accessible, no audio conversion will be performed.")
|
||||||
}
|
}
|
||||||
|
return
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if system, ok := controller.Systems.GetSystem(call.System); ok {
|
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))
|
stdout := bytes.NewBuffer([]byte(nil))
|
||||||
cmd.Stdout = stdout
|
cmd.Stdout = stdout
|
||||||
|
|
||||||
|
stderr := bytes.NewBuffer([]byte(nil))
|
||||||
|
cmd.Stderr = stderr
|
||||||
|
|
||||||
if err = cmd.Run(); err == nil {
|
if err = cmd.Run(); err == nil {
|
||||||
call.Audio = stdout.Bytes()
|
call.Audio = stdout.Bytes()
|
||||||
call.AudioType = "audio/mp4"
|
call.AudioType = "audio/mp4"
|
||||||
|
|
@ -114,9 +141,10 @@ func (controller *Controller) ConvertAudio(call *Call) error {
|
||||||
case string:
|
case string:
|
||||||
call.AudioName = fmt.Sprintf("%v.m4a", strings.TrimSuffix(v, path.Ext((v))))
|
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) {
|
func (controller *Controller) EmitCall(call *Call) {
|
||||||
|
|
@ -323,10 +351,7 @@ func (controller *Controller) IngestCall(call *Call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !controller.Options.DisableAudioConversion {
|
if !controller.Options.DisableAudioConversion {
|
||||||
if err = controller.ConvertAudio(call); err != nil {
|
controller.ConvertAudio(call)
|
||||||
logError(fmt.Errorf("convertaudio: %s", err.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if id, err = call.Write(controller.Database); err == nil {
|
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() {
|
func (controller *Controller) LogClientsCount() {
|
||||||
LogEvent(
|
LogEvent(
|
||||||
controller.Database,
|
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() {
|
func (controller *Controller) Terminate() {
|
||||||
if err := controller.Database.Sql.Close(); err != nil {
|
if err := controller.Database.Sql.Close(); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
|
|
@ -636,6 +643,10 @@ func (controller *Controller) Terminate() {
|
||||||
|
|
||||||
controller.Dirwatches.Stop()
|
controller.Dirwatches.Stop()
|
||||||
|
|
||||||
|
for c := range controller.Clients {
|
||||||
|
c.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
log.Println("terminated")
|
log.Println("terminated")
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
|
|
||||||
|
|
@ -62,14 +62,16 @@ func NewDaemon() *Daemon {
|
||||||
return &d
|
return &d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Daemon) Control(action string) (bool, error) {
|
func (d *Daemon) Control(action string) {
|
||||||
if action == "run" {
|
if action == "run" {
|
||||||
go d.Service.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{}
|
type DaemonInterface struct{}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -27,59 +26,52 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
initialized bool
|
|
||||||
Config *Config
|
Config *Config
|
||||||
DateTimeFormat string
|
DateTimeFormat string
|
||||||
Sql *sql.DB
|
Sql *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) Init(config *Config) error {
|
func NewDatabase(config *Config) *Database {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if db.initialized {
|
database := &Database{Config: config}
|
||||||
return errors.New("database already initialized")
|
|
||||||
}
|
|
||||||
|
|
||||||
db.initialized = true
|
switch config.DbType {
|
||||||
|
|
||||||
db.Config = config
|
|
||||||
|
|
||||||
switch db.Config.DbType {
|
|
||||||
case DbTypeSqlite:
|
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 {
|
if database.Sql, err = sql.Open("sqlite", dsn); err != nil {
|
||||||
return err
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case DbTypeMariadb, DbTypeMysql:
|
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 {
|
if database.Sql, err = sql.Open("mysql", dsn); err != nil {
|
||||||
return err
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unknown database type %s", db.Config.DbType)
|
log.Fatalf("unknown database type %s\n", config.DbType)
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Sql.SetConnMaxLifetime(0)
|
database.Sql.SetConnMaxLifetime(0)
|
||||||
db.Sql.SetMaxIdleConns(10)
|
database.Sql.SetMaxIdleConns(10)
|
||||||
db.Sql.SetMaxOpenConns(10)
|
database.Sql.SetMaxOpenConns(10)
|
||||||
|
|
||||||
if err = db.migrate(); err != nil {
|
if err = database.migrate(); err != nil {
|
||||||
return err
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = db.seed(); err != nil {
|
if err = database.seed(); err != nil {
|
||||||
return err
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return database
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) ParseDateTime(f interface{}) (time.Time, error) {
|
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")
|
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 {
|
if _, err := controller.Database.Sql.Exec("delete from `rdioScannerCalls` where `dateTime` < ?", date); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ func (dirwatch *Dirwatch) ingestTrunkRecorder(p string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if call.Audio, err = ioutil.ReadFile(audioName); err != nil {
|
if call.Audio, err = ioutil.ReadFile(audioName); err != nil {
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if b, err = ioutil.ReadFile(p); err != 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)
|
fp := path.Join(dirwatch.Directory, p)
|
||||||
|
|
||||||
if dirwatch.isDir(fp) {
|
if dirwatch.isDir(fp) {
|
||||||
|
|
@ -508,6 +509,9 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dirwatch *Dirwatch) Stop() {
|
func (dirwatch *Dirwatch) Stop() {
|
||||||
|
|
@ -582,11 +586,9 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
|
||||||
*dirwatches = append(*dirwatches, dirwatch)
|
*dirwatches = append(*dirwatches, dirwatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,8 +643,7 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rows, err = db.Sql.Query("select `_id` from `rdioScannerDirWatches`")
|
if rows, err = db.Sql.Query("select `_id` from `rdioScannerDirWatches`"); err != nil {
|
||||||
if err != nil {
|
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -661,12 +662,9 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -674,28 +672,13 @@ func (dirwatches *Dirwatches) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dirwatch *Dirwatch) isDir(d string) bool {
|
func (dirwatch *Dirwatch) isDir(d string) bool {
|
||||||
var isDir bool
|
if fi, err := os.Stat(d); err == nil {
|
||||||
|
|
||||||
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.IsDir() {
|
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 {
|
func (dirwatch *Dirwatch) walkDir(d string) error {
|
||||||
|
|
|
||||||
|
|
@ -337,23 +337,24 @@ func (downstreams *Downstreams) FromMap(f []interface{}) {
|
||||||
|
|
||||||
func (downstreams *Downstreams) Read(db *Database) error {
|
func (downstreams *Downstreams) Read(db *Database) error {
|
||||||
var (
|
var (
|
||||||
|
apikey interface{}
|
||||||
err error
|
err error
|
||||||
|
id uint
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
|
systems interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
*downstreams = Downstreams{}
|
*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 {
|
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() {
|
for rows.Next() {
|
||||||
var (
|
|
||||||
apikey interface{}
|
|
||||||
id uint
|
|
||||||
systems interface{}
|
|
||||||
)
|
|
||||||
|
|
||||||
downstream := Downstream{}
|
downstream := Downstream{}
|
||||||
if err = rows.Scan(&id, &apikey, &downstream.Disabled, &downstream.Order, &systems, &downstream.Url); err != nil {
|
if err = rows.Scan(&id, &apikey, &downstream.Disabled, &downstream.Order, &systems, &downstream.Url); err != nil {
|
||||||
break
|
break
|
||||||
|
|
@ -383,12 +384,10 @@ func (downstreams *Downstreams) Read(db *Database) error {
|
||||||
*downstreams = append(*downstreams, downstream)
|
*downstreams = append(*downstreams, downstream)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return err
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -473,12 +472,9 @@ func (downstreams *Downstreams) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,15 @@ require (
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||||
github.com/stretchr/testify v1.7.0 // indirect
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
golang.org/x/mod v0.5.1 // indirect
|
golang.org/x/mod v0.5.1 // indirect
|
||||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c // indirect
|
golang.org/x/net v0.0.0-20211208012354-db4efeb81f4b // indirect
|
||||||
golang.org/x/sys v0.0.0-20211204120058-94396e421777 // indirect
|
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/tools v0.1.8 // indirect
|
golang.org/x/tools v0.1.8 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
lukechampine.com/uint128 v1.1.1 // indirect
|
lukechampine.com/uint128 v1.1.1 // indirect
|
||||||
modernc.org/cc/v3 v3.35.18 // indirect
|
modernc.org/cc/v3 v3.35.18 // indirect
|
||||||
modernc.org/ccgo/v3 v3.12.86 // indirect
|
modernc.org/ccgo/v3 v3.12.87 // indirect
|
||||||
modernc.org/libc v1.11.88 // indirect
|
modernc.org/libc v1.11.89 // indirect
|
||||||
modernc.org/mathutil v1.4.1 // indirect
|
modernc.org/mathutil v1.4.1 // indirect
|
||||||
modernc.org/memory v1.0.5 // indirect
|
modernc.org/memory v1.0.5 // indirect
|
||||||
modernc.org/opt v0.1.1 // 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-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-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-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-20211208012354-db4efeb81f4b h1:MWaHNqZy3KTpuTMAGvv+Kw+ylsEpmyJZizz1dqxnu28=
|
||||||
golang.org/x/net v0.0.0-20211205041911-012df41ee64c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
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-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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-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-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-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-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
|
||||||
golang.org/x/sys v0.0.0-20211204120058-94396e421777/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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/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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
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.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY=
|
||||||
modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w=
|
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.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.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 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
|
||||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
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.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI=
|
||||||
modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE=
|
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.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.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.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
modernc.org/mathutil v1.2.2/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=
|
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)
|
*groups = append(*groups, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,12 +226,9 @@ func (groups *Groups) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,12 +229,10 @@ func NewLogResults(logOptions *LogOptions, db *Database) (*LogResults, error) {
|
||||||
logResults.Logs = append(logResults.Logs, log)
|
logResults.Logs = append(logResults.Logs, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return logResults, formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return logResults, formatError(err)
|
return nil, formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return logResults, nil
|
return logResults, nil
|
||||||
|
|
|
||||||
|
|
@ -40,27 +40,16 @@ func main() {
|
||||||
sslPort string
|
sslPort string
|
||||||
)
|
)
|
||||||
|
|
||||||
config := &Config{}
|
config := NewConfig()
|
||||||
ok, err := config.Init()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
database := &Database{}
|
controller := NewController(config)
|
||||||
if err = database.Init(config); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := &Controller{}
|
|
||||||
if err = controller.Init(config, database); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.newAdminPassword != "" {
|
if config.newAdminPassword != "" {
|
||||||
if hash, err := bcrypt.GenerateFromPassword([]byte(config.newAdminPassword), bcrypt.DefaultCost); err == nil {
|
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.adminPassword = string(hash)
|
||||||
controller.Options.adminPasswordNeedChange = config.newAdminPassword == defaults.adminPassword
|
controller.Options.adminPasswordNeedChange = config.newAdminPassword == defaults.adminPassword
|
||||||
|
|
||||||
|
|
@ -68,10 +57,6 @@ func main() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := controller.Options.Read(controller.Database); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
LogEvent(controller.Database, LogLevelInfo, "admin password changed.")
|
LogEvent(controller.Database, LogLevelInfo, "admin password changed.")
|
||||||
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
|
@ -84,7 +69,9 @@ func main() {
|
||||||
fmt.Printf("\nRdio Scanner v%s\n", Version)
|
fmt.Printf("\nRdio Scanner v%s\n", Version)
|
||||||
fmt.Printf("----------------------------------\n")
|
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 {
|
if h, err := os.Hostname(); err == nil {
|
||||||
hostname = h
|
hostname = h
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
initialized bool
|
|
||||||
cancel chan interface{}
|
|
||||||
Controller *Controller
|
Controller *Controller
|
||||||
Ticker *time.Ticker
|
Ticker *time.Ticker
|
||||||
|
cancel chan interface{}
|
||||||
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scheduler *Scheduler) Init(controller *Controller) error {
|
func NewScheduler(controller *Controller) *Scheduler {
|
||||||
if scheduler.initialized {
|
return &Scheduler{
|
||||||
return errors.New("scheduler already initialized")
|
Controller: controller,
|
||||||
|
cancel: make(chan interface{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Controller = controller
|
|
||||||
scheduler.cancel = make(chan interface{})
|
|
||||||
scheduler.initialized = true
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scheduler *Scheduler) run() {
|
func (scheduler *Scheduler) run() {
|
||||||
|
|
@ -55,14 +50,10 @@ func (scheduler *Scheduler) run() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scheduler *Scheduler) Start() error {
|
func (scheduler *Scheduler) Start() error {
|
||||||
if !scheduler.initialized {
|
if scheduler.running {
|
||||||
return errors.New("scheduler not initialized")
|
return errors.New("scheduler already running")
|
||||||
}
|
} else {
|
||||||
|
scheduler.running = true
|
||||||
if scheduler.Ticker != nil {
|
|
||||||
if err := scheduler.Stop(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Ticker = time.NewTicker(time.Hour)
|
scheduler.Ticker = time.NewTicker(time.Hour)
|
||||||
|
|
@ -83,12 +74,13 @@ func (scheduler *Scheduler) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scheduler *Scheduler) Stop() error {
|
func (scheduler *Scheduler) Stop() error {
|
||||||
if !scheduler.initialized {
|
if !scheduler.running {
|
||||||
return errors.New("scheduler not initialized")
|
return errors.New("scheduler not running")
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduler.Ticker.Stop()
|
scheduler.Ticker.Stop()
|
||||||
scheduler.Ticker = nil
|
scheduler.Ticker = nil
|
||||||
|
scheduler.running = false
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -283,8 +283,10 @@ func NewSearchResults(searchOptions *SearchOptions, client *Client) (*SearchResu
|
||||||
searchResults.Results = append(searchResults.Results, searchResult)
|
searchResults.Results = append(searchResults.Results, searchResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rows.Close()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = formatError(err)
|
return nil, formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return searchResults, err
|
return searchResults, err
|
||||||
|
|
|
||||||
|
|
@ -358,11 +358,9 @@ func (systems *Systems) Read(db *Database) error {
|
||||||
*systems = append(*systems, system)
|
*systems = append(*systems, system)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,12 +435,9 @@ func (systems *Systems) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,11 +166,9 @@ func (tags *Tags) Read(db *Database) error {
|
||||||
*tags = append(*tags, tag)
|
*tags = append(*tags, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,12 +225,9 @@ func (tags *Tags) Write(db *Database) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
rows.Close()
|
rows.Close()
|
||||||
return formatError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = rows.Close(); err != nil {
|
if err != nil {
|
||||||
return formatError(err)
|
return formatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,4 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
const Version = "6.0.3"
|
const Version = "6.0.4"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue