mod_devices/mod_devices.lua
author Matthew Wild <mwild1@gmail.com>
Tue, 18 Jan 2022 17:01:18 +0000
changeset 4880 0f5f2d4475b9
parent 3401 4cf65afd90f4
permissions -rw-r--r--
mod_http_xep227: Add support for import via APIs rather than direct store manipulation In particular this transitions PEP nodes and data to be imported via mod_pep's APIs, fixing issues with importing at runtime while PEP data may already be live in RAM. Next obvious candidate for this approach is rosters, so clients get immediate roster pushes and other special handling (such as emitting subscribes to reach the desired subscription state).
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3401
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     1
local it = require "util.iterators";
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
local new_id = require "util.id".medium;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     3
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
local max_user_devices = module:get_option_number("max_user_devices", 5);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     5
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
local device_store = module:open_store("devices");
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
local device_map_store = module:open_store("devices", "map");
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
--- Helper functions
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
local function _compare_device_timestamps(a, b)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
	return (a.last_activity_at or 0) < (b.last_activity_at or 0);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
local function sorted_devices(devices)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	return it.sorted_pairs(devices, _compare_device_timestamps);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
local function new_device(username, alt_ids)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
	local current_time = os.time();
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
	local device = {
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
		id = "dv-"..new_id();
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
		created_at = current_time;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
		last_activity = "created";
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
		last_activity_at = current_time;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
		alt_ids = alt_ids or {};
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
	};
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
	local devices = device_store:get(username);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
	if not devices then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
		devices = {};
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
	devices[device.id] = device;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
	local devices_ordered = {};
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
	for id in sorted_devices(devices) do
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
		table.insert(devices_ordered, id);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
	if #devices_ordered > max_user_devices then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
		-- Iterate through oldest devices that are above limit, backwards
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    39
		for i = #devices_ordered, max_user_devices+1, -1 do
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    40
			local id = table.remove(devices_ordered, i);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
			devices[id] = nil;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
			module:log("debug", "Removing old device for %s: %s", username, id);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
		end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
	device_store:set(username, devices);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    46
	return device;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
local function get_device_with_alt_id(username, alt_id_type, alt_id)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
	local devices = device_store:get(username);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
	if not devices then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
		return nil;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
	for _, device in pairs(devices) do
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
		if device.alt_ids[alt_id_type] == alt_id then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
			return device;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
		end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
local function set_device_alt_id(username, device_id, alt_id_type, alt_id)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
	local devices = device_store:get(username);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
	if not devices or not devices[device_id] then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
		return nil, "no such device";
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
	devices[device_id].alt_ids[alt_id_type] = alt_id;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
local function record_device_state(username, device_id, activity, time)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
	local device = device_map_store:get(username, device_id);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
	device.last_activity = activity;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
	device.last_activity_at = time or os.time();
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
	device_map_store:set(username, device_id, device);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
local function find_device(username, info)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
	for _, alt_id_type in ipairs({ "resumption_token", "resource" }) do
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    79
		local alt_id = info[alt_id_type];
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    80
		if alt_id then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    81
			local device = get_device_with_alt_id(username, alt_id_type, alt_id);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    82
			if device then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    83
				return device, alt_id_type;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    84
			end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    85
		end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    86
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    87
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    88
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    89
--- Information gathering
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    90
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    91
module:hook("pre-resource-bind", function (event)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    92
	event.session.device_requested_resource = event.resource;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    93
end, 1000);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    94
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    95
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    96
local function store_resumption_token(session, stanza)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    97
	session.device_requested_resume = stanza.attr.previd;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    98
end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    99
module:hook_stanza("urn:xmpp:sm:2", "resume", store_resumption_token, 5);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
module:hook_stanza("urn:xmpp:sm:3", "resume", store_resumption_token, 5);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   101
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   102
--- Identify device after resource bind
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   103
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   104
module:hook("resource-bind", function (event)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   105
	local info = {
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   106
		resource = event.session.device_requested_resource;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   107
		resumption_token = event.session.device_requested_resume;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   108
	};
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   109
	local device, source = find_device(event.session.username, info);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   110
	if device then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   111
		event.session.log("debug", "Associated with device %s (from %s)", device.id, source);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   112
		event.session.device_id = device.id;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   113
	else
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   114
		device = new_device(event.session.username, info);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   115
		event.session.log("debug", "Creating new device %s for session", device.id);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   116
		event.session.device_id = device.id;
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   117
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   118
	record_device_state(event.session.username, device.id, "login");
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   119
end, 1000);
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   120
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   121
module:hook("resource-unbind", function (event)
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   122
	if event.session.device_id then
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   123
		record_device_state(event.session.username, event.session.device_id, "logout");
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   124
	end
4cf65afd90f4 mod_devices: New module for device identification
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   125
end);