Compare commits
9 commits
3573ebcc08
...
eebc3fdae2
Author | SHA1 | Date | |
---|---|---|---|
eebc3fdae2 | |||
50663a561a | |||
6b5e5dbdf1 | |||
38300f247a | |||
e198adb60b | |||
9fc4823159 | |||
f71d9fee0d | |||
2dcbfd0f84 | |||
160da5b246 |
72 changed files with 332 additions and 91 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,6 +4,7 @@ mydb.sql
|
|||
client/calls/
|
||||
!client/calls/.gitkeep
|
||||
/gordio
|
||||
/stillbox
|
||||
/calls
|
||||
Session.vim
|
||||
*.log
|
||||
|
|
6
Makefile
6
Makefile
|
@ -4,15 +4,15 @@ BUILDDATE!=date '+%Y%m%d'
|
|||
LDFLAGS=-ldflags="-X '${VPKG}.Version=${VER}' -X '${VPKG}.Built=${BUILDDATE}'"
|
||||
|
||||
all: checkcalls
|
||||
go build -o gordio ${GOFLAGS} ${LDFLAGS} ./cmd/gordio/
|
||||
go build -o stillbox ${GOFLAGS} ${LDFLAGS} ./cmd/stillbox/
|
||||
go build -o calls ${GOFLAGS} ${LDFLAGS} ./cmd/calls/
|
||||
|
||||
buildpprof:
|
||||
go build -o gordio-pprof ${GOFLAGS} ${LDFLAGS} -tags pprof ./cmd/gordio
|
||||
go build -o stillbox-pprof ${GOFLAGS} ${LDFLAGS} -tags pprof ./cmd/stillbox
|
||||
|
||||
clean:
|
||||
rm -rf client/calls/ && mkdir client/calls && touch client/calls/.gitkeep
|
||||
rm -f gordio calls gordio-pprof
|
||||
rm -f stillbox calls stillbox-pprof
|
||||
|
||||
checkcalls:
|
||||
@test -e client/calls/index.html || make getcalls
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# stillbox
|
||||
|
||||
A Golang scanner call server (`gordio`), with the Calls webapp.
|
||||
A Golang scanner call server.
|
||||
|
||||
**NOTE**
|
||||
|
||||
If this message is still here, the database schema *initial migration* and protobuf definitions are **still subject to change**.
|
||||
|
||||
Once `gordio` is actually usable (but not necessarily feature-complete), I will remove this note, and start using DB migrations and
|
||||
Once `stillbox` is actually usable (but not necessarily feature-complete), I will remove this note, and start using DB migrations and
|
||||
protobuf best practices (i.e. not changing field numbers).
|
||||
|
|
25
client/admin/package-lock.json
generated
25
client/admin/package-lock.json
generated
|
@ -16,6 +16,8 @@
|
|||
"@angular/platform-browser": "^18.2.0",
|
||||
"@angular/platform-browser-dynamic": "^18.2.0",
|
||||
"@angular/router": "^18.2.0",
|
||||
"@ng-icons/core": "^29.6.1",
|
||||
"@ng-icons/ionicons": "^29.6.1",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.10"
|
||||
|
@ -3599,6 +3601,29 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@ng-icons/core": {
|
||||
"version": "29.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-29.6.1.tgz",
|
||||
"integrity": "sha512-PyDLfmBA8rvMm2edQmSHV4fyPz0aImOW6/183YD8tIovDaWyk9imr3v2qSxlc1BjEnE355uPtPLXnvLs5hkEbQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": ">=18.0.0",
|
||||
"@angular/core": ">=18.0.0",
|
||||
"rxjs": "^6.5.3 || ^7.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ng-icons/ionicons": {
|
||||
"version": "29.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@ng-icons/ionicons/-/ionicons-29.6.1.tgz",
|
||||
"integrity": "sha512-+ZIDHjFuqfVTexFfyw5vtasbxqpsQFcur5hKesOzzRqnq6o4KatNsCPjwY8GUoNviY/FKGwPSUXfsWj6YOnoDQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ngtools/webpack": {
|
||||
"version": "18.2.10",
|
||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.10.tgz",
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
"@angular/platform-browser": "^18.2.0",
|
||||
"@angular/platform-browser-dynamic": "^18.2.0",
|
||||
"@angular/router": "^18.2.0",
|
||||
"@ng-icons/core": "^29.6.1",
|
||||
"@ng-icons/ionicons": "^29.6.1",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.10"
|
||||
|
|
0
client/admin/src/app/alerts/alerts.component.css
Normal file
0
client/admin/src/app/alerts/alerts.component.css
Normal file
1
client/admin/src/app/alerts/alerts.component.html
Normal file
1
client/admin/src/app/alerts/alerts.component.html
Normal file
|
@ -0,0 +1 @@
|
|||
<p>alerts works!</p>
|
23
client/admin/src/app/alerts/alerts.component.spec.ts
Normal file
23
client/admin/src/app/alerts/alerts.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AlertsComponent } from './alerts.component';
|
||||
|
||||
describe('AlertsComponent', () => {
|
||||
let component: AlertsComponent;
|
||||
let fixture: ComponentFixture<AlertsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AlertsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AlertsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
client/admin/src/app/alerts/alerts.component.ts
Normal file
12
client/admin/src/app/alerts/alerts.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-alerts',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './alerts.component.html',
|
||||
styleUrl: './alerts.component.css'
|
||||
})
|
||||
export class AlertsComponent {
|
||||
|
||||
}
|
|
@ -1,26 +1,63 @@
|
|||
<div class="navbar bg-base-100">
|
||||
<a class="btn btn-ghost text-xl">Stillbox</a>
|
||||
</div>
|
||||
<div class="drawer lg:drawer-open">
|
||||
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content flex flex-col items-center justify-center">
|
||||
<!-- Page content here -->
|
||||
<div class="container mx-auto px-4">
|
||||
<router-outlet />
|
||||
<!-- Navbar -->
|
||||
<nav class="navbar justify-between bg-base-300">
|
||||
<!-- Logo -->
|
||||
<a class="btn btn-ghost text-lg">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" />
|
||||
</svg>
|
||||
|
||||
</a>
|
||||
|
||||
<!-- Menu for mobile -->
|
||||
<div class="dropdown dropdown-end sm:hidden">
|
||||
<button class="btn btn-ghost">
|
||||
<i class="fa-solid fa-bars text-lg"></i>
|
||||
</button>
|
||||
|
||||
<ul tabindex="0" class="dropdown-content menu z-[1] bg-base-200 p-6 rounded-box shadow w-56 gap-2">
|
||||
<li><a>Item</a></li>
|
||||
<a class="btn btn-sm btn-primary">Do</a>
|
||||
</ul>
|
||||
</div>
|
||||
<label for="my-drawer-2" class="btn btn-primary drawer-button lg:hidden">
|
||||
Open drawer
|
||||
</label>
|
||||
</div>
|
||||
<div class="drawer-side">
|
||||
<label
|
||||
for="my-drawer-2"
|
||||
aria-label="close sidebar"
|
||||
class="drawer-overlay"
|
||||
></label>
|
||||
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
||||
<li><a>Home</a></li>
|
||||
<li><a>Talkgroups</a></li>
|
||||
|
||||
<!-- Menu for desktop -->
|
||||
<ul class="hidden menu sm:menu-horizontal gap-2">
|
||||
<li><a>Item</a></li>
|
||||
<a class="btn btn-sm btn-primary">Do</a>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="flex overflow-hidden relative">
|
||||
<!-- Sidebar -->
|
||||
<aside class="h-screen sticky top-0 flex flex-col overflow-y-auto gap-2 py-6 px-2 bg-base-200">
|
||||
<a class="btn btn-square btn-ghost btn-secondary text-xl" title="Home" routerLink="/home" routerLinkActive="btn-active">
|
||||
<ng-icon name="ionHome"></ng-icon>
|
||||
</a>
|
||||
|
||||
<a routerLink="/calls" routerLinkActive="btn-active" class="btn btn-ghost btn-secondary text-xl" title="Calls">
|
||||
<ng-icon name="ionMegaphoneOutline"></ng-icon>
|
||||
</a>
|
||||
|
||||
<a class="btn btn-square btn-ghost text-xl" title="Talkgroups" routerLink="/talkgroups" routerLinkActive="btn-active">
|
||||
<ng-icon name="ionChatbubbles"></ng-icon>
|
||||
</a>
|
||||
|
||||
<div class="divider my-0"></div>
|
||||
|
||||
<a class="btn btn-square btn-ghost text-xl" title="Incidents" routerLink="/incidents" routerLinkActive="btn-active">
|
||||
<ng-icon name="ionNewspaperOutline"></ng-icon>
|
||||
</a>
|
||||
|
||||
<a class="btn btn-square btn-ghost text-xl" title="Alerts" routerLink="/alerts" routerLinkActive="btn-active">
|
||||
<ng-icon name="ionAlertCircleOutline"></ng-icon>
|
||||
</a>
|
||||
<div class="divider my-0"></div>
|
||||
|
||||
<a class="btn btn-circle btn-ghost text-xl" title="Listen">
|
||||
<ng-icon name="ionRadioOutline"></ng-icon>
|
||||
</a>
|
||||
</aside>
|
||||
<div class="container mx-auto px-4">
|
||||
<router-outlet />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { RouterModule, RouterOutlet, RouterLink } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AuthService } from './login/auth.service';
|
||||
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
import { ionMenuOutline, ionChatbubbles, ionNewspaperOutline, ionAlertCircleOutline, ionRadioOutline, ionHome, ionMegaphoneOutline } from '@ng-icons/ionicons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet],
|
||||
imports: [CommonModule, RouterOutlet, RouterModule, RouterLink, NgIconComponent],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.css',
|
||||
providers: [ provideIcons({ ionMenuOutline, ionChatbubbles, ionNewspaperOutline, ionAlertCircleOutline, ionRadioOutline, ionHome, ionMegaphoneOutline })],
|
||||
})
|
||||
export class AppComponent {
|
||||
auth: AuthService = inject(AuthService);
|
||||
title = 'admin';
|
||||
}
|
||||
|
|
|
@ -2,10 +2,18 @@ import { Routes } from '@angular/router';
|
|||
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { TalkgroupsComponent } from './talkgroups/talkgroups.component';
|
||||
import { CallsComponent } from './calls/calls.component';
|
||||
import { IncidentsComponent } from './incidents/incidents.component';
|
||||
import { AlertsComponent } from './alerts/alerts.component';
|
||||
import { AuthGuard } from './auth.guard';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'talkgroups', component: TalkgroupsComponent },
|
||||
{ path: 'calls', component: CallsComponent },
|
||||
{ path: 'incidents', component: IncidentsComponent },
|
||||
{ path: 'alerts', component: AlertsComponent },
|
||||
];
|
||||
|
|
0
client/admin/src/app/calls/calls.component.css
Normal file
0
client/admin/src/app/calls/calls.component.css
Normal file
1
client/admin/src/app/calls/calls.component.html
Normal file
1
client/admin/src/app/calls/calls.component.html
Normal file
|
@ -0,0 +1 @@
|
|||
<p>calls works!</p>
|
23
client/admin/src/app/calls/calls.component.spec.ts
Normal file
23
client/admin/src/app/calls/calls.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CallsComponent } from './calls.component';
|
||||
|
||||
describe('CallsComponent', () => {
|
||||
let component: CallsComponent;
|
||||
let fixture: ComponentFixture<CallsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CallsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(CallsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
client/admin/src/app/calls/calls.component.ts
Normal file
12
client/admin/src/app/calls/calls.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-calls',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './calls.component.html',
|
||||
styleUrl: './calls.component.css'
|
||||
})
|
||||
export class CallsComponent {
|
||||
|
||||
}
|
|
@ -1 +1,3 @@
|
|||
<p>Hi</p>
|
||||
<p>
|
||||
This will be a dashboard someday.
|
||||
</p>
|
||||
|
|
|
@ -7,4 +7,5 @@ import { Component } from '@angular/core';
|
|||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.css',
|
||||
})
|
||||
export class HomeComponent {}
|
||||
export class HomeComponent {
|
||||
}
|
||||
|
|
0
client/admin/src/app/incidents/incidents.component.css
Normal file
0
client/admin/src/app/incidents/incidents.component.css
Normal file
1
client/admin/src/app/incidents/incidents.component.html
Normal file
1
client/admin/src/app/incidents/incidents.component.html
Normal file
|
@ -0,0 +1 @@
|
|||
<p>incidents works!</p>
|
23
client/admin/src/app/incidents/incidents.component.spec.ts
Normal file
23
client/admin/src/app/incidents/incidents.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { IncidentsComponent } from './incidents.component';
|
||||
|
||||
describe('IncidentsComponent', () => {
|
||||
let component: IncidentsComponent;
|
||||
let fixture: ComponentFixture<IncidentsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [IncidentsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(IncidentsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
client/admin/src/app/incidents/incidents.component.ts
Normal file
12
client/admin/src/app/incidents/incidents.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-incidents',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './incidents.component.html',
|
||||
styleUrl: './incidents.component.css'
|
||||
})
|
||||
export class IncidentsComponent {
|
||||
|
||||
}
|
|
@ -11,11 +11,18 @@ export class Jwt {
|
|||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class APIService {
|
||||
export class AuthService {
|
||||
loggedIn: boolean = false;
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private _router: Router,
|
||||
) {}
|
||||
) {
|
||||
let ssJWT = sessionStorage.getItem('jwt');
|
||||
if (ssJWT) {
|
||||
this.loggedIn = true;
|
||||
this._router.navigateByUrl('/home');
|
||||
}
|
||||
}
|
||||
|
||||
login(username: string, password: string): Observable<HttpResponse<Jwt>> {
|
||||
return this.http
|
||||
|
@ -28,6 +35,7 @@ export class APIService {
|
|||
tap((event) => {
|
||||
if (event.status == 200) {
|
||||
sessionStorage.setItem('jwt', event.body?.jwt.toString() ?? '');
|
||||
this.loggedIn = true;
|
||||
this._router.navigateByUrl('/home');
|
||||
}
|
||||
}),
|
|
@ -8,6 +8,7 @@
|
|||
[(ngModel)]="username"
|
||||
class="grow"
|
||||
placeholder="login"
|
||||
(keyup.enter)="onSubmit()"
|
||||
/>
|
||||
</label>
|
||||
<label class="input input-bordered flex items-center gap-2 mb-2">
|
||||
|
@ -16,6 +17,7 @@
|
|||
[(ngModel)]="password"
|
||||
class="grow"
|
||||
placeholder="password"
|
||||
(keyup.enter)="onSubmit()"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, inject } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { APIService } from '../api.service';
|
||||
import { AuthService } from '../login/auth.service';
|
||||
import { catchError, of } from 'rxjs';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { Router } from '@angular/router';
|
|||
styleUrl: './login.component.css',
|
||||
})
|
||||
export class LoginComponent {
|
||||
apiService: APIService = inject(APIService);
|
||||
apiService: AuthService = inject(AuthService);
|
||||
router: Router = inject(Router);
|
||||
username: string = '';
|
||||
password: string = '';
|
||||
|
|
0
client/admin/src/app/talkgroups/talkgroups.component.css
Normal file
0
client/admin/src/app/talkgroups/talkgroups.component.css
Normal file
|
@ -0,0 +1 @@
|
|||
<p>talkgroups works!</p>
|
23
client/admin/src/app/talkgroups/talkgroups.component.spec.ts
Normal file
23
client/admin/src/app/talkgroups/talkgroups.component.spec.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TalkgroupsComponent } from './talkgroups.component';
|
||||
|
||||
describe('TalkgroupsComponent', () => {
|
||||
let component: TalkgroupsComponent;
|
||||
let fixture: ComponentFixture<TalkgroupsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TalkgroupsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TalkgroupsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
client/admin/src/app/talkgroups/talkgroups.component.ts
Normal file
12
client/admin/src/app/talkgroups/talkgroups.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-talkgroups',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './talkgroups.component.html',
|
||||
styleUrl: './talkgroups.component.css'
|
||||
})
|
||||
export class TalkgroupsComponent {
|
||||
|
||||
}
|
|
@ -9,9 +9,9 @@ import (
|
|||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/internal/version"
|
||||
"dynatron.me/x/stillbox/pkg/gordio"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/admin"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/cmd/serve"
|
||||
"dynatron.me/x/stillbox/pkg/cmd/admin"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ func main() {
|
|||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: common.TimeFormat})
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: gordio.AppName,
|
||||
Use: common.AppName,
|
||||
}
|
||||
rootCmd.PersistentFlags().BoolP("version", "V", false, "show version")
|
||||
cfg := config.New(rootCmd)
|
||||
|
@ -32,7 +32,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
cmds := append([]*cobra.Command{gordio.Command(cfg)}, admin.Command(cfg)...)
|
||||
cmds := append([]*cobra.Command{serve.Command(cfg)}, admin.Command(cfg)...)
|
||||
rootCmd.AddCommand(cmds...)
|
||||
|
||||
err := rootCmd.Execute()
|
|
@ -7,6 +7,8 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const AppName = "stillbox"
|
||||
|
||||
const (
|
||||
TimeFormat = "Jan 2 15:04:05"
|
||||
)
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"dynatron.me/x/stillbox/internal/forms"
|
||||
"dynatron.me/x/stillbox/internal/jsontime"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/alerting"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/alerting"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
@ -3,17 +3,19 @@ package version
|
|||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
)
|
||||
|
||||
var (
|
||||
Name = "gordio"
|
||||
Name = common.AppName
|
||||
Version = "unset"
|
||||
Built = "unset"
|
||||
)
|
||||
|
||||
func String() string {
|
||||
return fmt.Sprintf("gordio %s\nbuilt %s for %s-%s\n",
|
||||
Version, Built, runtime.GOOS, runtime.GOARCH)
|
||||
return fmt.Sprintf("%s %s\nbuilt %s for %s-%s\n",
|
||||
Name, Version, Built, runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
func HttpString(app string) string {
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
"time"
|
||||
|
||||
cl "dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/notify"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/sinks"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/notify"
|
||||
"dynatron.me/x/stillbox/pkg/sinks"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/timeseries"
|
||||
"dynatron.me/x/stillbox/internal/trending"
|
|
@ -13,7 +13,7 @@ import (
|
|||
"dynatron.me/x/stillbox/internal/jsontime"
|
||||
"dynatron.me/x/stillbox/internal/trending"
|
||||
cl "dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
|
@ -8,8 +8,8 @@ import (
|
|||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/internal/jsontime"
|
|
@ -6,7 +6,7 @@ import (
|
|||
"encoding/base64"
|
||||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/rs/zerolog/log"
|
|
@ -4,7 +4,7 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
)
|
||||
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
|
@ -63,6 +63,9 @@ func (a *Auth) AuthMiddleware() func(http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
func (a *Auth) initJWT() {
|
||||
if string(a.cfg.JWTSecret) == "super secret string" {
|
||||
log.Fatal().Msg("JWT secret is the default!")
|
||||
}
|
||||
a.jwt = jwtauth.New("HS256", []byte(a.cfg.JWTSecret), nil)
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/audio"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/auth"
|
||||
"dynatron.me/x/stillbox/pkg/auth"
|
||||
"dynatron.me/x/stillbox/pkg/pb"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
|
|
@ -3,7 +3,7 @@ package calls
|
|||
import (
|
||||
"context"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/pb"
|
||||
)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/ruletime"
|
||||
"dynatron.me/x/stillbox/internal/trending"
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/term"
|
|
@ -1,4 +1,4 @@
|
|||
package gordio
|
||||
package serve
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -6,14 +6,12 @@ import (
|
|||
"os/signal"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/server"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/server"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const AppName = "gordio"
|
||||
|
||||
type ServeOptions struct {
|
||||
cfg *config.Config
|
||||
}
|
||||
|
@ -22,7 +20,7 @@ func Command(cfg *config.Config) *cobra.Command {
|
|||
opts := makeOptions(cfg)
|
||||
serveCmd := &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "starts the" + AppName + " server",
|
||||
Short: "starts the" + common.AppName + " server",
|
||||
PersistentPreRunE: cfg.PreRunE(),
|
||||
RunE: common.RunE(opts),
|
||||
}
|
|
@ -116,7 +116,7 @@ func (c *Config) ReadConfig() error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Info().Str("configPath", c.configPath).Msg("read gordio config")
|
||||
log.Info().Str("configPath", c.configPath).Msg("read config")
|
||||
|
||||
return nil
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
sqlembed "dynatron.me/x/stillbox/sql"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
_ "github.com/golang-migrate/migrate/v4/database/pgx/v5"
|
|
@ -9,7 +9,7 @@ import (
|
|||
|
||||
"dynatron.me/x/stillbox/internal/version"
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/pb"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/pb"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
|
@ -5,7 +5,7 @@ import (
|
|||
stdhttp "net/http"
|
||||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/http"
|
|
@ -10,7 +10,7 @@ import (
|
|||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/rs/zerolog"
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
"dynatron.me/x/stillbox/client"
|
||||
"dynatron.me/x/stillbox/internal/version"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/httprate"
|
||||
|
@ -75,7 +75,7 @@ func (s *Server) clientRoute(r chi.Router, clientRoot fs.FS) {
|
|||
}
|
||||
|
||||
func ServerHeaderAdd(next http.Handler) http.Handler {
|
||||
serverString := version.HttpString("gordio")
|
||||
serverString := version.HttpString(version.Name)
|
||||
hfn := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(serverHeader, serverString)
|
||||
next.ServeHTTP(w, r)
|
|
@ -7,14 +7,14 @@ import (
|
|||
"time"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/alerting"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/auth"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/nexus"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/notify"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/sinks"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/sources"
|
||||
"dynatron.me/x/stillbox/pkg/alerting"
|
||||
"dynatron.me/x/stillbox/pkg/auth"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
"dynatron.me/x/stillbox/pkg/nexus"
|
||||
"dynatron.me/x/stillbox/pkg/notify"
|
||||
"dynatron.me/x/stillbox/pkg/sinks"
|
||||
"dynatron.me/x/stillbox/pkg/sources"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
|
@ -5,7 +5,7 @@ import (
|
|||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/gordio/config"
|
||||
"dynatron.me/x/stillbox/pkg/config"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||
"dynatron.me/x/stillbox/pkg/database"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/rs/zerolog/log"
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/nexus"
|
||||
"dynatron.me/x/stillbox/pkg/nexus"
|
||||
)
|
||||
|
||||
type NexusSink struct {
|
|
@ -8,7 +8,7 @@ import (
|
|||
"dynatron.me/x/stillbox/internal/common"
|
||||
"dynatron.me/x/stillbox/internal/forms"
|
||||
"dynatron.me/x/stillbox/pkg/calls"
|
||||
"dynatron.me/x/stillbox/pkg/gordio/auth"
|
||||
"dynatron.me/x/stillbox/pkg/auth"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
|
@ -6,7 +6,7 @@ sql:
|
|||
gen:
|
||||
go:
|
||||
package: "database"
|
||||
out: "../pkg/gordio/database"
|
||||
out: "../pkg/database"
|
||||
sql_package: "pgx/v5"
|
||||
query_parameter_limit: 3
|
||||
emit_json_tags: true
|
||||
|
|
Loading…
Reference in a new issue