Large API Refactor in prep for autobindings #494
43
app/app.go
43
app/app.go
|
@ -38,11 +38,10 @@ type application struct {
|
||||||
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
||||||
type Application interface {
|
type Application interface {
|
||||||
LoadProfiles(password string)
|
LoadProfiles(password string)
|
||||||
CreatePeer(name string, password string, attributes map[attr.ZonedPath]string)
|
CreateProfile(name string, password string, autostart bool)
|
||||||
// Deprecated in 1.10
|
|
||||||
CreateTaggedPeer(name string, password string, tag string)
|
|
||||||
ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error)
|
ImportProfile(exportedCwtchFile string, password string) (peer.CwtchPeer, error)
|
||||||
DeletePeer(onion string, currentPassword string)
|
DeleteProfile(onion string, currentPassword string)
|
||||||
AddPeerPlugin(onion string, pluginID plugins.PluginID)
|
AddPeerPlugin(onion string, pluginID plugins.PluginID)
|
||||||
|
|
||||||
GetPrimaryBus() event.Manager
|
GetPrimaryBus() event.Manager
|
||||||
|
@ -51,7 +50,7 @@ type Application interface {
|
||||||
QueryACNVersion()
|
QueryACNVersion()
|
||||||
|
|
||||||
ActivateEngines(doListn, doPeers, doServers bool)
|
ActivateEngines(doListn, doPeers, doServers bool)
|
||||||
ActivatePeerEngine(onion string, doListen, doPeers, doServers bool)
|
ActivatePeerEngine(onion string)
|
||||||
DeactivatePeerEngine(onion string)
|
DeactivatePeerEngine(onion string)
|
||||||
|
|
||||||
ReadSettings() GlobalSettings
|
ReadSettings() GlobalSettings
|
||||||
|
@ -67,8 +66,7 @@ type Application interface {
|
||||||
// LoadProfileFn is the function signature for a function in an app that loads a profile
|
// LoadProfileFn is the function signature for a function in an app that loads a profile
|
||||||
type LoadProfileFn func(profile peer.CwtchPeer)
|
type LoadProfileFn func(profile peer.CwtchPeer)
|
||||||
|
|
||||||
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
func InitApp(appDirectory string) *GlobalSettingsFile {
|
||||||
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
|
||||||
log.Debugf("NewApp(%v)\n", appDirectory)
|
log.Debugf("NewApp(%v)\n", appDirectory)
|
||||||
os.MkdirAll(path.Join(appDirectory, "profiles"), 0700)
|
os.MkdirAll(path.Join(appDirectory, "profiles"), 0700)
|
||||||
|
|
||||||
|
@ -79,6 +77,11 @@ func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error initializing global settings file %. Global settings might not be loaded or saves", err)
|
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 := &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)
|
app.peers = make(map[string]peer.CwtchPeer)
|
||||||
|
@ -159,6 +162,22 @@ 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
|
// Deprecated in 1.10
|
||||||
func (app *application) CreateTaggedPeer(name string, password string, tag string) {
|
func (app *application) CreateTaggedPeer(name string, password string, tag string) {
|
||||||
app.CreatePeer(name, password, map[attr.ZonedPath]string{attr.ProfileZone.ConstructZonedPath(constants.Tag): tag})
|
app.CreatePeer(name, password, map[attr.ZonedPath]string{attr.ProfileZone.ConstructZonedPath(constants.Tag): tag})
|
||||||
|
@ -192,8 +211,8 @@ func (app *application) CreatePeer(name string, password string, attributes map[
|
||||||
app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.GetOnion(), event.Created: event.True}))
|
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) {
|
func (app *application) DeleteProfile(onion string, password string) {
|
||||||
log.Debugf("DeletePeer called on %v\n", onion)
|
log.Debugf("DeleteProfile called on %v\n", onion)
|
||||||
app.appmutex.Lock()
|
app.appmutex.Lock()
|
||||||
defer app.appmutex.Unlock()
|
defer app.appmutex.Unlock()
|
||||||
|
|
||||||
|
@ -333,7 +352,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
|
// 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)
|
profile := app.GetPeer(onion)
|
||||||
if profile != nil {
|
if profile != nil {
|
||||||
if _, exists := app.engines[onion]; !exists {
|
if _, exists := app.engines[onion]; !exists {
|
||||||
|
@ -341,10 +360,10 @@ func (app *application) ActivatePeerEngine(onion string, doListen, doPeers, doSe
|
||||||
|
|
||||||
app.eventBuses[profile.GetOnion()].Publish(event.NewEventList(event.ProtocolEngineCreated))
|
app.eventBuses[profile.GetOnion()].Publish(event.NewEventList(event.ProtocolEngineCreated))
|
||||||
app.QueryACNStatus()
|
app.QueryACNStatus()
|
||||||
if doListen {
|
if true {
|
||||||
profile.Listen()
|
profile.Listen()
|
||||||
}
|
}
|
||||||
profile.StartConnections(doPeers, doServers)
|
profile.StartConnections(true, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,8 @@ type Field string
|
||||||
const (
|
const (
|
||||||
|
|
||||||
// A peers local onion address
|
// A peers local onion address
|
||||||
Onion = Field("Onion")
|
Onion = Field("Onion")
|
||||||
|
ProfileOnion = Field("ProfileOnion")
|
||||||
|
|
||||||
RemotePeer = Field("RemotePeer")
|
RemotePeer = Field("RemotePeer")
|
||||||
LastSeen = Field("LastSeen")
|
LastSeen = Field("LastSeen")
|
||||||
|
|
|
@ -178,6 +178,65 @@ func (om *OverlayMessage) ShouldAutoDL() bool {
|
||||||
return false
|
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.Infof("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.Infof("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
|
// DownloadFile given a profile, a conversation handle and a file sharing key, start off a download process
|
||||||
// to downloadFilePath
|
// to downloadFilePath
|
||||||
func (f *Functionality) DownloadFile(profile peer.CwtchPeer, conversationID int, downloadFilePath string, manifestFilePath string, key string, limit uint64) error {
|
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
|
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
|
// GetSharedFiles returns all file shares associated with a given conversation
|
||||||
func (f *Functionality) GetSharedFiles(profile peer.CwtchPeer, conversationID int) []SharedFile {
|
func (f *Functionality) GetSharedFiles(profile peer.CwtchPeer, conversationID int) []SharedFile {
|
||||||
sharedFiles := []SharedFile{}
|
sharedFiles := []SharedFile{}
|
||||||
|
|
|
@ -56,3 +56,5 @@ const SyncPreLastMessageTime = "SyncPreLastMessageTime"
|
||||||
const SyncMostRecentMessageTime = "SyncMostRecentMessageTime"
|
const SyncMostRecentMessageTime = "SyncMostRecentMessageTime"
|
||||||
|
|
||||||
const AttrLastConnectionTime = "last-connection-time"
|
const AttrLastConnectionTime = "last-connection-time"
|
||||||
|
const PeerAutostart = "autostart"
|
||||||
|
const Archived = "archived"
|
||||||
|
|
|
@ -75,6 +75,90 @@ type cwtchPeer struct {
|
||||||
experimentsLock sync.Mutex
|
experimentsLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cp *cwtchPeer) EnhancedGetMessages(conversation int, index int, count int) string {
|
||||||
sarah marked this conversation as resolved
|
|||||||
|
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.
|
// 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.
|
// this function is intended to be used by ProfileHooks to determine if they should execute experimental functionality.
|
||||||
func (cp *cwtchPeer) IsFeatureEnabled(featureName string) bool {
|
func (cp *cwtchPeer) IsFeatureEnabled(featureName string) bool {
|
||||||
|
@ -119,7 +203,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()
|
cp.mutex.Lock()
|
||||||
defer cp.mutex.Unlock()
|
defer cp.mutex.Unlock()
|
||||||
return cp.storage.Export(file)
|
return cp.storage.Export(file)
|
||||||
|
|
|
@ -48,6 +48,10 @@ type ModifyServers interface {
|
||||||
// SendMessages enables a caller to sender messages to a contact
|
// SendMessages enables a caller to sender messages to a contact
|
||||||
type SendMessages interface {
|
type SendMessages interface {
|
||||||
SendMessage(conversation int, message string) (int, error)
|
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)
|
SendInviteToConversation(conversationID int, inviteConversationID int) (int, error)
|
||||||
SendScopedZonedGetValToContact(conversationID int, scope attr.Scope, zone attr.Zone, key string)
|
SendScopedZonedGetValToContact(conversationID int, scope attr.Scope, zone attr.Zone, key string)
|
||||||
}
|
}
|
||||||
|
@ -105,6 +109,7 @@ type CwtchPeer interface {
|
||||||
// New Unified Conversation Interfaces
|
// New Unified Conversation Interfaces
|
||||||
NewContactConversation(handle string, acl model.AccessControl, accepted bool) (int, error)
|
NewContactConversation(handle string, acl model.AccessControl, accepted bool) (int, error)
|
||||||
FetchConversations() ([]*model.Conversation, error)
|
FetchConversations() ([]*model.Conversation, error)
|
||||||
|
ArchiveConversation(conversation int)
|
||||||
GetConversationInfo(conversation int) (*model.Conversation, error)
|
GetConversationInfo(conversation int) (*model.Conversation, error)
|
||||||
FetchConversationInfo(handle string) (*model.Conversation, error)
|
FetchConversationInfo(handle string) (*model.Conversation, error)
|
||||||
AcceptConversation(conversation int) error
|
AcceptConversation(conversation int) error
|
||||||
|
@ -121,6 +126,15 @@ type CwtchPeer interface {
|
||||||
GetMostRecentMessages(conversation int, channel int, offset int, limit int) ([]model.ConversationMessage, error)
|
GetMostRecentMessages(conversation int, channel int, offset int, limit int) ([]model.ConversationMessage, error)
|
||||||
UpdateMessageAttribute(conversation int, channel int, id int, key string, value string) 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
|
// Server Token APIS
|
||||||
// TODO move these to feature protected interfaces
|
// TODO move these to feature protected interfaces
|
||||||
StoreCachedTokens(tokenServer string, tokens []*privacypass.Token)
|
StoreCachedTokens(tokenServer string, tokens []*privacypass.Token)
|
||||||
|
@ -128,10 +142,20 @@ type CwtchPeer interface {
|
||||||
// Profile Management
|
// Profile Management
|
||||||
CheckPassword(password string) bool
|
CheckPassword(password string) bool
|
||||||
ChangePassword(oldpassword string, newpassword string, newpasswordAgain string) error
|
ChangePassword(oldpassword string, newpassword string, newpasswordAgain string) error
|
||||||
Export(file string) error
|
ExportProfile(file string) error
|
||||||
Delete()
|
Delete()
|
||||||
PublishEvent(resp event.Event)
|
PublishEvent(resp event.Event)
|
||||||
RegisterHook(hook ProfileHooks)
|
RegisterHook(hook ProfileHooks)
|
||||||
UpdateExperiments(enabled bool, experiments map[string]bool)
|
UpdateExperiments(enabled bool, experiments map[string]bool)
|
||||||
IsFeatureEnabled(featureName 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
|
||||||
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
const ServerAddr = "nfhxzvzxinripgdh4t2m4xcy3crf6p4cbhectgckuj3idsjsaotgowad"
|
const ServerAddr = "nfhxzvzxinripgdh4t2m4xcy3crf6p4cbhectgckuj3idsjsaotgowad"
|
||||||
serverKeyBundle, _ := base64.StdEncoding.DecodeString(ServerKeyBundleBase64)
|
serverKeyBundle, _ := base64.StdEncoding.DecodeString(ServerKeyBundleBase64)
|
||||||
|
|
||||||
app := app2.NewApp(acn, "./storage")
|
app := app2.NewApp(acn, "./storage", app2.InitApp("./storage"))
|
||||||
|
|
||||||
usr, _ := user.Current()
|
usr, _ := user.Current()
|
||||||
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
||||||
|
@ -152,31 +152,31 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
// ***** cwtchPeer setup *****
|
// ***** cwtchPeer setup *****
|
||||||
|
|
||||||
log.Infoln("Creating Alice...")
|
log.Infoln("Creating Alice...")
|
||||||
app.CreateTaggedPeer("Alice", "asdfasdf", "test")
|
app.CreateProfile("Alice", "asdfasdf", true)
|
||||||
|
|
||||||
log.Infoln("Creating Bob...")
|
log.Infoln("Creating Bob...")
|
||||||
app.CreateTaggedPeer("Bob", "asdfasdf", "test")
|
app.CreateProfile("Bob", "asdfasdf", true)
|
||||||
|
|
||||||
log.Infoln("Creating Carol...")
|
log.Infoln("Creating Carol...")
|
||||||
app.CreateTaggedPeer("Carol", "asdfasdf", "test")
|
app.CreateProfile("Carol", "asdfasdf", true)
|
||||||
|
|
||||||
alice := app2.WaitGetPeer(app, "Alice")
|
alice := app2.WaitGetPeer(app, "Alice")
|
||||||
aliceBus := app.GetEventBus(alice.GetOnion())
|
aliceBus := app.GetEventBus(alice.GetOnion())
|
||||||
app.ActivatePeerEngine(alice.GetOnion(), true, true, true)
|
app.ActivatePeerEngine(alice.GetOnion())
|
||||||
log.Infoln("Alice created:", alice.GetOnion())
|
log.Infoln("Alice created:", alice.GetOnion())
|
||||||
alice.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Alice")
|
alice.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Alice")
|
||||||
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||||
|
|
||||||
bob := app2.WaitGetPeer(app, "Bob")
|
bob := app2.WaitGetPeer(app, "Bob")
|
||||||
bobBus := app.GetEventBus(bob.GetOnion())
|
bobBus := app.GetEventBus(bob.GetOnion())
|
||||||
app.ActivatePeerEngine(bob.GetOnion(), true, true, true)
|
app.ActivatePeerEngine(bob.GetOnion())
|
||||||
log.Infoln("Bob created:", bob.GetOnion())
|
log.Infoln("Bob created:", bob.GetOnion())
|
||||||
bob.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Bob")
|
bob.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Bob")
|
||||||
bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||||
|
|
||||||
carol := app2.WaitGetPeer(app, "Carol")
|
carol := app2.WaitGetPeer(app, "Carol")
|
||||||
carolBus := app.GetEventBus(carol.GetOnion())
|
carolBus := app.GetEventBus(carol.GetOnion())
|
||||||
app.ActivatePeerEngine(carol.GetOnion(), true, true, true)
|
app.ActivatePeerEngine(carol.GetOnion())
|
||||||
log.Infoln("Carol created:", carol.GetOnion())
|
log.Infoln("Carol created:", carol.GetOnion())
|
||||||
carol.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Carol")
|
carol.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Carol")
|
||||||
carol.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
carol.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
||||||
|
|
|
@ -59,9 +59,9 @@ func TestEncryptedStorage(t *testing.T) {
|
||||||
|
|
||||||
defer acn.Close()
|
defer acn.Close()
|
||||||
acn.WaitTillBootstrapped()
|
acn.WaitTillBootstrapped()
|
||||||
app := app2.NewApp(acn, cwtchDir)
|
app := app2.NewApp(acn, cwtchDir, app2.InitApp(cwtchDir))
|
||||||
app.CreateTaggedPeer("alice", "password", constants.ProfileTypeV1Password)
|
app.CreateProfile("alice", "password", true)
|
||||||
app.CreateTaggedPeer("bob", "password", constants.ProfileTypeV1Password)
|
app.CreateProfile("bob", "password", true)
|
||||||
|
|
||||||
alice := app2.WaitGetPeer(app, "alice")
|
alice := app2.WaitGetPeer(app, "alice")
|
||||||
bob := app2.WaitGetPeer(app, "bob")
|
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)
|
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 {
|
if err != nil {
|
||||||
t.Fatalf("could not export profile: %v", err)
|
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")
|
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")
|
alice, err = app.ImportProfile("alice.tar.gz", "password")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("profile should have successfully imported: %s", err)
|
t.Fatalf("profile should have successfully imported: %s", err)
|
||||||
|
|
|
@ -97,7 +97,7 @@ func TestFileSharing(t *testing.T) {
|
||||||
acn.WaitTillBootstrapped()
|
acn.WaitTillBootstrapped()
|
||||||
defer acn.Close()
|
defer acn.Close()
|
||||||
|
|
||||||
app := app2.NewApp(acn, "./storage")
|
app := app2.NewApp(acn, "./storage", app2.InitApp("./storage"))
|
||||||
|
|
||||||
usr, _ := user.Current()
|
usr, _ := user.Current()
|
||||||
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
cwtchDir := path.Join(usr.HomeDir, ".cwtch")
|
||||||
|
@ -106,16 +106,16 @@ func TestFileSharing(t *testing.T) {
|
||||||
os.Mkdir(path.Join(cwtchDir, "testing"), 0700)
|
os.Mkdir(path.Join(cwtchDir, "testing"), 0700)
|
||||||
|
|
||||||
t.Logf("Creating Alice...")
|
t.Logf("Creating Alice...")
|
||||||
app.CreateTaggedPeer("alice", "asdfasdf", "testing")
|
app.CreateProfile("alice", "asdfasdf", true)
|
||||||
|
|
||||||
t.Logf("Creating Bob...")
|
t.Logf("Creating Bob...")
|
||||||
app.CreateTaggedPeer("bob", "asdfasdf", "testing")
|
app.CreateProfile("bob", "asdfasdf", true)
|
||||||
|
|
||||||
t.Logf("** Waiting for Alice, Bob...")
|
t.Logf("** Waiting for Alice, Bob...")
|
||||||
alice := app2.WaitGetPeer(app, "alice")
|
alice := app2.WaitGetPeer(app, "alice")
|
||||||
app.ActivatePeerEngine(alice.GetOnion(), true, true, true)
|
app.ActivatePeerEngine(alice.GetOnion())
|
||||||
bob := app2.WaitGetPeer(app, "bob")
|
bob := app2.WaitGetPeer(app, "bob")
|
||||||
app.ActivatePeerEngine(bob.GetOnion(), true, true, true)
|
app.ActivatePeerEngine(bob.GetOnion())
|
||||||
|
|
||||||
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.NewRetValMessageFromPeer})
|
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.NewRetValMessageFromPeer})
|
||||||
bob.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)
|
testBobDownloadFile(t, bob, filesharingFunctionality, queueOracle)
|
||||||
|
|
||||||
// test that we can delete bob...
|
// test that we can delete bob...
|
||||||
app.DeletePeer(bob.GetOnion(), "asdfasdf")
|
app.DeleteProfile(bob.GetOnion(), "asdfasdf")
|
||||||
|
|
||||||
queueOracle.Shutdown()
|
queueOracle.Shutdown()
|
||||||
app.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?