mirror of
https://github.com/chuot/rdio-scanner.git
synced 2026-08-15 17:33:01 -06:00
Version 6.1.7
This commit is contained in:
parent
0534693937
commit
1eebbc1154
|
|
@ -49,6 +49,14 @@ _v6.1.6_
|
||||||
|
|
||||||
- Fix webapp not reporting the correct version.
|
- Fix webapp not reporting the correct version.
|
||||||
|
|
||||||
|
_v6.1.7_
|
||||||
|
|
||||||
|
- More concurrency mutexes to resolve SQL_BUSY errors.
|
||||||
|
- Better internal management of dirwatches.
|
||||||
|
- Fix SDRTrunk files not being ingested (discussion #108).
|
||||||
|
- Fix Trunk Recorder talkgroup_tag assign to the wrong property (issue #115).
|
||||||
|
- Improved the way the talkgroup label and name are autopopulated. If Trunk Recorder sends a talkgroup_tag with an empty value or with a single `-`, it will not overwrite the talkgroup label.
|
||||||
|
|
||||||
## Version 6.0
|
## Version 6.0
|
||||||
|
|
||||||
- Backend server rewritten in Go for better performance and ease of installation.
|
- Backend server rewritten in Go for better performance and ease of installation.
|
||||||
|
|
|
||||||
16
COMPILING.md
16
COMPILING.md
|
|
@ -24,13 +24,13 @@ Clone the official repository on your computer and start the build process.
|
||||||
|
|
||||||
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
|
When finished, you will find the precompiled versions for various platforms in the `dist` folder.
|
||||||
|
|
||||||
rdio-scanner-darwin-amd64-v6.1.6.zip
|
rdio-scanner-darwin-amd64-v6.1.7.zip
|
||||||
rdio-scanner-darwin-arm64-v6.1.6.zip
|
rdio-scanner-darwin-arm64-v6.1.7.zip
|
||||||
rdio-scanner-freebsd-amd64-v6.1.6.zip
|
rdio-scanner-freebsd-amd64-v6.1.7.zip
|
||||||
rdio-scanner-linux-386-v6.1.6.zip
|
rdio-scanner-linux-386-v6.1.7.zip
|
||||||
rdio-scanner-linux-amd64-v6.1.6.zip
|
rdio-scanner-linux-amd64-v6.1.7.zip
|
||||||
rdio-scanner-linux-arm64-v6.1.6.zip
|
rdio-scanner-linux-arm64-v6.1.7.zip
|
||||||
rdio-scanner-linux-arm-v6.1.6.zip
|
rdio-scanner-linux-arm-v6.1.7.zip
|
||||||
rdio-scanner-windows-amd64-v6.1.6.zip
|
rdio-scanner-windows-amd64-v6.1.7.zip
|
||||||
|
|
||||||
**Happy Rdio scanning !**
|
**Happy Rdio scanning !**
|
||||||
4
Makefile
4
Makefile
|
|
@ -16,8 +16,8 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
app := rdio-scanner
|
app := rdio-scanner
|
||||||
date := 2022/01/24
|
date := 2022/01/27
|
||||||
ver := 6.1.6
|
ver := 6.1.7
|
||||||
|
|
||||||
client := $(wildcard client/*.json client/*.ts)
|
client := $(wildcard client/*.json client/*.ts)
|
||||||
server := $(wildcard server/*.go)
|
server := $(wildcard server/*.go)
|
||||||
|
|
|
||||||
2205
client/package-lock.json
generated
2205
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -25,7 +25,6 @@
|
||||||
"@typescript-eslint/parser": "^5.10.0",
|
"@typescript-eslint/parser": "^5.10.0",
|
||||||
"ajv-keywords": "^5.1.0",
|
"ajv-keywords": "^5.1.0",
|
||||||
"eslint": "^8.7.0",
|
"eslint": "^8.7.0",
|
||||||
"npm-check-updates": "^12.2.1",
|
|
||||||
"ts-node": "~10.4.0",
|
"ts-node": "~10.4.0",
|
||||||
"typescript": "~4.4.4"
|
"typescript": "~4.4.4"
|
||||||
},
|
},
|
||||||
|
|
@ -39,5 +38,5 @@
|
||||||
"build": "ng build --base-href ./ --configuration production",
|
"build": "ng build --base-href ./ --configuration production",
|
||||||
"start": "ng serve"
|
"start": "ng serve"
|
||||||
},
|
},
|
||||||
"version": "6.1.6"
|
"version": "6.1.7"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -470,7 +470,7 @@ export class RdioScannerMainComponent implements OnDestroy, OnInit {
|
||||||
|
|
||||||
this.callFrequency = typeof this.call.frequency === 'number'
|
this.callFrequency = typeof this.call.frequency === 'number'
|
||||||
? this.formatFrequency(this.call.frequency)
|
? this.formatFrequency(this.call.frequency)
|
||||||
: this.call.audioName?.replace(/\..+$/, '') || '';
|
: '';
|
||||||
|
|
||||||
this.callSpike = '';
|
this.callSpike = '';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
rdio@macos ~ % mkdir rdio-scanner
|
rdio@macos ~ % mkdir rdio-scanner
|
||||||
rdio@macos ~ % cd rdio-scanner
|
rdio@macos ~ % cd rdio-scanner
|
||||||
rdio@macos rdio-scanner % unzip \
|
rdio@macos rdio-scanner % unzip \
|
||||||
> ~/Downloads/rdio-scanner-darwin-arm64-v6.1.6.zip
|
> ~/Downloads/rdio-scanner-darwin-arm64-v6.1.7.zip
|
||||||
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.1.6.zip
|
Archive: /Users/rdio/Downloads/rdio-scanner-darwin-arm64-v6.1.7.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
inflating: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
rdio@macos rdio-scanner % ./rdio-scanner
|
rdio@macos rdio-scanner % ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:38:06 server started
|
2022/01/27 08:38:06 server started
|
||||||
2022/01/24 08:38:06 main interface at http://macos.local:3000
|
2022/01/27 08:38:06 main interface at http://macos.local:3000
|
||||||
2022/01/24 08:38:06 admin interface at http://macos.local:3000/admin
|
2022/01/27 08:38:06 admin interface at http://macos.local:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -77,11 +77,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
|
|
||||||
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
|
rdio@macos rdio-scanner % ./rdio-scanner --listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:48:03 server started
|
2022/01/27 08:48:03 server started
|
||||||
2022/01/24 08:48:03 main interface at http://macos.local
|
2022/01/27 08:48:03 main interface at http://macos.local
|
||||||
2022/01/24 08:48:03 admin interface at http://macos.local/admin
|
2022/01/27 08:48:03 admin interface at http://macos.local/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@macos rdio-scanner % ./rdio-scanner -ssl_create
|
rdio@macos rdio-scanner % ./rdio-scanner -ssl_create
|
||||||
2022/01/24 08:49:16 generating ssl certificate files
|
2022/01/27 08:49:16 generating ssl certificate files
|
||||||
2022/01/24 08:49:17 ssl files created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:50:58 server started
|
2022/01/27 08:50:58 server started
|
||||||
2022/01/24 08:50:58 main interface at http://macos.local
|
2022/01/27 08:50:58 main interface at http://macos.local
|
||||||
2022/01/24 08:50:58 main interface at https://macos.local
|
2022/01/27 08:50:58 main interface at https://macos.local
|
||||||
2022/01/24 08:50:58 admin interface at https://macos.local/admin
|
2022/01/27 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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
2022/01/24 08:52:24 rdio-scanner.ini file created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -140,12 +140,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:54:08 server started
|
2022/01/27 08:54:08 server started
|
||||||
2022/01/24 08:54:08 main interface at http://macos.local
|
2022/01/27 08:54:08 main interface at http://macos.local
|
||||||
2022/01/24 08:54:08 main interface at https://macos.local
|
2022/01/27 08:54:08 main interface at https://macos.local
|
||||||
2022/01/24 08:54:08 admin interface at https://macos.local/admin
|
2022/01/27 08:54:08 admin interface at https://macos.local/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
rdio@pc-freebsd:~ $ mkdir rdio-scanner
|
rdio@pc-freebsd:~ $ mkdir rdio-scanner
|
||||||
rdio@pc-freebsd:~ $ cd rdio-scanner
|
rdio@pc-freebsd:~ $ cd rdio-scanner
|
||||||
rdio@pc-freebsd:~/rdio-scanner $ unzip \
|
rdio@pc-freebsd:~/rdio-scanner $ unzip \
|
||||||
> ~/rdio-scanner-freebsd-amd64-v6.1.6.zip
|
> ~/rdio-scanner-freebsd-amd64-v6.1.7.zip
|
||||||
Archive: ../rdio-scanner-freebsd-amd64-v6.1.6.zip
|
Archive: ../rdio-scanner-freebsd-amd64-v6.1.7.zip
|
||||||
extracting: rdio-scanner
|
extracting: rdio-scanner
|
||||||
extracting: rdio-scanner.pdf
|
extracting: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
|
rdio@pc-freebsd:~/rdio-scanner $ ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:16:36 server started
|
2022/01/27 08:16:36 server started
|
||||||
2022/01/24 08:16:36 main interface at http://pc-freebsd:3000
|
2022/01/27 08:16:36 main interface at http://pc-freebsd:3000
|
||||||
2022/01/24 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
2022/01/27 08:16:36 admin interface at http://pc-freebsd:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -81,11 +81,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
Password:
|
Password:
|
||||||
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
|
root@pc-freebsd:/home/rdio/rdio-scanner # ./rdio-scanner -listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 08:19:38 server started
|
2022/01/27 08:19:38 server started
|
||||||
2022/01/24 08:19:38 main interface at http://pc-freebsd
|
2022/01/27 08:19:38 main interface at http://pc-freebsd
|
||||||
2022/01/24 08:19:38 admin interface at http://pc-freebsd/admin
|
2022/01/27 08:19:38 admin interface at http://pc-freebsd/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## Listening with SSL with self-signed certificates
|
||||||
|
|
||||||
|
|
@ -94,8 +94,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
|
||||||
2022/01/24 10:32:17 generating ssl certificate files
|
2022/01/27 10:32:17 generating ssl certificate files
|
||||||
2022/01/24 10:32:19 ssl files created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -114,12 +114,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 10:34:29 server started
|
2022/01/27 10:34:29 server started
|
||||||
2022/01/24 10:34:29 main interface at http://pc-freebsd
|
2022/01/27 10:34:29 main interface at http://pc-freebsd
|
||||||
2022/01/24 10:34:29 main interface at https://pc-freebsd
|
2022/01/27 10:34:29 main interface at https://pc-freebsd
|
||||||
2022/01/24 10:34:29 admin interface at https://pc-freebsd/admin
|
2022/01/27 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
|
||||||
|
|
||||||
|
|
@ -131,7 +131,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
|
||||||
2022/01/24 10:37:00 rdio-scanner.ini file created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -148,12 +148,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 10:38:28 server started
|
2022/01/27 10:38:28 server started
|
||||||
2022/01/24 10:38:29 main interface at http://pc-freebsd
|
2022/01/27 10:38:29 main interface at http://pc-freebsd
|
||||||
2022/01/24 10:38:29 main interface at https://pc-freebsd
|
2022/01/27 10:38:29 main interface at https://pc-freebsd
|
||||||
2022/01/24 10:38:29 admin interface at https://pc-freebsd/admin
|
2022/01/27 10:38:29 admin interface at https://pc-freebsd/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,8 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
[rdio@pc-linux ~]$ mkdir rdio-scanner
|
[rdio@pc-linux ~]$ mkdir rdio-scanner
|
||||||
[rdio@pc-linux ~]$ cd rdio-scanner
|
[rdio@pc-linux ~]$ cd rdio-scanner
|
||||||
[rdio@pc-linux rdio-scanner]$ unzip \
|
[rdio@pc-linux rdio-scanner]$ unzip \
|
||||||
> ~/Downloads/rdio-scanner-linux-amd64-v6.1.6.zip
|
> ~/Downloads/rdio-scanner-linux-amd64-v6.1.7.zip
|
||||||
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.1.6.zip
|
Archive: /home/rdio/Downloads/rdio-scanner-linux-amd64-v6.1.7.zip
|
||||||
inflating: rdio-scanner
|
inflating: rdio-scanner
|
||||||
inflating: rdio-scanner.pdf
|
inflating: rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -51,11 +51,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
|
[rdio@pc-linux rdio-scanner]$ ./rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 09:11:48 server started
|
2022/01/27 09:11:48 server started
|
||||||
2022/01/24 09:11:48 main interface at http://pc-linux:3000
|
2022/01/27 09:11:48 main interface at http://pc-linux:3000
|
||||||
2022/01/24 09:11:48 admin interface at http://pc-linux:3000/admin
|
2022/01/27 09:11:48 admin interface at http://pc-linux:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
[rdio@pc-linux rdio-scanner]$ sudo ./rdio-scanner -listen :80
|
||||||
[sudo] password for rdio:
|
[sudo] password for rdio:
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 09:14:00 server started
|
2022/01/27 09:14:00 server started
|
||||||
2022/01/24 09:14:00 main interface at http://pc-linux
|
2022/01/27 09:14:00 main interface at http://pc-linux
|
||||||
2022/01/24 09:14:00 admin interface at http://pc-linux/admin
|
2022/01/27 09:14:00 admin interface at http://pc-linux/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## Listening with SSL with self-signed certificates
|
||||||
|
|
||||||
|
|
@ -91,8 +91,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
|
||||||
2022/01/24 09:15:03 generating ssl certificate files
|
2022/01/27 09:15:03 generating ssl certificate files
|
||||||
2022/01/24 09:15:05 ssl files created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -110,12 +110,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 09:16:47 server started
|
2022/01/27 09:16:47 server started
|
||||||
2022/01/24 09:16:47 main interface at http://pc-linux
|
2022/01/27 09:16:47 main interface at http://pc-linux
|
||||||
2022/01/24 09:16:47 main interface at https://pc-linux
|
2022/01/27 09:16:47 main interface at https://pc-linux
|
||||||
2022/01/24 09:16:47 admin interface at https://pc-linux/admin
|
2022/01/27 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
|
||||||
|
|
||||||
|
|
@ -127,7 +127,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
|
||||||
2022/01/24 09:19:29 rdio-scanner.ini file created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -143,12 +143,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 09:20:40 server started
|
2022/01/27 09:20:40 server started
|
||||||
2022/01/24 09:20:40 main interface at http://pc-linux
|
2022/01/27 09:20:40 main interface at http://pc-linux
|
||||||
2022/01/24 09:20:40 main interface at https://pc-linux
|
2022/01/27 09:20:40 main interface at https://pc-linux
|
||||||
2022/01/24 09:20:40 admin interface at https://pc-linux/admin
|
2022/01/27 09:20:40 admin interface at https://pc-linux/admin
|
||||||
|
|
||||||
## Install Rdio Scanner as a service
|
## Install Rdio Scanner as a service
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
C:\Users\rdio> cd rdio-scanner
|
C:\Users\rdio> cd rdio-scanner
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
C:\Users\rdio\rdio-scanner> tar -xvf ^
|
||||||
..\downloads\rdio-scanner-windows-amd64-v6.1.6.zip
|
..\downloads\rdio-scanner-windows-amd64-v6.1.7.zip
|
||||||
x rdio-scanner.exe
|
x rdio-scanner.exe
|
||||||
x rdio-scanner.pdf
|
x rdio-scanner.pdf
|
||||||
|
|
||||||
|
|
@ -52,11 +52,11 @@ ALWAYS DOWNLOAD THE LATEST VERSION OF [RDIO SCANNER](https://github.com/chuot/rd
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner>rdio-scanner
|
C:\Users\rdio\rdio-scanner>rdio-scanner
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 13:48:48 server started
|
2022/01/27 13:48:48 server started
|
||||||
2022/01/24 13:48:48 main interface at http://pc-windows:3000
|
2022/01/27 13:48:48 main interface at http://pc-windows:3000
|
||||||
2022/01/24 13:48:48 admin interface at http://pc-windows:3000/admin
|
2022/01/27 13:48:48 admin interface at http://pc-windows:3000/admin
|
||||||
|
|
||||||
4. Access the administrative dashboard to finalize the configuration.
|
4. Access the administrative dashboard to finalize the configuration.
|
||||||
|
|
||||||
|
|
@ -78,11 +78,11 @@ Here we want our [Rdio Scanner](https://guthub.com/chuot/rdio-scanner) instance
|
||||||
|
|
||||||
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
|
C:\Users\rdio\rdio-scanner>rdio-scanner -listen :80
|
||||||
|
|
||||||
Rdio Scanner v6.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 10:53:31 server started
|
2022/01/27 10:53:31 server started
|
||||||
2022/01/24 10:53:31 main interface at http://pc-windows
|
2022/01/27 10:53:31 main interface at http://pc-windows
|
||||||
2022/01/24 10:53:31 admin interface at http://pc-windows/admin
|
2022/01/27 10:53:31 admin interface at http://pc-windows/admin
|
||||||
|
|
||||||
## Listening with SSL with self-signed certificates
|
## Listening with SSL with self-signed certificates
|
||||||
|
|
||||||
|
|
@ -91,8 +91,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
|
||||||
2022/01/24 10:58:51 generating ssl certificate files
|
2022/01/27 10:58:51 generating ssl certificate files
|
||||||
2022/01/24 10:58:54 ssl files created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -109,12 +109,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 11:05:43 server started
|
2022/01/27 11:05:43 server started
|
||||||
2022/01/24 11:05:43 main interface at http://pc-windows
|
2022/01/27 11:05:43 main interface at http://pc-windows
|
||||||
2022/01/24 11:05:43 main interface at https://pc-windows
|
2022/01/27 11:05:43 main interface at https://pc-windows
|
||||||
2022/01/24 11:05:43 admin interface at https://pc-windows/admin
|
2022/01/27 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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
2022/01/24 11:08:28 rdio-scanner.ini file created
|
2022/01/27 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.
|
||||||
|
|
||||||
|
|
@ -141,12 +141,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.1.6
|
Rdio Scanner v6.1.7
|
||||||
----------------------------------
|
----------------------------------
|
||||||
2022/01/24 11:11:28 server started
|
2022/01/27 11:11:28 server started
|
||||||
2022/01/24 11:11:28 main interface at http://pc-windows
|
2022/01/27 11:11:28 main interface at http://pc-windows
|
||||||
2022/01/24 11:11:28 main interface at https://pc-windows
|
2022/01/27 11:11:28 main interface at https://pc-windows
|
||||||
2022/01/24 11:11:28 admin interface at https://pc-windows/admin
|
2022/01/27 11:11:28 admin interface at https://pc-windows/admin
|
||||||
|
|
||||||
\pagebreak{}
|
\pagebreak{}
|
||||||
|
|
||||||
|
|
|
||||||
6
package-lock.json
generated
Normal file
6
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "rdio-scanner",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {}
|
||||||
|
}
|
||||||
1
package.json
Normal file
1
package.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
|
|
@ -127,13 +127,13 @@ func (access *Access) HasExpired() bool {
|
||||||
|
|
||||||
type Accesses struct {
|
type Accesses struct {
|
||||||
List []*Access
|
List []*Access
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAccesses() *Accesses {
|
func NewAccesses() *Accesses {
|
||||||
return &Accesses{
|
return &Accesses{
|
||||||
List: []*Access{},
|
List: []*Access{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,8 +154,8 @@ func (accesses *Accesses) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (accesses *Accesses) GetAccess(code string) (access *Access, ok bool) {
|
func (accesses *Accesses) GetAccess(code string) (access *Access, ok bool) {
|
||||||
accesses.mutex.RLock()
|
accesses.mutex.Lock()
|
||||||
defer accesses.mutex.RUnlock()
|
defer accesses.mutex.Unlock()
|
||||||
|
|
||||||
for _, access := range accesses.List {
|
for _, access := range accesses.List {
|
||||||
if access.Code == code {
|
if access.Code == code {
|
||||||
|
|
@ -167,8 +167,8 @@ func (accesses *Accesses) GetAccess(code string) (access *Access, ok bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (accesses *Accesses) IsRestricted() bool {
|
func (accesses *Accesses) IsRestricted() bool {
|
||||||
accesses.mutex.RLock()
|
accesses.mutex.Lock()
|
||||||
defer accesses.mutex.RUnlock()
|
defer accesses.mutex.Unlock()
|
||||||
|
|
||||||
return len(accesses.List) > 0
|
return len(accesses.List) > 0
|
||||||
}
|
}
|
||||||
|
|
@ -185,8 +185,8 @@ func (accesses *Accesses) Read(db *Database) error {
|
||||||
t time.Time
|
t time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
accesses.mutex.RLock()
|
accesses.mutex.Lock()
|
||||||
defer accesses.mutex.RUnlock()
|
defer accesses.mutex.Unlock()
|
||||||
|
|
||||||
accesses.List = []*Access{}
|
accesses.List = []*Access{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
|
@ -47,6 +48,7 @@ type Admin struct {
|
||||||
Register chan *websocket.Conn
|
Register chan *websocket.Conn
|
||||||
Tokens []string
|
Tokens []string
|
||||||
Unregister chan *websocket.Conn
|
Unregister chan *websocket.Conn
|
||||||
|
mutex sync.Mutex
|
||||||
running bool
|
running bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,6 +70,7 @@ func NewAdmin(controller *Controller) *Admin {
|
||||||
Register: make(chan *websocket.Conn, 100),
|
Register: make(chan *websocket.Conn, 100),
|
||||||
Tokens: []string{},
|
Tokens: []string{},
|
||||||
Unregister: make(chan *websocket.Conn, 100),
|
Unregister: make(chan *websocket.Conn, 100),
|
||||||
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +148,11 @@ func (admin *Admin) ConfigHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
admin.Controller.Calls.mutex.Lock()
|
||||||
|
admin.mutex.Lock()
|
||||||
|
defer admin.mutex.Unlock()
|
||||||
|
defer admin.Controller.Calls.mutex.Unlock()
|
||||||
|
|
||||||
logError := func(err error) {
|
logError := func(err error) {
|
||||||
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelError, fmt.Sprintf("admin.confighandler.put: %s", err.Error()))
|
admin.Controller.Logs.LogEvent(admin.Controller.Database, LogLevelError, fmt.Sprintf("admin.confighandler.put: %s", err.Error()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,13 +110,13 @@ func (apikey *Apikey) HasAccess(call *Call) bool {
|
||||||
|
|
||||||
type Apikeys struct {
|
type Apikeys struct {
|
||||||
List []*Apikey
|
List []*Apikey
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewApikeys() *Apikeys {
|
func NewApikeys() *Apikeys {
|
||||||
return &Apikeys{
|
return &Apikeys{
|
||||||
List: []*Apikey{},
|
List: []*Apikey{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,8 +137,8 @@ func (apikeys *Apikeys) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (apikeys *Apikeys) GetApikey(key string) (apikey *Apikey, ok bool) {
|
func (apikeys *Apikeys) GetApikey(key string) (apikey *Apikey, ok bool) {
|
||||||
apikeys.mutex.RLock()
|
apikeys.mutex.Lock()
|
||||||
defer apikeys.mutex.RUnlock()
|
defer apikeys.mutex.Unlock()
|
||||||
|
|
||||||
for _, apikey := range apikeys.List {
|
for _, apikey := range apikeys.List {
|
||||||
if apikey.Key == key && !apikey.Disabled {
|
if apikey.Key == key && !apikey.Disabled {
|
||||||
|
|
@ -157,8 +157,8 @@ func (apikeys *Apikeys) Read(db *Database) error {
|
||||||
systems string
|
systems string
|
||||||
)
|
)
|
||||||
|
|
||||||
apikeys.mutex.RLock()
|
apikeys.mutex.Lock()
|
||||||
defer apikeys.mutex.RUnlock()
|
defer apikeys.mutex.Unlock()
|
||||||
|
|
||||||
apikeys.List = []*Apikey{}
|
apikeys.List = []*Apikey{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,20 +106,20 @@ func (call *Call) ToJson() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Calls struct {
|
type Calls struct {
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCalls() *Calls {
|
func NewCalls() *Calls {
|
||||||
return &Calls{
|
return &Calls{
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (calls *Calls) CheckDuplicate(call *Call, msTimeFrame uint, db *Database) bool {
|
func (calls *Calls) CheckDuplicate(call *Call, msTimeFrame uint, db *Database) bool {
|
||||||
var count uint
|
var count uint
|
||||||
|
|
||||||
calls.mutex.RLock()
|
calls.mutex.Lock()
|
||||||
defer calls.mutex.RUnlock()
|
defer calls.mutex.Unlock()
|
||||||
|
|
||||||
d := time.Duration(msTimeFrame) * time.Millisecond
|
d := time.Duration(msTimeFrame) * time.Millisecond
|
||||||
from := call.DateTime.Add(-d).Format(db.DateTimeFormat)
|
from := call.DateTime.Add(-d).Format(db.DateTimeFormat)
|
||||||
|
|
@ -142,8 +142,8 @@ func (calls *Calls) GetCall(id uint, db *Database) (*Call, error) {
|
||||||
t time.Time
|
t time.Time
|
||||||
)
|
)
|
||||||
|
|
||||||
calls.mutex.RLock()
|
calls.mutex.Lock()
|
||||||
defer calls.mutex.RUnlock()
|
defer calls.mutex.Unlock()
|
||||||
|
|
||||||
call := Call{}
|
call := Call{}
|
||||||
|
|
||||||
|
|
@ -209,8 +209,8 @@ func (calls *Calls) Search(searchOptions *CallsSearchOptions, client *Client) (*
|
||||||
where string = "true"
|
where string = "true"
|
||||||
)
|
)
|
||||||
|
|
||||||
calls.mutex.RLock()
|
calls.mutex.Lock()
|
||||||
defer calls.mutex.RUnlock()
|
defer calls.mutex.Unlock()
|
||||||
|
|
||||||
db := client.Controller.Database
|
db := client.Controller.Database
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ func (config *Config) GetPath(p string) string {
|
||||||
if path.IsAbs(p) {
|
if path.IsAbs(p) {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
return path.Join(config.BaseDir, p)
|
return filepath.Join(config.BaseDir, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *Config) GetSslCaCertFilePath() string {
|
func (config *Config) GetSslCaCertFilePath() string {
|
||||||
|
|
|
||||||
|
|
@ -81,10 +81,6 @@ func NewController(config *Config) *Controller {
|
||||||
return controller
|
return controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func (controller *Controller) CheckDuplicate(call *Call) bool {
|
|
||||||
return controller.Calls.CheckDuplicate(call, controller.Options.DuplicateDetectionTimeFrame, controller.Database)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (controller *Controller) ConvertAudio(call *Call) {
|
func (controller *Controller) ConvertAudio(call *Call) {
|
||||||
var (
|
var (
|
||||||
args = []string{"-i", "-"}
|
args = []string{"-i", "-"}
|
||||||
|
|
@ -295,7 +291,6 @@ func (controller *Controller) IngestCall(call *Call) {
|
||||||
GroupId: groupId,
|
GroupId: groupId,
|
||||||
Id: call.Talkgroup,
|
Id: call.Talkgroup,
|
||||||
Label: fmt.Sprintf("%d", call.Talkgroup),
|
Label: fmt.Sprintf("%d", call.Talkgroup),
|
||||||
Name: fmt.Sprintf("Talkgroup %d", call.Talkgroup),
|
|
||||||
TagId: tagId,
|
TagId: tagId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,6 +311,11 @@ func (controller *Controller) IngestCall(call *Call) {
|
||||||
populated = true
|
populated = true
|
||||||
talkgroup.Name = v
|
talkgroup.Name = v
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
if len(talkgroup.Name) == 0 {
|
||||||
|
populated = true
|
||||||
|
talkgroup.Name = talkgroup.Label
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,7 +350,7 @@ func (controller *Controller) IngestCall(call *Call) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !controller.Options.DisableDuplicateDetection {
|
if !controller.Options.DisableDuplicateDetection {
|
||||||
if controller.CheckDuplicate(call) {
|
if controller.Calls.CheckDuplicate(call, controller.Options.DuplicateDetectionTimeFrame, controller.Database) {
|
||||||
logCall(call, LogLevelWarn, "duplicate call rejected")
|
logCall(call, LogLevelWarn, "duplicate call rejected")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,10 @@ func NewDatabase(config *Config) *Database {
|
||||||
log.Fatalf("unknown database type %s\n", config.DbType)
|
log.Fatalf("unknown database type %s\n", config.DbType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
database.Sql.SetConnMaxIdleTime(time.Second * 5)
|
||||||
database.Sql.SetConnMaxLifetime(0)
|
database.Sql.SetConnMaxLifetime(0)
|
||||||
database.Sql.SetMaxIdleConns(10)
|
database.Sql.SetMaxIdleConns(64)
|
||||||
database.Sql.SetMaxOpenConns(10)
|
database.Sql.SetMaxOpenConns(64)
|
||||||
|
|
||||||
if err = database.migrate(); err != nil {
|
if err = database.migrate(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,7 @@ var defaults Defaults = Defaults{
|
||||||
"Air",
|
"Air",
|
||||||
"EMS",
|
"EMS",
|
||||||
"Fire",
|
"Fire",
|
||||||
|
"Interop",
|
||||||
"Law",
|
"Law",
|
||||||
},
|
},
|
||||||
keypadBeeps: "uniden",
|
keypadBeeps: "uniden",
|
||||||
|
|
@ -102,15 +103,13 @@ var defaults Defaults = Defaults{
|
||||||
},
|
},
|
||||||
systems: []System{},
|
systems: []System{},
|
||||||
tags: []string{
|
tags: []string{
|
||||||
"Air Apron",
|
"Air Traffic Control",
|
||||||
"Air Ground",
|
"Emergency ",
|
||||||
"Air Traffic",
|
|
||||||
"EMS Dispatch ",
|
|
||||||
"EMS Operations ",
|
|
||||||
"Fire Dispatch",
|
"Fire Dispatch",
|
||||||
"Fire Tac",
|
"Fire Tac",
|
||||||
"Fire Talk",
|
"Fire Talk",
|
||||||
"Law Dispatch",
|
"Interop",
|
||||||
"Law Talk",
|
"Security",
|
||||||
|
"Service",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"mime"
|
"mime"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -57,6 +58,7 @@ type Dirwatch struct {
|
||||||
UsePolling bool `json:"usePolling"`
|
UsePolling bool `json:"usePolling"`
|
||||||
controller *Controller
|
controller *Controller
|
||||||
dirs map[string]bool
|
dirs map[string]bool
|
||||||
|
pending map[string]*time.Timer
|
||||||
running bool
|
running bool
|
||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
}
|
}
|
||||||
|
|
@ -465,7 +467,11 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
|
|
||||||
newTimer := func(eventName string) *time.Timer {
|
newTimer := func(eventName string) *time.Timer {
|
||||||
return time.AfterFunc(2*time.Second, func() {
|
return time.AfterFunc(2*time.Second, func() {
|
||||||
dirwatch.Ingest(eventName)
|
if dirwatch.running {
|
||||||
|
if _, err := os.Stat(eventName); err == nil {
|
||||||
|
dirwatch.Ingest(eventName)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -475,6 +481,7 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
if dirwatch.watcher == nil {
|
if dirwatch.watcher == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if event, ok := <-dirwatch.watcher.Events; ok {
|
if event, ok := <-dirwatch.watcher.Events; ok {
|
||||||
switch event.Op {
|
switch event.Op {
|
||||||
case fsnotify.Create:
|
case fsnotify.Create:
|
||||||
|
|
@ -482,11 +489,16 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
case uint:
|
case uint:
|
||||||
time.Sleep(time.Duration(v) * time.Millisecond)
|
time.Sleep(time.Duration(v) * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dirwatch.isDir(event.Name) {
|
if dirwatch.isDir(event.Name) {
|
||||||
if err := dirwatch.walkDir(event.Name); err != nil {
|
if err := dirwatch.walkDir(event.Name); err != nil {
|
||||||
logError(err)
|
logError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if pending[event.Name] != nil {
|
||||||
|
pending[event.Name].Stop()
|
||||||
|
}
|
||||||
pending[event.Name] = newTimer(event.Name)
|
pending[event.Name] = newTimer(event.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -501,16 +513,28 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
|
|
||||||
case fsnotify.Write:
|
case fsnotify.Write:
|
||||||
if pending[event.Name] != nil {
|
if pending[event.Name] != nil {
|
||||||
pending[event.Name].Stop()
|
if pending[event.Name] != nil {
|
||||||
|
pending[event.Name].Stop()
|
||||||
|
}
|
||||||
pending[event.Name] = newTimer(event.Name)
|
pending[event.Name] = newTimer(event.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if dirwatch.running {
|
} else if dirwatch.running {
|
||||||
dirwatch.watcher.Close()
|
if dirwatch.watcher != nil {
|
||||||
dirwatch.watcher, _ = fsnotify.NewWatcher()
|
dirwatch.watcher.Close()
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
if dirwatch.watcher, err = fsnotify.NewWatcher(); err != nil {
|
||||||
|
controller.Logs.LogEvent(
|
||||||
|
controller.Database,
|
||||||
|
LogLevelError,
|
||||||
|
fmt.Sprintf("dirwatch.watcher.restart: %s", err.Error()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
dirwatch.Stop()
|
dirwatch.Stop()
|
||||||
break
|
break
|
||||||
|
|
@ -521,10 +545,12 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
go watcher()
|
go watcher()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
time.Sleep(2 * time.Second)
|
if err := fs.WalkDir(os.DirFS(dirwatch.Directory), ".", func(p string, d fs.DirEntry, err error) error {
|
||||||
|
if !dirwatch.running {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
fs.WalkDir(os.DirFS(dirwatch.Directory), ".", func(p string, d fs.DirEntry, err error) error {
|
fp := filepath.Join(dirwatch.Directory, p)
|
||||||
fp := path.Join(dirwatch.Directory, p)
|
|
||||||
|
|
||||||
if dirwatch.isDir(fp) {
|
if dirwatch.isDir(fp) {
|
||||||
dirwatch.dirs[fp] = true
|
dirwatch.dirs[fp] = true
|
||||||
|
|
@ -533,31 +559,42 @@ func (dirwatch *Dirwatch) Start(controller *Controller) error {
|
||||||
} else if dirwatch.DeleteAfter {
|
} else if dirwatch.DeleteAfter {
|
||||||
dirwatch.Ingest(fp)
|
dirwatch.Ingest(fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
})
|
}); err != nil {
|
||||||
|
controller.Logs.LogEvent(
|
||||||
|
controller.Database,
|
||||||
|
LogLevelError,
|
||||||
|
fmt.Sprintf("dirwatch.walkdir: %s", err.Error()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dirwatch *Dirwatch) Stop() {
|
func (dirwatch *Dirwatch) Stop() {
|
||||||
|
dirwatch.running = false
|
||||||
|
|
||||||
|
for k := range dirwatch.pending {
|
||||||
|
dirwatch.pending[k].Stop()
|
||||||
|
}
|
||||||
|
|
||||||
if dirwatch.watcher != nil {
|
if dirwatch.watcher != nil {
|
||||||
dirwatch.watcher.Close()
|
dirwatch.watcher.Close()
|
||||||
dirwatch.watcher = nil
|
dirwatch.watcher = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
dirwatch.running = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dirwatches struct {
|
type Dirwatches struct {
|
||||||
List []*Dirwatch
|
List []*Dirwatch
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDirwatches() *Dirwatches {
|
func NewDirwatches() *Dirwatches {
|
||||||
return &Dirwatches{
|
return &Dirwatches{
|
||||||
List: []*Dirwatch{},
|
List: []*Dirwatch{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -594,8 +631,8 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
|
||||||
talkgroupId sql.NullFloat64
|
talkgroupId sql.NullFloat64
|
||||||
)
|
)
|
||||||
|
|
||||||
dirwatches.mutex.RLock()
|
dirwatches.mutex.Lock()
|
||||||
defer dirwatches.mutex.RUnlock()
|
defer dirwatches.mutex.Unlock()
|
||||||
|
|
||||||
dirwatches.Stop()
|
dirwatches.Stop()
|
||||||
|
|
||||||
|
|
@ -610,7 +647,7 @@ func (dirwatches *Dirwatches) Read(db *Database) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
dirwatch := &Dirwatch{}
|
dirwatch := &Dirwatch{pending: map[string]*time.Timer{}}
|
||||||
|
|
||||||
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
|
if err = rows.Scan(&id, &delay, &dirwatch.DeleteAfter, &dirwatch.Directory, &dirwatch.Disabled, &extension, &frequency, &mask, &order, &systemId, &talkgroupId, &kind, &dirwatch.UsePolling); err != nil {
|
||||||
break
|
break
|
||||||
|
|
@ -770,7 +807,7 @@ func (dirwatch *Dirwatch) walkDir(d string) error {
|
||||||
dfs := os.DirFS(d)
|
dfs := os.DirFS(d)
|
||||||
|
|
||||||
return fs.WalkDir(dfs, ".", func(p string, de fs.DirEntry, err error) error {
|
return fs.WalkDir(dfs, ".", func(p string, de fs.DirEntry, err error) error {
|
||||||
fp := path.Join(d, p)
|
fp := filepath.Join(d, p)
|
||||||
if dirwatch.isDir(fp) {
|
if dirwatch.isDir(fp) {
|
||||||
if !dirwatch.dirs[fp] {
|
if !dirwatch.dirs[fp] {
|
||||||
dirwatch.dirs[fp] = true
|
dirwatch.dirs[fp] = true
|
||||||
|
|
|
||||||
|
|
@ -350,13 +350,13 @@ func (downstream *Downstream) Send(call *Call) error {
|
||||||
|
|
||||||
type Downstreams struct {
|
type Downstreams struct {
|
||||||
List []*Downstream
|
List []*Downstream
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDownstreams() *Downstreams {
|
func NewDownstreams() *Downstreams {
|
||||||
return &Downstreams{
|
return &Downstreams{
|
||||||
List: []*Downstream{},
|
List: []*Downstream{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,8 +384,8 @@ func (downstreams *Downstreams) Read(db *Database) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
downstreams.mutex.RLock()
|
downstreams.mutex.Lock()
|
||||||
defer downstreams.mutex.RUnlock()
|
defer downstreams.mutex.Unlock()
|
||||||
|
|
||||||
downstreams.List = []*Downstream{}
|
downstreams.List = []*Downstream{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ require (
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
modernc.org/cc/v3 v3.35.22 // indirect
|
modernc.org/cc/v3 v3.35.22 // indirect
|
||||||
modernc.org/ccgo/v3 v3.15.11 // indirect
|
modernc.org/ccgo/v3 v3.15.13 // indirect
|
||||||
modernc.org/libc v1.14.4 // indirect
|
modernc.org/libc v1.14.5 // 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
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,12 @@ modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6
|
||||||
modernc.org/ccgo/v3 v3.15.1/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
|
modernc.org/ccgo/v3 v3.15.1/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
|
||||||
modernc.org/ccgo/v3 v3.15.9/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
|
modernc.org/ccgo/v3 v3.15.9/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0=
|
||||||
modernc.org/ccgo/v3 v3.15.10/go.mod h1:wQKxoFn0ynxMuCLfFD09c8XPUCc8obfchoVR9Cn0fI8=
|
modernc.org/ccgo/v3 v3.15.10/go.mod h1:wQKxoFn0ynxMuCLfFD09c8XPUCc8obfchoVR9Cn0fI8=
|
||||||
modernc.org/ccgo/v3 v3.15.11 h1:rBUQkkX3u/Sh1ipCDCCwGnaPIjaErgtR23S5mHzuJH4=
|
modernc.org/ccgo/v3 v3.15.12/go.mod h1:VFePOWoCd8uDGRJpq/zfJ29D0EVzMSyID8LCMWYbX6I=
|
||||||
modernc.org/ccgo/v3 v3.15.11/go.mod h1:VFePOWoCd8uDGRJpq/zfJ29D0EVzMSyID8LCMWYbX6I=
|
modernc.org/ccgo/v3 v3.15.13 h1:hqlCzNJTXLrhS70y1PqWckrF9x1btSQRC7JFuQcBg5c=
|
||||||
modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA=
|
modernc.org/ccgo/v3 v3.15.13/go.mod h1:QHtvdpeODlXjdK3tsbpyK+7U9JV4PQsrPGIbtmc0KfY=
|
||||||
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
|
modernc.org/ccorpus v1.11.4 h1:YOmQBBzE8GC/puUx76D5j/gJYIZQsydrh6VMJVfXF0M=
|
||||||
|
modernc.org/ccorpus v1.11.4/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
|
||||||
|
|
@ -201,8 +203,8 @@ modernc.org/libc v1.13.2/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
|
||||||
modernc.org/libc v1.14.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
|
modernc.org/libc v1.14.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk=
|
||||||
modernc.org/libc v1.14.2/go.mod h1:MX1GBLnRLNdvmK9azU9LCxZ5lMyhrbEMK8rG3X/Fe34=
|
modernc.org/libc v1.14.2/go.mod h1:MX1GBLnRLNdvmK9azU9LCxZ5lMyhrbEMK8rG3X/Fe34=
|
||||||
modernc.org/libc v1.14.3/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ=
|
modernc.org/libc v1.14.3/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ=
|
||||||
modernc.org/libc v1.14.4 h1:Sw2GDhSQbQF75VKC6RSd5//QH2gj9TgBzjLNZTW6m00=
|
modernc.org/libc v1.14.5 h1:DAHvwGoVRDZs5iJXnX9RJrgXSsorupCWmJ2ac964Owk=
|
||||||
modernc.org/libc v1.14.4/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ=
|
modernc.org/libc v1.14.5/go.mod h1:2PJHINagVxO4QW/5OQdRrvMYo+bm5ClpUFfyXCYl9ak=
|
||||||
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=
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ func (group *Group) FromMap(m map[string]interface{}) {
|
||||||
|
|
||||||
type Groups struct {
|
type Groups struct {
|
||||||
List []*Group
|
List []*Group
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGroups() *Groups {
|
func NewGroups() *Groups {
|
||||||
return &Groups{
|
return &Groups{
|
||||||
List: []*Group{},
|
List: []*Group{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,8 +69,8 @@ func (groups *Groups) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (groups *Groups) GetGroup(f interface{}) (group *Group, ok bool) {
|
func (groups *Groups) GetGroup(f interface{}) (group *Group, ok bool) {
|
||||||
groups.mutex.RLock()
|
groups.mutex.Lock()
|
||||||
defer groups.mutex.RUnlock()
|
defer groups.mutex.Unlock()
|
||||||
|
|
||||||
switch v := f.(type) {
|
switch v := f.(type) {
|
||||||
case uint:
|
case uint:
|
||||||
|
|
@ -165,8 +165,8 @@ func (groups *Groups) Read(db *Database) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
groups.mutex.RLock()
|
groups.mutex.Lock()
|
||||||
defer groups.mutex.RUnlock()
|
defer groups.mutex.Unlock()
|
||||||
|
|
||||||
groups.List = []*Group{}
|
groups.List = []*Group{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ import (
|
||||||
|
|
||||||
type Livefeed struct {
|
type Livefeed struct {
|
||||||
Matrix map[uint]map[uint]bool
|
Matrix map[uint]map[uint]bool
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLivefeed() *Livefeed {
|
func NewLivefeed() *Livefeed {
|
||||||
return &Livefeed{
|
return &Livefeed{
|
||||||
Matrix: map[uint]map[uint]bool{},
|
Matrix: map[uint]map[uint]bool{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,8 +66,8 @@ func (livefeed *Livefeed) FromMap(f interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (livefeed *Livefeed) IsAllOff() bool {
|
func (livefeed *Livefeed) IsAllOff() bool {
|
||||||
livefeed.mutex.RLock()
|
livefeed.mutex.Lock()
|
||||||
defer livefeed.mutex.RUnlock()
|
defer livefeed.mutex.Unlock()
|
||||||
|
|
||||||
for _, sys := range livefeed.Matrix {
|
for _, sys := range livefeed.Matrix {
|
||||||
for _, tg := range sys {
|
for _, tg := range sys {
|
||||||
|
|
@ -81,8 +81,8 @@ func (livefeed *Livefeed) IsAllOff() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (livefeed *Livefeed) IsEnabled(call *Call) bool {
|
func (livefeed *Livefeed) IsEnabled(call *Call) bool {
|
||||||
livefeed.mutex.RLock()
|
livefeed.mutex.Lock()
|
||||||
defer livefeed.mutex.RUnlock()
|
defer livefeed.mutex.Unlock()
|
||||||
|
|
||||||
if call != nil {
|
if call != nil {
|
||||||
if livefeed.Matrix[call.System][call.Talkgroup] {
|
if livefeed.Matrix[call.System][call.Talkgroup] {
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,12 @@ type Log struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Logs struct {
|
type Logs struct {
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogs() *Logs {
|
func NewLogs() *Logs {
|
||||||
return &Logs{
|
return &Logs{
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,8 +94,8 @@ func (logs *Logs) Search(searchOptions *LogsSearchOptions, db *Database) (*LogsS
|
||||||
where string = "true"
|
where string = "true"
|
||||||
)
|
)
|
||||||
|
|
||||||
logs.mutex.RLock()
|
logs.mutex.Lock()
|
||||||
defer logs.mutex.RUnlock()
|
defer logs.mutex.Unlock()
|
||||||
|
|
||||||
formatError := func(err error) error {
|
formatError := func(err error) error {
|
||||||
return fmt.Errorf("newLogResults: %v", err)
|
return fmt.Errorf("newLogResults: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,13 @@ type Options struct {
|
||||||
TagsToggle bool `json:"tagsToggle"`
|
TagsToggle bool `json:"tagsToggle"`
|
||||||
adminPassword string
|
adminPassword string
|
||||||
adminPasswordNeedChange bool
|
adminPasswordNeedChange bool
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
secret string
|
secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOptions() *Options {
|
func NewOptions() *Options {
|
||||||
return &Options{
|
return &Options{
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,8 +129,8 @@ func (options *Options) Read(db *Database) error {
|
||||||
f interface{}
|
f interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
options.mutex.RLock()
|
options.mutex.Lock()
|
||||||
defer options.mutex.RUnlock()
|
defer options.mutex.Unlock()
|
||||||
|
|
||||||
defaultPassword, _ = bcrypt.GenerateFromPassword([]byte(defaults.adminPassword), bcrypt.DefaultCost)
|
defaultPassword, _ = bcrypt.GenerateFromPassword([]byte(defaults.adminPassword), bcrypt.DefaultCost)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func ParseSdrTrunkMeta(call *Call, controller *Controller) error {
|
||||||
|
|
||||||
s = regexp.MustCompile(`^([0-9]+)$`).FindStringSubmatch(m.Artist())
|
s = regexp.MustCompile(`^([0-9]+)$`).FindStringSubmatch(m.Artist())
|
||||||
if len(s) == 2 {
|
if len(s) == 2 {
|
||||||
if i, err = strconv.Atoi(s[1]); err == nil {
|
if i, err = strconv.Atoi(s[1]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
|
|
@ -271,22 +271,22 @@ func ParseMultipartContent(call *Call, p *multipart.Part, b []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case "talkgroupGroup":
|
case "talkgroupGroup":
|
||||||
if s := string(b); len(s) > 1 {
|
if s := string(b); len(s) > 0 && s != "-" {
|
||||||
call.talkgroupGroup = s
|
call.talkgroupGroup = s
|
||||||
}
|
}
|
||||||
|
|
||||||
case "talkgroupLabel":
|
case "talkgroupLabel":
|
||||||
if s := string(b); len(s) > 1 {
|
if s := string(b); len(s) > 0 && s != "-" {
|
||||||
call.talkgroupLabel = s
|
call.talkgroupLabel = s
|
||||||
}
|
}
|
||||||
|
|
||||||
case "talkgroupName":
|
case "talkgroupName":
|
||||||
if s := string(b); len(s) > 1 {
|
if s := string(b); len(s) > 0 && s != "-" {
|
||||||
call.talkgroupName = s
|
call.talkgroupName = s
|
||||||
}
|
}
|
||||||
|
|
||||||
case "talkgroupTag":
|
case "talkgroupTag":
|
||||||
if s := string(b); len(s) > 1 {
|
if s := string(b); len(s) > 0 && s != "-" {
|
||||||
call.talkgroupTag = s
|
call.talkgroupTag = s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -425,9 +425,9 @@ func ParseTrunkRecorderMeta(call *Call, b []byte) error {
|
||||||
|
|
||||||
switch v := m["talkgroup_tag"].(type) {
|
switch v := m["talkgroup_tag"].(type) {
|
||||||
case string:
|
case string:
|
||||||
call.talkgroupTag = v
|
if len(v) > 0 && v != "-" {
|
||||||
call.talkgroupLabel = v
|
call.talkgroupLabel = v
|
||||||
call.talkgroupName = v
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -95,13 +95,13 @@ type SystemMap map[string]interface{}
|
||||||
|
|
||||||
type Systems struct {
|
type Systems struct {
|
||||||
List []*System
|
List []*System
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSystems() *Systems {
|
func NewSystems() *Systems {
|
||||||
return &Systems{
|
return &Systems{
|
||||||
List: []*System{},
|
List: []*System{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,8 +122,8 @@ func (systems *Systems) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (systems *Systems) GetNewSystemId() uint {
|
func (systems *Systems) GetNewSystemId() uint {
|
||||||
systems.mutex.RLock()
|
systems.mutex.Lock()
|
||||||
defer systems.mutex.RUnlock()
|
defer systems.mutex.Unlock()
|
||||||
|
|
||||||
NextId:
|
NextId:
|
||||||
for i := uint(1); i < 65535; i++ {
|
for i := uint(1); i < 65535; i++ {
|
||||||
|
|
@ -138,8 +138,8 @@ NextId:
|
||||||
}
|
}
|
||||||
|
|
||||||
func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) {
|
func (systems *Systems) GetSystem(f interface{}) (system *System, ok bool) {
|
||||||
systems.mutex.RLock()
|
systems.mutex.Lock()
|
||||||
defer systems.mutex.RUnlock()
|
defer systems.mutex.Unlock()
|
||||||
|
|
||||||
switch v := f.(type) {
|
switch v := f.(type) {
|
||||||
case uint:
|
case uint:
|
||||||
|
|
@ -319,8 +319,8 @@ func (systems *Systems) Read(db *Database) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
systems.mutex.RLock()
|
systems.mutex.Lock()
|
||||||
defer systems.mutex.RUnlock()
|
defer systems.mutex.Unlock()
|
||||||
|
|
||||||
systems.List = []*System{}
|
systems.List = []*System{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ func (tag *Tag) FromMap(m map[string]interface{}) {
|
||||||
|
|
||||||
type Tags struct {
|
type Tags struct {
|
||||||
List []*Tag
|
List []*Tag
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTags() *Tags {
|
func NewTags() *Tags {
|
||||||
return &Tags{
|
return &Tags{
|
||||||
List: []*Tag{},
|
List: []*Tag{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,8 +69,8 @@ func (tags *Tags) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tags *Tags) GetTag(f interface{}) (tag *Tag, ok bool) {
|
func (tags *Tags) GetTag(f interface{}) (tag *Tag, ok bool) {
|
||||||
tags.mutex.RLock()
|
tags.mutex.Lock()
|
||||||
defer tags.mutex.RUnlock()
|
defer tags.mutex.Unlock()
|
||||||
|
|
||||||
switch v := f.(type) {
|
switch v := f.(type) {
|
||||||
case uint:
|
case uint:
|
||||||
|
|
@ -165,8 +165,8 @@ func (tags *Tags) Read(db *Database) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
tags.mutex.RLock()
|
tags.mutex.Lock()
|
||||||
defer tags.mutex.RUnlock()
|
defer tags.mutex.Unlock()
|
||||||
|
|
||||||
tags.List = []*Tag{}
|
tags.List = []*Tag{}
|
||||||
|
|
||||||
|
|
@ -93,13 +93,13 @@ type TalkgroupMap map[string]interface{}
|
||||||
|
|
||||||
type Talkgroups struct {
|
type Talkgroups struct {
|
||||||
List []*Talkgroup
|
List []*Talkgroup
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTalkgroups() *Talkgroups {
|
func NewTalkgroups() *Talkgroups {
|
||||||
return &Talkgroups{
|
return &Talkgroups{
|
||||||
List: []*Talkgroup{},
|
List: []*Talkgroup{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,8 +120,8 @@ func (talkgroups *Talkgroups) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (talkgroups *Talkgroups) GetTalkgroup(f interface{}) (system *Talkgroup, ok bool) {
|
func (talkgroups *Talkgroups) GetTalkgroup(f interface{}) (system *Talkgroup, ok bool) {
|
||||||
talkgroups.mutex.RLock()
|
talkgroups.mutex.Lock()
|
||||||
defer talkgroups.mutex.RUnlock()
|
defer talkgroups.mutex.Unlock()
|
||||||
|
|
||||||
switch v := f.(type) {
|
switch v := f.(type) {
|
||||||
case uint:
|
case uint:
|
||||||
|
|
@ -149,8 +149,8 @@ func (talkgroups *Talkgroups) Read(db *Database, systemId uint) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
talkgroups.mutex.RLock()
|
talkgroups.mutex.Lock()
|
||||||
defer talkgroups.mutex.RUnlock()
|
defer talkgroups.mutex.Unlock()
|
||||||
|
|
||||||
talkgroups.List = []*Talkgroup{}
|
talkgroups.List = []*Talkgroup{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,13 @@ func (unit *Unit) FromMap(m map[string]interface{}) {
|
||||||
|
|
||||||
type Units struct {
|
type Units struct {
|
||||||
List []*Unit
|
List []*Unit
|
||||||
mutex sync.RWMutex
|
mutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUnits() *Units {
|
func NewUnits() *Units {
|
||||||
return &Units{
|
return &Units{
|
||||||
List: []*Unit{},
|
List: []*Unit{},
|
||||||
mutex: sync.RWMutex{},
|
mutex: sync.Mutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +88,9 @@ func (units *Units) FromMap(f []interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Units) Merge(units *Units) {
|
func (u *Units) Merge(units *Units) {
|
||||||
|
units.mutex.Lock()
|
||||||
|
defer units.mutex.Unlock()
|
||||||
|
|
||||||
for _, v := range units.List {
|
for _, v := range units.List {
|
||||||
u.Add(v.Id, v.Label)
|
u.Add(v.Id, v.Label)
|
||||||
}
|
}
|
||||||
|
|
@ -99,8 +102,8 @@ func (units *Units) Read(db *Database, systemId uint) error {
|
||||||
rows *sql.Rows
|
rows *sql.Rows
|
||||||
)
|
)
|
||||||
|
|
||||||
units.mutex.RLock()
|
units.mutex.Lock()
|
||||||
defer units.mutex.RUnlock()
|
defer units.mutex.Unlock()
|
||||||
|
|
||||||
units.List = []*Unit{}
|
units.List = []*Unit{}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,4 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
const Version = "6.1.6"
|
const Version = "6.1.7"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue