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.

appService.go 5.5KB

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