main.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package main
  2. import (
  3. libapp "cwtch.im/cwtch/app"
  4. "cwtch.im/cwtch/model"
  5. "cwtch.im/ui/go/characters"
  6. "cwtch.im/ui/go/cwtchthings"
  7. "cwtch.im/ui/go/cwutil"
  8. "cwtch.im/ui/go/gobjects"
  9. "cwtch.im/ui/go/gothings"
  10. "cwtch.im/ui/go/the"
  11. "fmt"
  12. "git.openprivacy.ca/openprivacy/libricochet-go/application"
  13. "git.openprivacy.ca/openprivacy/libricochet-go/channels"
  14. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  15. "github.com/therecipe/qt/core"
  16. "github.com/therecipe/qt/quick"
  17. "github.com/therecipe/qt/quickcontrols2"
  18. "github.com/therecipe/qt/widgets"
  19. "log"
  20. "os"
  21. "os/user"
  22. "path"
  23. )
  24. func init() {
  25. // make go-defined types available in qml
  26. gothings.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher")
  27. }
  28. func main() {
  29. // our globals
  30. gcd := gothings.NewGrandCentralDispatcher(nil)
  31. gcd.UIState = gothings.NewUIState(gcd)
  32. the.AcknowledgementIDs = make(map[uint32]uint)
  33. gcd.OutgoingMessages = make(chan gobjects.Letter, 1000)
  34. //TODO: put theme stuff somewhere better
  35. gcd.SetThemeScale(1.0)
  36. // this is to load local qml files quickly when developing
  37. var qmlSource *core.QUrl
  38. if len(os.Args) == 2 && os.Args[1] == "-local" {
  39. qmlSource = core.QUrl_FromLocalFile("./qml/main.qml")
  40. } else {
  41. qmlSource = core.NewQUrl3("qrc:/qml/main.qml", 0)
  42. }
  43. // window construction boilerplate
  44. view := initializeQtView()
  45. // variables we want to access from inside qml
  46. view.RootContext().SetContextProperty("gcd", gcd)
  47. // this actually loads the qml
  48. view.SetSource(qmlSource)
  49. // these are long-lived pollers/listeners for incoming messages and status changes
  50. loadCwtchData(gcd)
  51. go characters.PostmanPat(gcd.OutgoingMessages)
  52. go characters.TorStatusPoller(gcd.TorStatus)
  53. go characters.PresencePoller(gcd.UIState.GetContact, gcd.UIState.AddContact, gcd.UIState.UpdateContact)
  54. go characters.GroupPoller(gcd.UIState.GetContact, gcd.UIState.UpdateContact)
  55. // here we go!
  56. view.Show()
  57. widgets.QApplication_Exec()
  58. }
  59. // window construction boilerplate
  60. func initializeQtView() *quick.QQuickView {
  61. core.QCoreApplication_SetAttribute(core.Qt__AA_EnableHighDpiScaling, true)
  62. widgets.NewQApplication(len(os.Args), os.Args)
  63. quickcontrols2.QQuickStyle_SetStyle("Universe")
  64. view := quick.NewQQuickView(nil)
  65. view.SetResizeMode(quick.QQuickView__SizeRootObjectToView)
  66. view.SetMinimumHeight(280)
  67. view.SetMinimumWidth(300)
  68. view.SetTitle("cwtch")
  69. return view
  70. }
  71. // this is mostly going to get factored out when we add profile support
  72. // for now, it loads a single peer and fills the ui with its data
  73. func loadCwtchData(gcd *gothings.GrandCentralDispatcher) {
  74. var err error
  75. if os.Getenv("CWTCH_FOLDER") != "" {
  76. the.CwtchDir = os.Getenv("CWTCH_FOLDER")
  77. } else {
  78. usr, err := user.Current()
  79. if err != nil {
  80. fmt.Printf("\nerror: could not load current user: %v\n", err)
  81. os.Exit(1)
  82. }
  83. the.CwtchDir = path.Join(usr.HomeDir, ".cwtch")
  84. }
  85. /*_, err := app2.NewApp(dirname, "/data/data/org.qtproject.example.go/lib/libtor.so")
  86. if err != nil {
  87. log.Printf("ERROR CREATING CWTCH APP: %v", err)
  88. }
  89. time.Sleep(time.Second * 10)
  90. */
  91. os.MkdirAll(the.CwtchDir, 0700)
  92. mn, err := connectivity.StartTor(the.CwtchDir, "")
  93. if err != nil {
  94. log.Printf("[!!!] Could not start Tor: %v", err)
  95. }
  96. the.CwtchApp = libapp.NewApp(mn, the.CwtchDir)
  97. err = the.CwtchApp.LoadProfiles("be gay do crime")
  98. if err != nil {
  99. //TODO no more fatalfs
  100. log.Fatalf("couldn't load profiles: %v", err)
  101. }
  102. if len(the.CwtchApp.ListPeers()) == 0 {
  103. log.Printf("couldn't load your config file. attempting to create one now")
  104. the.Peer, err = the.CwtchApp.CreatePeer("alice", "be gay do crime")
  105. if err != nil {
  106. log.Fatalf("couldn't create one. is your cwtch folder writable?")
  107. }
  108. the.CwtchApp.SaveProfile(the.Peer)
  109. } else {
  110. the.Peer = the.CwtchApp.PrimaryIdentity()
  111. }
  112. gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, cwutil.RandomProfileImage(the.Peer.GetProfile().Onion))
  113. aif := application.ApplicationInstanceFactory{}
  114. aif.Init()
  115. app := new(application.RicochetApplication)
  116. aif.AddHandler("im.ricochet.chat", func(rai *application.ApplicationInstance) func() channels.Handler {
  117. ccl := new(cwtchthings.ChatChannelListener)
  118. ccl.Init(rai, app, gcd.UIState.AddMessage, gcd.Acknowledged)
  119. return func() channels.Handler {
  120. chat := new(channels.ChatChannel)
  121. chat.Handler = ccl
  122. return chat
  123. }
  124. })
  125. the.Peer.SetApplicationInstanceFactory(aif)
  126. the.CwtchApp.LaunchPeers()
  127. contacts := the.Peer.GetContacts()
  128. for i := range contacts {
  129. contact, _ := the.Peer.GetProfile().GetContact(contacts[i])
  130. displayName, _ := contact.GetAttribute("name")
  131. gcd.UIState.AddContact(&gobjects.Contact{
  132. contacts[i],
  133. displayName,
  134. cwutil.RandomProfileImage(contacts[i]),
  135. "",
  136. 0,
  137. 0,
  138. contact.Trusted,
  139. })
  140. }
  141. groups := the.Peer.GetGroups()
  142. for i := range groups {
  143. log.Printf("adding saved group %v", groups[i])
  144. group := the.Peer.GetGroup(groups[i])
  145. group.NewMessage = make(chan model.Message)
  146. go characters.CwtchListener(gcd.UIState.AddMessage, groups[i], group.NewMessage)
  147. the.Peer.JoinServer(group.GroupServer)
  148. nick, exists := group.GetAttribute("nick")
  149. if !exists {
  150. nick = group.GroupID[:12]
  151. }
  152. gcd.UIState.AddContact(&gobjects.Contact{
  153. group.GroupID,
  154. nick,
  155. cwutil.RandomGroupImage(group.GroupID),
  156. group.GroupServer,
  157. 0,
  158. 0,
  159. group.Accepted,
  160. })
  161. }
  162. }