...
This commit is contained in:
7
libwip/clients/livekit/.heroscript
Normal file
7
libwip/clients/livekit/.heroscript
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
!!hero_code.generate_client
|
||||
name:'livekit'
|
||||
classname:'LivekitClient'
|
||||
singleton:0
|
||||
default:1
|
||||
active:0
|
||||
152
libwip/clients/livekit/access_token.v
Normal file
152
libwip/clients/livekit/access_token.v
Normal file
@@ -0,0 +1,152 @@
|
||||
module livekit
|
||||
|
||||
// import time
|
||||
// import rand
|
||||
// import crypto.hmac
|
||||
// import crypto.sha256
|
||||
// import encoding.base64
|
||||
// import json
|
||||
|
||||
// // Define AccessTokenOptions struct
|
||||
// pub struct AccessTokenOptions {
|
||||
// pub mut:
|
||||
// ttl int | string // TTL in seconds or a time span (e.g., '2d', '5h')
|
||||
// name string // Display name for the participant
|
||||
// identity string // Identity of the user
|
||||
// metadata string // Custom metadata to be passed to participants
|
||||
// }
|
||||
|
||||
// // Struct representing grants
|
||||
// pub struct ClaimGrants {
|
||||
// pub mut:
|
||||
// video VideoGrant
|
||||
// iss string
|
||||
// exp i64
|
||||
// nbf int
|
||||
// sub string
|
||||
// name string
|
||||
// }
|
||||
|
||||
// // VideoGrant struct placeholder
|
||||
// pub struct VideoGrant {
|
||||
// pub mut:
|
||||
// room string
|
||||
// room_join bool @[json: 'roomJoin']
|
||||
// can_publish bool @[json: 'canPublish']
|
||||
// can_publish_data bool @[json: 'canPublishData']
|
||||
// can_subscribe bool @[json: 'canSubscribe']
|
||||
// }
|
||||
|
||||
// // SIPGrant struct placeholder
|
||||
// struct SIPGrant {}
|
||||
|
||||
// // AccessToken class
|
||||
// pub struct AccessToken {
|
||||
// mut:
|
||||
// api_key string
|
||||
// api_secret string
|
||||
// grants ClaimGrants
|
||||
// identity string
|
||||
// ttl int | string
|
||||
// }
|
||||
|
||||
// // Constructor for AccessToken
|
||||
// pub fn new_access_token(api_key string, api_secret string, options AccessTokenOptions) !AccessToken {
|
||||
// if api_key == '' || api_secret == '' {
|
||||
// return error('API key and API secret must be set')
|
||||
// }
|
||||
|
||||
// ttl := if options.ttl is int { options.ttl } else { 21600 } // Default TTL of 6 hours (21600 seconds)
|
||||
|
||||
// return AccessToken{
|
||||
// api_key: api_key
|
||||
// api_secret: api_secret
|
||||
// identity: options.identity
|
||||
// ttl: ttl
|
||||
// grants: ClaimGrants{
|
||||
// exp: time.now().unix()+ttl
|
||||
// iss: api_key
|
||||
// sub: options.name
|
||||
// name: options.name
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Method to add a video grant to the token
|
||||
// pub fn (mut token AccessToken) add_video_grant(grant VideoGrant) {
|
||||
// token.grants.video = grant
|
||||
// }
|
||||
|
||||
// // Method to generate a JWT token
|
||||
// pub fn (token AccessToken) to_jwt() !string {
|
||||
// // Create JWT payload
|
||||
// payload := json.encode(token.grants)
|
||||
|
||||
// println('payload: ${payload}')
|
||||
|
||||
// // Create JWT header
|
||||
// header := '{"alg":"HS256","typ":"JWT"}'
|
||||
|
||||
// // Encode header and payload in base64
|
||||
// header_encoded := base64.url_encode_str(header)
|
||||
// payload_encoded := base64.url_encode_str(payload)
|
||||
|
||||
// // Create the unsigned token
|
||||
// unsigned_token := '${header_encoded}.${payload_encoded}'
|
||||
|
||||
// // Create the HMAC-SHA256 signature
|
||||
// signature := hmac.new(token.api_secret.bytes(), unsigned_token.bytes(), sha256.sum, sha256.block_size)
|
||||
|
||||
// // Encode the signature in base64
|
||||
// signature_encoded := base64.url_encode(signature)
|
||||
|
||||
// // Create the final JWT
|
||||
// jwt := '${unsigned_token}.${signature_encoded}'
|
||||
// return jwt
|
||||
// }
|
||||
|
||||
// // TokenVerifier class
|
||||
// pub struct TokenVerifier {
|
||||
// api_key string
|
||||
// api_secret string
|
||||
// }
|
||||
|
||||
// // Constructor for TokenVerifier
|
||||
// pub fn new_token_verifier(api_key string, api_secret string) !TokenVerifier {
|
||||
// if api_key == '' || api_secret == '' {
|
||||
// return error('API key and API secret must be set')
|
||||
// }
|
||||
// return TokenVerifier{
|
||||
// api_key: api_key
|
||||
// api_secret: api_secret
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Method to verify the JWT token
|
||||
// pub fn (verifier TokenVerifier) verify(token string) !ClaimGrants {
|
||||
// // Split the token into parts
|
||||
// parts := token.split('.')
|
||||
// if parts.len != 3 {
|
||||
// return error('Invalid token')
|
||||
// }
|
||||
|
||||
// // Decode header, payload, and signature
|
||||
// payload_encoded := parts[1]
|
||||
// signature_encoded := parts[2]
|
||||
|
||||
// // Recompute the HMAC-SHA256 signature
|
||||
// unsigned_token := '${parts[0]}.${parts[1]}'
|
||||
// expected_signature := hmac.new(verifier.api_secret.bytes(), unsigned_token.bytes(), sha256.sum, sha256.block_size)
|
||||
// expected_signature_encoded := base64.url_encode(expected_signature)
|
||||
|
||||
// // Verify the signature
|
||||
// if signature_encoded != expected_signature_encoded {
|
||||
// return error('Invalid token signature')
|
||||
// }
|
||||
|
||||
// // Decode the payload
|
||||
// payload_json := base64.url_decode_str(payload_encoded)
|
||||
|
||||
// // Parse and return the claims as ClaimGrants
|
||||
// return json.decode(ClaimGrants, payload_json)
|
||||
// }
|
||||
37
libwip/clients/livekit/client.v
Normal file
37
libwip/clients/livekit/client.v
Normal file
@@ -0,0 +1,37 @@
|
||||
module livekit
|
||||
|
||||
import net.http
|
||||
import json
|
||||
import time
|
||||
|
||||
fn (mut c LivekitClient) post(path string, body any) !http.Response {
|
||||
mut token := c.new_access_token(
|
||||
identity: 'api'
|
||||
name: 'API User'
|
||||
ttl: 10 * 60 // 10 minutes
|
||||
)!
|
||||
token.add_video_grant(VideoGrant{
|
||||
room_create: true
|
||||
room_admin: true
|
||||
room_list: true
|
||||
})
|
||||
jwt := token.to_jwt()!
|
||||
|
||||
mut header := http.new_header()
|
||||
header.add('Authorization', 'Bearer ' + jwt)!
|
||||
header.add('Content-Type', 'application/json')!
|
||||
|
||||
url := '${c.url}/${path}'
|
||||
data := json.encode(body)
|
||||
mut req := http.Request{
|
||||
method: .post
|
||||
url: url
|
||||
header: header
|
||||
data: data
|
||||
}
|
||||
resp := http.fetch(req)!
|
||||
if resp.status_code != 200 {
|
||||
return error('failed to execute request: ${resp.body}')
|
||||
}
|
||||
return resp
|
||||
}
|
||||
37
libwip/clients/livekit/client_mgmt.v
Normal file
37
libwip/clients/livekit/client_mgmt.v
Normal file
@@ -0,0 +1,37 @@
|
||||
module livekit
|
||||
|
||||
// import incubaid.herolib.data.caching
|
||||
import os
|
||||
|
||||
// const CACHING_METHOD = caching.CachingMethod.once_per_process
|
||||
|
||||
fn _init() ! {
|
||||
if caching.is_set(key: 'livekit_clients') {
|
||||
return
|
||||
}
|
||||
caching.set[map[string]LivekitClient](
|
||||
key: 'livekit_clients'
|
||||
val: map[string]LivekitClient{}
|
||||
)!
|
||||
}
|
||||
|
||||
fn _get() !map[string]LivekitClient {
|
||||
_init()!
|
||||
return caching.get[map[string]LivekitClient](key: 'livekit_clients')!
|
||||
}
|
||||
|
||||
pub fn get(name string) !LivekitClient {
|
||||
mut clients := _get()!
|
||||
return clients[name] or { return error('livekit client ${name} not found') }
|
||||
}
|
||||
|
||||
pub fn set(client LivekitClient) ! {
|
||||
mut clients := _get()!
|
||||
clients[client.name] = client
|
||||
caching.set[map[string]LivekitClient](key: 'livekit_clients', val: clients)!
|
||||
}
|
||||
|
||||
pub fn exists(name string) !bool {
|
||||
mut clients := _get()!
|
||||
return name in clients
|
||||
}
|
||||
18
libwip/clients/livekit/data.v
Normal file
18
libwip/clients/livekit/data.v
Normal file
@@ -0,0 +1,18 @@
|
||||
module livekit
|
||||
|
||||
pub struct SendDataArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
data []u8
|
||||
kind DataPacket_Kind
|
||||
destination_sids []string
|
||||
}
|
||||
|
||||
pub enum DataPacket_Kind {
|
||||
reliable
|
||||
lossy
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) send_data(args SendDataArgs) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/SendData', args)!
|
||||
}
|
||||
95
libwip/clients/livekit/egress.v
Normal file
95
libwip/clients/livekit/egress.v
Normal file
@@ -0,0 +1,95 @@
|
||||
module livekit
|
||||
|
||||
import json
|
||||
|
||||
pub struct EgressInfo {
|
||||
pub mut:
|
||||
egress_id string
|
||||
room_id string
|
||||
status string
|
||||
started_at i64
|
||||
ended_at i64
|
||||
error string
|
||||
}
|
||||
|
||||
pub struct StartRoomCompositeEgressArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
layout string
|
||||
audio_only bool
|
||||
video_only bool
|
||||
custom_base_url string
|
||||
}
|
||||
|
||||
pub struct StartTrackCompositeEgressArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
audio_track_id string
|
||||
video_track_id string
|
||||
}
|
||||
|
||||
pub struct StartWebEgressArgs {
|
||||
pub mut:
|
||||
url string
|
||||
audio_only bool
|
||||
video_only bool
|
||||
}
|
||||
|
||||
pub struct UpdateStreamArgs {
|
||||
pub mut:
|
||||
add_output_urls []string
|
||||
remove_output_urls []string
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) start_room_composite_egress(args StartRoomCompositeEgressArgs) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/StartRoomCompositeEgress', args)!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) start_track_composite_egress(args StartTrackCompositeEgressArgs) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/StartTrackCompositeEgress', args)!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) start_web_egress(args StartWebEgressArgs) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/StartWebEgress', args)!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) update_layout(egress_id string, layout string) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/UpdateLayout', {
|
||||
'egress_id': egress_id
|
||||
'layout': layout
|
||||
})!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) update_stream(egress_id string, args UpdateStreamArgs) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/UpdateStream', {
|
||||
'egress_id': egress_id
|
||||
'add_output_urls': args.add_output_urls
|
||||
'remove_output_urls': args.remove_output_urls
|
||||
})!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) list_egress(room_name string) ![]EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/ListEgress', {
|
||||
'room_name': room_name
|
||||
})!
|
||||
egress_infos := json.decode[[]EgressInfo](resp.body)!
|
||||
return egress_infos
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) stop_egress(egress_id string) !EgressInfo {
|
||||
mut resp := c.post('twirp/livekit.Egress/StopEgress', {
|
||||
'egress_id': egress_id
|
||||
})!
|
||||
egress_info := json.decode[EgressInfo](resp.body)!
|
||||
return egress_info
|
||||
}
|
||||
7
libwip/clients/livekit/factory.v
Normal file
7
libwip/clients/livekit/factory.v
Normal file
@@ -0,0 +1,7 @@
|
||||
module livekit
|
||||
|
||||
pub fn new(client Client) Client {
|
||||
return Client{
|
||||
...client
|
||||
}
|
||||
}
|
||||
141
libwip/clients/livekit/ingress.v
Normal file
141
libwip/clients/livekit/ingress.v
Normal file
@@ -0,0 +1,141 @@
|
||||
module livekit
|
||||
|
||||
import json
|
||||
|
||||
pub struct IngressInfo {
|
||||
pub mut:
|
||||
ingress_id string
|
||||
name string
|
||||
stream_key string
|
||||
url string
|
||||
input_type IngressInput
|
||||
audio IngressAudioOptions
|
||||
video IngressVideoOptions
|
||||
state IngressState
|
||||
}
|
||||
|
||||
pub enum IngressInput {
|
||||
rtmp_input
|
||||
whip_input
|
||||
}
|
||||
|
||||
pub struct IngressAudioOptions {
|
||||
pub mut:
|
||||
name string
|
||||
source TrackSource
|
||||
preset AudioPreset
|
||||
}
|
||||
|
||||
pub struct IngressVideoOptions {
|
||||
pub mut:
|
||||
name string
|
||||
source TrackSource
|
||||
preset VideoPreset
|
||||
}
|
||||
|
||||
pub enum TrackSource {
|
||||
camera
|
||||
microphone
|
||||
screen_share
|
||||
screen_share_audio
|
||||
}
|
||||
|
||||
pub enum AudioPreset {
|
||||
opus_stereo_96kbps
|
||||
opus_mono_64kbps
|
||||
}
|
||||
|
||||
pub enum VideoPreset {
|
||||
h264_720p_30fps_3mbps
|
||||
h264_1080p_30fps_4_5mbps
|
||||
h264_540p_25fps_2mbps
|
||||
}
|
||||
|
||||
pub struct IngressState {
|
||||
pub mut:
|
||||
status IngressStatus
|
||||
error string
|
||||
video InputVideoState
|
||||
audio InputAudioState
|
||||
room_id string
|
||||
started_at i64
|
||||
}
|
||||
|
||||
pub enum IngressStatus {
|
||||
endpoint_inactive
|
||||
endpoint_buffering
|
||||
endpoint_publishing
|
||||
}
|
||||
|
||||
pub struct InputVideoState {
|
||||
pub mut:
|
||||
mime_type string
|
||||
width u32
|
||||
height u32
|
||||
framerate u32
|
||||
}
|
||||
|
||||
pub struct InputAudioState {
|
||||
pub mut:
|
||||
mime_type string
|
||||
channels u32
|
||||
sample_rate u32
|
||||
}
|
||||
|
||||
pub struct CreateIngressArgs {
|
||||
pub mut:
|
||||
name string
|
||||
room_name string
|
||||
participant_identity string
|
||||
participant_name string
|
||||
input_type IngressInput
|
||||
audio IngressAudioOptions
|
||||
video IngressVideoOptions
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) create_ingress(args CreateIngressArgs) !IngressInfo {
|
||||
mut resp := c.post('twirp/livekit.Ingress/CreateIngress', args)!
|
||||
ingress_info := json.decode[IngressInfo](resp.body)!
|
||||
return ingress_info
|
||||
}
|
||||
|
||||
pub struct UpdateIngressArgs {
|
||||
pub mut:
|
||||
ingress_id string
|
||||
name string
|
||||
room_name string
|
||||
participant_identity string
|
||||
participant_name string
|
||||
audio IngressAudioOptions
|
||||
video IngressVideoOptions
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) update_ingress(args UpdateIngressArgs) !IngressInfo {
|
||||
mut resp := c.post('twirp/livekit.Ingress/UpdateIngress', {
|
||||
'ingress_id': args.ingress_id
|
||||
'name': args.name
|
||||
'room_name': args.room_name
|
||||
'participant_identity': args.participant_identity
|
||||
'participant_name': args.participant_name
|
||||
'audio': args.audio
|
||||
'video': args.video
|
||||
})!
|
||||
ingress_info := json.decode[IngressInfo](resp.body)!
|
||||
return ingress_info
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) list_ingress(room_name string) ![]IngressInfo {
|
||||
mut resp := c.post('twirp/livekit.Ingress/ListIngress', {
|
||||
'room_name': room_name
|
||||
})!
|
||||
ingress_infos := json.decode[[]IngressInfo](resp.body)!
|
||||
return ingress_infos
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) delete_ingress(ingress_id string) !IngressInfo {
|
||||
mut resp := c.post('twirp/livekit.Ingress/DeleteIngress', {
|
||||
'ingress_id': ingress_id
|
||||
})!
|
||||
ingress_info := json.decode[IngressInfo](resp.body)!
|
||||
return ingress_info
|
||||
}
|
||||
140
libwip/clients/livekit/livekit_factory_.v
Normal file
140
libwip/clients/livekit/livekit_factory_.v
Normal file
@@ -0,0 +1,140 @@
|
||||
module livekit
|
||||
|
||||
import incubaid.herolib.core.base
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.ui.console
|
||||
import json
|
||||
|
||||
__global (
|
||||
livekit_global map[string]&LivekitClient
|
||||
livekit_default string
|
||||
)
|
||||
|
||||
/////////FACTORY
|
||||
|
||||
@[params]
|
||||
pub struct ArgsGet {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
fromdb bool // will load from filesystem
|
||||
create bool // default will not create if not exist
|
||||
}
|
||||
|
||||
pub fn new(args ArgsGet) !&LivekitClient {
|
||||
mut obj := LivekitClient{
|
||||
name: args.name
|
||||
}
|
||||
set(obj)!
|
||||
return get(name: args.name)!
|
||||
}
|
||||
|
||||
pub fn get(args ArgsGet) !&LivekitClient {
|
||||
mut context := base.context()!
|
||||
livekit_default = args.name
|
||||
if args.fromdb || args.name !in livekit_global {
|
||||
mut r := context.redis()!
|
||||
if r.hexists('context:livekit', args.name)! {
|
||||
data := r.hget('context:livekit', args.name)!
|
||||
if data.len == 0 {
|
||||
print_backtrace()
|
||||
return error('LivekitClient with name: livekit does not exist, prob bug.')
|
||||
}
|
||||
mut obj := json.decode(LivekitClient, data)!
|
||||
set_in_mem(obj)!
|
||||
} else {
|
||||
if args.create {
|
||||
new(args)!
|
||||
} else {
|
||||
print_backtrace()
|
||||
return error("LivekitClient with name 'livekit' does not exist")
|
||||
}
|
||||
}
|
||||
return get(name: args.name)! // no longer from db nor create
|
||||
}
|
||||
return livekit_global[args.name] or {
|
||||
print_backtrace()
|
||||
return error('could not get config for livekit with name:livekit')
|
||||
}
|
||||
}
|
||||
|
||||
// register the config for the future
|
||||
pub fn set(o LivekitClient) ! {
|
||||
mut o2 := set_in_mem(o)!
|
||||
livekit_default = o2.name
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hset('context:livekit', o2.name, json.encode(o2))!
|
||||
}
|
||||
|
||||
// does the config exists?
|
||||
pub fn exists(args ArgsGet) !bool {
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
return r.hexists('context:livekit', args.name)!
|
||||
}
|
||||
|
||||
pub fn delete(args ArgsGet) ! {
|
||||
mut context := base.context()!
|
||||
mut r := context.redis()!
|
||||
r.hdel('context:livekit', args.name)!
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct ArgsList {
|
||||
pub mut:
|
||||
fromdb bool // will load from filesystem
|
||||
}
|
||||
|
||||
// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem
|
||||
pub fn list(args ArgsList) ![]&LivekitClient {
|
||||
mut res := []&LivekitClient{}
|
||||
mut context := base.context()!
|
||||
if args.fromdb {
|
||||
// reset what is in mem
|
||||
livekit_global = map[string]&LivekitClient{}
|
||||
livekit_default = ''
|
||||
}
|
||||
if args.fromdb {
|
||||
mut r := context.redis()!
|
||||
mut l := r.hkeys('context:livekit')!
|
||||
|
||||
for name in l {
|
||||
res << get(name: name, fromdb: true)!
|
||||
}
|
||||
return res
|
||||
} else {
|
||||
// load from memory
|
||||
for _, client in livekit_global {
|
||||
res << client
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// only sets in mem, does not set as config
|
||||
fn set_in_mem(o LivekitClient) !LivekitClient {
|
||||
mut o2 := obj_init(o)!
|
||||
livekit_global[o2.name] = &o2
|
||||
livekit_default = o2.name
|
||||
return o2
|
||||
}
|
||||
|
||||
pub fn play(mut plbook PlayBook) ! {
|
||||
if !plbook.exists(filter: 'livekit.') {
|
||||
return
|
||||
}
|
||||
mut install_actions := plbook.find(filter: 'livekit.configure')!
|
||||
if install_actions.len > 0 {
|
||||
for mut install_action in install_actions {
|
||||
heroscript := install_action.heroscript()
|
||||
mut obj2 := heroscript_loads(heroscript)!
|
||||
set(obj2)!
|
||||
install_action.done = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// switch instance to be used for livekit
|
||||
pub fn switch(name string) {
|
||||
livekit_default = name
|
||||
}
|
||||
44
libwip/clients/livekit/livekit_model.v
Normal file
44
libwip/clients/livekit/livekit_model.v
Normal file
@@ -0,0 +1,44 @@
|
||||
module livekit
|
||||
|
||||
import incubaid.herolib.data.paramsparser
|
||||
import incubaid.herolib.data.encoderhero
|
||||
import os
|
||||
|
||||
pub const version = '0.0.0'
|
||||
const singleton = false
|
||||
const default = true
|
||||
|
||||
@[heap]
|
||||
pub struct LivekitClient {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
url string @[required]
|
||||
api_key string @[required]
|
||||
api_secret string @[required; secret]
|
||||
}
|
||||
|
||||
// your checking & initialization code if needed
|
||||
fn obj_init(mycfg_ LivekitClient) !LivekitClient {
|
||||
mut mycfg := mycfg_
|
||||
if mycfg.url == '' {
|
||||
return error('url needs to be filled in for ${mycfg.name}')
|
||||
}
|
||||
if mycfg.api_key == '' {
|
||||
return error('api_key needs to be filled in for ${mycfg.name}')
|
||||
}
|
||||
if mycfg.api_secret == '' {
|
||||
return error('api_secret needs to be filled in for ${mycfg.name}')
|
||||
}
|
||||
return mycfg
|
||||
}
|
||||
|
||||
/////////////NORMALLY NO NEED TO TOUCH
|
||||
|
||||
pub fn heroscript_dumps(obj LivekitClient) !string {
|
||||
return encoderhero.encode[LivekitClient](obj)!
|
||||
}
|
||||
|
||||
pub fn heroscript_loads(heroscript string) !LivekitClient {
|
||||
mut obj := encoderhero.decode[LivekitClient](heroscript)!
|
||||
return obj
|
||||
}
|
||||
65
libwip/clients/livekit/participant.v
Normal file
65
libwip/clients/livekit/participant.v
Normal file
@@ -0,0 +1,65 @@
|
||||
module livekit
|
||||
|
||||
import json
|
||||
|
||||
pub struct ParticipantInfo {
|
||||
pub mut:
|
||||
sid string
|
||||
identity string
|
||||
state string
|
||||
metadata string
|
||||
joined_at i64
|
||||
name string
|
||||
version u32
|
||||
permission string
|
||||
region string
|
||||
publisher bool
|
||||
}
|
||||
|
||||
pub struct UpdateParticipantArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
identity string
|
||||
metadata string
|
||||
permission string
|
||||
}
|
||||
|
||||
pub struct MutePublishedTrackArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
identity string
|
||||
track_sid string
|
||||
muted bool
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) list_participants(room_name string) ![]ParticipantInfo {
|
||||
mut resp := c.post('twirp/livekit.RoomService/ListParticipants', {
|
||||
'room': room_name
|
||||
})!
|
||||
participants := json.decode[[]ParticipantInfo](resp.body)!
|
||||
return participants
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) get_participant(room_name string, identity string) !ParticipantInfo {
|
||||
mut resp := c.post('twirp/livekit.RoomService/GetParticipant', {
|
||||
'room': room_name
|
||||
'identity': identity
|
||||
})!
|
||||
participant := json.decode[ParticipantInfo](resp.body)!
|
||||
return participant
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) remove_participant(room_name string, identity string) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/RemoveParticipant', {
|
||||
'room': room_name
|
||||
'identity': identity
|
||||
})!
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) update_participant(args UpdateParticipantArgs) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/UpdateParticipant', args)!
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) mute_published_track(args MutePublishedTrackArgs) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/MutePublishedTrack', args)!
|
||||
}
|
||||
167
libwip/clients/livekit/play.v
Normal file
167
libwip/clients/livekit/play.v
Normal file
@@ -0,0 +1,167 @@
|
||||
module livekit
|
||||
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.core.texttools
|
||||
import incubaid.herolib.ui.console
|
||||
|
||||
pub fn play(mut plbook PlayBook) ! {
|
||||
if !plbook.exists(filter: 'livekit.') {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle livekit.init - configure the client
|
||||
if plbook.exists_once(filter: 'livekit.init') {
|
||||
mut action := plbook.get(filter: 'livekit.init')!
|
||||
mut p := action.params
|
||||
|
||||
name := texttools.name_fix(p.get_default('name', 'default')!)
|
||||
url := p.get('url')!
|
||||
api_key := p.get('api_key')!
|
||||
api_secret := p.get('api_secret')!
|
||||
|
||||
mut client := LivekitClient{
|
||||
name: name
|
||||
url: url
|
||||
api_key: api_key
|
||||
api_secret: api_secret
|
||||
}
|
||||
|
||||
set(client)!
|
||||
console.print_header('LiveKit client "${name}" configured')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle room creation
|
||||
mut room_create_actions := plbook.find(filter: 'livekit.room_create')!
|
||||
for mut action in room_create_actions {
|
||||
mut p := action.params
|
||||
|
||||
client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
room_name := p.get('name')!
|
||||
empty_timeout := p.get_u32_default('empty_timeout', 300)!
|
||||
max_participants := p.get_u32_default('max_participants', 50)!
|
||||
metadata := p.get_default('metadata', '')!
|
||||
|
||||
mut client := get(name: client_name)!
|
||||
|
||||
room := client.create_room(
|
||||
name: room_name
|
||||
empty_timeout: empty_timeout
|
||||
max_participants: max_participants
|
||||
metadata: metadata
|
||||
)!
|
||||
|
||||
console.print_header('Room "${room_name}" created successfully')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle room deletion
|
||||
mut room_delete_actions := plbook.find(filter: 'livekit.room_delete')!
|
||||
for mut action in room_delete_actions {
|
||||
mut p := action.params
|
||||
|
||||
client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
room_name := p.get('name')!
|
||||
|
||||
mut client := get(name: client_name)!
|
||||
client.delete_room(room_name)!
|
||||
|
||||
console.print_header('Room "${room_name}" deleted successfully')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle participant removal
|
||||
mut participant_remove_actions := plbook.find(filter: 'livekit.participant_remove')!
|
||||
for mut action in participant_remove_actions {
|
||||
mut p := action.params
|
||||
|
||||
client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
room_name := p.get('room')!
|
||||
identity := p.get('identity')!
|
||||
|
||||
mut client := get(name: client_name)!
|
||||
client.remove_participant(room_name, identity)!
|
||||
|
||||
console.print_header('Participant "${identity}" removed from room "${room_name}"')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle participant mute/unmute
|
||||
mut participant_mute_actions := plbook.find(filter: 'livekit.participant_mute')!
|
||||
for mut action in participant_mute_actions {
|
||||
mut p := action.params
|
||||
|
||||
client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
room_name := p.get('room')!
|
||||
identity := p.get('identity')!
|
||||
track_sid := p.get('track_sid')!
|
||||
muted := p.get_default_true('muted')
|
||||
|
||||
mut client := get(name: client_name)!
|
||||
client.mute_published_track(
|
||||
room_name: room_name
|
||||
identity: identity
|
||||
track_sid: track_sid
|
||||
muted: muted
|
||||
)!
|
||||
|
||||
status := if muted { 'muted' } else { 'unmuted' }
|
||||
console.print_header('Track "${track_sid}" ${status} for participant "${identity}"')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle room metadata update
|
||||
mut room_update_actions := plbook.find(filter: 'livekit.room_update')!
|
||||
for mut action in room_update_actions {
|
||||
mut p := action.params
|
||||
|
||||
client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
room_name := p.get('room')!
|
||||
metadata := p.get('metadata')!
|
||||
|
||||
mut client := get(name: client_name)!
|
||||
client.update_room_metadata(
|
||||
room_name: room_name
|
||||
metadata: metadata
|
||||
)!
|
||||
|
||||
console.print_header('Room "${room_name}" metadata updated')
|
||||
action.done = true
|
||||
}
|
||||
|
||||
// Handle access token generation
|
||||
mut token_create_actions := plbook.find(filter: 'livekit.token_create')!
|
||||
// for mut action in token_create_actions {
|
||||
// mut p := action.params
|
||||
|
||||
// client_name := texttools.name_fix(p.get_default('client', 'default')!)
|
||||
// identity := p.get('identity')!
|
||||
// name := p.get_default('name', identity)!
|
||||
// room := p.get_default('room', '')!
|
||||
// ttl := p.get_int_default('ttl', 21600)!
|
||||
// can_publish := p.get_default_false('can_publish')
|
||||
// can_subscribe := p.get_default_true('can_subscribe')
|
||||
// can_publish_data := p.get_default_false('can_publish_data')
|
||||
|
||||
// mut client := get(name: client_name)!
|
||||
|
||||
// mut token := client.new_access_token(
|
||||
// identity: identity
|
||||
// name: name
|
||||
// ttl: ttl
|
||||
// )!
|
||||
|
||||
// token.add_video_grant(VideoGrant{
|
||||
// room: room
|
||||
// room_join: true
|
||||
// can_publish: can_publish
|
||||
// can_subscribe: can_subscribe
|
||||
// can_publish_data: can_publish_data
|
||||
// })
|
||||
|
||||
// jwt := token.to_jwt()!
|
||||
// console.print_header('Access token generated for "${identity}"')
|
||||
// console.print_debug('Token: ${jwt}')
|
||||
// action.done = true
|
||||
// }
|
||||
}
|
||||
22
libwip/clients/livekit/readme.md
Normal file
22
libwip/clients/livekit/readme.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# livekit
|
||||
|
||||
To get started
|
||||
|
||||
```v
|
||||
|
||||
import incubaid.herolib.clients.livekit
|
||||
|
||||
mut client:= livekit.get()!
|
||||
|
||||
client...
|
||||
|
||||
```
|
||||
|
||||
## example heroscript
|
||||
|
||||
```hero
|
||||
!!livekit.configure
|
||||
livekit_url:''
|
||||
livekit_api_key:''
|
||||
livekit_api_secret:''
|
||||
```
|
||||
49
libwip/clients/livekit/room.v
Normal file
49
libwip/clients/livekit/room.v
Normal file
@@ -0,0 +1,49 @@
|
||||
module livekit
|
||||
|
||||
import json
|
||||
import net.http
|
||||
|
||||
pub struct Room {
|
||||
pub mut:
|
||||
sid string
|
||||
name string
|
||||
empty_timeout u32
|
||||
max_participants u32
|
||||
creation_time i64
|
||||
turn_password string
|
||||
enabled_codecs []string
|
||||
metadata string
|
||||
num_participants u32
|
||||
num_connected_participants u32
|
||||
active_recording bool
|
||||
}
|
||||
|
||||
pub struct CreateRoomArgs {
|
||||
pub mut:
|
||||
name string
|
||||
empty_timeout u32
|
||||
max_participants u32
|
||||
metadata string
|
||||
}
|
||||
|
||||
pub struct UpdateRoomMetadataArgs {
|
||||
pub mut:
|
||||
room_name string
|
||||
metadata string
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) create_room(args CreateRoomArgs) !Room {
|
||||
mut resp := c.post('twirp/livekit.RoomService/CreateRoom', args)!
|
||||
room := json.decode[Room](resp.body)!
|
||||
return room
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) delete_room(room_name string) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/DeleteRoom', {
|
||||
'room': room_name
|
||||
})!
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) update_room_metadata(args UpdateRoomMetadataArgs) ! {
|
||||
_ = c.post('twirp/livekit.RoomService/UpdateRoomMetadata', args)!
|
||||
}
|
||||
33
libwip/clients/livekit/room_model.v
Normal file
33
libwip/clients/livekit/room_model.v
Normal file
@@ -0,0 +1,33 @@
|
||||
module livekit
|
||||
|
||||
import net.http
|
||||
import json
|
||||
|
||||
pub struct Codec {
|
||||
pub:
|
||||
fmtp_line string
|
||||
mime string
|
||||
}
|
||||
|
||||
pub struct Version {
|
||||
pub:
|
||||
ticks u64
|
||||
unix_micro string
|
||||
}
|
||||
|
||||
// pub struct Room {
|
||||
// pub:
|
||||
// active_recording bool
|
||||
// creation_time string
|
||||
// departure_timeout int
|
||||
// empty_timeout int
|
||||
// enabled_codecs []Codec
|
||||
// max_participants int
|
||||
// metadata string
|
||||
// name string
|
||||
// num_participants int
|
||||
// num_publishers int
|
||||
// sid string
|
||||
// turn_password string
|
||||
// version Version
|
||||
// }
|
||||
25
libwip/clients/livekit/room_test.v
Normal file
25
libwip/clients/livekit/room_test.v
Normal file
@@ -0,0 +1,25 @@
|
||||
module livekit
|
||||
|
||||
import os
|
||||
import incubaid.herolib.osal.core as osal
|
||||
|
||||
const env_file = '${os.dir(@FILE)}/.env'
|
||||
|
||||
fn testsuite_begin() ! {
|
||||
if os.exists(env_file) {
|
||||
osal.load_env_file(env_file)!
|
||||
}
|
||||
}
|
||||
|
||||
fn new_test_client() Client {
|
||||
return new(
|
||||
url: os.getenv('LIVEKIT_URL')
|
||||
api_key: os.getenv('LIVEKIT_API_KEY')
|
||||
api_secret: os.getenv('LIVEKIT_API_SECRET')
|
||||
)
|
||||
}
|
||||
|
||||
fn test_client_list_rooms() ! {
|
||||
client := new_test_client()
|
||||
rooms := client.list_rooms()!
|
||||
}
|
||||
199
libwip/clients/livekit/server_client.v
Normal file
199
libwip/clients/livekit/server_client.v
Normal file
@@ -0,0 +1,199 @@
|
||||
module livekit
|
||||
|
||||
import net.http
|
||||
import json
|
||||
|
||||
// // pub struct Client {
|
||||
// // pub:
|
||||
// // host string
|
||||
// // token string
|
||||
// // }
|
||||
|
||||
// // pub struct Room {
|
||||
// // pub mut:
|
||||
// // sid string
|
||||
// // name string
|
||||
// // empty_timeout string
|
||||
// // max_participants string
|
||||
// // creation_time string
|
||||
// // turn_password string
|
||||
// // metadata string
|
||||
// // num_participants u32
|
||||
// // active_recording bool
|
||||
// // }
|
||||
|
||||
// pub struct ParticipantInfo {
|
||||
// pub mut:
|
||||
// sid string
|
||||
// identity string
|
||||
// name string
|
||||
// state string
|
||||
// tracks []TrackInfo
|
||||
// metadata string
|
||||
// joined_at i64
|
||||
// permission ParticipantPermission
|
||||
// is_publisher bool
|
||||
// }
|
||||
|
||||
// pub struct TrackInfo {
|
||||
// pub mut:
|
||||
// sid string
|
||||
// typ string @[json: 'type']
|
||||
// source string
|
||||
// name string
|
||||
// mime_type string
|
||||
// muted bool
|
||||
// width u32
|
||||
// height u32
|
||||
// simulcast bool
|
||||
// disable_dtx bool
|
||||
// layers []VideoLayer
|
||||
// }
|
||||
|
||||
// pub struct ParticipantPermission {
|
||||
// pub mut:
|
||||
// can_subscribe bool
|
||||
// can_publish bool
|
||||
// can_publish_data bool
|
||||
// }
|
||||
|
||||
// pub struct VideoLayer {
|
||||
// pub mut:
|
||||
// quality string
|
||||
// width u32
|
||||
// height u32
|
||||
// }
|
||||
|
||||
// // Helper method to make POST requests to LiveKit API
|
||||
// fn (client Client) make_post_request(url string, body string) !http.Response {
|
||||
// mut headers := http.new_header()
|
||||
// headers.add_custom('Authorization', 'Bearer ${client.token}')!
|
||||
// headers.add_custom('Content-Type', 'application/json')!
|
||||
|
||||
// req := http.Request{
|
||||
// method: http.Method.post
|
||||
// url: url
|
||||
// data: body
|
||||
// header: headers
|
||||
// }
|
||||
// return req.do()!
|
||||
// }
|
||||
|
||||
// pub struct CreateRoomArgs {
|
||||
// pub:
|
||||
// name string
|
||||
// empty_timeout u32
|
||||
// max_participants u32
|
||||
// metadata string
|
||||
// }
|
||||
|
||||
// // RoomService API methods
|
||||
// pub fn (client Client) create_room(args CreateRoomArgs) !Room {
|
||||
// body := json.encode(args)
|
||||
// url := '${client.host}/twirp/livekit.RoomService/CreateRoom'
|
||||
// response := client.make_post_request(url, body)!
|
||||
|
||||
// return json.decode(Room, response.body)!
|
||||
// }
|
||||
|
||||
// // pub fn (client Client) list_rooms(names []string) ![]Room {
|
||||
// // body := json.encode({
|
||||
// // 'names': names
|
||||
// // })
|
||||
// // url := '${client.host}/twirp/livekit.RoomService/ListRooms'
|
||||
// // response := client.make_post_request(url, body)!
|
||||
|
||||
// // return json.decode([]Room, response.body)!
|
||||
// // }
|
||||
|
||||
// pub fn (client Client) delete_room(room_name string) ! {
|
||||
// body := json.encode({
|
||||
// 'room': room_name
|
||||
// })
|
||||
// url := '${client.host}/twirp/livekit.RoomService/DeleteRoom'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
|
||||
// pub fn (client Client) list_participants(room_name string) ![]ParticipantInfo {
|
||||
// body := json.encode({
|
||||
// 'room': room_name
|
||||
// })
|
||||
// url := '${client.host}/twirp/livekit.RoomService/ListParticipants'
|
||||
// response := client.make_post_request(url, body)!
|
||||
|
||||
// return json.decode([]ParticipantInfo, response.body)!
|
||||
// }
|
||||
|
||||
// pub fn (client Client) get_participant(room_name string, identity string) !ParticipantInfo {
|
||||
// body := json.encode({
|
||||
// 'room': room_name
|
||||
// 'identity': identity
|
||||
// })
|
||||
// url := '${client.host}/twirp/livekit.RoomService/GetParticipant'
|
||||
// response := client.make_post_request(url, body)!
|
||||
|
||||
// return json.decode(ParticipantInfo, response.body)!
|
||||
// }
|
||||
|
||||
// pub fn (client Client) remove_participant(room_name string, identity string) ! {
|
||||
// body := json.encode({
|
||||
// 'room': room_name
|
||||
// 'identity': identity
|
||||
// })
|
||||
// url := '${client.host}/twirp/livekit.RoomService/RemoveParticipant'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
|
||||
// pub struct MutePublishedTrackArgs {
|
||||
// pub:
|
||||
// room_name string
|
||||
// identity string
|
||||
// track_sid string
|
||||
// muted bool
|
||||
// }
|
||||
|
||||
// pub fn (client Client) mute_published_track(args MutePublishedTrackArgs) ! {
|
||||
// body := json.encode(args)
|
||||
// url := '${client.host}/twirp/livekit.RoomService/MutePublishedTrack'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
|
||||
// pub struct UpdateParticipantArgs {
|
||||
// pub:
|
||||
// room_name string @[json: 'room']
|
||||
// identity string
|
||||
// metadata string
|
||||
// permission ParticipantPermission
|
||||
// }
|
||||
|
||||
// pub fn (client Client) update_participant(args UpdateParticipantArgs) ! {
|
||||
// body := json.encode(args)
|
||||
// url := '${client.host}/twirp/livekit.RoomService/UpdateParticipant'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
|
||||
// pub struct UpdateRoomMetadataArgs {
|
||||
// pub:
|
||||
// room_name string @[json: 'room']
|
||||
// metadata string
|
||||
// }
|
||||
|
||||
// pub fn (client Client) update_room_metadata(args UpdateRoomMetadataArgs) ! {
|
||||
// body := json.encode(args)
|
||||
// url := '${client.host}/twirp/livekit.RoomService/UpdateRoomMetadata'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
|
||||
// pub struct SendDataArgs {
|
||||
// pub:
|
||||
// room_name string @[json: 'room']
|
||||
// data []u8
|
||||
// kind string
|
||||
// destination_identities []string
|
||||
// }
|
||||
|
||||
// pub fn (client Client) send_data(args SendDataArgs) ! {
|
||||
// body := json.encode(args)
|
||||
// url := '${client.host}/twirp/livekit.RoomService/SendData'
|
||||
// _ := client.make_post_request(url, body)!
|
||||
// }
|
||||
52
libwip/clients/livekit/token.v
Normal file
52
libwip/clients/livekit/token.v
Normal file
@@ -0,0 +1,52 @@
|
||||
module livekit
|
||||
|
||||
// import jwt
|
||||
import time
|
||||
|
||||
pub struct AccessToken {
|
||||
pub mut:
|
||||
api_key string
|
||||
api_secret string
|
||||
identity string
|
||||
name string
|
||||
ttl int
|
||||
video_grant VideoGrant
|
||||
}
|
||||
|
||||
pub struct VideoGrant {
|
||||
pub mut:
|
||||
room_create bool
|
||||
room_admin bool
|
||||
room_join bool
|
||||
room_list bool
|
||||
can_publish bool
|
||||
can_subscribe bool
|
||||
can_publish_data bool
|
||||
room string
|
||||
}
|
||||
|
||||
pub fn (mut c LivekitClient) new_access_token(identity string, name string, ttl int) !AccessToken {
|
||||
return AccessToken{
|
||||
api_key: c.api_key
|
||||
api_secret: c.api_secret
|
||||
identity: identity
|
||||
name: name
|
||||
ttl: ttl
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut t AccessToken) add_video_grant(grant VideoGrant) {
|
||||
t.video_grant = grant
|
||||
}
|
||||
|
||||
pub fn (t AccessToken) to_jwt() !string {
|
||||
mut claims := jwt.new_claims()
|
||||
claims.iss = t.api_key
|
||||
claims.sub = t.identity
|
||||
claims.exp = time.now().unix_time() + t.ttl
|
||||
claims.nbf = time.now().unix_time()
|
||||
claims.iat = time.now().unix_time()
|
||||
claims.name = t.name
|
||||
claims.video = t.video_grant
|
||||
return jwt.encode(claims, t.api_secret, .hs256)
|
||||
}
|
||||
77
libwip/clients/livekit/token_model.v
Normal file
77
libwip/clients/livekit/token_model.v
Normal file
@@ -0,0 +1,77 @@
|
||||
module livekit
|
||||
|
||||
import time
|
||||
import rand
|
||||
import crypto.hmac
|
||||
import crypto.sha256
|
||||
import encoding.base64
|
||||
import json
|
||||
|
||||
// Struct representing grants
|
||||
pub struct ClaimGrants {
|
||||
pub mut:
|
||||
video VideoGrant
|
||||
iss string
|
||||
exp i64
|
||||
nbf int
|
||||
sub string
|
||||
name string
|
||||
}
|
||||
|
||||
// // VideoGrant struct placeholder
|
||||
// pub struct VideoGrant {
|
||||
// pub mut:
|
||||
// room string
|
||||
// room_join bool @[json: 'roomJoin']
|
||||
// room_list bool @[json: 'roomList']
|
||||
// can_publish bool @[json: 'canPublish']
|
||||
// can_publish_data bool @[json: 'canPublishData']
|
||||
// can_subscribe bool @[json: 'canSubscribe']
|
||||
// }
|
||||
|
||||
// SIPGrant struct placeholder
|
||||
struct SIPGrant {}
|
||||
|
||||
// // AccessToken class
|
||||
// pub struct AccessToken {
|
||||
// mut:
|
||||
// api_key string
|
||||
// api_secret string
|
||||
// grants ClaimGrants
|
||||
// identity string
|
||||
// ttl int
|
||||
// }
|
||||
|
||||
// Method to add a video grant to the token
|
||||
// pub fn (mut token AccessToken) add_video_grant(grant VideoGrant) {
|
||||
// token.grants.video = grant
|
||||
// }
|
||||
|
||||
// // Method to generate a JWT token
|
||||
// pub fn (token AccessToken) to_jwt() !string {
|
||||
// // Create JWT payload
|
||||
// payload := json.encode(token.grants)
|
||||
|
||||
// println('payload: ${payload}')
|
||||
|
||||
// // Create JWT header
|
||||
// header := '{"alg":"HS256","typ":"JWT"}'
|
||||
|
||||
// // Encode header and payload in base64
|
||||
// header_encoded := base64.url_encode_str(header)
|
||||
// payload_encoded := base64.url_encode_str(payload)
|
||||
|
||||
// // Create the unsigned token
|
||||
// unsigned_token := '${header_encoded}.${payload_encoded}'
|
||||
|
||||
// // Create the HMAC-SHA256 signature
|
||||
// signature := hmac.new(token.api_secret.bytes(), unsigned_token.bytes(), sha256.sum,
|
||||
// sha256.block_size)
|
||||
|
||||
// // Encode the signature in base64
|
||||
// signature_encoded := base64.url_encode(signature)
|
||||
|
||||
// // Create the final JWT
|
||||
// jwt := '${unsigned_token}.${signature_encoded}'
|
||||
// return jwt
|
||||
// }
|
||||
Reference in New Issue
Block a user