Skip to content

Commit

Permalink
Add get_launchdata to url
Browse files Browse the repository at this point in the history
  • Loading branch information
gaymeowing committed Aug 31, 2024
1 parent aedc42a commit b6e755e
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 74 deletions.
55 changes: 27 additions & 28 deletions docs/url.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,18 @@ Small utility with basic functions handling url querys and encoding/decoding url

```luau
local Players = game:GetService("Players")
local safeteleport = require("safeteleport")
local url = require("url")
local launch_data_start = "&launchdata="
local start_len = #launch_data_start
local function get_launch_data(player: Player): string?
local launch_data = player:GetJoinData().LaunchData
if launch_data and #launch_data == 0 then
return nil
elseif not launch_data then
return nil
end
local decoded = url.decode(launch_data)
local start = string.find(decoded, launch_data_start, 1, true)
if start then
-- url does not contain launchdata
return nil
end
local data_start = start + start_len
-- this shouldnt ever be nil unless roblox does some insane changes to deeplinks
local end_char_pos = string.find(data, "&", data_start, true)
return string.sub(decoded, data_start, if end_char_pos then end_char_pos - 1 else #data)
end
Players.PlayerAdded:Connect(function(player)
local data = get_launch_data(player)
local data = url.launchdata(player)
if data then
-- do stuff
local placeid = tonumber(string.match(data, "placeid=%d+"))
if placeid then
safeteleport(placeid, player)
end
end
end)
Expand All @@ -45,7 +25,7 @@ end)

### `encode`

Encodes the given string using [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding), so that reserved characters except for spaces properly encode with `%` and two hexadecimal characters. Spaces by defualt are encoded as `+`, but can be specified to be encoded as `%20` with the second arg.
Encodes the given string using [percent-encoding](https://en.wikipedia.org/wiki/Percent-encoding), so that reserved characters except for spaces properly encode with `%` and two hexadecimal characters. Spaces by defualt are encoded as `%20`, but can be specified to be encoded as `+` with the second arg.

```luau
local content = "Je suis allé au cinéma." -- French for "I went to the movies"
Expand All @@ -58,6 +38,9 @@ print(encoded) -- "Je+suis+all%C3%A9+au+cin%C3%A9ma."

