|
|
|
@ -0,0 +1,123 @@
|
|
|
|
|
package servers
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cwtch.im/cwtch/event"
|
|
|
|
|
"cwtch.im/cwtch/model"
|
|
|
|
|
"cwtch.im/cwtch/model/attr"
|
|
|
|
|
"cwtch.im/cwtch/model/constants"
|
|
|
|
|
"cwtch.im/cwtch/peer"
|
|
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
|
|
|
|
"cwtch.im/cwtch/settings"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// ServerList is a json encoded list of servers
|
|
|
|
|
ServerList = event.Field("ServerList")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
// UpdateServerInfo is an event containing a ProfileOnion and a ServerList
|
|
|
|
|
UpdateServerInfo = event.Type("UpdateServerInfo")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Functionality groups some common UI triggered functions for contacts...
|
|
|
|
|
type Functionality struct {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Functionality) NotifySettingsUpdate(settings settings.GlobalSettings) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Functionality) EventsToRegister() []event.Type {
|
|
|
|
|
return []event.Type{event.ProtocolEngineCreated, event.ManifestReceived, event.FileDownloaded}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Functionality) ExperimentsToRegister() []string {
|
|
|
|
|
return []string{constants.GroupsExperiment}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OnEvent handles File Sharing Hooks like Manifest Received and FileDownloaded
|
|
|
|
|
func (f *Functionality) OnEvent(ev event.Event, profile peer.CwtchPeer) {
|
|
|
|
|
if profile.IsFeatureEnabled(constants.GroupsExperiment) {
|
|
|
|
|
switch ev.EventType {
|
|
|
|
|
// keep the UI in sync with the current backend server updates...
|
|
|
|
|
// TODO: do we need a secondary heartbeat for less common updates?
|
|
|
|
|
case event.Heartbeat:
|
|
|
|
|
f.PublishServerUpdate(profile)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Functionality) OnContactRequestValue(profile peer.CwtchPeer, conversation model.Conversation, eventID string, path attr.ScopedZonedPath) {
|
|
|
|
|
// nop
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *Functionality) OnContactReceiveValue(profile peer.CwtchPeer, conversation model.Conversation, path attr.ScopedZonedPath, value string, exists bool) {
|
|
|
|
|
// nopt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FunctionalityGate returns filesharing functionality - gates now happen on function calls.
|
|
|
|
|
func FunctionalityGate() *Functionality {
|
|
|
|
|
return new(Functionality)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ServerKey packages up key information...
|
|
|
|
|
// TODO: Can this be merged with KeyBundle?
|
|
|
|
|
type ServerKey struct {
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
Key string `json:"key"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SyncStatus packages up server sync information...
|
|
|
|
|
type SyncStatus struct {
|
|
|
|
|
StartTime string `json:"startTime"`
|
|
|
|
|
LastMessageTime string `json:"lastMessageTime"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Server encapsulates the information needed to represent a server...
|
|
|
|
|
type Server struct {
|
|
|
|
|
Onion string `json:"onion"`
|
|
|
|
|
Identifier int `json:"identifier"`
|
|
|
|
|
Status string `json:"status"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Keys []ServerKey `json:"keys"`
|
|
|
|
|
SyncProgress SyncStatus `json:"syncProgress"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublishServerUpdate serializes the current list of group servers and publishes an event with this information
|
|
|
|
|
func (f *Functionality) PublishServerUpdate(profile peer.CwtchPeer) {
|
|
|
|
|
serverListForOnion := f.GetServerInfoList(profile)
|
|
|
|
|
serversListBytes, _ := json.Marshal(serverListForOnion)
|
|
|
|
|
profile.PublishEvent(event.NewEvent(UpdateServerInfo, map[event.Field]string{"ProfileOnion": profile.GetOnion(), ServerList: string(serversListBytes)}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetServerInfoList compiles all the information the UI might need regarding all servers..
|
|
|
|
|
func (f *Functionality) GetServerInfoList(profile peer.CwtchPeer) []Server {
|
|
|
|
|
var servers []Server
|
|
|
|
|
for _, server := range profile.GetServers() {
|
|
|
|
|
servers = append(servers, f.GetServerInfo(profile, server))
|
|
|
|
|
}
|
|
|
|
|
return servers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetServerInfo compiles all the information the UI might need regarding a particular server including any verified
|
|
|
|
|
// cryptographic keys
|
|
|
|
|
func (f *Functionality) GetServerInfo(profile peer.CwtchPeer, serverOnion string) Server {
|
|
|
|
|
serverInfo, _ := profile.FetchConversationInfo(serverOnion)
|
|
|
|
|
keyTypes := []model.KeyType{model.KeyTypeServerOnion, model.KeyTypeTokenOnion, model.KeyTypePrivacyPass}
|
|
|
|
|
var serverKeys []ServerKey
|
|
|
|
|
|
|
|
|
|
for _, keyType := range keyTypes {
|
|
|
|
|
if key, has := serverInfo.GetAttribute(attr.PublicScope, attr.ServerKeyZone, string(keyType)); has {
|
|
|
|
|
serverKeys = append(serverKeys, ServerKey{Type: string(keyType), Key: key})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
description, _ := serverInfo.GetAttribute(attr.LocalScope, attr.ServerZone, constants.Description)
|
|
|
|
|
startTimeStr := serverInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.SyncPreLastMessageTime)).ToString()]
|
|
|
|
|
recentTimeStr := serverInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.SyncMostRecentMessageTime)).ToString()]
|
|
|
|
|
syncStatus := SyncStatus{startTimeStr, recentTimeStr}
|
|
|
|
|
|
|
|
|
|
return Server{Onion: serverOnion, Identifier: serverInfo.ID, Status: connections.ConnectionStateName[profile.GetPeerState(serverInfo.Handle)], Keys: serverKeys, Description: description, SyncProgress: syncStatus}
|
|
|
|
|
}
|