mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
live backend setup
This commit is contained in:
committed by
Matt Hill
parent
c232ee6a81
commit
09c85b79c3
@@ -4,6 +4,8 @@ import { RouteReuseStrategy } from '@angular/router';
|
|||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { ApiService } from './services/api/api.service'
|
import { ApiService } from './services/api/api.service'
|
||||||
import { MockApiService } from './services/api/mock-api.service'
|
import { MockApiService } from './services/api/mock-api.service'
|
||||||
|
import { LiveApiService } from './services/api/live-api.service'
|
||||||
|
import { HttpService } from './services/api/http.service'
|
||||||
|
|
||||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||||
import * as config from './config/config'
|
import * as config from './config/config'
|
||||||
@@ -23,9 +25,14 @@ import { AppRoutingModule } from './app-routing.module';
|
|||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
{
|
{
|
||||||
provide: ApiService ,
|
provide: ApiService ,
|
||||||
useFactory: () => {
|
useFactory: (http: HttpService) => {
|
||||||
return new MockApiService()
|
if(config.config.useMocks) {
|
||||||
|
return new MockApiService()
|
||||||
|
} else {
|
||||||
|
return new LiveApiService(http)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
deps: [HttpService]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
|||||||
178
setup-wizard/src/app/services/api/http.service.ts
Normal file
178
setup-wizard/src/app/services/api/http.service.ts
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||||
|
import { Observable, from, interval, race, Subject } from 'rxjs'
|
||||||
|
import { map, take } from 'rxjs/operators'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class HttpService {
|
||||||
|
private unauthorizedApiResponse$ = new Subject()
|
||||||
|
fullUrl: string
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private readonly http: HttpClient,
|
||||||
|
) {
|
||||||
|
const port = window.location.port
|
||||||
|
this.fullUrl = `${window.location.protocol}//${window.location.hostname}:${port}`
|
||||||
|
}
|
||||||
|
|
||||||
|
watchUnauth$ (): Observable<{ }> {
|
||||||
|
return this.unauthorizedApiResponse$.asObservable()
|
||||||
|
}
|
||||||
|
|
||||||
|
async rpcRequest<T> (rpcOpts: RPCOptions): Promise<T> {
|
||||||
|
rpcOpts.params = rpcOpts.params || { }
|
||||||
|
const httpOpts = {
|
||||||
|
method: Method.POST,
|
||||||
|
body: rpcOpts,
|
||||||
|
url: `this.fullUrl`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.httpRequest<RPCResponse<T>>(httpOpts)
|
||||||
|
|
||||||
|
if (isRpcError(res)) {
|
||||||
|
if (res.error.code === 34) this.unauthorizedApiResponse$.next(true)
|
||||||
|
throw new RpcError(res.error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRpcSuccess(res)) return res.result
|
||||||
|
}
|
||||||
|
|
||||||
|
async httpRequest<T> (httpOpts: HttpOptions): Promise<T> {
|
||||||
|
if (httpOpts.withCredentials !== false) {
|
||||||
|
httpOpts.withCredentials = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlIsRelative = httpOpts.url.startsWith('/')
|
||||||
|
const url = urlIsRelative ?
|
||||||
|
this.fullUrl + httpOpts.url :
|
||||||
|
httpOpts.url
|
||||||
|
|
||||||
|
Object.keys(httpOpts.params || { }).forEach(key => {
|
||||||
|
if (httpOpts.params[key] === undefined) {
|
||||||
|
delete httpOpts.params[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
responseType: httpOpts.responseType || 'json',
|
||||||
|
body: httpOpts.body,
|
||||||
|
observe: 'events',
|
||||||
|
reportProgress: false,
|
||||||
|
withCredentials: httpOpts.withCredentials,
|
||||||
|
headers: httpOpts.headers,
|
||||||
|
params: httpOpts.params,
|
||||||
|
timeout: httpOpts.timeout,
|
||||||
|
} as any
|
||||||
|
|
||||||
|
let req: Observable<{ body: T }>
|
||||||
|
switch (httpOpts.method) {
|
||||||
|
case Method.GET: req = this.http.get(url, options) as any; break
|
||||||
|
case Method.POST: req = this.http.post(url, httpOpts.body, options) as any; break
|
||||||
|
case Method.PUT: req = this.http.put(url, httpOpts.body, options) as any; break
|
||||||
|
case Method.PATCH: req = this.http.patch(url, httpOpts.body, options) as any; break
|
||||||
|
case Method.DELETE: req = this.http.delete(url, options) as any; break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (httpOpts.timeout ? withTimeout(req, httpOpts.timeout) : req)
|
||||||
|
.toPromise()
|
||||||
|
.then(res => res.body)
|
||||||
|
.catch(e => { throw new HttpError(e) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RpcError (e: RPCError['error']): void {
|
||||||
|
const { code, message, data } = e
|
||||||
|
|
||||||
|
this.code = code
|
||||||
|
this.message = message
|
||||||
|
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
this.details = e.data
|
||||||
|
} else {
|
||||||
|
this.details = data.details
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function HttpError (e: HttpErrorResponse): void {
|
||||||
|
const { status, statusText } = e
|
||||||
|
|
||||||
|
this.code = status
|
||||||
|
this.message = statusText
|
||||||
|
this.details = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRpcError<Error, Result> (arg: { error: Error } | { result: Result}): arg is { error: Error } {
|
||||||
|
return !!(arg as any).error
|
||||||
|
}
|
||||||
|
|
||||||
|
function isRpcSuccess<Error, Result> (arg: { error: Error } | { result: Result}): arg is { result: Result } {
|
||||||
|
return !!(arg as any).result
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Method {
|
||||||
|
GET = 'GET',
|
||||||
|
POST = 'POST',
|
||||||
|
PUT = 'PUT',
|
||||||
|
PATCH = 'PATCH',
|
||||||
|
DELETE = 'DELETE',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RPCOptions {
|
||||||
|
method: string
|
||||||
|
// @TODO what are valid params? object, bool?
|
||||||
|
params?: {
|
||||||
|
[param: string]: string | number | boolean | object | string[] | number[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RPCBase {
|
||||||
|
jsonrpc: '2.0'
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RPCRequest<T> extends RPCBase {
|
||||||
|
method: string
|
||||||
|
params?: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RPCSuccess<T> extends RPCBase {
|
||||||
|
result: T
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RPCError extends RPCBase {
|
||||||
|
error: {
|
||||||
|
code: number,
|
||||||
|
message: string
|
||||||
|
data?: {
|
||||||
|
details: string
|
||||||
|
} | string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RPCResponse<T> = RPCSuccess<T> | RPCError
|
||||||
|
|
||||||
|
type HttpError = HttpErrorResponse & { error: { code: string, message: string } }
|
||||||
|
|
||||||
|
export interface HttpOptions {
|
||||||
|
method: Method
|
||||||
|
url: string
|
||||||
|
headers?: HttpHeaders | {
|
||||||
|
[header: string]: string | string[]
|
||||||
|
}
|
||||||
|
params?: HttpParams | {
|
||||||
|
[param: string]: string | string[]
|
||||||
|
}
|
||||||
|
responseType?: 'json' | 'text'
|
||||||
|
withCredentials?: boolean
|
||||||
|
body?: any
|
||||||
|
timeout?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
function withTimeout<U> (req: Observable<U>, timeout: number): Observable<U> {
|
||||||
|
return race(
|
||||||
|
from(req.toPromise()), // this guarantees it only emits on completion, intermediary emissions are suppressed.
|
||||||
|
interval(timeout).pipe(take(1), map(() => { throw new Error('timeout') })),
|
||||||
|
)
|
||||||
|
}
|
||||||
75
setup-wizard/src/app/services/api/live-api.service.ts
Normal file
75
setup-wizard/src/app/services/api/live-api.service.ts
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { pauseFor } from '../state.service'
|
||||||
|
import { ApiService } from './api.service'
|
||||||
|
import { HttpService } from './http.service'
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class LiveApiService extends ApiService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly http: HttpService
|
||||||
|
) { super() }
|
||||||
|
|
||||||
|
async verifyProductKey(key) {
|
||||||
|
await pauseFor(2000)
|
||||||
|
return {
|
||||||
|
"is-recovering": false,
|
||||||
|
"tor-address": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDataTransferProgress() {
|
||||||
|
tries = Math.min(tries + 1, 4)
|
||||||
|
return {
|
||||||
|
'bytes-transfered': tries,
|
||||||
|
'total-bytes': 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEmbassyDrives() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
logicalname: 'Name1',
|
||||||
|
labels: ['label 1', 'label 2'],
|
||||||
|
capacity: 1600.66666,
|
||||||
|
used: 200.1255312,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logicalname: 'Name2',
|
||||||
|
labels: [],
|
||||||
|
capacity: 1600.01234,
|
||||||
|
used: 0.00,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRecoveryDrives() {
|
||||||
|
await pauseFor(2000)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
logicalname: 'Name1',
|
||||||
|
version: '0.3.3',
|
||||||
|
name: 'My Embassy'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
logicalname: 'Name2',
|
||||||
|
version: '0.2.7',
|
||||||
|
name: 'My Embassy'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyRecoveryPassword(logicalname, password) {
|
||||||
|
await pauseFor(2000)
|
||||||
|
return password.length > 8
|
||||||
|
}
|
||||||
|
|
||||||
|
async setupEmbassy (setupInfo) {
|
||||||
|
await pauseFor(2000)
|
||||||
|
return { "tor-address": 'asdfasdfasdf.onion' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tries = 0
|
||||||
Reference in New Issue
Block a user