Large API Refactor in prep for autobindings #494
111
app/app.go
111
app/app.go
|
@ -35,14 +35,24 @@ type application struct {
|
|||
settings *GlobalSettingsFile
|
||||
}
|
||||
|
||||
func (app *application) IsFeatureEnabled(experiment string) bool {
|
||||
settings := app.ReadSettings()
|
||||
if settings.ExperimentsEnabled {
|
||||
if status, exists := settings.Experiments[experiment]; exists {
|
||||
return status
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
||||
type Application interface {
|
||||
LoadProfiles(password string)
|
||||
CreatePeer(name string, password string, attributes map[attr.ZonedPath]string)
|
||||
// Deprecated in 1.10
|
||||
CreateTaggedPeer(name string, password string, tag string)
|
||||
CreateProfile(name string, password string, autostart bool)
|
||||
|
||||
ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error)
|
||||
DeletePeer(onion string, currentPassword string)
|
||||
EnhancedImportProfile(exportedCwtchFile string, password string) string
|
||||
DeleteProfile(onion string, currentPassword string)
|
||||
AddPeerPlugin(onion string, pluginID plugins.PluginID)
|
||||
|
||||
GetPrimaryBus() event.Manager
|
||||
|
@ -51,11 +61,12 @@ type Application interface {
|
|||
QueryACNVersion()
|
||||
|
||||
ActivateEngines(doListn, doPeers, doServers bool)
|
||||
ActivatePeerEngine(onion string, doListen, doPeers, doServers bool)
|
||||
ActivatePeerEngine(onion string)
|
||||
DeactivatePeerEngine(onion string)
|
||||
|
||||
ReadSettings() GlobalSettings
|
||||
UpdateSettings(settings GlobalSettings)
|
||||
IsFeatureEnabled(experiment string) bool
|
||||
|
||||
ShutdownPeer(string)
|
||||
Shutdown()
|
||||
|
@ -67,8 +78,7 @@ type Application interface {
|
|||
// LoadProfileFn is the function signature for a function in an app that loads a profile
|
||||
type LoadProfileFn func(profile peer.CwtchPeer)
|
||||
|
||||
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
||||
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
||||
func LoadAppSettings(appDirectory string) *GlobalSettingsFile {
|
||||
log.Debugf("NewApp(%v)\n", appDirectory)
|
||||
os.MkdirAll(path.Join(appDirectory, "profiles"), 0700)
|
||||
|
||||
|
@ -79,6 +89,11 @@ func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
|||
if err != nil {
|
||||
log.Errorf("error initializing global settings file %. Global settings might not be loaded or saves", err)
|
||||
}
|
||||
return settings
|
||||
}
|
||||
|
||||
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
||||
func NewApp(acn connectivity.ACN, appDirectory string, settings *GlobalSettingsFile) Application {
|
||||
|
||||
app := &application{engines: make(map[string]connections.Engine), eventBuses: make(map[string]event.Manager), directory: appDirectory, appBus: event.NewEventManager(), settings: settings}
|
||||
app.peers = make(map[string]peer.CwtchPeer)
|
||||
|
@ -110,6 +125,14 @@ func (app *application) UpdateSettings(settings GlobalSettings) {
|
|||
defer app.peerLock.Unlock()
|
||||
for _, profile := range app.peers {
|
||||
profile.UpdateExperiments(settings.ExperimentsEnabled, settings.Experiments)
|
||||
|
||||
// Explicitly toggle blocking/unblocking of unknown connections for profiles
|
||||
// that have been loaded.
|
||||
if settings.BlockUnknownConnections {
|
||||
profile.BlockUnknownConnections()
|
||||
} else {
|
||||
profile.AllowUnknownConnections()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,11 +182,45 @@ func (ap *application) AddPlugin(peerid string, id plugins.PluginID, bus event.M
|
|||
}
|
||||
}
|
||||
|
||||
func (app *application) CreateProfile(name string, password string, autostart bool) {
|
||||
autostartVal := constants.True
|
||||
if !autostart {
|
||||
autostartVal = constants.False
|
||||
}
|
||||
tagVal := constants.ProfileTypeV1Password
|
||||
if password == DefactoPasswordForUnencryptedProfiles {
|
||||
tagVal = constants.ProfileTypeV1DefaultPassword
|
||||
}
|
||||
|
||||
app.CreatePeer(name, password, map[attr.ZonedPath]string{
|
||||
attr.ProfileZone.ConstructZonedPath(constants.Tag): tagVal,
|
||||
attr.ProfileZone.ConstructZonedPath(constants.PeerAutostart): autostartVal,
|
||||
})
|
||||
}
|
||||
|
||||
// Deprecated in 1.10
|
||||
func (app *application) CreateTaggedPeer(name string, password string, tag string) {
|
||||
app.CreatePeer(name, password, map[attr.ZonedPath]string{attr.ProfileZone.ConstructZonedPath(constants.Tag): tag})
|
||||
}
|
||||
|
||||
func (app *application) setupPeer(profile peer.CwtchPeer) {
|
||||
eventBus := event.NewEventManager()
|
||||
app.eventBuses[profile.GetOnion()] = eventBus
|
||||
|
||||
// Initialize the Peer with the Given Event Bus
|
||||
app.peers[profile.GetOnion()] = profile
|
||||
profile.Init(app.eventBuses[profile.GetOnion()])
|
||||
|
||||
// Update the Peer with the Most Recent Experiment State...
|
||||
settings := app.settings.ReadGlobalSettings()
|
||||
profile.UpdateExperiments(settings.ExperimentsEnabled, settings.Experiments)
|
||||
app.registerHooks(profile)
|
||||
|
||||
// Register the Peer With Application Plugins..
|
||||
app.AddPeerPlugin(profile.GetOnion(), plugins.CONNECTIONRETRY) // Now Mandatory
|
||||
|
||||
}
|
||||
|
||||
func (app *application) CreatePeer(name string, password string, attributes map[attr.ZonedPath]string) {
|
||||
app.appmutex.Lock()
|
||||
defer app.appmutex.Unlock()
|
||||
|
@ -177,26 +234,26 @@ func (app *application) CreatePeer(name string, password string, attributes map[
|
|||
return
|
||||
}
|
||||
|
||||
eventBus := event.NewEventManager()
|
||||
app.eventBuses[profile.GetOnion()] = eventBus
|
||||
profile.Init(app.eventBuses[profile.GetOnion()])
|
||||
app.registerHooks(profile)
|
||||
app.peers[profile.GetOnion()] = profile
|
||||
app.setupPeer(profile)
|
||||
|
||||
for zp, val := range attributes {
|
||||
zone, key := attr.ParseZone(zp.ToString())
|
||||
profile.SetScopedZonedAttribute(attr.LocalScope, zone, key, val)
|
||||
}
|
||||
|
||||
app.AddPeerPlugin(profile.GetOnion(), plugins.CONNECTIONRETRY) // Now Mandatory
|
||||
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.True}))
|
||||
}
|
||||
|
||||
func (app *application) DeletePeer(onion string, password string) {
|
||||
log.Debugf("DeletePeer called on %v\n", onion)
|
||||
func (app *application) DeleteProfile(onion string, password string) {
|
||||
log.Debugf("DeleteProfile called on %v\n", onion)
|
||||
app.appmutex.Lock()
|
||||
defer app.appmutex.Unlock()
|
||||
|
||||
// allow a blank password to delete "unencrypted" accounts...
|
||||
if password == "" {
|
||||
password = DefactoPasswordForUnencryptedProfiles
|
||||
}
|
||||
|
||||
if app.peers[onion].CheckPassword(password) {
|
||||
// soft-shutdown
|
||||
app.peers[onion].Shutdown()
|
||||
|
@ -226,6 +283,14 @@ func (app *application) ImportProfile(exportedCwtchFile string, password string)
|
|||
return profile, err
|
||||
}
|
||||
|
||||
func (app *application) EnhancedImportProfile(exportedCwtchFile string, password string) string {
|
||||
_, err := app.ImportProfile(exportedCwtchFile, password)
|
||||
if err == nil {
|
||||
return ""
|
||||
}
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
// LoadProfiles takes a password and attempts to load any profiles it can from storage with it and create Peers for them
|
||||
func (app *application) LoadProfiles(password string) {
|
||||
count := 0
|
||||
|
@ -291,14 +356,8 @@ func (app *application) installProfile(profile peer.CwtchPeer) bool {
|
|||
|
||||
// Only attempt to finalize the profile if we don't have one loaded...
|
||||
if app.peers[profile.GetOnion()] == nil {
|
||||
eventBus := event.NewEventManager()
|
||||
app.eventBuses[profile.GetOnion()] = eventBus
|
||||
profile.Init(app.eventBuses[profile.GetOnion()])
|
||||
app.registerHooks(profile)
|
||||
app.peers[profile.GetOnion()] = profile
|
||||
|
||||
app.AddPeerPlugin(profile.GetOnion(), plugins.CONNECTIONRETRY) // Now Mandatory
|
||||
|
||||
app.setupPeer(profile)
|
||||
// Finalize the Creation of Peer / Notify any Interfaces..
|
||||
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.False}))
|
||||
return true
|
||||
}
|
||||
|
@ -333,7 +392,7 @@ func (app *application) ActivateEngines(doListen, doPeers, doServers bool) {
|
|||
}
|
||||
|
||||
// ActivePeerEngine creates a peer engine for use with an ACN, should be called once the underlying ACN is online
|
||||
func (app *application) ActivatePeerEngine(onion string, doListen, doPeers, doServers bool) {
|
||||
func (app *application) ActivatePeerEngine(onion string) {
|
||||
profile := app.GetPeer(onion)
|
||||
if profile != nil {
|
||||
if _, exists := app.engines[onion]; !exists {
|
||||
|
@ -341,10 +400,10 @@ func (app *application) ActivatePeerEngine(onion string, doListen, doPeers, doSe
|
|||
|
||||
app.eventBuses[profile.GetOnion()].Publish(event.NewEventList(event.ProtocolEngineCreated))
|
||||
app.QueryACNStatus()
|
||||
if doListen {
|
||||
if true {
|
||||
profile.Listen()
|
||||
}
|
||||
profile.StartConnections(doPeers, doServers)
|
||||
profile.StartConnections(true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,7 +228,8 @@ type Field string
|
|||
const (
|
||||
|
||||
// A peers local onion address
|
||||
Onion = Field("Onion")
|
||||
Onion = Field("Onion")
|
||||
ProfileOnion = Field("ProfileOnion")
|
||||
|
||||
RemotePeer = Field("RemotePeer")
|
||||
LastSeen = Field("LastSeen")
|
||||
|
|
|
@ -178,6 +178,65 @@ func (om *OverlayMessage) ShouldAutoDL() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (f *Functionality) VerifyOrResumeDownload(profile peer.CwtchPeer, conversation int, fileKey string) {
|
||||
if manifestFilePath, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.manifest", fileKey)); exists {
|
||||
if downloadfilepath, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", fileKey)); exists {
|
||||
log.Debugf("resuming %s", fileKey)
|
||||
f.DownloadFile(profile, conversation, downloadfilepath, manifestFilePath, fileKey, files.MaxManifestSize*files.DefaultChunkSize)
|
||||
} else {
|
||||
log.Errorf("found manifest path but not download path for %s", fileKey)
|
||||
}
|
||||
} else {
|
||||
log.Errorf("no stored manifest path found for %s", fileKey)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Functionality) CheckDownloadStatus(profile peer.CwtchPeer, fileKey string) {
|
||||
path, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", fileKey))
|
||||
if value, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.complete", fileKey)); exists && value == event.True {
|
||||
profile.PublishEvent(event.NewEvent(event.FileDownloaded, map[event.Field]string{
|
||||
event.ProfileOnion: profile.GetOnion(),
|
||||
event.FileKey: fileKey,
|
||||
event.FilePath: path,
|
||||
event.TempFile: "",
|
||||
}))
|
||||
} else {
|
||||
log.Debugf("CheckDownloadStatus found .path but not .complete")
|
||||
profile.PublishEvent(event.NewEvent(event.FileDownloadProgressUpdate, map[event.Field]string{
|
||||
event.ProfileOnion: profile.GetOnion(),
|
||||
event.FileKey: fileKey,
|
||||
event.Progress: "-1",
|
||||
event.FileSizeInChunks: "-1",
|
||||
event.FilePath: path,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Functionality) EnhancedShareFile(profile peer.CwtchPeer, conversationID int, sharefilepath string) string {
|
||||
fileKey, overlay, err := f.ShareFile(sharefilepath, profile)
|
||||
if err != nil {
|
||||
log.Errorf("error sharing file: %v", err)
|
||||
} else if conversationID == -1 {
|
||||
// FIXME: At some point we might want to allow arbitrary public files, but for now this API will assume
|
||||
// there is only one, and it is the custom profile image...
|
||||
profile.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.CustomProfileImageKey, fileKey)
|
||||
} else {
|
||||
// Set a new attribute so we can associate this download with this conversation...
|
||||
profile.SetConversationAttribute(conversationID, attr.ConversationScope.ConstructScopedZonedPath(attr.FilesharingZone.ConstructZonedPath(fileKey)), "")
|
||||
id, err := profile.SendMessage(conversationID, overlay)
|
||||
if err == nil {
|
||||
return profile.EnhancedGetMessageById(conversationID, id)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// DownloadFileDefaultLimit given a profile, a conversation handle and a file sharing key, start off a download process
|
||||
// to downloadFilePath with a default filesize limit
|
||||
func (f *Functionality) DownloadFileDefaultLimit(profile peer.CwtchPeer, conversationID int, downloadFilePath string, manifestFilePath string, key string) error {
|
||||
return f.DownloadFile(profile, conversationID, downloadFilePath, manifestFilePath, key, files.MaxManifestSize*files.DefaultChunkSize)
|
||||
}
|
||||
|
||||
// DownloadFile given a profile, a conversation handle and a file sharing key, start off a download process
|
||||
// to downloadFilePath
|
||||
func (f *Functionality) DownloadFile(profile peer.CwtchPeer, conversationID int, downloadFilePath string, manifestFilePath string, key string, limit uint64) error {
|
||||
|
@ -409,6 +468,14 @@ type SharedFile struct {
|
|||
Expired bool
|
||||
}
|
||||
|
||||
func (f *Functionality) EnhancedGetSharedFiles(profile peer.CwtchPeer, conversationID int) string {
|
||||
data, err := json.Marshal(f.GetSharedFiles(profile, conversationID))
|
||||
if err == nil {
|
||||
return string(data)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetSharedFiles returns all file shares associated with a given conversation
|
||||
func (f *Functionality) GetSharedFiles(profile peer.CwtchPeer, conversationID int) []SharedFile {
|
||||
sharedFiles := []SharedFile{}
|
||||
|
|
|
@ -56,3 +56,5 @@ const SyncPreLastMessageTime = "SyncPreLastMessageTime"
|
|||
const SyncMostRecentMessageTime = "SyncMostRecentMessageTime"
|
||||
|
||||
const AttrLastConnectionTime = "last-connection-time"
|
||||
const PeerAutostart = "autostart"
|
||||
const Archived = "archived"
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package model
|
||||
|
||||
import "sync"
|
||||
|
||||
// Experiments are optional functionality that can be enabled/disabled by an application either completely or individually.
|
||||
// examples of experiments include File Sharing, Profile Images and Groups.
|
||||
type Experiments struct {
|
||||
enabled bool
|
||||
experiments map[string]bool
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// InitExperiments encapsulates a set of experiments separate from their storage in GlobalSettings.
|
||||
|
@ -24,6 +27,10 @@ func (e *Experiments) IsEnabled(experiment string) bool {
|
|||
// todo handle default-enabled functionality
|
||||
return false
|
||||
}
|
||||
|
||||
// go will sometimes panic if we do not lock this read-only map...
|
||||
e.lock.Lock()
|
||||
defer e.lock.Unlock()
|
||||
enabled, exists := e.experiments[experiment]
|
||||
if !exists {
|
||||
return false
|
||||
|
|
|
@ -75,6 +75,94 @@ type cwtchPeer struct {
|
|||
experimentsLock sync.Mutex
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) EnhancedImportBundle(importString string) string {
|
||||
sarah marked this conversation as resolved
|
||||
return cp.ImportBundle(importString).Error()
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) EnhancedGetMessages(conversation int, index int, count int) string {
|
||||
var emessages []EnhancedMessage = make([]EnhancedMessage, count)
|
||||
|
||||
messages, err := cp.GetMostRecentMessages(conversation, 0, index, count)
|
||||
if err == nil {
|
||||
|
||||
for i, message := range messages {
|
||||
|
||||
time, _ := time.Parse(time.RFC3339Nano, message.Attr[constants.AttrSentTimestamp])
|
||||
emessages[i].Message = model.Message{
|
||||
Message: message.Body,
|
||||
Acknowledged: message.Attr[constants.AttrAck] == constants.True,
|
||||
Error: message.Attr[constants.AttrErr],
|
||||
PeerID: message.Attr[constants.AttrAuthor],
|
||||
Timestamp: time,
|
||||
}
|
||||
emessages[i].ID = message.ID
|
||||
emessages[i].Attributes = message.Attr
|
||||
emessages[i].ContentHash = model.CalculateContentHash(message.Attr[constants.AttrAuthor], message.Body)
|
||||
}
|
||||
}
|
||||
|
||||
bytes, _ := json.Marshal(emessages)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) EnhancedGetMessageById(conversation int, messageID int) string {
|
||||
var message EnhancedMessage
|
||||
dbmessage, attr, err := cp.GetChannelMessage(conversation, 0, messageID)
|
||||
if err == nil {
|
||||
time, _ := time.Parse(time.RFC3339Nano, attr[constants.AttrSentTimestamp])
|
||||
message.Message = model.Message{
|
||||
Message: dbmessage,
|
||||
Acknowledged: attr[constants.AttrAck] == constants.True,
|
||||
Error: attr[constants.AttrErr],
|
||||
PeerID: attr[constants.AttrAuthor],
|
||||
Timestamp: time,
|
||||
}
|
||||
message.ID = messageID
|
||||
message.Attributes = attr
|
||||
message.ContentHash = model.CalculateContentHash(attr[constants.AttrAuthor], dbmessage)
|
||||
}
|
||||
bytes, _ := json.Marshal(message)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) EnhancedGetMessageByContentHash(conversation int, contentHash string) string {
|
||||
var message EnhancedMessage
|
||||
offset, err := cp.GetChannelMessageByContentHash(conversation, 0, contentHash)
|
||||
if err == nil {
|
||||
messages, err := cp.GetMostRecentMessages(conversation, 0, offset, 1)
|
||||
if err == nil {
|
||||
time, _ := time.Parse(time.RFC3339Nano, messages[0].Attr[constants.AttrSentTimestamp])
|
||||
message.Message = model.Message{
|
||||
Message: messages[0].Body,
|
||||
Acknowledged: messages[0].Attr[constants.AttrAck] == constants.True,
|
||||
Error: messages[0].Attr[constants.AttrErr],
|
||||
PeerID: messages[0].Attr[constants.AttrAuthor],
|
||||
Timestamp: time,
|
||||
}
|
||||
message.ID = messages[0].ID
|
||||
message.Attributes = messages[0].Attr
|
||||
message.LocalIndex = offset
|
||||
message.ContentHash = contentHash
|
||||
} else {
|
||||
log.Errorf("error fetching local index {} ", err)
|
||||
}
|
||||
}
|
||||
bytes, _ := json.Marshal(message)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) EnhancedSendMessage(conversation int, message string) string {
|
||||
mid, err := cp.SendMessage(conversation, message)
|
||||
if err == nil {
|
||||
return cp.EnhancedGetMessageById(conversation, mid)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) ArchiveConversation(conversationID int) {
|
||||
cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Archived)), constants.True)
|
||||
}
|
||||
|
||||
// IsFeatureEnabled returns true if the functionality defined by featureName has been enabled by the application, false otherwise.
|
||||
// this function is intended to be used by ProfileHooks to determine if they should execute experimental functionality.
|
||||
func (cp *cwtchPeer) IsFeatureEnabled(featureName string) bool {
|
||||
|
@ -119,7 +207,7 @@ func (cp *cwtchPeer) StoreCachedTokens(tokenServer string, tokens []*privacypass
|
|||
}
|
||||
}
|
||||
|
||||
func (cp *cwtchPeer) Export(file string) error {
|
||||
func (cp *cwtchPeer) ExportProfile(file string) error {
|
||||
cp.mutex.Lock()
|
||||
defer cp.mutex.Unlock()
|
||||
return cp.storage.Export(file)
|
||||
|
|
|
@ -48,6 +48,10 @@ type ModifyServers interface {
|
|||
// SendMessages enables a caller to sender messages to a contact
|
||||
type SendMessages interface {
|
||||
SendMessage(conversation int, message string) (int, error)
|
||||
|
||||
// EnhancedSendMessage Attempts to Send a Message and Immediately Attempts to Lookup the Message in the Database
|
||||
EnhancedSendMessage(conversation int, message string) string
|
||||
|
||||
SendInviteToConversation(conversationID int, inviteConversationID int) (int, error)
|
||||
SendScopedZonedGetValToContact(conversationID int, scope attr.Scope, zone attr.Zone, key string)
|
||||
}
|
||||
|
@ -101,10 +105,12 @@ type CwtchPeer interface {
|
|||
|
||||
// Import Bundle
|
||||
ImportBundle(string) error
|
||||
EnhancedImportBundle(string) string
|
||||
|
||||
// New Unified Conversation Interfaces
|
||||
NewContactConversation(handle string, acl model.AccessControl, accepted bool) (int, error)
|
||||
FetchConversations() ([]*model.Conversation, error)
|
||||
ArchiveConversation(conversation int)
|
||||
GetConversationInfo(conversation int) (*model.Conversation, error)
|
||||
FetchConversationInfo(handle string) (*model.Conversation, error)
|
||||
AcceptConversation(conversation int) error
|
||||
|
@ -121,6 +127,15 @@ type CwtchPeer interface {
|
|||
GetMostRecentMessages(conversation int, channel int, offset int, limit int) ([]model.ConversationMessage, error)
|
||||
UpdateMessageAttribute(conversation int, channel int, id int, key string, value string) error
|
||||
|
||||
// EnhancedGetMessageById returns a json-encoded enhanced message, suitable for rendering in a UI
|
||||
EnhancedGetMessageById(conversation int, mid int) string
|
||||
sarah marked this conversation as resolved
dan
commented
ah by enhanced you mean with all the extra stuff lg was injecting? i slightly like the term "enriched" or possibly something else? but enhanced more or less conveys the same too, to preference or taste i guess :) ah by enhanced you mean with all the extra stuff lg was injecting? i slightly like the term "enriched" or possibly something else? but enhanced more or less conveys the same too, to preference or taste i guess :)
|
||||
|
||||
// EnhancedGetMessageByContentHash returns a json-encoded enhanced message, suitable for rendering in a UI
|
||||
EnhancedGetMessageByContentHash(conversation int, hash string) string
|
||||
|
||||
// EnhancedGetMessages returns a set of json-encoded enhanced messages, suitable for rendering in a UI
|
||||
EnhancedGetMessages(conversation int, index int, count int) string
|
||||
|
||||
// Server Token APIS
|
||||
// TODO move these to feature protected interfaces
|
||||
StoreCachedTokens(tokenServer string, tokens []*privacypass.Token)
|
||||
|
@ -128,10 +143,20 @@ type CwtchPeer interface {
|
|||
// Profile Management
|
||||
CheckPassword(password string) bool
|
||||
ChangePassword(oldpassword string, newpassword string, newpasswordAgain string) error
|
||||
Export(file string) error
|
||||
ExportProfile(file string) error
|
||||
Delete()
|
||||
PublishEvent(resp event.Event)
|
||||
RegisterHook(hook ProfileHooks)
|
||||
UpdateExperiments(enabled bool, experiments map[string]bool)
|
||||
IsFeatureEnabled(featureName string) bool
|
||||
}
|
||||
|
||||
// EnhancedMessage wraps a Cwtch model.Message with some additional data to reduce calls from the UI.
|
||||
type EnhancedMessage struct {
|
||||
model.Message
|
||||
ID int // the actual ID of the message in the database (not the row number)
|
||||
LocalIndex int // local index in the DB (row #). Can be empty (most calls supply it) but lookup by hash will fill it
|
||||
ContentHash string
|
||||
ContactImage string
|
||||
Attributes map[string]string
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func (fsss *FileSharingSubSystem) ShareFile(fileKey string, serializedManifest s
|
|||
log.Errorf("could not share file %v", err)
|
||||
return
|
||||
}
|
||||
log.Debugf("sharing file: %v %v", fileKey, serializedManifest)
|
||||
log.Infof("sharing file: %v %v", fileKey, serializedManifest)
|
||||
sarah marked this conversation as resolved
dan
commented
debug? debug?
|
||||
fsss.activeShares.Store(fileKey, &manifest)
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
|||
const ServerAddr = "nfhxzvzxinripgdh4t2m4xcy3crf6p4cbhectgckuj3idsjsaotgowad"
|
||||
serverKeyBundle, _ := base64.StdEncoding.DecodeString(ServerKeyBundleBase64)
|
||||
|
||||
app := app2.NewApp(acn, "./storage")
|
||||
app := app2.NewApp(acn, "./storage", app2.InitApp("./storage"))
|
||||
|
||||
usr, _ := user.Current()
|
||||
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
||||
|
@ -152,31 +152,31 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
|||
// ***** cwtchPeer setup *****
|
||||
|
||||
log.Infoln("Creating Alice...")
|
||||
app.CreateTaggedPeer("Alice", "asdfasdf", "test")
|
||||
app.CreateProfile("Alice", "asdfasdf", true)
|
||||
|
||||
log.Infoln("Creating Bob...")
|
||||
app.CreateTaggedPeer("Bob", "asdfasdf", "test")
|
||||
app.CreateProfile("Bob", "asdfasdf", true)
|
||||
|
||||
log.Infoln("Creating Carol...")
|
||||
app.CreateTaggedPeer("Carol", "asdfasdf", "test")
|
||||
app.CreateProfile("Carol", "asdfasdf", true)
|
||||
|
||||
alice := app2.WaitGetPeer(app, "Alice")
|
||||
aliceBus := app.GetEventBus(alice.GetOnion())
|
||||
app.ActivatePeerEngine(alice.GetOnion(), true, true, true)
|
||||
app.ActivatePeerEngine(alice.GetOnion())
|
||||
log.Infoln("Alice created:", alice.GetOnion())
|
||||
alice.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Alice")
|
||||
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||
|
||||
bob := app2.WaitGetPeer(app, "Bob")
|
||||
bobBus := app.GetEventBus(bob.GetOnion())
|
||||
app.ActivatePeerEngine(bob.GetOnion(), true, true, true)
|
||||
app.ActivatePeerEngine(bob.GetOnion())
|
||||
log.Infoln("Bob created:", bob.GetOnion())
|
||||
bob.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Bob")
|
||||
bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||
|
||||
carol := app2.WaitGetPeer(app, "Carol")
|
||||
carolBus := app.GetEventBus(carol.GetOnion())
|
||||
app.ActivatePeerEngine(carol.GetOnion(), true, true, true)
|
||||
app.ActivatePeerEngine(carol.GetOnion())
|
||||
log.Infoln("Carol created:", carol.GetOnion())
|
||||
carol.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Carol")
|
||||
carol.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||
|
|
|
@ -59,9 +59,9 @@ func TestEncryptedStorage(t *testing.T) {
|
|||
|
||||
defer acn.Close()
|
||||
acn.WaitTillBootstrapped()
|
||||
app := app2.NewApp(acn, cwtchDir)
|
||||
app.CreateTaggedPeer("alice", "password", constants.ProfileTypeV1Password)
|
||||
app.CreateTaggedPeer("bob", "password", constants.ProfileTypeV1Password)
|
||||
app := app2.NewApp(acn, cwtchDir, app2.InitApp(cwtchDir))
|
||||
app.CreateProfile("alice", "password", true)
|
||||
app.CreateProfile("bob", "password", true)
|
||||
|
||||
alice := app2.WaitGetPeer(app, "alice")
|
||||
bob := app2.WaitGetPeer(app, "bob")
|
||||
|
@ -130,7 +130,7 @@ func TestEncryptedStorage(t *testing.T) {
|
|||
t.Fatalf("expeced GetMostRecentMessages to return 1, instead returned: %v %v", len(messages), messages)
|
||||
}
|
||||
|
||||
err = alice.Export("alice.tar.gz")
|
||||
err = alice.ExportProfile("alice.tar.gz")
|
||||
if err != nil {
|
||||
t.Fatalf("could not export profile: %v", err)
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ func TestEncryptedStorage(t *testing.T) {
|
|||
t.Fatal("profile is already imported...this should fail")
|
||||
}
|
||||
|
||||
app.DeletePeer(alice.GetOnion(), "password")
|
||||
app.DeleteProfile(alice.GetOnion(), "password")
|
||||
alice, err = app.ImportProfile("alice.tar.gz", "password")
|
||||
if err != nil {
|
||||
t.Fatalf("profile should have successfully imported: %s", err)
|
||||
|
|
|
@ -97,7 +97,7 @@ func TestFileSharing(t *testing.T) {
|
|||
acn.WaitTillBootstrapped()
|
||||
defer acn.Close()
|
||||
|
||||
app := app2.NewApp(acn, "./storage")
|
||||
app := app2.NewApp(acn, "./storage", app2.InitApp("./storage"))
|
||||
|
||||
usr, _ := user.Current()
|
||||
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
||||
|
@ -106,16 +106,16 @@ func TestFileSharing(t *testing.T) {
|
|||
os.Mkdir(path.Join(cwtchDir, "testing"), 0700)
|
||||
|
||||
t.Logf("Creating Alice...")
|
||||
app.CreateTaggedPeer("alice", "asdfasdf", "testing")
|
||||
app.CreateProfile("alice", "asdfasdf", true)
|
||||
|
||||
t.Logf("Creating Bob...")
|
||||
app.CreateTaggedPeer("bob", "asdfasdf", "testing")
|
||||
app.CreateProfile("bob", "asdfasdf", true)
|
||||
|
||||
t.Logf("** Waiting for Alice, Bob...")
|
||||
alice := app2.WaitGetPeer(app, "alice")
|
||||
app.ActivatePeerEngine(alice.GetOnion(), true, true, true)
|
||||
app.ActivatePeerEngine(alice.GetOnion())
|
||||
bob := app2.WaitGetPeer(app, "bob")
|
||||
app.ActivatePeerEngine(bob.GetOnion(), true, true, true)
|
||||
app.ActivatePeerEngine(bob.GetOnion())
|
||||
|
||||
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.NewRetValMessageFromPeer})
|
||||
bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.NewRetValMessageFromPeer})
|
||||
|
@ -178,7 +178,7 @@ func TestFileSharing(t *testing.T) {
|
|||
testBobDownloadFile(t, bob, filesharingFunctionality, queueOracle)
|
||||
|
||||
// test that we can delete bob...
|
||||
app.DeletePeer(bob.GetOnion(), "asdfasdf")
|
||||
app.DeleteProfile(bob.GetOnion(), "asdfasdf")
|
||||
|
||||
queueOracle.Shutdown()
|
||||
app.Shutdown()
|
||||
|
|
Loading…
Reference in New Issue
what's this for? Seems a weird "enhancement" that doesnt return an error just the string of the error?