barertc

package
v0.0.0-...-0e46d6e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2024 License: GPL-3.0 Imports: 34 Imported by: 0

Documentation

Index

Constants

View Source
const PingInterval = 30 * time.Second
View Source
const PollingUserTimeout = time.Minute

Polling user timeout before disconnecting them.

View Source
const (
	WebhookReport = "report"
)

The available and supported webhook event names.

Variables

View Source
var (
	// TODO: configurable
	MaxPhotoWidth = 1280
)
View Source
var SubscriberID int

Auto incrementing Subscriber ID, assigned in AddSubscriber.

Functions

func AboutPage

func AboutPage() http.HandlerFunc

AboutPage returns the HTML template for the about page.

func BanUser

func BanUser(username string, duration time.Duration)

BanUser adds a user to the ban list.

func GetCachedBlocklist

func GetCachedBlocklist(username string) []string

GetCachedBlocklist returns the blocklist for a username.

func GetWebhook

func GetWebhook(name string) (config.WebhookURL, bool)

GetWebhook gets a configured webhook.

func IndexPage

func IndexPage() http.HandlerFunc

IndexPage returns the HTML template for the chat room.

func IsBanned

func IsBanned(username string) bool

IsBanned returns whether the username is currently banned.

func IsLoggingChannel

func IsLoggingChannel(channel string) bool

IsLoggingChannel checks whether the app is currently logging a public channel.

func IsLoggingUsername

func IsLoggingUsername(sub *Subscriber) bool

IsLoggingUsername checks whether the app is currently configured to log a user's DMs.

func LogChannel

func LogChannel(s *Server, channel string, username string, msg messages.Message)

LogChannel appends to a channel's conversation log.

func LogMessage

func LogMessage(sub *Subscriber, otherUsername, senderUsername string, msg messages.Message)

LogMessage appends to a user's conversation log.

func LogoutPage

func LogoutPage() http.HandlerFunc

LogoutPage returns the HTML template for the logout page.

func PostWebhook

func PostWebhook(name string, payload any) ([]byte, error)

PostWebhook submits a JSON body to one of the app's configured webhooks.

Returns the bytes of the response body (hopefully, JSON data) and any errors.

func ProcessImage

func ProcessImage(fileType string, data []byte) ([]byte, int, int)

ProcessImage treats user uploaded images:

- Scales them down to a reasonable size - Strips EXIF metadata

and returns the modified image again as bytes.

Also returns the suggested preview width, height to draw the image at. This may be smaller than its true width x height.

Filetype should be image/jpeg, image/gif or image/png.

func RenderMarkdown

func RenderMarkdown(input string) string

Rendermarkdown from untrusted sources.

func Scale

func Scale(src image.Image, rect image.Rectangle, scale draw.Scaler) image.Image

Scale down an image. Example:

scaled := Scale(src, image.Rect(0, 0, 200, 200), draw.ApproxBiLinear)

func SetCachedBlocklist

func SetCachedBlocklist(username string, blocklist []string)

SetCachedBlocklist sets the blocklist cache for a user.

func StringifyBannedUsers

func StringifyBannedUsers() string

StringifyBannedUsers returns a stringified list of all the current banned users.

func UnbanUser

func UnbanUser(username string) bool

UnbanUser lifts the ban of a user early.

func WebhookEnabled

func WebhookEnabled(name string) bool

WebhookEnabled checks if the named webhook is enabled.

Types

type Ban

type Ban struct {
	Username  string
	ExpiresAt time.Time
}

Ban is an entry on the ban list.

type LogCacheable

type LogCacheable interface {
	GetLogFilehandleCache() map[string]io.WriteCloser
}

Interface for objects that hold log filehandle caches.

type PollMessage

type PollMessage struct {
	// Send the username after authenticated.
	Username string `json:"username,omitempty"`

	// SessionID for authentication.
	SessionID string `json:"session_id,omitempty"`

	// BareRTC protocol message.
	Message messages.Message `json:"msg"`
}

JSON payload structure for polling API.

type PollResponse

type PollResponse struct {
	// Session ID.
	Username  string `json:"username,omitempty"`
	SessionID string `json:"session_id,omitempty"`

	// Pending messages.
	Messages []messages.Message `json:"messages"`
}

func PollResponseError

func PollResponseError(message string) PollResponse

Helper method to send an error as a PollResponse.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the primary back-end server struct for BareRTC, see main.go

func NewServer

