forked from CFC-Servers/cfc_chat_transit
Feature/larynx (#40)
This commit is contained in:
parent
8d142056b9
commit
bcd5f73e9a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
.env
|
||||
.idea
|
||||
|
1
lua/autorun/client/cfc_chat_transit_init.lua
Normal file
1
lua/autorun/client/cfc_chat_transit_init.lua
Normal file
@ -0,0 +1 @@
|
||||
return include("cfc_chat_transit/client/init.lua")
|
6
lua/autorun/server/sv_chat_transit_init.lua
Normal file
6
lua/autorun/server/sv_chat_transit_init.lua
Normal file
@ -0,0 +1,6 @@
|
||||
require("steamlookup")
|
||||
include("cfc_chat_transit/server/init.lua")
|
||||
include("cfc_chat_transit/server/remote_messages.lua")
|
||||
AddCSLuaFile("cfc_chat_transit/client/init.lua")
|
||||
AddCSLuaFile("cfc_chat_transit/client/menu.lua")
|
||||
return AddCSLuaFile("cfc_chat_transit/client/receive_remote_message.lua")
|
2
lua/cfc_chat_transit/client/init.lua
Normal file
2
lua/cfc_chat_transit/client/init.lua
Normal file
@ -0,0 +1,2 @@
|
||||
ChatTransit = { }
|
||||
return include("receive_remote_message.lua")
|
31
lua/cfc_chat_transit/client/menu.lua
Normal file
31
lua/cfc_chat_transit/client/menu.lua
Normal file
@ -0,0 +1,31 @@
|
||||
local alertPreference
|
||||
alertPreference = function(val)
|
||||
net.Start("CFC_ChatTransit_RemoteMessagePreference")
|
||||
net.WriteBool(val)
|
||||
return net.SendToServer()
|
||||
end
|
||||
local initHookName = "CFC_ChatTransit_AlertRemoteMessagePreference"
|
||||
hook.Add("Think", initHookName, function()
|
||||
hook.Remove("Think", initHookName)
|
||||
alertPreference(ChatTransit.shouldReceiveRemoteMessages:GetBool())
|
||||
return nil
|
||||
end)
|
||||
local populatePanel
|
||||
populatePanel = function(panel)
|
||||
local label = "Should show remote messages"
|
||||
do
|
||||
local _with_0 = panel:CheckBox(label, "cfc_chat_transit_remote_messages")
|
||||
_with_0.OnChange = function(_, val)
|
||||
return ChatTransit.alertPreference(val)
|
||||
end
|
||||
return _with_0
|
||||
end
|
||||
end
|
||||
hook.Add("AddToolMenuCategories", "CFC_ChatTransit_MenuCategory", function()
|
||||
return AddToolCategory("Options", "CFC", "CFC")
|
||||
end)
|
||||
return hook.Add("PopulateToolMenu", "CFC_ChatTransit_MenuOption", function()
|
||||
return AddToolMenuOption("Options", "CFC", "should_receive_remote_messages", "Remote Messages", "", "", function(panel)
|
||||
return populatePanel(panel)
|
||||
end)
|
||||
end)
|
73
lua/cfc_chat_transit/client/receive_remote_message.lua
Normal file
73
lua/cfc_chat_transit/client/receive_remote_message.lua
Normal file
@ -0,0 +1,73 @@
|
||||
local Start, Receive, ReadBool, ReadColor, ReadString, WriteBool, SendToServer
|
||||
do
|
||||
local _obj_0 = net
|
||||
Start, Receive, ReadBool, ReadColor, ReadString, WriteBool, SendToServer = _obj_0.Start, _obj_0.Receive, _obj_0.ReadBool, _obj_0.ReadColor, _obj_0.ReadString, _obj_0.WriteBool, _obj_0.SendToServer
|
||||
end
|
||||
local AddToolCategory, AddToolMenuOption
|
||||
do
|
||||
local _obj_0 = spawnmenu
|
||||
AddToolCategory, AddToolMenuOption = _obj_0.AddToolCategory, _obj_0.AddToolMenuOption
|
||||
end
|
||||
local shouldReceiveRemoteMessages = CreateConVar("cfc_chat_transit_remote_messages", 1, FCVAR_ARCHIVE, "Should receive remote messges in chat", 0, 1)
|
||||
local colors = {
|
||||
white = Color(255, 255, 255),
|
||||
blurple = Color(142, 163, 247)
|
||||
}
|
||||
Receive("CFC_ChatTransit_RemoteMessageReceive", function()
|
||||
if not (shouldReceiveRemoteMessages:GetBool()) then
|
||||
return
|
||||
end
|
||||
local author = ReadString()
|
||||
local authorColor = ReadColor()
|
||||
local message = ReadString()
|
||||
if not (author) then
|
||||
return
|
||||
end
|
||||
if not (authorColor) then
|
||||
return
|
||||
end
|
||||
if not (message) then
|
||||
return
|
||||
end
|
||||
local addTextParams = {
|
||||
colors.blurple,
|
||||
"[Discord] ",
|
||||
authorColor,
|
||||
author,
|
||||
colors.white,
|
||||
": " .. tostring(message)
|
||||
}
|
||||
hook.Run("CFC_ChatTransit_RemoteMessageReceive", addTextParams)
|
||||
return chat.AddText(unpack(addTextParams))
|
||||
end)
|
||||
local alertPreference
|
||||
alertPreference = function(val)
|
||||
Start("CFC_ChatTransit_RemoteMessagePreference")
|
||||
WriteBool(val)
|
||||
return SendToServer()
|
||||
end
|
||||
local initHookName = "CFC_ChatTransit_AlertRemoteMessagePreference"
|
||||
hook.Add("Think", initHookName, function()
|
||||
hook.Remove("Think", initHookName)
|
||||
alertPreference(shouldReceiveRemoteMessages:GetBool())
|
||||
return nil
|
||||
end)
|
||||
local populatePanel
|
||||
populatePanel = function(panel)
|
||||
local label = "Should show remote messages"
|
||||
do
|
||||
local _with_0 = panel:CheckBox(label, "cfc_chat_transit_remote_messages")
|
||||
_with_0.OnChange = function(_, val)
|
||||
return alertPreference(val)
|
||||
end
|
||||
return _with_0
|
||||
end
|
||||
end
|
||||
hook.Add("AddToolMenuCategories", "CFC_ChatTransit_MenuCategory", function()
|
||||
return AddToolCategory("Options", "CFC", "CFC")
|
||||
end)
|
||||
return hook.Add("PopulateToolMenu", "CFC_ChatTransit_MenuOption", function()
|
||||
return AddToolMenuOption("Options", "CFC", "should_receive_remote_messages", "Remote Messages", "", "", function(panel)
|
||||
return populatePanel(panel)
|
||||
end)
|
||||
end)
|
90
lua/cfc_chat_transit/server/avatar_service.lua
Normal file
90
lua/cfc_chat_transit/server/avatar_service.lua
Normal file
@ -0,0 +1,90 @@
|
||||
local TableToJSON
|
||||
TableToJSON = util.TableToJSON
|
||||
local HTTP = HTTP
|
||||
local avatarServiceAddress = CreateConVar("cfc_avatar_service_address", "", FCVAR_ARCHIVE + FCVAR_PROTECTED)
|
||||
local AvatarService
|
||||
do
|
||||
local _class_0
|
||||
local _base_0 = {
|
||||
getAvatar = function(self, steamID64)
|
||||
local url = steamID64 and "https://avatarservice.cfcservers.org/avatars/" .. tostring(steamID64) .. ".png" or nil
|
||||
if self.processedIds[steamID64] then
|
||||
url = url and tostring(url) .. "?processed=true"
|
||||
end
|
||||
return url
|
||||
end,
|
||||
processAvatar = function(self, avatarUrl, outlineColor, steamID64)
|
||||
local body = TableToJSON({
|
||||
avatarUrl = avatarUrl,
|
||||
outlineColor = outlineColor,
|
||||
steamID = steamID64
|
||||
})
|
||||
self.logger:debug("Sending data to outliner: ", body)
|
||||
local failed
|
||||
do
|
||||
local _base_1 = self.logger
|
||||
local _fn_0 = _base_1.error
|
||||
failed = function(...)
|
||||
return _fn_0(_base_1, ...)
|
||||
end
|
||||
end
|
||||
local success
|
||||
success = function(code, body)
|
||||
self.logger:debug("Avatar request succeeded with code: " .. tostring(code) .. " | Body: " .. tostring(body))
|
||||
self.processedIds[steamID64] = true
|
||||
end
|
||||
return HTTP({
|
||||
success = success,
|
||||
failed = failed,
|
||||
body = body,
|
||||
url = self.outlinerUrl,
|
||||
method = "POST",
|
||||
type = "application/json"
|
||||
})
|
||||
end,
|
||||
outlineAvatar = function(self, ply, data)
|
||||
self.logger:debug("Received request to outline avatar for ply: " .. tostring(ply:Nick()))
|
||||
local avatar = data.response.players[1].avatarfull
|
||||
local outlineColor = ChatTransit:GetTeamColor(ply:Team())
|
||||
local steamID64 = ply:SteamID64()
|
||||
return self:processAvatar(avatar, outlineColor, steamID64)
|
||||
end
|
||||
}
|
||||
_base_0.__index = _base_0
|
||||
_class_0 = setmetatable({
|
||||
__init = function(self, logger)
|
||||
self.logger = logger:scope("AvatarService")
|
||||
self.outlinerUrl = tostring(avatarServiceAddress:GetString()) .. "/outline"
|
||||
self.processedIds = { }
|
||||
end,
|
||||
__base = _base_0,
|
||||
__name = "AvatarService"
|
||||
}, {
|
||||
__index = _base_0,
|
||||
__call = function(cls, ...)
|
||||
local _self_0 = setmetatable({}, _base_0)
|
||||
cls.__init(_self_0, ...)
|
||||
return _self_0
|
||||
end
|
||||
})
|
||||
_base_0.__class = _class_0
|
||||
AvatarService = _class_0
|
||||
end
|
||||
hook.Add("InitPostEntity", "CFC_ChatTrahsit_AvatarServiceInit", function()
|
||||
ChatTransit.AvatarService = AvatarService(ChatTransit.Logger)
|
||||
end)
|
||||
return hook.Add("CFC_SteamLookup_SuccessfulPlayerData", "CFC_ChatTransit_AvatarService", function(dataName, ply, data)
|
||||
if not (dataName == "PlayerSummary") then
|
||||
return
|
||||
end
|
||||
if not (data) then
|
||||
return
|
||||
end
|
||||
local success, err = pcall(function()
|
||||
return ChatTransit.AvatarService:outlineAvatar(ply, data)
|
||||
end)
|
||||
if not (success) then
|
||||
ErrorNoHaltWithStack(err, dataName, ply)
|
||||
end
|
||||
return nil
|
||||
end)
|
89
lua/cfc_chat_transit/server/init.lua
Normal file
89
lua/cfc_chat_transit/server/init.lua
Normal file
@ -0,0 +1,89 @@
|
||||
require("gwsockets")
|
||||
require("logger")
|
||||
ChatTransit = {
|
||||
Logger = Logger("ChatTransit")
|
||||
}
|
||||
include("cfc_chat_transit/server/avatar_service.lua")
|
||||
include("cfc_chat_transit/server/player_count.lua")
|
||||
local Read
|
||||
Read = file.Read
|
||||
local GetColor
|
||||
GetColor = team.GetColor
|
||||
local TableToJSON
|
||||
TableToJSON = util.TableToJSON
|
||||
local logger = ChatTransit.Logger
|
||||
local relayHost = CreateConVar("cfc_relay_host", "", FCVAR_NONE)
|
||||
local loadHook = "ChatTransit_WebsocketLoad"
|
||||
hook.Add("Think", loadHook, function()
|
||||
hook.Remove("Think", loadHook)
|
||||
ChatTransit.WebSocket = GWSockets.createWebSocket("wss://" .. tostring(relayHost:GetString()) .. "/relay", false)
|
||||
ChatTransit.Realm = CreateConVar("cfc_realm", "unknown", FCVAR_REPLICATED + FCVAR_ARCHIVE, "The Realm Name")
|
||||
do
|
||||
local _with_0 = ChatTransit.WebSocket
|
||||
_with_0.reconnectTimerName = "CFC_ChatTransit_WebsocketReconnect"
|
||||
_with_0.onConnected = function(self)
|
||||
logger:info("Established websocket connection")
|
||||
return timer.Remove(_with_0.reconnectTimerName)
|
||||
end
|
||||
_with_0.onDisconnected = function(self)
|
||||
logger:warn("Lost websocket connection!")
|
||||
if timer.Exists(_with_0.reconnectTimerName) then
|
||||
return logger:warn("Will retry " .. tostring(timer.RepsLeft(_with_0.reconnectTimerName)) .. " more times")
|
||||
end
|
||||
return timer.Create(_with_0.reconnectTimerName, 2, 30, function()
|
||||
return _with_0:open()
|
||||
end)
|
||||
end
|
||||
_with_0.onError = function(self, message)
|
||||
return logger:error("Websocket Error!", message)
|
||||
end
|
||||
_with_0:open()
|
||||
end
|
||||
return nil
|
||||
end)
|
||||
ChatTransit.Send = function(self, data)
|
||||
logger:debug("Sending '" .. tostring(data.Type) .. "'")
|
||||
local steamID64 = data.Data.SteamId
|
||||
data.Data.Avatar = data.Data.Avatar or ChatTransit.AvatarService:getAvatar(steamID64)
|
||||
data.Realm = self.Realm:GetString()
|
||||
data.Data.SteamId = data.Data.SteamId or ""
|
||||
return self.WebSocket:write(TableToJSON(data))
|
||||
end
|
||||
ChatTransit.TeamColorCache = { }
|
||||
ChatTransit.GetTeamColor = function(self, teamName)
|
||||
if self.TeamColorCache[teamName] then
|
||||
return self.TeamColorCache[teamName]
|
||||
end
|
||||
local teamColor = tostring(GetColor(teamName))
|
||||
self.TeamColorCache[teamName] = teamColor
|
||||
return teamColor
|
||||
end
|
||||
ChatTransit.guard = function(f, delay)
|
||||
return function(...)
|
||||
local args = {
|
||||
...
|
||||
}
|
||||
local action
|
||||
action = function()
|
||||
local success, err = pcall(function()
|
||||
return f(unpack(args))
|
||||
end)
|
||||
if not (success) then
|
||||
return ErrorNoHaltWithStack(err)
|
||||
end
|
||||
end
|
||||
if delay then
|
||||
timer.Simple(delay, action)
|
||||
else
|
||||
action()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
logger:info("Loading modules...")
|
||||
local _list_0 = file.Find("cfc_chat_transit/server/modules/*.lua", "LUA")
|
||||
for _index_0 = 1, #_list_0 do
|
||||
local f = _list_0[_index_0]
|
||||
logger:info("Loading modules/" .. tostring(f))
|
||||
include("modules/" .. tostring(f))
|
||||
end
|
37
lua/cfc_chat_transit/server/modules/anticrash.lua
Normal file
37
lua/cfc_chat_transit/server/modules/anticrash.lua
Normal file
@ -0,0 +1,37 @@
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
local isstring
|
||||
isstring = _G.isstring
|
||||
ChatTransit.AnticrashEvent = function(self, eventText)
|
||||
if not (isstring(eventText)) then
|
||||
eventText = "Heavy lag detected!"
|
||||
end
|
||||
return self:Send({
|
||||
Type = "anticrash_event",
|
||||
Data = {
|
||||
Content = eventText,
|
||||
SteamName = "CFC Anticrash"
|
||||
}
|
||||
})
|
||||
end
|
||||
hook.Add("z_anticrash_LagDetect", "CFC_ChatTransit_AnticrashEventListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.AnticrashEvent
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)()))
|
||||
hook.Add("z_anticrash_LagStuck", "CFC_ChatTransit_AnticrashEventListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.AnticrashEvent
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)()))
|
||||
return hook.Add("z_anticrash_CrashPrevented", "CFC_ChatTransit_AnticrashEventListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.AnticrashEvent
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)()))
|
34
lua/cfc_chat_transit/server/modules/chat.lua
Normal file
34
lua/cfc_chat_transit/server/modules/chat.lua
Normal file
@ -0,0 +1,34 @@
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
ChatTransit.ReceiveMessage = function(self, ply, text, teamChat)
|
||||
local shouldRelay = hook.Run("CFC_ChatTransit_ShouldRelayChatMessage", ply, text, teamChat)
|
||||
if shouldRelay == false then
|
||||
return
|
||||
end
|
||||
if teamChat then
|
||||
return
|
||||
end
|
||||
if not (text) then
|
||||
return
|
||||
end
|
||||
if text == "" then
|
||||
return
|
||||
end
|
||||
return self:Send({
|
||||
Type = "message",
|
||||
Data = {
|
||||
Type = "message",
|
||||
Content = text,
|
||||
SteamName = ply:Nick(),
|
||||
SteamId = ply:SteamID64(),
|
||||
IrisId = "none"
|
||||
}
|
||||
})
|
||||
end
|
||||
return hook.Add("PlayerSay", "CFC_ChatTransit_MessageListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.ReceiveMessage
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)()), HOOK_MONITOR_LOW)
|
48
lua/cfc_chat_transit/server/modules/connect.lua
Normal file
48
lua/cfc_chat_transit/server/modules/connect.lua
Normal file
@ -0,0 +1,48 @@
|
||||
local delay, guard
|
||||
do
|
||||
local _obj_0 = ChatTransit
|
||||
delay, guard = _obj_0.delay, _obj_0.guard
|
||||
end
|
||||
local SteamIDTo64
|
||||
SteamIDTo64 = util.SteamIDTo64
|
||||
ChatTransit.PlayerConnect = function(self, data)
|
||||
local bot, name, steamId
|
||||
bot, name, steamId = data.bot, data.name, data.networkid
|
||||
bot = tobool(bot)
|
||||
if bot then
|
||||
steamId = nil
|
||||
end
|
||||
return self:Send({
|
||||
Type = "connect",
|
||||
Data = {
|
||||
SteamName = name,
|
||||
SteamId = steamId and SteamIDTo64(steamId),
|
||||
PlayerCountCurrent = ChatTransit.playerCount,
|
||||
PlayerCountMax = game:MaxPlayers()
|
||||
}
|
||||
})
|
||||
end
|
||||
ChatTransit.PlayerInitialSpawn = function(self, ply)
|
||||
return self:Send({
|
||||
Type = "spawn",
|
||||
Data = {
|
||||
SteamName = ply:Nick(),
|
||||
SteamId = ply:SteamID64()
|
||||
}
|
||||
})
|
||||
end
|
||||
gameevent.Listen("player_connect")
|
||||
hook.Add("player_connect", "CFC_ChatTransit_SpawnListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.PlayerConnect
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)(), 0))
|
||||
return hook.Add("PlayerInitialSpawn", "CFC_ChatTransit_SpawnListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.PlayerInitialSpawn
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)()))
|
32
lua/cfc_chat_transit/server/modules/disconnect.lua
Normal file
32
lua/cfc_chat_transit/server/modules/disconnect.lua
Normal file
@ -0,0 +1,32 @@
|
||||
local delay, guard
|
||||
do
|
||||
local _obj_0 = ChatTransit
|
||||
delay, guard = _obj_0.delay, _obj_0.guard
|
||||
end
|
||||
local GetBySteamID
|
||||
GetBySteamID = player.GetBySteamID
|
||||
local SteamIDTo64
|
||||
SteamIDTo64 = util.SteamIDTo64
|
||||
ChatTransit.PlayerDisconnected = function(self, data)
|
||||
local name, reason, steamId
|
||||
name, reason, steamId = data.name, data.reason, data.networkid
|
||||
local ply = GetBySteamID(steamId)
|
||||
return self:Send({
|
||||
Type = "disconnect",
|
||||
Data = {
|
||||
SteamName = ply and ply:Nick() or name,
|
||||
SteamId = ply and ply:SteamID64() or SteamIDTo64(steamId),
|
||||
PlayerCountCurrent = ChatTransit.playerCount,
|
||||
PlayerCountMax = game:MaxPlayers(),
|
||||
Content = reason
|
||||
}
|
||||
})
|
||||
end
|
||||
gameevent.Listen("player_disconnect")
|
||||
return hook.Add("player_disconnect", "CFC_ChatTransit_DisconnectListener", guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.PlayerDisconnected
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)(), 0))
|
17
lua/cfc_chat_transit/server/modules/pvp.lua
Normal file
17
lua/cfc_chat_transit/server/modules/pvp.lua
Normal file
@ -0,0 +1,17 @@
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
ChatTransit.PvPEvent = function(self, ply, newMode)
|
||||
local eventText = tostring(ply:Nick()) .. " has entered " .. tostring(newMode) .. " mode"
|
||||
return self:Send({
|
||||
Type = "pvp_status_change",
|
||||
Data = {
|
||||
Content = eventText
|
||||
}
|
||||
})
|
||||
end
|
||||
hook.Add("CFC_PvP_PlayerEnterPvp", "CFC_ChatTransit_Relay", guard(function(ply)
|
||||
return ChatTransit:PvPEvent(ply, "PvP")
|
||||
end))
|
||||
return hook.Add("CFC_PvP_PlayerExitPvp", "CFC_ChatTransit_Relay", guard(function(ply)
|
||||
return ChatTransit:PvPEvent(ply, "Build")
|
||||
end))
|
26
lua/cfc_chat_transit/server/modules/startup.lua
Normal file
26
lua/cfc_chat_transit/server/modules/startup.lua
Normal file
@ -0,0 +1,26 @@
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
local GetMap
|
||||
GetMap = game.GetMap
|
||||
ChatTransit.MapStartup = function(self, data)
|
||||
local eventText = ""
|
||||
local map = GetMap()
|
||||
if SysTime() > 500 then
|
||||
eventText = "Map switched to " .. map
|
||||
else
|
||||
eventText = "Server restarted! Current map is " .. map
|
||||
end
|
||||
return self:Send({
|
||||
Type = "map_init",
|
||||
Data = {
|
||||
Content = eventText
|
||||
}
|
||||
})
|
||||
end
|
||||
return hook.Add("InitPostEntity", "CFC_ChatTransit_StartListener", timer.Simple(1, guard((function()
|
||||
local _base_0 = ChatTransit
|
||||
local _fn_0 = _base_0.MapStartup
|
||||
return function(...)
|
||||
return _fn_0(_base_0, ...)
|
||||
end
|
||||
end)())))
|
40
lua/cfc_chat_transit/server/modules/ulx.lua
Normal file
40
lua/cfc_chat_transit/server/modules/ulx.lua
Normal file
@ -0,0 +1,40 @@
|
||||
_Msg = Msg
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
local isstring
|
||||
isstring = _G.isstring
|
||||
local Replace
|
||||
Replace = string.Replace
|
||||
ChatTransit.ReceiveULXAction = function(self, msg)
|
||||
msg = Replace(msg, "\n", "")
|
||||
self.Logger:debug("Received global ULX message", msg)
|
||||
return self:Send({
|
||||
Type = "ulx_action",
|
||||
Data = {
|
||||
Type = "ulx_action",
|
||||
Content = msg
|
||||
}
|
||||
})
|
||||
end
|
||||
local M
|
||||
M = function(...)
|
||||
_Msg(...)
|
||||
return ChatTransit:ReceiveULXAction(...)
|
||||
end
|
||||
return hook.Add("InitPostEntity", "ChatTransit_WrapUlxLog", guard(function()
|
||||
if not (ulx) then
|
||||
return
|
||||
end
|
||||
ulx._ChatTransit_fancyLogAdmin = ulx._ChatTransit_fancyLogAdmin or ulx.fancyLogAdmin
|
||||
ulx.fancyLogAdmin = function(...)
|
||||
local args = {
|
||||
...
|
||||
}
|
||||
if not (isstring(args[2])) then
|
||||
return ulx._ChatTransit_fancyLogAdmin(...)
|
||||
end
|
||||
Msg = M
|
||||
ulx._ChatTransit_fancyLogAdmin(...)
|
||||
Msg = _Msg
|
||||
end
|
||||
end))
|
42
lua/cfc_chat_transit/server/modules/voice.lua
Normal file
42
lua/cfc_chat_transit/server/modules/voice.lua
Normal file
@ -0,0 +1,42 @@
|
||||
local IsValid
|
||||
IsValid = _G.IsValid
|
||||
local guard
|
||||
guard = ChatTransit.guard
|
||||
local proxVoice
|
||||
local proxVoiceEnabled
|
||||
proxVoiceEnabled = function()
|
||||
proxVoice = proxVoice or GetConVar("force_proximity_voice")
|
||||
if not (proxVoice) then
|
||||
return false
|
||||
end
|
||||
return proxVoice:GetBool()
|
||||
end
|
||||
ChatTransit.ReceiveVoiceTranscript = function(self, steamID64, data)
|
||||
if proxVoiceEnabled() then
|
||||
return
|
||||
end
|
||||
local ply = player.GetBySteamID64(steamID64)
|
||||
if not (IsValid(ply)) then
|
||||
return
|
||||
end
|
||||
if ply.ulx_gagged then
|
||||
return
|
||||
end
|
||||
if ply:GetInfoNum("proximity_voice_enabled", 0) ~= 0 then
|
||||
return
|
||||
end
|
||||
local shouldRelay = hook.Run("CFC_ChatTransit_ShouldRelayTranscript", ply, transcript)
|
||||
if shouldRelay == false then
|
||||
return
|
||||
end
|
||||
return self:Send({
|
||||
Type = "voice_transcript",
|
||||
Data = {
|
||||
Type = "voice_transcript",
|
||||
Content = data,
|
||||
SteamName = ply:Nick(),
|
||||
SteamId = ply:SteamID64(),
|
||||
IrisId = "none"
|
||||
}
|
||||
})
|
||||
end
|
19
lua/cfc_chat_transit/server/player_count.lua
Normal file
19
lua/cfc_chat_transit/server/player_count.lua
Normal file
@ -0,0 +1,19 @@
|
||||
ChatTransit.playerCount = 0
|
||||
local increment
|
||||
increment = function()
|
||||
ChatTransit.playerCount = ChatTransit.playerCount + 1
|
||||
end
|
||||
local decrement
|
||||
decrement = function()
|
||||
ChatTransit.playerCount = ChatTransit.playerCount - 1
|
||||
end
|
||||
hook.Add("ClientSignOnStateChanged", "ChatTransit_PlayerCount", function(_, oldstate)
|
||||
if not (oldstate == 7) then
|
||||
return
|
||||
end
|
||||
return increment()
|
||||
end)
|
||||
gameevent.Listen("player_connect")
|
||||
hook.Add("player_connect", "ChatTransit_PlayerCount", increment)
|
||||
gameevent.Listen("player_disconnect")
|
||||
return hook.Add("player_disconnect", "ChatTransit_PlayerCount", decrement)
|
58
lua/cfc_chat_transit/server/remote_messages.lua
Normal file
58
lua/cfc_chat_transit/server/remote_messages.lua
Normal file
@ -0,0 +1,58 @@
|
||||
local IsValid
|
||||
IsValid = _G.IsValid
|
||||
local AddNetworkString
|
||||
AddNetworkString = util.AddNetworkString
|
||||
local Start, Receive, ReadBool, WriteColor, WriteString, Send
|
||||
do
|
||||
local _obj_0 = net
|
||||
Start, Receive, ReadBool, WriteColor, WriteString, Send = _obj_0.Start, _obj_0.Receive, _obj_0.ReadBool, _obj_0.WriteColor, _obj_0.WriteString, _obj_0.Send
|
||||
end
|
||||
local ToColor
|
||||
ToColor = string.ToColor
|
||||
AddNetworkString("CFC_ChatTransit_RemoteMessagePreference")
|
||||
AddNetworkString("CFC_ChatTransit_RemoteMessageReceive")
|
||||
local recipients = RecipientFilter()
|
||||
local adminRecipients = RecipientFilter()
|
||||
local shouldTransmit = CreateConVar("cfc_chat_transit_should_transmit_remote", 1, FCVAR_ARCHIVE, "Should transmit remote messages", 0, 1)
|
||||
local adminOnly = CreateConVar("cfc_chat_transit_transmit_admin_only", 1, FCVAR_ARCHIVE, "Should only transmit to Admins?", 0, 1)
|
||||
Receive("CFC_ChatTransit_RemoteMessagePreference", function(_, ply)
|
||||
local shouldReceive = ReadBool()
|
||||
if shouldReceive then
|
||||
recipients:AddPlayer(ply)
|
||||
if adminOnly:GetBool() and ply:IsAdmin() then
|
||||
adminRecipients:AddPlayer(ply)
|
||||
end
|
||||
return
|
||||
end
|
||||
recipients:RemovePlayer(ply)
|
||||
return adminRecipients:RemovePlayer(ply)
|
||||
end)
|
||||
local broadcastMessage
|
||||
broadcastMessage = function(ply, cmd, args, argStr)
|
||||
if not (shouldTransmit:GetBool()) then
|
||||
return
|
||||
end
|
||||
if IsValid(ply) then
|
||||
return
|
||||
end
|
||||
local author = rawget(args, 1)
|
||||
local authorColor = rawget(args, 2)
|
||||
local message = rawget(args, 3)
|
||||
if not (author) then
|
||||
return
|
||||
end
|
||||
if not (authorColor) then
|
||||
return
|
||||
end
|
||||
if not (message) then
|
||||
return
|
||||
end
|
||||
authorColor = ToColor(authorColor)
|
||||
local sendingTo = adminOnly:GetBool() and adminRecipients or recipients
|
||||
Start("CFC_ChatTransit_RemoteMessageReceive")
|
||||
WriteString(author)
|
||||
WriteColor(authorColor)
|
||||
WriteString(message)
|
||||
return Send(sendingTo)
|
||||
end
|
||||
return concommand.Add("chat_transit", broadcastMessage)
|
@ -7,7 +7,7 @@ class AvatarService
|
||||
|
||||
new: (logger) =>
|
||||
@logger = logger\scope "AvatarService"
|
||||
@outlinerUrl = "http://#{avatarServiceAddress\GetString!}/outline"
|
||||
@outlinerUrl = "#{avatarServiceAddress\GetString!}/outline"
|
||||
@processedIds = {}
|
||||
|
||||
getAvatar: (steamID64) =>
|
||||
@ -18,11 +18,11 @@ class AvatarService
|
||||
|
||||
processAvatar: (avatarUrl, outlineColor, steamID64) =>
|
||||
body = TableToJSON { :avatarUrl, :outlineColor, steamID: steamID64 }
|
||||
@logger\info "Sending data to outliner: ", body
|
||||
@logger\debug "Sending data to outliner: ", body
|
||||
|
||||
failed = @logger\error
|
||||
success = (code, body) ->
|
||||
@logger\info "Avatar request succeeded with code: #{code} | Body: #{body}"
|
||||
@logger\debug "Avatar request succeeded with code: #{code} | Body: #{body}"
|
||||
@processedIds[steamID64] = true
|
||||
|
||||
HTTP
|
||||
@ -34,7 +34,7 @@ class AvatarService
|
||||
type: "application/json"
|
||||
|
||||
outlineAvatar: (ply, data) =>
|
||||
@logger\info "Received request to outline avatar for ply: #{ply\Nick!}"
|
||||
@logger\debug "Received request to outline avatar for ply: #{ply\Nick!}"
|
||||
avatar = data.response.players[1].avatarfull
|
||||
outlineColor = ChatTransit\GetTeamColor ply\Team!
|
||||
steamID64 = ply\SteamID64!
|
||||
|
@ -16,8 +16,8 @@ loadHook = "ChatTransit_WebsocketLoad"
|
||||
hook.Add "Think", loadHook, ->
|
||||
hook.Remove "Think", loadHook
|
||||
|
||||
ChatTransit.WebSocket = GWSockets.createWebSocket "ws://#{relayHost\GetString!}/relay"
|
||||
ChatTransit.Realm = CreateConVar "cfc_realm", "", FCVAR_NONE, "CFC Realm Name"
|
||||
ChatTransit.WebSocket = GWSockets.createWebSocket "wss://#{relayHost\GetString!}/relay", false
|
||||
ChatTransit.Realm = CreateConVar "cfc_realm", "unknown", FCVAR_REPLICATED + FCVAR_ARCHIVE, "The Realm Name"
|
||||
|
||||
with ChatTransit.WebSocket
|
||||
.reconnectTimerName = "CFC_ChatTransit_WebsocketReconnect"
|
||||
@ -41,7 +41,7 @@ hook.Add "Think", loadHook, ->
|
||||
return nil
|
||||
|
||||
ChatTransit.Send = (data) =>
|
||||
logger\info "Sending '#{data.Type}'"
|
||||
logger\debug "Sending '#{data.Type}'"
|
||||
steamID64 = data.Data.SteamId
|
||||
|
||||
data.Data.Avatar or= ChatTransit.AvatarService\getAvatar steamID64
|
||||
|
30
moon/cfc_chat_transit/server/modules/voice.moon
Normal file
30
moon/cfc_chat_transit/server/modules/voice.moon
Normal file
@ -0,0 +1,30 @@
|
||||
import IsValid from _G
|
||||
import guard from ChatTransit
|
||||
|
||||
local proxVoice
|
||||
|
||||
proxVoiceEnabled = ->
|
||||
proxVoice or= GetConVar "force_proximity_voice"
|
||||
return false unless proxVoice
|
||||
return proxVoice\GetBool!
|
||||
|
||||
ChatTransit.ReceiveVoiceTranscript = (steamID64, data) =>
|
||||
return if proxVoiceEnabled!
|
||||
|
||||
ply = player.GetBySteamID64 steamID64
|
||||
return unless IsValid ply
|
||||
|
||||
return if ply.ulx_gagged
|
||||
return if ply\GetInfoNum("proximity_voice_enabled", 0) ~= 0
|
||||
|
||||
shouldRelay = hook.Run "CFC_ChatTransit_ShouldRelayTranscript", ply, transcript
|
||||
return if shouldRelay == false
|
||||
|
||||
@Send
|
||||
Type: "voice_transcript"
|
||||
Data:
|
||||
Type: "voice_transcript"
|
||||
Content: data
|
||||
SteamName: ply\Nick!
|
||||
SteamId: ply\SteamID64!
|
||||
IrisId: "none"
|
@ -1,13 +1,14 @@
|
||||
FROM python:3.9.0
|
||||
|
||||
RUN mkdir /avatars
|
||||
RUN mkdir /avatar-service
|
||||
WORKDIR /avatar-service
|
||||
COPY . /avatar-service
|
||||
|
||||
RUN pip install -U --upgrade pip
|
||||
|
||||
RUN mkdir /avatars
|
||||
WORKDIR /avatar-service
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --upgrade -r ./requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
COPY entrypoint.sh /usr/bin/
|
||||
RUN chmod +x /usr/bin/entrypoint.sh
|
||||
ENTRYPOINT ["entrypoint.sh"]
|
@ -12,7 +12,7 @@ services:
|
||||
service:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.service
|
||||
dockerfile: Dockerfile
|
||||
command: flask run --host 0.0.0.0 --port 8080
|
||||
container_name: "${REALM}_chat_transit_avatar_service"
|
||||
ports:
|
||||
@ -22,5 +22,4 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./:/build/src
|
||||
- "$AVATARS_DIR:/avatars:z"
|
||||
|
0
web/avatar_service/entrypoint.sh
Normal file → Executable file
0
web/avatar_service/entrypoint.sh
Normal file → Executable file
@ -4,6 +4,10 @@ ENV GOPATH=/build
|
||||
ENV GOBIN=/usr/local/go/bin
|
||||
|
||||
WORKDIR $GOPATH/src
|
||||
COPY go.mod .
|
||||
COPY go.sum .
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
ARG BRANCH=HEAD
|
||||
|
@ -9,3 +9,4 @@ services:
|
||||
- .env
|
||||
volumes:
|
||||
- ./:/build/src
|
||||
restart: always
|
||||
|
@ -3,7 +3,8 @@ module github.com/cfc-servers/cfc_chat_transit
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/bwmarrin/discordgo v0.23.2
|
||||
github.com/bwmarrin/discordgo v0.25.0
|
||||
github.com/getsentry/sentry-go v0.9.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
)
|
||||
|
@ -9,6 +9,8 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
|
||||
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
|
||||
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
|
||||
github.com/bwmarrin/discordgo v0.25.0 h1:NXhdfHRNxtwso6FPdzW2i3uBvvU7UIQTghmV2T4nqAs=
|
||||
github.com/bwmarrin/discordgo v0.25.0/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
@ -96,6 +98,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@ -141,6 +145,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@ -150,6 +156,7 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -159,8 +166,12 @@ golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/cfc-servers/cfc_chat_transit/voice"
|
||||
)
|
||||
|
||||
var discord *discordgo.Session
|
||||
@ -30,11 +31,25 @@ type EventData struct {
|
||||
PlayerCountCurrent float32
|
||||
}
|
||||
|
||||
var MessageQueue = make(chan []byte, 100)
|
||||
type VoiceMessageOperation struct {
|
||||
Message string
|
||||
MessageId string
|
||||
SteamId string
|
||||
SteamName string
|
||||
Avatar string
|
||||
IsFinal bool
|
||||
}
|
||||
|
||||
var MessageQueue = make(chan []byte, 10000)
|
||||
|
||||
var WebhookId string = os.Getenv("WEBHOOK_ID")
|
||||
var WebhookSecret string = os.Getenv("WEBHOOK_SECRET")
|
||||
|
||||
var VoiceWebhookId string = os.Getenv("VOICE_WEBHOOK_ID")
|
||||
var VoiceWebhookSecret string = os.Getenv("VOICE_WEBHOOK_SECRET")
|
||||
|
||||
var DiscordToken string = os.Getenv("DISCORD_TOKEN")
|
||||
|
||||
const urlRegexString = `https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`
|
||||
|
||||
const (
|
||||
@ -43,9 +58,11 @@ const (
|
||||
EMOJI_HALTED = "<:halted:398133588010336259>"
|
||||
EMOJI_BUILD = "<:build:933512140395012107>"
|
||||
EMOJI_PVP = "<:bk:812130062379515906>"
|
||||
EMOJI_PLAY = "<:playbuttonsmaller:1017716044485382154>"
|
||||
EMOJI_MAP = "🗺️"
|
||||
EMOJI_CONNECT = "📡"
|
||||
EMOJI_ULX = "⌨️"
|
||||
EMOJI_VOICE = "🗣️"
|
||||
|
||||
COLOR_RED = 0xE7373E
|
||||
COLOR_GREEN = 0x37E73E
|
||||
@ -89,7 +106,7 @@ func sendMessage(discord *discordgo.Session, message EventStruct) {
|
||||
}
|
||||
}
|
||||
|
||||
func sendEvent(discord *discordgo.Session, event EventStruct, eventText string, color int, emoji string) {
|
||||
func sendEvent(discord *discordgo.Session, event EventStruct, eventText string, color int, emoji string) *discordgo.Message {
|
||||
params := &discordgo.WebhookParams{
|
||||
AllowedMentions: &discordgo.MessageAllowedMentions{
|
||||
Parse: []discordgo.AllowedMentionType{},
|
||||
@ -104,11 +121,13 @@ func sendEvent(discord *discordgo.Session, event EventStruct, eventText string,
|
||||
},
|
||||
}
|
||||
|
||||
_, err := discord.WebhookExecute(WebhookId, WebhookSecret, true, params)
|
||||
message, err := discord.WebhookExecute(WebhookId, WebhookSecret, true, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
func sendConnectMessage(discord *discordgo.Session, event EventStruct) {
|
||||
@ -170,10 +189,88 @@ func sendPvpStatusChange(discord *discordgo.Session, event EventStruct) {
|
||||
sendEvent(discord, event, event.Data.Content, color, emoji)
|
||||
}
|
||||
|
||||
func queueGroomer() {
|
||||
discord, err := discordgo.New("")
|
||||
func sendVoiceText(discord *discordgo.Session, data *voice.Session) string {
|
||||
transcript := data.Message
|
||||
steamName := data.SteamName
|
||||
avatar := data.Avatar
|
||||
// fileName := data.FileName
|
||||
messageId := data.MessageId
|
||||
// isFinal := data.Finished
|
||||
|
||||
log.Println(WebhookId, WebhookSecret)
|
||||
// var voiceLink string
|
||||
// if len(fileName) > 0 {
|
||||
// voiceLink = fmt.Sprintf("https://larynx.cfcservers.org/%v.ogg", fileName)
|
||||
// }
|
||||
|
||||
// var description string
|
||||
|
||||
// if isFinal && len(voiceLink) > 0 {
|
||||
// description = fmt.Sprintf("%v [%v](%v) %v", EMOJI_VOICE, EMOJI_PLAY, voiceLink, transcript)
|
||||
// } else {
|
||||
// description = fmt.Sprintf("%v %v", EMOJI_VOICE, transcript)
|
||||
// }
|
||||
|
||||
description := fmt.Sprintf("%v %v", EMOJI_VOICE, transcript)
|
||||
|
||||
embeds := []*discordgo.MessageEmbed{
|
||||
{
|
||||
Description: description,
|
||||
Color: COLOR_BLUE,
|
||||
},
|
||||
}
|
||||
|
||||
if len(messageId) == 0 {
|
||||
log.Println("Creating new message for voice")
|
||||
params := &discordgo.WebhookParams{
|
||||
AllowedMentions: &discordgo.MessageAllowedMentions{
|
||||
Parse: []discordgo.AllowedMentionType{},
|
||||
},
|
||||
Username: steamName,
|
||||
AvatarURL: avatar,
|
||||
Embeds: embeds,
|
||||
}
|
||||
|
||||
message, err := discord.WebhookExecute(VoiceWebhookId, VoiceWebhookSecret, true, params)
|
||||
|
||||
if err != nil {
|
||||
log.Println("Error sending webhook message create")
|
||||
log.Println(err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return message.ID
|
||||
} else {
|
||||
log.Println("Updating existing message for voice")
|
||||
params := &discordgo.WebhookEdit{
|
||||
Embeds: embeds,
|
||||
}
|
||||
|
||||
log.Println(messageId)
|
||||
log.Println(params.Embeds[0].Description)
|
||||
|
||||
message, err := discord.WebhookMessageEdit(VoiceWebhookId, VoiceWebhookSecret, messageId, params)
|
||||
if err != nil {
|
||||
log.Println("Error sending webhook message edit")
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
return message.ID
|
||||
}
|
||||
}
|
||||
|
||||
func processVoiceText(queueVoiceText func(string, string, string, string), event EventStruct) {
|
||||
steamId := event.Data.SteamId
|
||||
steamName := event.Data.SteamName
|
||||
avatar := event.Data.Avatar
|
||||
data := event.Data.Content
|
||||
log.Println(data)
|
||||
|
||||
queueVoiceText(steamId, steamName, avatar, data)
|
||||
}
|
||||
|
||||
func queueGroomer() {
|
||||
discord, err := discordgo.New(DiscordToken)
|
||||
voiceManager := voice.NewManager(discord, sendVoiceText)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("error connecting:", err)
|
||||
@ -211,6 +308,9 @@ func queueGroomer() {
|
||||
sendUlxAction(discord, message)
|
||||
case "pvp_status_change":
|
||||
sendPvpStatusChange(discord, message)
|
||||
}
|
||||
case "voice_transcript":
|
||||
processVoiceText(voiceManager.ReceiveVoiceTranscript, message)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
166
web/discord_relay/voice/voice.go
Normal file
166
web/discord_relay/voice/voice.go
Normal file
@ -0,0 +1,166 @@
|
||||
package voice
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
SteamId string
|
||||
SteamName string
|
||||
Message string
|
||||
MessageId string
|
||||
FileName string
|
||||
Avatar string
|
||||
Finished bool
|
||||
}
|
||||
|
||||
type Operation struct {
|
||||
Session *Session
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
Sessions map[string]*Session
|
||||
Operations []*Operation
|
||||
discord *discordgo.Session
|
||||
opmutex *sync.Mutex
|
||||
sendMessage func(*discordgo.Session, *Session) string
|
||||
}
|
||||
|
||||
// MessageData The "Content" key of the Event that comes into the Main package
|
||||
type MessageData struct {
|
||||
Message string `json:"transcript"`
|
||||
FileName string `json:"file_name"`
|
||||
SessionID string `json:"session_id"`
|
||||
IsFinal bool `json:"is_final"`
|
||||
}
|
||||
|
||||
func (v *Manager) runSendQueue() {
|
||||
bucket := v.discord.Ratelimiter.GetBucket("voiceTranscriptions")
|
||||
|
||||
wait := func() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
|
||||
for {
|
||||
wait()
|
||||
|
||||
// This should be a blocking call
|
||||
// Unblocks when bucket has bandwidth
|
||||
v.discord.Ratelimiter.LockBucketObject(bucket).Unlock()
|
||||
|
||||
if len(v.Operations) == 0 {
|
||||
wait()
|
||||
continue
|
||||
}
|
||||
|
||||
v.opmutex.Lock()
|
||||
|
||||
firstOperation := v.Operations[0]
|
||||
log.Printf("Processing message for session %v", firstOperation.Session.FileName)
|
||||
v.Operations = v.Operations[1:]
|
||||
|
||||
session := firstOperation.Session
|
||||
description := session.Message
|
||||
|
||||
if len(description) == 0 {
|
||||
log.Printf("No description for session %v", session.FileName)
|
||||
// What is this? Why are you showing this to me
|
||||
v.opmutex.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
messageId := v.sendMessage(v.discord, session)
|
||||
|
||||
if len(messageId) == 0 {
|
||||
log.Println("Received no message ID from sendMessage")
|
||||
// Failed to send/update message, send to back of queue
|
||||
v.Operations = append(v.Operations, firstOperation)
|
||||
v.opmutex.Unlock()
|
||||
continue
|
||||
} else {
|
||||
session.MessageId = messageId
|
||||
}
|
||||
|
||||
v.opmutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Manager) ReceiveVoiceTranscript(steamId string, steamName string, avatar string, data string) {
|
||||
messageData := MessageData{}
|
||||
err := json.Unmarshal([]byte(data), &messageData)
|
||||
if err != nil {
|
||||
log.Printf("Error parsing voice message: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
newMessage := messageData.Message
|
||||
isFinal := messageData.IsFinal
|
||||
fileName := messageData.FileName
|
||||
sessionId := messageData.SessionID
|
||||
|
||||
session, ok := v.Sessions[sessionId]
|
||||
|
||||
if !ok {
|
||||
session = &Session{
|
||||
SteamId: steamId,
|
||||
SteamName: steamName,
|
||||
Message: newMessage,
|
||||
MessageId: "",
|
||||
Finished: isFinal,
|
||||
Avatar: avatar,
|
||||
FileName: fileName,
|
||||
}
|
||||
|
||||
v.Sessions[sessionId] = session
|
||||
} else {
|
||||
// Nothing changed - we don't need to queue an Operation for this
|
||||
if !isFinal && session.Message == newMessage {
|
||||
return
|
||||
}
|
||||
|
||||
session.Message = newMessage
|
||||
session.Finished = isFinal
|
||||
session.FileName = fileName
|
||||
}
|
||||
|
||||
if isFinal {
|
||||
// Final message for this transcription, we can stop tracking it
|
||||
// TODO: do I use delete here?
|
||||
v.Sessions[sessionId] = nil
|
||||
}
|
||||
|
||||
v.opmutex.Lock()
|
||||
defer v.opmutex.Unlock()
|
||||
|
||||
if ok {
|
||||
// Session already existed for sessionID
|
||||
// Do we already have a pending Operation?
|
||||
for _, operation := range v.Operations {
|
||||
if operation.Session == session {
|
||||
// If so, we don't need to add another operation
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v.Operations = append(v.Operations, &Operation{
|
||||
Session: session,
|
||||
})
|
||||
}
|
||||
|
||||
func NewManager(discord *discordgo.Session, sendMessage func(*discordgo.Session, *Session) string) *Manager {
|
||||
manager := &Manager{
|
||||
Sessions: make(map[string]*Session),
|
||||
Operations: make([]*Operation, 0),
|
||||
discord: discord,
|
||||
opmutex: &sync.Mutex{},
|
||||
sendMessage: sendMessage,
|
||||
}
|
||||
|
||||
go manager.runSendQueue()
|
||||
return manager
|
||||
}
|
Loading…
Reference in New Issue
Block a user