mirror of
https://github.com/balzack/databag.git
synced 2025-04-20 16:45:25 +00:00
passing ice params through webapp
This commit is contained in:
parent
8e2e0d6a6c
commit
de043e1f36
26
doc/api.oa3
26
doc/api.oa3
@ -3855,7 +3855,15 @@ components:
|
||||
type: string
|
||||
pushSupported:
|
||||
type: boolean
|
||||
|
||||
enableIce:
|
||||
type: boolean
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
type: string
|
||||
icePassword:
|
||||
type: string
|
||||
|
||||
Seal:
|
||||
type: object
|
||||
required:
|
||||
@ -3904,7 +3912,9 @@ components:
|
||||
type: boolean
|
||||
seal:
|
||||
$ref: '#/components/schemas/Seal'
|
||||
|
||||
enableIce:
|
||||
type: boolean
|
||||
|
||||
AccountProfile:
|
||||
type: object
|
||||
required:
|
||||
@ -4614,6 +4624,12 @@ components:
|
||||
keepAlive:
|
||||
type: integer
|
||||
format: int32
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
type: string
|
||||
icePassword:
|
||||
type: string
|
||||
|
||||
Ring:
|
||||
type: object
|
||||
@ -4629,6 +4645,12 @@ components:
|
||||
index:
|
||||
type: integer
|
||||
format: int32
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
type: string
|
||||
icePassword:
|
||||
type: string
|
||||
|
||||
securitySchemes:
|
||||
|
||||
|
@ -61,6 +61,9 @@ func AddCall(w http.ResponseWriter, r *http.Request) {
|
||||
// allocate bridge
|
||||
callerToken := hex.EncodeToString(callerBin);
|
||||
calleeToken := hex.EncodeToString(calleeBin);
|
||||
iceUrl := getStrConfigValue(CNFIceUrl, "")
|
||||
iceUsername := getStrConfigValue(CNFIceUsername, "")
|
||||
icePassword := getStrConfigValue(CNFIcePassword, "")
|
||||
bridgeRelay.AddBridge(account.ID, callId, cardId, callerToken, calleeToken);
|
||||
|
||||
// create response
|
||||
@ -69,6 +72,9 @@ func AddCall(w http.ResponseWriter, r *http.Request) {
|
||||
CardId: cardId,
|
||||
CallerToken: callerToken,
|
||||
CalleeToken: calleeToken,
|
||||
IceUrl: iceUrl,
|
||||
IceUsername: iceUsername,
|
||||
IcePassword: icePassword,
|
||||
KeepAlive: BridgeKeepAlive,
|
||||
}
|
||||
WriteResponse(w, call);
|
||||
|
@ -36,6 +36,7 @@ func GetAccountStatus(w http.ResponseWriter, r *http.Request) {
|
||||
status.ForwardingAddress = account.Forward
|
||||
status.Searchable = account.Searchable
|
||||
status.Sealable = true
|
||||
status.EnableIce = getBoolConfigValue(CNFEnableIce, false)
|
||||
status.PushEnabled = session.PushEnabled
|
||||
status.Seal = seal
|
||||
WriteResponse(w, status)
|
||||
|
@ -22,6 +22,10 @@ func GetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
config.EnableVideo = getBoolConfigValue(CNFEnableVideo, true)
|
||||
config.KeyType = getStrConfigValue(CNFKeyType, APPRSA4096)
|
||||
config.PushSupported = getBoolConfigValue(CNFPushSupported, true)
|
||||
config.EnableIce = getBoolConfigValue(CNFEnableIce, false)
|
||||
config.IceUrl = getStrConfigValue(CNFIceUrl, "")
|
||||
config.IceUsername = getStrConfigValue(CNFIceUsername, "")
|
||||
config.IcePassword = getStrConfigValue(CNFIcePassword, "")
|
||||
|
||||
WriteResponse(w, config)
|
||||
}
|
||||
|
@ -82,6 +82,38 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert push supported
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"bool_value"}),
|
||||
}).Create(&store.Config{ConfigID: CNFEnableIce, BoolValue: config.EnableIce}).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert key type
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"str_value"}),
|
||||
}).Create(&store.Config{ConfigID: CNFIceUrl, StrValue: config.IceUrl}).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert key type
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"str_value"}),
|
||||
}).Create(&store.Config{ConfigID: CNFIceUsername, StrValue: config.IceUsername}).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert key type
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"str_value"}),
|
||||
}).Create(&store.Config{ConfigID: CNFIcePassword, StrValue: config.IcePassword}).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@ -89,5 +121,27 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// increment revision of all account data
|
||||
var accounts []*store.Account
|
||||
if err := store.DB.Find(&accounts).Error; err != nil {
|
||||
ErrMsg(err);
|
||||
return
|
||||
}
|
||||
err = store.DB.Transaction(func(tx *gorm.DB) error {
|
||||
for _, account := range accounts {
|
||||
if res := tx.Model(account).Update("account_revision", account.AccountRevision+1).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
ErrMsg(err);
|
||||
return
|
||||
}
|
||||
for _, account := range accounts {
|
||||
SetStatus(account)
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
@ -129,6 +129,9 @@ func SetRing(card *store.Card, ring Ring) {
|
||||
var phone Phone
|
||||
phone.CallID = ring.CallID
|
||||
phone.CalleeToken = ring.CalleeToken
|
||||
phone.IceUrl = ring.IceUrl
|
||||
phone.IceUsername = ring.IceUsername
|
||||
phone.IcePassword = ring.IcePassword
|
||||
phone.CardID = card.CardSlot.CardSlotID
|
||||
var a Activity
|
||||
a.Phone = ☎
|
||||
|
@ -45,6 +45,19 @@ const CNFEnableVideo = "enable_video"
|
||||
//CNFKeyType specifies the type of key to use for identity
|
||||
const CNFKeyType = "key_type"
|
||||
|
||||
//CNFEnableIce specifies whether webrtc is enabled
|
||||
const CNFEnableIce = "enable_ice"
|
||||
|
||||
//CNFIceUrl specifies the ice candidate url
|
||||
const CNFIceUrl = "ice_url"
|
||||
|
||||
//CNFIceUrl specifies the ice candidate username
|
||||
const CNFIceUsername = "ice_username"
|
||||
|
||||
//CNFIceUrl specifies the ice candidate url
|
||||
const CNFIcePassword = "ice_password"
|
||||
|
||||
|
||||
func getStrConfigValue(configID string, empty string) string {
|
||||
var config store.Config
|
||||
err := store.DB.Where("config_id = ?", configID).First(&config).Error
|
||||
|
@ -61,6 +61,5 @@ func SetCredentials(r *http.Request, login string) {
|
||||
func ParseRequest(r *http.Request, w http.ResponseWriter, obj interface{}) error {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, APPBodyLimit)
|
||||
dec := json.NewDecoder(r.Body)
|
||||
dec.DisallowUnknownFields()
|
||||
return dec.Decode(&obj)
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ type AccountStatus struct {
|
||||
Sealable bool `json:"sealable"`
|
||||
|
||||
Seal *Seal `json:"seal,omitempty"`
|
||||
|
||||
EnableIce bool `json:"enableIce"`
|
||||
}
|
||||
|
||||
//Announce initial message sent on websocket
|
||||
@ -354,6 +356,14 @@ type NodeConfig struct {
|
||||
|
||||
EnableVideo bool `json:"enableVideo"`
|
||||
|
||||
EnableIce bool `json:"enableIce"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
|
||||
IcePassword string `json:"icePassword"`
|
||||
|
||||
KeyType string `json:"keyType"`
|
||||
|
||||
AccountStorage int64 `json:"accountStorage"`
|
||||
@ -422,6 +432,12 @@ type Phone struct {
|
||||
CallID string `json:"callId"`
|
||||
|
||||
CalleeToken string `json:"calleeToken"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
|
||||
IcePassword string `json:"icePassword"`
|
||||
}
|
||||
|
||||
//Seal key for channel sealing
|
||||
@ -522,7 +538,11 @@ type Call struct {
|
||||
|
||||
KeepAlive int32 `json:"keepAlive"`
|
||||
|
||||
SturnPort int32 `json:"sturnPort"`
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
|
||||
IcePassword string `json:"icePassword"`
|
||||
}
|
||||
|
||||
type Ring struct {
|
||||
@ -532,4 +552,10 @@ type Ring struct {
|
||||
CalleeToken string `json:"calleeToken"`
|
||||
|
||||
Index int32 `json:"index"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
|
||||
IcePassword string `json:"icePassword"`
|
||||
}
|
||||
|
@ -373,9 +373,9 @@ export function useRingContext() {
|
||||
|
||||
// create call
|
||||
const call = await addCall(access.current, cardId);
|
||||
const { id, keepAlive, callerToken, calleeToken } = call;
|
||||
const { id, keepAlive, callerToken, calleeToken, iceUrl, iceUsername, icePassword } = call;
|
||||
try {
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
@ -397,7 +397,7 @@ export function useRingContext() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
@ -127,20 +127,51 @@ export function Dashboard() {
|
||||
<Switch onChange={(e) => actions.setPushSupported(e)} size="small"
|
||||
defaultChecked={true} checked={state.pushSupported} />
|
||||
</div>
|
||||
<div className="field label">
|
||||
<span>Topic Content:</span>
|
||||
</div>
|
||||
<Tooltip placement="topLeft" title="Allows images to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Image Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableImage(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableImage} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Allows for audio to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Audio Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableAudio(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableAudio} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Allows videos to be posted and processed in topics">
|
||||
<div className="field">
|
||||
<div>Enable Video Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableVideo(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableVideo} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Tooltip placement="topLeft" title="Enabled audio and video calls to contacts">
|
||||
<div className="field label">
|
||||
<div>Enable WebRTC calls: </div>
|
||||
<Switch onChange={(e) => actions.setEnableIce(e)} size="small"
|
||||
defaultChecked={false} checked={state.enableIce} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="field">
|
||||
<div>Enable Image Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableImage(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableImage} />
|
||||
<div>WebRTC Server URL: </div>
|
||||
<Input placeholder="turn:ip:port?transport=udp" onChange={(e) => actions.setIceUrl(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUrl} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>Enable Audio Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableAudio(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableAudio} />
|
||||
<div>WebRTC Username: </div>
|
||||
<Input placeholder="username" onChange={(e) => actions.setIceUsername(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUsername} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>Enable Video Queue: </div>
|
||||
<Switch onChange={(e) => actions.setEnableVideo(e)} size="small"
|
||||
defaultChecked={true} checked={state.enableVideo} />
|
||||
<div>WebRTC Password: </div>
|
||||
<Input placeholder="password" onChange={(e) => actions.setIcePassword(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.icePassword} />
|
||||
</div>
|
||||
</SettingsLayout>
|
||||
</Modal>
|
||||
|
@ -86,6 +86,12 @@ export const AlertIcon = styled.div`
|
||||
export const SettingsLayout = styled(Space)`
|
||||
width: 100%;
|
||||
|
||||
.label {
|
||||
border-top: 1px solid ${Colors.divider};
|
||||
padding-top: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.field {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
|
@ -17,6 +17,10 @@ export function useDashboard() {
|
||||
enableImage: null,
|
||||
enableAudio: null,
|
||||
enableVideo: null,
|
||||
enableIce: null,
|
||||
iceUrl: null,
|
||||
iceUsername: null,
|
||||
icePassword: null,
|
||||
|
||||
configError: false,
|
||||
accountsError: false,
|
||||
@ -87,6 +91,18 @@ export function useDashboard() {
|
||||
setEnableVideo: (enableVideo) => {
|
||||
updateState({ enableVideo });
|
||||
},
|
||||
setEnableIce: (enableIce) => {
|
||||
updateState({ enableIce });
|
||||
},
|
||||
setIceUrl: (iceUrl) => {
|
||||
updateState({ iceUrl });
|
||||
},
|
||||
setIceUsername: (iceUsername) => {
|
||||
updateState({ iceUsername });
|
||||
},
|
||||
setIcePassword: (icePassword) => {
|
||||
updateState({ icePassword });
|
||||
},
|
||||
setShowSettings: (value) => {
|
||||
updateState({ showSettings: value });
|
||||
},
|
||||
@ -101,9 +117,9 @@ export function useDashboard() {
|
||||
if (!state.busy) {
|
||||
updateState({ busy: true });
|
||||
try {
|
||||
const { domain, keyType, accountStorage, pushSupported, enableImage, enableAudio, enableVideo } = state;
|
||||
const { domain, keyType, accountStorage, pushSupported, enableImage, enableAudio, enableVideo, enableIce, iceUrl, iceUsername, icePassword } = state;
|
||||
const storage = accountStorage * 1073741824;
|
||||
const config = { domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, pushSupported };
|
||||
const config = { domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, pushSupported, enableIce, iceUrl, iceUsername, icePassword };
|
||||
await setNodeConfig(app.state.adminToken, config);
|
||||
updateState({ busy: false, showSettings: false });
|
||||
}
|
||||
@ -119,9 +135,9 @@ export function useDashboard() {
|
||||
const syncConfig = async () => {
|
||||
try {
|
||||
const config = await getNodeConfig(app.state.adminToken);
|
||||
const { storage, domain, keyType, pushSupported, enableImage, enableAudio, enableVideo } = config;
|
||||
const { storage, domain, keyType, pushSupported, enableImage, enableAudio, enableVideo, enableIce, iceUrl, iceUsername, icePassword } = config;
|
||||
const accountStorage = Math.ceil(storage / 1073741824);
|
||||
updateState({ configError: false, domain, accountStorage, keyType, enableImage, enableAudio, enableVideo, pushSupported });
|
||||
updateState({ configError: false, domain, accountStorage, keyType, enableImage, enableAudio, enableVideo, pushSupported, enableIce, iceUrl, iceUsername, icePassword });
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
|
@ -72,7 +72,7 @@ export function Cards({ closeCards, openContact, openChannel, openListing }) {
|
||||
{ state.cards.length > 0 && (
|
||||
<List local={{ emptyText: '' }} itemLayout="horizontal" dataSource={state.cards} gutter="0"
|
||||
renderItem={item => (
|
||||
<CardItem item={item} tooltip={state.tooltip} resync={() => actions.resync(item.cardId)}
|
||||
<CardItem item={item} enableIce={state.enableIce} tooltip={state.tooltip} resync={() => actions.resync(item.cardId)}
|
||||
open={() => openContact(item.guid)} message={() => message(item.cardId)}
|
||||
call={() => call(item)} />
|
||||
)} />
|
||||
|
@ -6,7 +6,7 @@ import { Logo } from 'logo/Logo';
|
||||
import { Tooltip } from 'antd';
|
||||
import { MessageOutlined, PhoneOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
export function CardItem({ item, tooltip, resync, open, call, message }) {
|
||||
export function CardItem({ item, tooltip, enableIce, resync, open, call, message }) {
|
||||
|
||||
const onResync = (e) => {
|
||||
e.stopPropagation();
|
||||
@ -48,9 +48,11 @@ export function CardItem({ item, tooltip, resync, open, call, message }) {
|
||||
<Tooltip className="option" placement="left" title="message contact">
|
||||
<MessageOutlined onClick={onMessage} />
|
||||
</Tooltip>
|
||||
<Tooltip className="option" placement="left" title="call contact">
|
||||
<PhoneOutlined onClick={onCall} />
|
||||
</Tooltip>
|
||||
{ enableIce && (
|
||||
<Tooltip className="option" placement="left" title="call contact">
|
||||
<PhoneOutlined onClick={onCall} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</ComOptions>
|
||||
)}
|
||||
{ item.status === 'connected' && (
|
||||
|
@ -3,6 +3,7 @@ import { CardContext } from 'context/CardContext';
|
||||
import { ViewportContext } from 'context/ViewportContext';
|
||||
import { StoreContext } from 'context/StoreContext';
|
||||
import { ChannelContext } from 'context/ChannelContext';
|
||||
import { AccountContext } from 'context/AccountContext';
|
||||
import { RingContext } from 'context/RingContext';
|
||||
|
||||
export function useCards() {
|
||||
@ -13,10 +14,12 @@ export function useCards() {
|
||||
tooltip: false,
|
||||
sorted: false,
|
||||
display: 'small',
|
||||
enableIce: false,
|
||||
cards: [],
|
||||
});
|
||||
|
||||
const ring = useContext(RingContext);
|
||||
const account = useContext(AccountContext);
|
||||
const card = useContext(CardContext);
|
||||
const channel = useContext(ChannelContext);
|
||||
const store = useContext(StoreContext);
|
||||
@ -31,6 +34,11 @@ export function useCards() {
|
||||
updateState({ display });
|
||||
}, [viewport.state]);
|
||||
|
||||
useEffect(() => {
|
||||
const { enableIce } = account.state?.status || {};
|
||||
updateState({ enableIce });
|
||||
}, [account.state]);
|
||||
|
||||
useEffect(() => {
|
||||
const contacts = Array.from(card.state.cards.values()).map(item => {
|
||||
const profile = item?.data?.cardProfile;
|
||||
|
Loading…
x
Reference in New Issue
Block a user