func NewServer() *Server

NewServer initializes the Server.

func (*Server) AddSubscriber

func (s *Server) AddSubscriber(sub *Subscriber)

AddSubscriber adds a WebSocket subscriber to the server.

func (*Server) Authenticate

func (s *Server) Authenticate() http.HandlerFunc

Authenticate (/api/authenticate) for the chatbot API.

This endpoint will sign a JWT token using the claims you pass in. It requires the shared secret `AdminAPIKey` from your settings.toml and will sign the JWT claims you give it.

It is a POST request with a json body containing the following schema:

{
	"APIKey": "from settings.toml",
	"Claims": {
		"sub": "username",
		"nick": "Display Name",
		"op": false,
		"img": "/static/photos/avatar.png",
		"url": "/users/username",
		"emoji": "🤖",
		"gender": "m"
	}
}

The return schema looks like:

{
	"OK": true,
	"Error": "error string, omitted if none",
	"JWT": "jwt token string"
}

func (*Server) BanCommand

func (s *Server) BanCommand(words []string, sub *Subscriber)

BanCommand handles the `/ban` operator command.

func (*Server) BansCommand

func (s *Server) BansCommand(words []string, sub *Subscriber)

BansCommand handles the `/bans` operator command.

func (*Server) BlockList

func (s *Server) BlockList() http.HandlerFunc

BlockList (/api/blocklist) allows your website to pre-sync mute lists between your user accounts, so that when they see each other in chat they will pre-emptively mute or boot one another.

It is a POST request with a json body containing the following schema:

{
	"APIKey": "from settings.toml",
	"Username": "soandso",
	"Blocklist": [ "list", "of", "other", "usernames" ],
}

The chat server will remember these mappings (until rebooted). How they are used is that the blocklist is embedded in the front-end page when the username signs in later. As part of the On Connect handler, the front-end will send the list of usernames in a bulk `mute` command to the server. This way even if the chat server reboots while the user is connected, when it comes back up and the user reconnects they will retransmit their block list.

func (*Server) BlockNow

func (s *Server) BlockNow() http.HandlerFunc

BlockNow (/api/block/now) allows your website to add to a current online chatter's blocked list immediately.

For example: the BlockList endpoint does a bulk sync of the blocklist at the time a user joins the chat room, but if users are already on chat when the blocking begins, it doesn't take effect until one or the other re-joins the room. This API endpoint can apply the blocking immediately to the currently online users.

It is a POST request with a json body containing the following schema:

{
	"APIKey": "from settings.toml",
	"Usernames": [ "source", "target" ]
}

The pair of usernames will be the two users who block one another (in any order). If any of the users are currently connected to the chat, they will all mutually block one another immediately.

func (*Server) Broadcast

func (s *Server) Broadcast(msg messages.Message)

Broadcast a message to the chat room.

func (*Server) ClearMessages

func (s *Server) ClearMessages() http.HandlerFunc

ClearMessages (/api/message/clear) deletes all the stored direct messages for a user.

It can be called by the authenticated user themself (with JWTToken), or from your website (with APIKey) in which case you can remotely clear history for a user.

It is a POST request with a json body containing the following schema:

{
	"JWTToken": "the caller's jwt token",
	"APIKey": "your website's admin API key"
	"Username": "if using your APIKey to specify a user to delete",
}

The response JSON will look like the following:

{
	"OK": true,
	"Error": "only on error responses",
	"MessagesErased": 123,
}

The Remaining value is how many older messages still exist to be loaded.

func (*Server) CutCommand

func (s *Server) CutCommand(words []string, sub *Subscriber)

