Official cwtch.im peer and server implementations. https://cwtch.im
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
4.6KB

  1. package app
  2. import (
  3. "cwtch.im/cwtch/event"
  4. "cwtch.im/cwtch/model"
  5. "cwtch.im/cwtch/protocol/connections"
  6. "cwtch.im/cwtch/storage"
  7. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  8. "git.openprivacy.ca/openprivacy/libricochet-go/identity"
  9. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  10. "path"
  11. "strconv"
  12. )
  13. const (
  14. // DestApp should be used as a destination for IPC messages that are for the application itself an not a peer
  15. DestApp = "app"
  16. )
  17. type applicationService struct {
  18. applicationBridge
  19. appletACN
  20. storage map[string]storage.ProfileStore
  21. engines map[string]connections.Engine
  22. }
  23. // ApplicationService is the back end of an application that manages engines and writing storage and communicates to an ApplicationClient by an IPCBridge
  24. type ApplicationService interface {
  25. Shutdown()
  26. }
  27. // NewAppService returns an ApplicationService that runs the backend of an app and communicates with a client by the supplied IPCBridge
  28. func NewAppService(acn connectivity.ACN, appDirectory string, bridge event.IPCBridge) ApplicationService {
  29. appService := &applicationService{storage: make(map[string]storage.ProfileStore), engines: make(map[string]connections.Engine), applicationBridge: applicationBridge{applicationCore: *newAppCore(appDirectory), bridge: bridge}}
  30. fn := func(progress int, status string) {
  31. progStr := strconv.Itoa(progress)
  32. appService.bridge.Write(&event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.ACNStatus, event.Progreess, progStr, event.Status, status)})
  33. }
  34. appService.appletACN.init(acn, fn)
  35. appService.handle = appService.handleEvent
  36. go appService.listen()
  37. log.Infoln("Created new App Service")
  38. return appService
  39. }
  40. func (as *applicationService) handleEvent(ev *event.Event) {
  41. log.Infof("app Service handleEvent %v\n", ev.EventType)
  42. switch ev.EventType {
  43. case event.CreatePeer:
  44. profileName := ev.Data[event.ProfileName]
  45. password := ev.Data[event.Password]
  46. as.createPeer(profileName, password)
  47. case event.LoadProfiles:
  48. password := ev.Data[event.Password]
  49. as.loadProfiles(password)
  50. }
  51. }
  52. func (as *applicationService) createPeer(name, password string) {
  53. log.Infof("app Service create peer %v %v\n", name, password)
  54. profile, err := as.applicationCore.CreatePeer(name, password)
  55. as.eventBuses[profile.Onion] = event.IPCEventManagerFrom(as.bridge, profile.Onion, as.eventBuses[profile.Onion])
  56. if err != nil {
  57. log.Errorf("Could not create Peer: %v\n", err)
  58. message := event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.PeerError, event.Error, err.Error())}
  59. as.bridge.Write(&message)
  60. return
  61. }
  62. profileStore := storage.NewProfileWriterStore(as.eventBuses[profile.Onion], path.Join(as.directory, "profiles", profile.LocalID), password, profile)
  63. blockedPeers := profile.BlockedPeers()
  64. // TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
  65. identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
  66. engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, as.acn, as.eventBuses[profile.Onion], blockedPeers)
  67. as.storage[profile.Onion] = profileStore
  68. as.engines[profile.Onion] = engine
  69. message := event.IPCMessage{Dest: DestApp, Message: event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.LocalID, event.Password: password})}
  70. as.bridge.Write(&message)
  71. }
  72. func (as *applicationService) loadProfiles(password string) {
  73. count := 0
  74. as.applicationCore.LoadProfiles(password, func(profile *model.Profile, profileStore storage.ProfileStore) {
  75. as.eventBuses[profile.Onion] = event.IPCEventManagerFrom(as.bridge, profile.Onion, as.eventBuses[profile.Onion])
  76. blockedPeers := profile.BlockedPeers()
  77. identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
  78. engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, as.acn, as.eventBuses[profile.Onion], blockedPeers)
  79. as.mutex.Lock()
  80. as.storage[profile.Onion] = profileStore
  81. as.engines[profile.Onion] = engine
  82. as.mutex.Unlock()
  83. message := event.IPCMessage{Dest: DestApp, Message: event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.LocalID, event.Password: password})}
  84. as.bridge.Write(&message)
  85. count++
  86. })
  87. if count == 0 {
  88. message := event.IPCMessage{Dest: DestApp, Message: event.NewEventList(event.AppError, event.Error, event.AppErrLoaded0)}
  89. as.bridge.Write(&message)
  90. }
  91. }
  92. // Shutdown shuts down the application Service and all peer related backend parts
  93. func (as *applicationService) Shutdown() {
  94. for id := range as.engines {
  95. as.engines[id].Shutdown()
  96. as.storage[id].Shutdown()
  97. as.eventBuses[id].Shutdown()
  98. }
  99. }