Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

channelmanager.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // Copyright (c) 2017 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "sort"
  6. "sync"
  7. "github.com/oragono/oragono/irc/utils"
  8. )
  9. type channelManagerEntry struct {
  10. channel *Channel
  11. // this is a refcount for joins, so we can avoid a race where we incorrectly
  12. // think the channel is empty (without holding a lock across the entire Channel.Join()
  13. // call)
  14. pendingJoins int
  15. skeleton string
  16. }
  17. // ChannelManager keeps track of all the channels on the server,
  18. // providing synchronization for creation of new channels on first join,
  19. // cleanup of empty channels on last part, and renames.
  20. type ChannelManager struct {
  21. sync.RWMutex // tier 2
  22. // chans is the main data structure, mapping casefolded name -> *Channel
  23. chans map[string]*channelManagerEntry
  24. chansSkeletons utils.StringSet // skeletons of *unregistered* chans
  25. registeredChannels utils.StringSet // casefolds of registered chans
  26. registeredSkeletons utils.StringSet // skeletons of registered chans
  27. purgedChannels utils.StringSet // casefolds of purged chans
  28. server *Server
  29. }
  30. // NewChannelManager returns a new ChannelManager.
  31. func (cm *ChannelManager) Initialize(server *Server) {
  32. cm.chans = make(map[string]*channelManagerEntry)
  33. cm.chansSkeletons = make(utils.StringSet)
  34. cm.server = server
  35. cm.loadRegisteredChannels(server.Config())
  36. // purging should work even if registration is disabled
  37. cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
  38. }
  39. func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
  40. if !config.Channels.Registration.Enabled {
  41. return
  42. }
  43. rawNames := cm.server.channelRegistry.AllChannels()
  44. registeredChannels := make(utils.StringSet, len(rawNames))
  45. registeredSkeletons := make(utils.StringSet, len(rawNames))
  46. for _, name := range rawNames {
  47. cfname, err := CasefoldChannel(name)
  48. if err == nil {
  49. registeredChannels.Add(cfname)
  50. }
  51. skeleton, err := Skeleton(name)
  52. if err == nil {
  53. registeredSkeletons.Add(skeleton)
  54. }
  55. }
  56. cm.Lock()
  57. defer cm.Unlock()
  58. cm.registeredChannels = registeredChannels
  59. cm.registeredSkeletons = registeredSkeletons
  60. }
  61. // Get returns an existing channel with name equivalent to `name`, or nil
  62. func (cm *ChannelManager) Get(name string) (channel *Channel) {
  63. name, err := CasefoldChannel(name)
  64. if err == nil {
  65. cm.RLock()
  66. defer cm.RUnlock()
  67. entry := cm.chans[name]
  68. // if the channel is still loading, pretend we don't have it
  69. if entry != nil && entry.channel.IsLoaded() {
  70. return entry.channel
  71. }
  72. }
  73. return nil
  74. }
  75. // Join causes `client` to join the channel named `name`, creating it if necessary.
  76. func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin bool, rb *ResponseBuffer) (err error, forward string) {
  77. server := client.server
  78. casefoldedName, err := CasefoldChannel(name)
  79. skeleton, skerr := Skeleton(name)
  80. if err != nil || skerr != nil || len(casefoldedName) > server.Config().Limits.ChannelLen {
  81. return errNoSuchChannel, ""
  82. }
  83. channel, err := func() (*Channel, error) {
  84. cm.Lock()
  85. defer cm.Unlock()
  86. if cm.purgedChannels.Has(casefoldedName) {
  87. return nil, errChannelPurged
  88. }
  89. entry := cm.chans[casefoldedName]
  90. if entry == nil {
  91. registered := cm.registeredChannels.Has(casefoldedName)
  92. // enforce OpOnlyCreation
  93. if !registered && server.Config().Channels.OpOnlyCreation && !client.HasRoleCapabs("chanreg") {
  94. return nil, errInsufficientPrivs
  95. }
  96. // enforce confusables
  97. if !registered && (cm.chansSkeletons.Has(skeleton) || cm.registeredSkeletons.Has(skeleton)) {
  98. return nil, errConfusableIdentifier
  99. }
  100. entry = &channelManagerEntry{
  101. channel: NewChannel(server, name, casefoldedName, registered),
  102. pendingJoins: 0,
  103. }
  104. if !registered {
  105. // for an unregistered channel, we already have the correct unfolded name
  106. // and therefore the final skeleton. for a registered channel, we don't have
  107. // the unfolded name yet (it needs to be loaded from the db), but we already
  108. // have the final skeleton in `registeredSkeletons` so we don't need to track it
  109. cm.chansSkeletons.Add(skeleton)
  110. entry.skeleton = skeleton
  111. }
  112. cm.chans[casefoldedName] = entry
  113. }
  114. entry.pendingJoins += 1
  115. return entry.channel, nil
  116. }()
  117. if err != nil {
  118. return err, ""
  119. }
  120. channel.EnsureLoaded()
  121. err, forward = channel.Join(client, key, isSajoin, rb)
  122. cm.maybeCleanup(channel, true)
  123. return
  124. }
  125. func (cm *ChannelManager) maybeCleanup(channel *Channel, afterJoin bool) {
  126. cm.Lock()
  127. defer cm.Unlock()
  128. cfname := channel.NameCasefolded()
  129. entry := cm.chans[cfname]
  130. if entry == nil || entry.channel != channel {
  131. return
  132. }
  133. if afterJoin {
  134. entry.pendingJoins -= 1
  135. }
  136. if entry.pendingJoins == 0 && entry.channel.IsClean() {
  137. delete(cm.chans, cfname)
  138. if entry.skeleton != "" {
  139. delete(cm.chansSkeletons, entry.skeleton)
  140. }
  141. }
  142. }
  143. // Part parts `client` from the channel named `name`, deleting it if it's empty.
  144. func (cm *ChannelManager) Part(client *Client, name string, message string, rb *ResponseBuffer) error {
  145. var channel *Channel
  146. casefoldedName, err := CasefoldChannel(name)
  147. if err != nil {
  148. return errNoSuchChannel
  149. }
  150. cm.RLock()
  151. entry := cm.chans[casefoldedName]
  152. if entry != nil {
  153. channel = entry.channel
  154. }
  155. cm.RUnlock()
  156. if channel == nil {
  157. return errNoSuchChannel
  158. }
  159. channel.Part(client, message, rb)
  160. return nil
  161. }
  162. func (cm *ChannelManager) Cleanup(channel *Channel) {
  163. cm.maybeCleanup(channel, false)
  164. }
  165. func (cm *ChannelManager) SetRegistered(channelName string, account string) (err error) {
  166. if cm.server.Defcon() <= 4 {
  167. return errFeatureDisabled
  168. }
  169. var channel *Channel
  170. cfname, err := CasefoldChannel(channelName)
  171. if err != nil {
  172. return err
  173. }
  174. var entry *channelManagerEntry
  175. defer func() {
  176. if err == nil && channel != nil {
  177. // registration was successful: make the database reflect it
  178. err = channel.Store(IncludeAllAttrs)
  179. }
  180. }()
  181. cm.Lock()
  182. defer cm.Unlock()
  183. entry = cm.chans[cfname]
  184. if entry == nil {
  185. return errNoSuchChannel
  186. }
  187. channel = entry.channel
  188. err = channel.SetRegistered(account)
  189. if err != nil {
  190. return err
  191. }
  192. // transfer the skeleton from chansSkeletons to registeredSkeletons
  193. skeleton := entry.skeleton
  194. delete(cm.chansSkeletons, skeleton)
  195. entry.skeleton = ""
  196. cm.chans[cfname] = entry
  197. cm.registeredChannels.Add(cfname)
  198. cm.registeredSkeletons.Add(skeleton)
  199. return nil
  200. }
  201. func (cm *ChannelManager) SetUnregistered(channelName string, account string) (err error) {
  202. cfname, err := CasefoldChannel(channelName)
  203. if err != nil {
  204. return err
  205. }
  206. info, err := cm.server.channelRegistry.LoadChannel(cfname)
  207. if err != nil {
  208. return err
  209. }
  210. if info.Founder != account {
  211. return errChannelNotOwnedByAccount
  212. }
  213. defer func() {
  214. if err == nil {
  215. err = cm.server.channelRegistry.Delete(info)
  216. }
  217. }()
  218. cm.Lock()
  219. defer cm.Unlock()
  220. entry := cm.chans[cfname]
  221. if entry != nil {
  222. entry.channel.SetUnregistered(account)
  223. delete(cm.registeredChannels, cfname)
  224. // transfer the skeleton from registeredSkeletons to chansSkeletons
  225. if skel, err := Skeleton(entry.channel.Name()); err == nil {
  226. delete(cm.registeredSkeletons, skel)
  227. cm.chansSkeletons.Add(skel)
  228. entry.skeleton = skel
  229. cm.chans[cfname] = entry
  230. }
  231. }
  232. return nil
  233. }
  234. // Rename renames a channel (but does not notify the members)
  235. func (cm *ChannelManager) Rename(name string, newName string) (err error) {
  236. oldCfname, err := CasefoldChannel(name)
  237. if err != nil {
  238. return errNoSuchChannel
  239. }
  240. newCfname, err := CasefoldChannel(newName)
  241. if err != nil {
  242. return errInvalidChannelName
  243. }
  244. newSkeleton, err := Skeleton(newName)
  245. if err != nil {
  246. return errInvalidChannelName
  247. }
  248. var channel *Channel
  249. var info RegisteredChannel
  250. defer func() {
  251. if channel != nil && info.Founder != "" {
  252. channel.Store(IncludeAllAttrs)
  253. // we just flushed the channel under its new name, therefore this delete
  254. // cannot be overwritten by a write to the old name:
  255. cm.server.channelRegistry.Delete(info)
  256. }
  257. }()
  258. cm.Lock()
  259. defer cm.Unlock()
  260. entry := cm.chans[oldCfname]
  261. if entry == nil || !entry.channel.IsLoaded() {
  262. return errNoSuchChannel
  263. }
  264. channel = entry.channel
  265. info = channel.ExportRegistration(IncludeInitial)
  266. registered := info.Founder != ""
  267. oldSkeleton, err := Skeleton(info.Name)
  268. if err != nil {
  269. return errNoSuchChannel // ugh
  270. }
  271. if newCfname != oldCfname {
  272. if cm.chans[newCfname] != nil || cm.registeredChannels.Has(newCfname) {
  273. return errChannelNameInUse
  274. }
  275. }
  276. if oldSkeleton != newSkeleton {
  277. if cm.chansSkeletons.Has(newSkeleton) || cm.registeredSkeletons.Has(newSkeleton) {
  278. return errConfusableIdentifier
  279. }
  280. }
  281. delete(cm.chans, oldCfname)
  282. if !registered {
  283. entry.skeleton = newSkeleton
  284. }
  285. cm.chans[newCfname] = entry
  286. if registered {
  287. delete(cm.registeredChannels, oldCfname)
  288. cm.registeredChannels.Add(newCfname)
  289. delete(cm.registeredSkeletons, oldSkeleton)
  290. cm.registeredSkeletons.Add(newSkeleton)
  291. } else {
  292. delete(cm.chansSkeletons, oldSkeleton)
  293. cm.chansSkeletons.Add(newSkeleton)
  294. }
  295. entry.channel.Rename(newName, newCfname)
  296. return nil
  297. }
  298. // Len returns the number of channels
  299. func (cm *ChannelManager) Len() int {
  300. cm.RLock()
  301. defer cm.RUnlock()
  302. return len(cm.chans)
  303. }
  304. // Channels returns a slice containing all current channels
  305. func (cm *ChannelManager) Channels() (result []*Channel) {
  306. cm.RLock()
  307. defer cm.RUnlock()
  308. result = make([]*Channel, 0, len(cm.chans))
  309. for _, entry := range cm.chans {
  310. if entry.channel.IsLoaded() {
  311. result = append(result, entry.channel)
  312. }
  313. }
  314. return
  315. }
  316. // Purge marks a channel as purged.
  317. func (cm *ChannelManager) Purge(chname string, record ChannelPurgeRecord) (err error) {
  318. chname, err = CasefoldChannel(chname)
  319. if err != nil {
  320. return errInvalidChannelName
  321. }
  322. cm.Lock()
  323. cm.purgedChannels.Add(chname)
  324. cm.Unlock()
  325. cm.server.channelRegistry.PurgeChannel(chname, record)
  326. return nil
  327. }
  328. // IsPurged queries whether a channel is purged.
  329. func (cm *ChannelManager) IsPurged(chname string) (result bool) {
  330. chname, err := CasefoldChannel(chname)
  331. if err != nil {
  332. return false
  333. }
  334. cm.RLock()
  335. result = cm.purgedChannels.Has(chname)
  336. cm.RUnlock()
  337. return
  338. }
  339. // Unpurge deletes a channel's purged status.
  340. func (cm *ChannelManager) Unpurge(chname string) (err error) {
  341. chname, err = CasefoldChannel(chname)
  342. if err != nil {
  343. return errNoSuchChannel
  344. }
  345. cm.Lock()
  346. found := cm.purgedChannels.Has(chname)
  347. delete(cm.purgedChannels, chname)
  348. cm.Unlock()
  349. cm.server.channelRegistry.UnpurgeChannel(chname)
  350. if !found {
  351. return errNoSuchChannel
  352. }
  353. return nil
  354. }
  355. func (cm *ChannelManager) ListPurged() (result []string) {
  356. cm.RLock()
  357. result = make([]string, 0, len(cm.purgedChannels))
  358. for c := range cm.purgedChannels {
  359. result = append(result, c)
  360. }
  361. cm.RUnlock()
  362. sort.Strings(result)
  363. return
  364. }