1313import hashlib
1414import io
1515import os
16- import socket
1716import sqlite3
1817import sys
1918import threading
2019import time
20+ import uuid
2121from dataclasses import dataclass
2222from functools import cached_property
2323from pathlib import Path
@@ -49,6 +49,17 @@ class CLISessionDatabaseConnection:
4949 timestamp INTEGER NOT NULL
5050 )
5151 """
52+ _CREATE_HOST_ID_TABLE = """
53+ CREATE TABLE IF NOT EXISTS host_id (
54+ key INTEGER PRIMARY KEY,
55+ id TEXT UNIQUE NOT NULL
56+ )
57+ """
58+ _INSERT_HOST_ID = """
59+ INSERT OR IGNORE INTO host_id (
60+ key, id
61+ ) VALUES (?, ?)
62+ """
5263 _ENABLE_WAL = 'PRAGMA journal_mode=WAL'
5364
5465 def __init__ (self , connection = None ):
@@ -69,12 +80,28 @@ def execute(self, query, *parameters):
6980 return sqlite3 .Cursor (self ._connection )
7081
7182 def _ensure_database_setup (self ):
72- self ._create_record_table ()
83+ self ._create_session_table ()
84+ self ._create_host_id_table ()
85+ self ._ensure_host_id ()
7386 self ._try_to_enable_wal ()
7487
75- def _create_record_table (self ):
88+ def _create_session_table (self ):
7689 self .execute (self ._CREATE_TABLE )
7790
91+ def _create_host_id_table (self ):
92+ self .execute (self ._CREATE_HOST_ID_TABLE )
93+
94+ def _ensure_host_id (self ):
95+ self .execute (
96+ self ._INSERT_HOST_ID ,
97+ # Hardcode `0` as primary key to ensure
98+ # there's only ever 1 host id in the table.
99+ (
100+ 0 ,
101+ str (uuid .uuid4 ()),
102+ ),
103+ )
104+
78105 def _try_to_enable_wal (self ):
79106 try :
80107 self .execute (self ._ENABLE_WAL )
@@ -111,6 +138,11 @@ class CLISessionDatabaseReader:
111138 FROM session
112139 WHERE key = ?
113140 """
141+ _READ_HOST_ID = """
142+ SELECT id
143+ FROM host_id
144+ WHERE key = 0
145+ """
114146
115147 def __init__ (self , connection ):
116148 self ._connection = connection
@@ -122,6 +154,10 @@ def read(self, key):
122154 return
123155 return CLISessionData (* result )
124156
157+ def read_host_id (self ):
158+ cursor = self ._connection .execute (self ._READ_HOST_ID )
159+ return cursor .fetchone ()[0 ]
160+
125161
126162class CLISessionDatabaseSweeper :
127163 _DELETE_RECORDS = """
@@ -142,11 +178,11 @@ def sweep(self, timestamp):
142178
143179
144180class CLISessionGenerator :
145- def generate_session_id (self , hostname , tty , timestamp ):
146- return self ._generate_md5_hash (hostname , tty , timestamp )
181+ def generate_session_id (self , host_id , tty , timestamp ):
182+ return self ._generate_md5_hash (host_id , tty , timestamp )
147183
148- def generate_cache_key (self , hostname , tty ):
149- return self ._generate_md5_hash (hostname , tty )
184+ def generate_cache_key (self , host_id , tty ):
185+ return self ._generate_md5_hash (host_id , tty )
150186
151187 def _generate_md5_hash (self , * args ):
152188 str_to_hash = ""
@@ -167,12 +203,12 @@ def __init__(self, generator, writer, reader, sweeper):
167203
168204 @cached_property
169205 def cache_key (self ):
170- return self ._generator .generate_cache_key (self ._hostname , self ._tty )
206+ return self ._generator .generate_cache_key (self ._host_id , self ._tty )
171207
172208 @cached_property
173209 def _session_id (self ):
174210 return self ._generator .generate_session_id (
175- self ._hostname , self ._tty , self ._timestamp
211+ self ._host_id , self ._tty , self ._timestamp
176212 )
177213
178214 @cached_property
@@ -206,12 +242,12 @@ def _tty(self):
206242 except (OSError , io .UnsupportedOperation ):
207243 # Standard input was redirected to a pseudofile.
208244 # This can happen when running tests on IDEs or
209- # running scripts with redirected input.
245+ # running scripts with redirected input, etc .
210246 return
211247
212248 @cached_property
213- def _hostname (self ):
214- return socket . gethostname ()
249+ def _host_id (self ):
250+ return self . _reader . read_host_id ()
215251
216252 @cached_property
217253 def _timestamp (self ):
0 commit comments