CutCommand handles the `/cut` operator command (force a user's camera to turn off).

func (*Server) DeleteSubscriber

func (s *Server) DeleteSubscriber(sub *Subscriber)

DeleteSubscriber removes a subscriber from the server.

func (*Server) DeopCommand

func (s *Server) DeopCommand(words []string, sub *Subscriber)

DeopCommand handles the `/deop` operator command.

func (*Server) DisconnectNow

func (s *Server) DisconnectNow() http.HandlerFunc

DisconnectNow (/api/disconnect/now) allows your website to remove a user from the chat room if they are currently online.

For example: a user on your website has deactivated their account, and so should not be allowed to remain in the chat room.

It is a POST request with a json body containing the following schema:

{
	"APIKey": "from settings.toml",
	"Usernames": [ "alice", "bob" ],
	"Message": "An optional ChatServer message to send them first.",
	"Kick": false,
}

The `Message` parameter, if provided, will be sent to that user as a ChatServer error before they are removed from the room. You can use this to provide them context as to why they are being kicked. For example: "You have been logged out of chat because you deactivated your profile on the main website."

The `Kick` boolean is whether the removal should manifest to other users in chat as a "kick" (sending a presence message of "has been kicked from the room!"). By default (false), BareRTC will tell the user to disconnect and it will manifest as a regular "has left the room" event to other online chatters.

func (*Server) ExpandMedia

func (s *Server) ExpandMedia(message string) string

ExpandMedia detects media URLs such as YouTube videos and stylizes the message up with embeds.

func (*Server) GetLogFilehandleCache

func (s *Server) GetLogFilehandleCache() map[string]io.WriteCloser

func (*Server) GetSubscriber

func (s *Server) GetSubscriber(username string) (*Subscriber, error)

GetSubscriber by username.

func (*Server) IsVideoNotAllowed

func (s *Server) IsVideoNotAllowed(sub *Subscriber, other *Subscriber) (bool, string)

IsVideoNotAllowed verifies whether a viewer can open a broadcaster's camera.

Returns a boolean and an error message to return if false.

func (*Server) IterSubscribers

func (s *Server) IterSubscribers() []*Subscriber

IterSubscribers loops over the subscriber list with a read lock.

func (*Server) KickAllCommand

func (s *Server) KickAllCommand()

KickAllCommand kicks everybody out of the room.

func (*Server) KickCommand

func (s *Server) KickCommand(words []string, sub *Subscriber)

KickCommand handles the `/kick` operator command.

func (*Server) KickIdlePollUsers

func (s *Server) KickIdlePollUsers()

KickIdlePollUsers is a goroutine that will disconnect polling API users who haven't been seen in a while.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(address string) error

ListenAndServe starts the web server.

func (*Server) MessageHistory

func (s *Server) MessageHistory() http.HandlerFunc

MessageHistory (/api/message/history) fetches past direct messages for a user.

This endpoint looks up earlier chat messages between the current user and a target. It will only run with a valid JWT auth token, to protect users' privacy.

It is a POST request with a json body containing the following schema:

{
	"JWTToken": "the caller's jwt token",
	"Username": "other party",
	"BeforeID": 1234,
}

The "BeforeID" parameter is for pagination and is optional: by default the most recent page of messages are returned. To retrieve an older page, the BeforeID will contain the MessageID of the oldest message you received so far, so that the message before that will be the first returned on the next page.

The response JSON will look like the following:

{
	"OK": true,
	"Error": "only on error responses",
	"Messages": [
		{
			// Standard BareRTC Message objects...
			"MessageID": 1234,
			"Username": "other party",
			"Message": "hello!",
		}
	],
	"Remaining": 42,
}

The Remaining value is how many older messages still exist to be loaded.

func (*Server) NSFWCommand

func (s *Server) NSFWCommand(words []string, sub *Subscriber)

NSFWCommand handles the `/nsfw` operator command.

func (*Server) NewPollingSubscriber

func (s *Server) NewPollingSubscriber(ctx context.Context, cancelFunc func()) *Subscriber

NewPollingSubscriber returns a new subscriber using the polling API.

func (*Server) NewSubscriber

func (s *Server) NewSubscriber(ctx context.Context, cancelFunc func()) *Subscriber

NewSubscriber initializes a connected chat user.

func (*Server) NewWebSocketSubscriber

func (s *Server) NewWebSocketSubscriber(ctx context.Context, conn *websocket.Conn, cancelFunc func()) *Subscriber

NewWebSocketSubscriber returns a new subscriber with a WebSocket connection.

func (*Server) OnBlock

func (s *Server) OnBlock(sub *Subscriber, msg messages.Message)

OnBlock is a user placing a hard block (hide from) another user.

func (*Server) OnBlocklist

func (s *Server) OnBlocklist(sub *Subscriber, msg messages.Message)

OnBlocklist is a bulk user mute from the CachedBlocklist sent by the website.

func (*Server) OnBoot

func (s *Server) OnBoot(sub *Subscriber, msg messages.Message, boot bool)

OnBoot is a user kicking you off their video stream.

func (*Server) OnCandidate

func (s *Server) OnCandidate(sub *Subscriber, msg messages.Message)

OnCandidate handles WebRTC candidate signaling.

func (*Server) OnClientMessage

func (s *Server) OnClientMessage(sub *Subscriber, msg messages.Message)

OnClientMessage handles a chat protocol message from the user's WebSocket or polling API.

func (*Server) OnFile

func (s *Server) OnFile(sub *Subscriber, msg messages.Message)

OnFile handles a picture shared in chat with a channel.

func (*Server) OnLogin

func (s *Server) OnLogin(sub *Subscriber, msg messages.Message)

OnLogin handles "login" actions from the client.

func (*Server) OnMe

func (s *Server) OnMe(sub *Subscriber, msg messages.Message)

OnMe handles current user state updates.

func (*Server) OnMessage

func (s *Server) OnMessage(sub *Subscriber, msg messages.Message)

OnMessage handles a chat message posted by the user.

func (*Server) OnMute

func (s *Server) OnMute(sub *Subscriber, msg messages.Message, mute bool)

OnMute is a user kicking setting the mute flag for another user.

func (*Server) OnOpen

func (s *Server) OnOpen(sub *Subscriber, msg messages.Message)

OnOpen is a client wanting to start WebRTC with another, e.g. to see their camera.

func (*Server) OnReact

func (s *Server) OnReact(sub *Subscriber, msg messages.Message)

OnReact handles emoji reactions for chat messages.

func (*Server) OnReport

func (s *Server) OnReport(sub *Subscriber, msg messages.Message)

OnReport handles a user's report of a message.

func (*Server) OnSDP

func (s *Server) OnSDP(sub *Subscriber, msg messages.Message)

OnSDP handles WebRTC sdp signaling.

func (*Server) OnTakeback

func (s *Server) OnTakeback(sub *Subscriber, msg messages.Message)

OnTakeback handles takebacks (delete your message for everybody)

func (*Server) OnUnwatch

func (s *Server) OnUnwatch(sub *Subscriber, msg messages.Message)

OnUnwatch communicates video Unwatching status between users.

func (*Server) OnWatch

func (s *Server) OnWatch(sub *Subscriber, msg messages.Message)

OnWatch communicates video watching status between users.

func (*Server) OpCommand

func (s *Server) OpCommand(words []string, sub *Subscriber)

OpCommand handles the `/op` operator command.

func (*Server) PollingAPI

func (s *Server) PollingAPI() http.HandlerFunc

Functions for the Polling API as an alternative to WebSockets.

func (*Server) ProcessCommand

func (s *Server) ProcessCommand(sub *Subscriber, msg messages.Message) bool

ProcessCommand parses a chat message for "/commands"

func (*Server) ReconfigureCommand

func (s *Server) ReconfigureCommand(sub *Subscriber)

ReconfigureCommand handles the `/reconfigure` operator command.

func (*Server) SendTo

func (s *Server) SendTo(username string, msg messages.Message) error

SendTo sends a message to a given username.

func (*Server) SendWhoList

func (s *Server) SendWhoList()

SendWhoList broadcasts the connected members to everybody in the room.

func (*Server) Setup

func (s *Server) Setup() error

Setup the server: configure HTTP routes, etc.

func (*Server) ShutdownAPI

func (s *Server) ShutdownAPI() http.HandlerFunc

Shutdown (/api/shutdown) the chat server, hopefully to reboot it.

This endpoint is equivalent to the operator '/shutdown' command but may be invoked by your website, or your chatbot. It requires the AdminAPIKey.

It is a POST request with a json body containing the following schema:

{
	"APIKey": "from settings.toml",
}

The return schema looks like:

{
	"OK": true,
	"Error": "error string, omitted if none",
}

func (*Server) Statistics

func (s *Server) Statistics() http.HandlerFunc

Statistics (/api/statistics) returns info about the users currently logged onto the chat, for your website to call via CORS. The URL to your site needs to be in the CORSHosts array of your settings.toml.

func (*Server) UnbanCommand

func (s *Server) UnbanCommand(words []string, sub *Subscriber)

UnbanCommand handles the `/unban` operator command.

func (*Server) UniqueUsername

func (s *Server) UniqueUsername(username string) (string, error)

UniqueUsername ensures a username will be unique or renames it. If the name is already unique, the error result is nil.

func (*Server) UnmuteAllCommand

func (s *Server) UnmuteAllCommand(words []string, sub *Subscriber)

UnmuteAllCommand handles the `/unmute-all` operator command (remove all mutes for the current user).

It enables an operator to see public messages from any user who muted/blocked them. Note: from the other side of the mute, the operator's public messages may still be hidden from those users.

It is useful for an operator chatbot if you want users to be able to block it but still retain the bot's ability to moderate public channel messages, and send warnings in DMs to misbehaving users even despite a mute being in place.

func (*Server) UserProfile

func (s *Server) UserProfile() http.HandlerFunc

UserProfile (/api/profile) fetches profile information about a user.

This endpoint will proxy to your WebhookURL for the "profile" endpoint. If your webhook is not configured or not reachable, this endpoint returns an error to the caller.

Authentication: the caller must send their current chat JWT token when hitting this endpoint.

It is a POST request with a json body containing the following schema:

{
	"JWTToken": "the caller's jwt token",
	"Username": [ "soandso" ]
}

The response JSON will look like the following (this also mirrors the response json as sent by your site's webhook URL):

{
	"OK": true,
    "Error": "only on errors",
    "ProfileFields": [
		{
			"Name": "Age",
			"Value": "30yo",
		},
		{
			"Name": "Gender",
			"Value": "Man",
		},
		...
	]
}

func (*Server) WebSocket

func (s *Server) WebSocket() http.HandlerFunc

WebSocket handles the /ws websocket connection endpoint.

type Subscriber

type Subscriber struct {
	// User properties
	ID          int // ID assigned by server
	Username    string
	ChatStatus  string
	VideoStatus int
	DND         bool // Do Not Disturb status (DMs are closed)
	JWTClaims   *jwt.Claims
	// contains filtered or unexported fields
}

Subscriber represents a connected WebSocket session.

func (*Subscriber) Blocks

func (s *Subscriber) Blocks(other *Subscriber) bool

Blocks checks whether the subscriber blocks the username, or vice versa (blocking goes both directions).

func (*Subscriber) Boots

func (s *Subscriber) Boots(username string) bool

Boots checks whether the subscriber has blocked username from their camera.

func (*Subscriber) ChatServer

func (sub *Subscriber) ChatServer(message string, v ...interface{})

ChatServer is a convenience function to deliver a ChatServer error to the client.

func (*Subscriber) FlushPollResponse

func (sub *Subscriber) FlushPollResponse() PollResponse

FlushPollResponse returns a response for the polling API that will flush all pending messages sent to the client.

func (*Subscriber) GetLogFilehandleCache

func (sub *Subscriber) GetLogFilehandleCache() map[string]io.WriteCloser

Implementations of LogCacheable.

func (*Subscriber) GetModerationRule

func (sub *Subscriber) GetModerationRule() *config.ModerationRule

GetModerationRule loads any moderation rules applied to the user.

Moderation rules can be applied by your chat server (in settings.toml) or provided by your website (in the custom JWT claims "rules" key).

func (*Subscriber) IsAdmin

func (sub *Subscriber) IsAdmin() bool

IsAdmin safely checks if the subscriber is an admin.

func (*Subscriber) IsVIP

func (sub *Subscriber) IsVIP() bool

IsVIP safely checks if the subscriber has VIP status.

func (*Subscriber) Mutes

func (s *Subscriber) Mutes(username string) bool

Mutes checks whether the subscriber has muted username.

func (*Subscriber) ReadLoop

func (sub *Subscriber) ReadLoop(s *Server)

ReadLoop spawns a goroutine that reads from the websocket connection.

func (*Subscriber) SendCut

func (sub *Subscriber) SendCut()

SendCut sends the client a 'cut' message to deactivate their camera.

func (*Subscriber) SendJSON

func (sub *Subscriber) SendJSON(v interface{}) error

SendJSON sends a JSON message to the websocket client.

func (*Subscriber) SendMe

func (sub *Subscriber) SendMe()

SendMe sends the current user state to the client.

type WebhookRequest

type WebhookRequest struct {
	Action string
	APIKey string

	// Relevant body per request.
	Report WebhookRequestReport `json:",omitempty"`
}

WebhookRequest is a JSON request wrapper around all webhook messages.

type WebhookRequestReport

type WebhookRequestReport struct {
	FromUsername  string
	AboutUsername string
	Channel       string
	Timestamp     string
	Reason        string
	Message       string
	Comment       string
}

WebhookRequestReport is the body for 'report' webhook messages.

Directories

Path Synopsis
Package log centralizes logging for the app.
Package log centralizes logging for the app.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL
JackTT - Gopher 🇻🇳