async def info(self, ctx): channel_info = await self.get_channel_config(ctx.channel.id) if not channel_info: return await ctx.send( embed=util.info_embed("Phone status", "Not a phone channel")) addr = channel_info['id'] title = f"{addr} status" fields = [] now = datetime.utcnow() def delta(ts): return util.format_timedelta(datetime.utcfromtimestamp(ts), now) incoming = await self.bot.database.execute_fetchall( "SELECT * FROM calls WHERE to_id = ?", (addr, )) fields.extend( map( lambda x: [ "Incoming call", f"From {x['from_id']} - for {delta(x['start_time'])}" ], incoming)) outgoing = await self.bot.database.execute_fetchall( "SELECT * FROM calls WHERE from_id = ?", (addr, )) fields.extend( map( lambda x: [ "Outgoing call", f"To {x['to_id']} - for {delta(x['start_time'])}" ], outgoing)) await ctx.send(embed=util.info_embed( title, f"Connected: {len(incoming) + len(outgoing)}", fields))
async def hangup(self, ctx): channel_info = await self.get_channel_config(ctx.channel.id) addr = channel_info["id"] if not channel_info: return await ctx.send( embed=util.error_embed("Not in a phone channel.")) from_here = await self.bot.database.execute_fetchone( "SELECT * FROM calls WHERE from_id = ?", (addr, )) to_here = await self.bot.database.execute_fetchone( "SELECT * FROM calls WHERE to_id = ?", (addr, )) if (not to_here) and (not from_here): return await ctx.send( embed=util.error_embed("No calls are active.")) other = None if from_here: other = from_here["to_id"] await self.bot.database.execute( "DELETE FROM calls WHERE from_id = ? AND to_id = ?", (addr, other)) elif to_here: other = to_here["from_id"] await self.bot.database.execute( "DELETE FROM calls WHERE to_id = ? AND from_id = ?", (addr, other)) await self.bot.database.commit() other_channel = (await self.get_addr_config(other))["channel_id"] await eventbus.remove_bridge_link(self.bot.database, ("discord", other_channel), ("discord", ctx.channel.id)) await asyncio.gather( ctx.send(embed=util.info_embed("Hung up", f"Call to {other} disconnected.")), self.bot.get_channel(other_channel).send(embed=util.info_embed( "Hung up", f"Call to {addr} disconnected.")))
async def dial(self, ctx, address): # basic checks - ensure this is a phone channel and has no other open calls channel_info = await self.get_channel_config(ctx.channel.id) if not channel_info: return await ctx.send( embed=util.error_embed("Not in a phone channel.")) originating_address = channel_info["id"] if address == originating_address: return await ctx.send(embed=util.error_embed( "A channel cannot dial itself. That means *you*, Gibson.")) recv_info = await self.get_addr_config(address) if not recv_info: return await ctx.send(embed=util.error_embed( "Destination address not found. Please check for typos and/or antimemes." )) current_call = await self.bot.database.execute_fetchone( "SELECT * FROM calls WHERE from_id = ?", (originating_address, )) if current_call: return await ctx.send(embed=util.error_embed( f"A call is already open (to {current_call['to_id']}) from this channel. Currently, only one outgoing call is permitted at a time." )) # post embed in the receiving channel prompting people to accept/decline call recv_channel = self.bot.get_channel(recv_info["channel_id"]) _, call_message = await asyncio.gather( ctx.send(embed=util.info_embed("Outgoing call", f"Dialing {address}...")), recv_channel.send(embed=util.info_embed( "Incoming call", f"Call from {originating_address}. Click :white_check_mark: to accept or :negative_squared_cross_mark: to decline." ))) # add clickable reactions to it await asyncio.gather(call_message.add_reaction("✅"), call_message.add_reaction("❎")) def check(re, u): return (str(re.emoji) == "✅" or str(re.emoji) == "❎") and u != self.bot.user reaction = None # wait until someone clicks the reactions, or time out and say so try: reaction, user = await self.bot.wait_for( "reaction_add", timeout=util.config["call_timeout"], check=check) except asyncio.TimeoutError: await asyncio.gather( ctx.send(embed=util.error_embed( "Timed out", "Outgoing call timed out - the other end did not pick up.") ), recv_channel.send(embed=util.error_embed( "Timed out", "Call timed out - no response in time"))) await asyncio.gather(call_message.remove_reaction("✅", self.bot.user), call_message.remove_reaction("❎", self.bot.user)) em = str(reaction.emoji) if reaction else "❎" if em == "✅": # accept call await self.bot.database.execute( "INSERT INTO calls VALUES (?, ?, ?)", (originating_address, address, util.timestamp())) await self.bot.database.commit() await eventbus.add_bridge_link(self.bot.database, ("discord", ctx.channel.id), ("discord", recv_channel.id), "telephone") await asyncio.gather( ctx.send(embed=util.info_embed( "Outgoing call", "Call accepted and connected.")), recv_channel.send(embed=util.info_embed( "Incoming call", "Call accepted and connected."))) elif em == "❎": # drop call await ctx.send(embed=util.error_embed("Your call was declined.", "Call declined"))