Decodes the given string, into how it originally was before it was [encoded](#encode)

> [!NOTE]
> If the spaces in the url are encoded as `+`, you need to specifiy this using the second arg for it to be properly decoded
```luau
local encoded = "Je%20suis%20all%C3%A9%20au%20cinema%2E"
local decoded = url.decode(input)
Expand Down Expand Up @@ -88,3 +71,19 @@ local tbl = url.read_query(query)
print(tbl.meow, tbl.mrrp) -- "mrrp", "meow"
```

### `get_launchdata`

Gets the launchdata for the given player (the actual launchdata not the full join url that [`Player:GetJoinData().LaunchData`](https://create.roblox.com/docs/reference/engine/classes/Player#GetJoinData) gives), and decodes it

```luau
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player)
local launchdata = url.get_launchdata(player)
if launchdata then
print(`{player.Name}'s launchdata: {launchdata}`)
end
end)
```
98 changes: 55 additions & 43 deletions libs/Url/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,78 @@

export type SpaceEncoding = "+" | "%20"

-- these dont have fast calls
local string_format = string.format
local string_gmatch = string.gmatch
local string_gsub = string.gsub
local LAUNCH_DATA_START = "&launchdata="
local START_LEN = #LAUNCH_DATA_START
local FORMAT = string.format
local GMATCH = string.gmatch
local MATCH = string.match
local GSUB = string.gsub

local function char_to_code(char: string): string
return string_format("%%%02X", string.byte(char))
local function CHAR_TO_CODE(char: string): string
return FORMAT("%%%02X", string.byte(char))
end

local function code_to_char(code: string): string
local function CODE_TO_CHAR(code: string): string
return string.char(tonumber(code, 16) :: any)
end

-- i just wanted to do this because i find it funny,
-- sure its a bit less readable but its not thaaaat bad
local function encode_url(url: string, encode_spaces_as: SpaceEncoding?): string
return (
string_gsub(
string_gsub(
string_gsub(url, "([^%w _%%%-%.~])", char_to_code),
"\n", "\r\n"
),
"%s+", if encode_spaces_as == "%20" then "%%20" else "+"
)
)
-- modified from:
-- https://devforum.roblox.com/t/233570/2
local function DECODE(url: string, spaces_encoded_as: SpaceEncoding?): string
local chars_decoded = GSUB(url, "%%(%x%x)", CODE_TO_CHAR)

if spaces_encoded_as == "+" then
return (GSUB(chars_decoded, "+", " "))
else
return chars_decoded
end
end

local function queryify(tbl: { [string]: string }, encode_spaces_as: SpaceEncoding?): string
local query_strings = {} :: { string }
local function ENCODE(url: string, encode_spaces_as: SpaceEncoding?): string
local space_encode_char = if encode_spaces_as == "+" then "+" else "%%20"
local chars_encoded = (GSUB(url, "([^%w _%%%-%.~])", CHAR_TO_CODE))
local new_line_encoded = (GSUB(chars_encoded, "\n", "\r\n"))

for key, value in tbl do
local encoded_value = encode_url(value, encode_spaces_as)
local encoded_key = encode_url(key, encode_spaces_as)
table.insert(query_strings, `{encoded_key}={encoded_value}`)
end
return `?{table.concat(query_strings, "&")}`
return (GSUB(new_line_encoded, "%s+", space_encode_char))
end

-- modified from:
-- https://devforum.roblox.com/t/233570/2
local function decode_url(url: string): string
return (string_gsub(
string_gsub(url, "%%(%x%x)", code_to_char),
"+", " "
))
local url = {}

function url.get_launchdata(player: Player, launchdata_spaces_encoded_as: SpaceEncoding?): string?
local launch_data = player:GetJoinData().LaunchData

if launch_data and #launch_data ~= 0 then
local decoded = DECODE(launch_data, launchdata_spaces_encoded_as)
-- pattern for getting a string with a non zero length
-- right after "&launchdata=" that doesn't include the & character
return MATCH(decoded, "&launchdata=([^&]+)")
else
return nil
end
end

-- modified from: https://stackoverflow.com/questions/28916182/parse-parameters-out-of-url-in-lua
local function read_query(url: string): { [string]: string }
local query_tbl = {} :: { [string]: string }
function url.read_query(url: string, spaces_encoded_as: SpaceEncoding?): { [string]: string }
local query_tbl = {}

for key, value: any in string_gmatch(decode_url(url), "([^&=?]-)=([^&=?]+)") do
for key, value: any in GMATCH(DECODE(url, spaces_encoded_as), "([^&=?]-)=([^&=?]+)") do
query_tbl[key] = value
end
return query_tbl
end

return table.freeze {
read_query = read_query,
queryify = queryify,
decode = decode_url,
encode = encode_url,
}
function url.queryify(t: { [string]: string }, encode_spaces_as: SpaceEncoding?): string
local query_strings = {} :: { string }

for key, value in t do
local encoded_value = ENCODE(value, encode_spaces_as)
local encoded_key = ENCODE(key, encode_spaces_as)
table.insert(query_strings, `{encoded_key}={encoded_value}`)
end
return `?{table.concat(query_strings, "&")}`
end

url.encode = ENCODE
url.decode = DECODE

return table.freeze(url)
19 changes: 16 additions & 3 deletions libs/Url/test.luau
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ local TEST, CASE, CHECK, FINISH = testkit.test()

TEST("url", function()
do CASE("encode %%20")
CHECK(url.encode("Je suis allé au cinéma.", "%20") == "Je%20suis%20all%C3%A9%20au%20cin%C3%A9ma.")
CHECK(url.encode("Je suis allé au cinéma.") == "Je%20suis%20all%C3%A9%20au%20cin%C3%A9ma.")
end

do CASE("encode +")
CHECK(url.encode("Je suis allé au cinéma.") == "Je+suis+all%C3%A9+au+cin%C3%A9ma.")
CHECK(url.encode("Je suis allé au cinéma.", "+") == "Je+suis+all%C3%A9+au+cin%C3%A9ma.")
end

do CASE("decode %%20")
CHECK(url.decode("Je%20suis%20all%C3%A9%20au%20cin%C3%A9ma.") == "Je suis allé au cinéma.")
end

do CASE("decode +")
CHECK(url.decode("Je+suis+all%C3%A9+au+cin%C3%A9ma.") == "Je suis allé au cinéma.")
CHECK(url.decode("Je+suis+all%C3%A9+au+cin%C3%A9ma.", "+") == "Je suis allé au cinéma.")
end

do CASE("queryify")
Expand All @@ -35,4 +35,17 @@ TEST("url", function()

CHECK(tbl.meow == "mrrp" and tbl.mrrp == "meow")
end

do CASE("get_launchdata")
local launchdata = "https://libs.luau.lol/lmao&meow=mrrp&mrrp=meow&launchdata=kitty catters unite now!"
local mock_player = table.freeze({
GetJoinData = function()
return table.freeze({
LaunchData = launchdata
})
end
})

CHECK(url.get_launchdata(mock_player :: any) == "kitty catters unite now!")
end
end)

0 comments on commit b6e755e

Please sign in to comment.