Browse Source

initial implementation of draft/persistence

tags/v2.11.0-rc1
Shivaram Lingamneni 1 year ago
parent
commit
99d27ff737
6 changed files with 101 additions and 1 deletions
  1. 6
    0
      gencapdefs.py
  2. 6
    1
      irc/caps/defs.go
  3. 4
    0
      irc/commands.go
  4. 75
    0
      irc/handlers.go
  5. 7
    0
      irc/help.go
  6. 3
    0
      irc/server.go

+ 6
- 0
gencapdefs.py View File

@@ -189,6 +189,12 @@ CAPDEFS = [
189 189
         url="https://github.com/ircv3/ircv3-specifications/pull/489",
190 190
         standard="draft IRCv3",
191 191
     ),
192
+    CapDef(
193
+        identifier="Persistence",
194
+        name="draft/persistence",
195
+        url="https://gist.github.com/slingamn/e3645a0d0418b736b755746bfd65f2a6",
196
+        standard="proposed IRCv3",
197
+    ),
192 198
 ]
193 199
 
194 200
 def validate_defs():

+ 6
- 1
irc/caps/defs.go View File

@@ -7,7 +7,7 @@ package caps
7 7
 
8 8
 const (
9 9
 	// number of recognized capabilities:
10
-	numCapabs = 29
10
+	numCapabs = 30
11 11
 	// length of the uint64 array that represents the bitset:
12 12
 	bitsetLen = 1
13 13
 )
@@ -61,6 +61,10 @@ const (
61 61
 	// https://github.com/ircv3/ircv3-specifications/pull/398
62 62
 	Multiline Capability = iota
63 63
 
64
+	// Persistence is the proposed IRCv3 capability named "draft/persistence":
65
+	// https://gist.github.com/slingamn/e3645a0d0418b736b755746bfd65f2a6
66
+	Persistence Capability = iota
67
+
64 68
 	// ReadMarker is the draft IRCv3 capability named "draft/read-marker":
65 69
 	// https://github.com/ircv3/ircv3-specifications/pull/489
66 70
 	ReadMarker Capability = iota
@@ -145,6 +149,7 @@ var (
145 149
 		"draft/event-playback",
146 150
 		"draft/languages",
147 151
 		"draft/multiline",
152
+		"draft/persistence",
148 153
 		"draft/read-marker",
149 154
 		"draft/relaymsg",
150 155
 		"echo-message",

+ 4
- 0
irc/commands.go View File

@@ -233,6 +233,10 @@ func init() {
233 233
 			usablePreReg: true,
234 234
 			minParams:    1,
235 235
 		},
236
+		"PERSISTENCE": {
237
+			handler:   persistenceHandler,
238
+			minParams: 1,
239
+		},
236 240
 		"PING": {
237 241
 			handler:      pingHandler,
238 242
 			usablePreReg: true,

+ 75
- 0
irc/handlers.go View File

@@ -2599,6 +2599,81 @@ func passHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
2599 2599
 	return false
2600 2600
 }
2601 2601
 
2602
+// PERSISTENCE <subcommand> [params...]
2603
+func persistenceHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
2604
+	account := client.Account()
2605
+	if account == "" {
2606
+		rb.Add(nil, server.name, "FAIL", "PERSISTENCE", "ACCOUNT_REQUIRED", client.t("You're not logged into an account"))
2607
+		return false
2608
+	}
2609
+
2610
+	switch strings.ToUpper(msg.Params[0]) {
2611
+	case "GET":
2612
+		reportPersistenceStatus(client, rb)
2613
+	case "SET":
2614
+		if len(msg.Params) == 1 {
2615
+			goto fail
2616
+		}
2617
+		var desiredSetting PersistentStatus
2618
+		switch strings.ToUpper(msg.Params[1]) {
2619
+		case "DEFAULT":
2620
+			desiredSetting = PersistentUnspecified
2621
+		case "OFF":
2622
+			desiredSetting = PersistentDisabled
2623
+		case "ON":
2624
+			desiredSetting = PersistentMandatory
2625
+		default:
2626
+			goto fail
2627
+		}
2628
+
2629
+		_, err := server.accounts.ModifyAccountSettings(account,
2630
+			func(input AccountSettings) (output AccountSettings, err error) {
2631
+				output = input
2632
+				output.AlwaysOn = desiredSetting
2633
+				return
2634
+			})
2635
+		if err != nil {
2636
+			server.logger.Error("internal", "couldn't modify persistence setting", err.Error())
2637
+			rb.Add(nil, server.name, "FAIL", "PERSISTENCE", "UNKNOWN_ERROR", client.t("An error occurred"))
2638
+			return false
2639
+		}
2640
+
2641
+		reportPersistenceStatus(client, rb)
2642
+
2643
+	default:
2644
+		goto fail
2645
+	}
2646
+
2647
+	return false
2648
+
2649
+fail:
2650
+	rb.Add(nil, server.name, "FAIL", "PERSISTENCE", "INVALID_PARAMS", client.t("Invalid parameters"))
2651
+	return false
2652
+}
2653
+
2654
+func reportPersistenceStatus(client *Client, rb *ResponseBuffer) {
2655
+	settings := client.AccountSettings()
2656
+	serverSetting := client.server.Config().Accounts.Multiclient.AlwaysOn
2657
+	effectiveSetting := persistenceEnabled(serverSetting, settings.AlwaysOn)
2658
+	toString := func(setting PersistentStatus) string {
2659
+		switch setting {
2660
+		case PersistentUnspecified:
2661
+			return "DEFAULT"
2662
+		case PersistentDisabled:
2663
+			return "OFF"
2664
+		case PersistentMandatory:
2665
+			return "ON"
2666
+		default:
2667
+			return "*" // impossible
2668
+		}
2669
+	}
2670
+	effectiveSettingStr := "OFF"
2671
+	if effectiveSetting {
2672
+		effectiveSettingStr = "ON"
2673
+	}
2674
+	rb.Add(nil, client.server.name, "PERSISTENCE", "STATUS", toString(settings.AlwaysOn), effectiveSettingStr)
2675
+}
2676
+
2602 2677
 // PING [params...]
2603 2678
 func pingHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
2604 2679
 	rb.Add(nil, server.name, "PONG", server.name, msg.Params[0])

+ 7
- 0
irc/help.go View File

@@ -413,6 +413,13 @@ Leaves the given channels and shows people the given reason.`,
413 413
 
414 414
 When the server requires a connection password to join, used to send us the
415 415
 password.`,
416
+	},
417
+	"persistence": {
418
+		text: `PERSISTENCE [params]
419
+
420
+PERSISTENCE is a command associated with an IRC protocol extension for
421
+persistent connections. End users should probably use /NS GET ALWAYS-ON
422
+and /NS SET ALWAYS-ON instead.`,
416 423
 	},
417 424
 	"ping": {
418 425
 		text: `PING <args>...

+ 3
- 0
irc/server.go View File

@@ -420,6 +420,9 @@ func (server *Server) playRegistrationBurst(session *Session) {
420 420
 
421 421
 	rb := NewResponseBuffer(session)
422 422
 	server.RplISupport(c, rb)
423
+	if session.capabilities.Has(caps.Persistence) {
424
+		reportPersistenceStatus(c, rb)
425
+	}
423 426
 	server.Lusers(c, rb)
424 427
 	server.MOTD(c, rb)
425 428
 	rb.Send(true)

Loading…
Cancel
Save