import {
Injectable,
Inject,
} from '@angular/core'
import {
firstValueFrom,
} from 'rxjs'
import {
randomString,
EncryptionHandler,
GcmHandler,
RccRtc,
throwError
} from '@rcc/core'
import {
RccTransmission,
AbstractTransmissionService
} from '@rcc/common'
import {
RtcTransmissionMeta,
isRtcTransmissionMeta,
RtcTransmissionConfig,
isRtcTransmissionConfig,
RTC_SIGNAL_SERVER,
RTC_STUN_SERVERS
} from './rtc-transmission.commons'
//TODO needs rework or removal, see combined
export class RtcTransmission implements RccTransmission{
protected data : unknown
protected url : string
protected channel : string
protected signalServer : string
protected stunServers : string[]
protected key : string
protected encryptionHandler : EncryptionHandler
protected rccRtc : RccRtc
public ready : Promise<void>
constructor(config: RtcTransmissionConfig, encryptionHandler?: EncryptionHandler){
isRtcTransmissionConfig(config, false) || throwError(new Error("RtcTransmission.constructor() invalid config"))
this.data = config.data
this.signalServer = config.signalServer
this.stunServers = config.stunServers
this.channel = randomString(20)
this.ready = this.setup()
}
public async setup() : Promise<void> {
const encryption_setup = await GcmHandler.generate()
this.key = encryption_setup[0]
const encryptionHandler = encryption_setup[1]
const url = this.signalServer
const stunServers = this.stunServers
const channel = this.channel
this.rccRtc = new RccRtc({
url,
channel,
encryptionHandler,
stunServers
})
}
get meta() : any {
return ['rcc-rtc', this.channel, this.key]
}
async start() : Promise<void> {
await this.rccRtc.open({
timeoutPeer: 60*1000,
timeoutConnection: 3*1000
})
await this.rccRtc.send(this.data)
await this.rccRtc.close()
}
async cancel(): Promise<void> {
await this.rccRtc.close()
}
}
@Injectable()
export class RtcTransmissionService extends AbstractTransmissionService {
constructor(
@Inject(RTC_STUN_SERVERS)
protected stunServers : string[],
@Inject(RTC_SIGNAL_SERVER)
protected signalServer : string
){
super()
}
public validateMeta(meta:unknown): boolean {
return isRtcTransmissionMeta(meta)
}
public async setup(data:any) : Promise<RtcTransmission> {
this.stunServers || throwError(new Error("RtcTransmissionService.setup(): missing stun servers. Please use RtcTransmissionServiceModul.forRoot() to set these up."))
this.signalServer || throwError(new Error("RtcTransmissionService.setup(): missing signal server. Please use RtcTransmissionServiceModul.forRoot() to set this up."))
const stunServers = this.stunServers
const signalServer = this.signalServer
const transmission = new RtcTransmission({data, signalServer, stunServers})
await transmission.ready
return transmission
}
public async listen(meta: RtcTransmissionMeta) : Promise<unknown> {
isRtcTransmissionMeta(meta) || throwError(new Error("RtcTransmissionService.listen(): invalid meta data") )
const [channel, key] = meta.slice(1)
const url = this.signalServer
const stunServers = this.stunServers
const encryptionHandler = new GcmHandler(key)
const rccRtc = new RccRtc({url, channel, encryptionHandler, stunServers})
const data = firstValueFrom(rccRtc.data$)
await rccRtc.open({
timeoutPeer: 60*1000,
timeoutConnection: 3*1000
})
const result = await data
await rccRtc.done()
void rccRtc.close()
return result
}
}