
    &0j7                    \    d Z ddlmZ ddlZddlZddlZddlZddlmZ  G d d          Z	dS )u  多用户部署的 SQLite 存储:邀请码门禁 + 会话进度(引擎快照)。

- invites:预生成的邀请码,一码一会话(首次激活即绑定一个 session,之后该码作废);
- sessions:每个用户的独立进度,存引擎快照 JSON——离开即存档,回来从此恢复续播。
线程安全:每线程一条 sqlite 连接(HTTP handler 多线程);写操作各自 commit。
    )annotationsN)Pathc                  h    e Zd Zd dZd!dZd"dZd#dZd$d%dZd&dZd'dZ	d(dZ
d)dZd*dZd+dZdS ),SessionStoredb_path
str | PathreturnNonec                    t          |          | _        t          | j                  j                            dd           t          j                    | _        |                                  d S )NT)parentsexist_ok)	str_db_pathr   parentmkdir	threadinglocal_local_init)selfr   s     //root/genesis-world/src/genesis/server/store.py__init__zSessionStore.__init__   sU    GT]"(((EEEo''

    sqlite3.Connectionc                    t          | j        d          sNt          j        | j        dd          }t          j        |_        |                    d           || j        _        | j        j        S )NconnF
   )check_same_threadtimeoutzPRAGMA journal_mode=WAL)	hasattrr   sqlite3connectr   Rowrow_factoryexecuter   )r   cs     r   _connzSessionStore._conn   s`    t{F++ 	!PRSSSA#KAMII/000 DK{r   c                ,   |                                                      d           dD ]C}	 |                                                      d| d           /# t          j        $ r Y @w xY w|                                                                   d S )Na  
        CREATE TABLE IF NOT EXISTS invites(
          code TEXT PRIMARY KEY,
          world TEXT,
          session_id TEXT,
          created_at REAL,
          activated_at REAL);
        CREATE TABLE IF NOT EXISTS sessions(
          session_id TEXT PRIMARY KEY,
          invite_code TEXT,
          world TEXT,
          created_at REAL,
          last_active REAL,
          step INTEGER DEFAULT 0,
          snapshot TEXT);
        )invitessessionszALTER TABLE z ADD COLUMN world TEXT)r'   executescriptr%   r!   OperationalErrorcommit)r   tbls     r   r   zSessionStore._init    s    

"" $ 	 	 	  + 	 	C

$$%OC%O%O%OPPPP+   

s   +AA+*A+nintworldr   	list[str]c                L   |                                  t          j                    g }}}t          |          D ]V}t          j        d                                          }|                    d|||f           |                    |           W|                                 |S )uJ   为指定世界预生成 n 个邀请码(8 位十六进制,大写好念)。   zFINSERT OR IGNORE INTO invites(code, world, created_at) VALUES(?, ?, ?))	r'   timerangesecrets	token_hexupperr%   appendr-   )r   r/   r1   r&   nowcodes_codes           r   gen_inviteszSessionStore.gen_invites9   s    

dikk23q 	 	A$Q''--//DII^aeglnq`rsssLL	


r   N
str | None
list[dict]c                    d}d}|r|dz  }|f}|                                                      |dz   |                                          }d |D             S )NzESELECT code, world, session_id, created_at, activated_at FROM invites z WHERE world=?z ORDER BY created_atc                ,    g | ]}t          |          S rC   )dict).0rs     r   
<listcomp>z-SessionStore.list_invites.<locals>.<listcomp>I   s    &&&AQ&&&r   )r'   r%   fetchall)r   r1   qargsrowss        r   list_inviteszSessionStore.list_invitesC   sh    S 	3!!A5(4zz||##A(>$>EENNPP&&&&&&r   r>   tuple[str, str] | Nonec                   |pd                                                                 }|                                 }|                    d|f                                          }||d         rdS |d         }t          j        d          t          j                    }}|                    d|||f           |j        dk    r|	                                 dS |                    d	|||||f           |
                                 ||fS )
uz   激活邀请码:未用则创建新会话并绑定到该码的世界,返回 (session_id, world);无效/已用返回 None。 z2SELECT session_id, world FROM invites WHERE code=?N
session_idr1      zSUPDATE invites SET session_id=?, activated_at=? WHERE code=? AND session_id IS NULLr   z_INSERT INTO sessions(session_id, invite_code, world, created_at, last_active) VALUES(?,?,?,?,?))stripr9   r'   r%   fetchoner7   r8   r5   total_changesrollbackr-   )r   r>   r&   rowr1   sidr;   s          r   activate_invitezSessionStore.activate_inviteK   s   
!!##))++JJLLiiLtgVV__aa;#l+;4G$R(($)++S			gT"	$ 	$ 	$?aJJLLL4			seS#.	0 	0 	0	


Ezr   rX   c                    |sdS |                                                      d|f                                          }|r|d         ndS )u>   会话绑定的世界 id(路由到对应世界的引擎池)。Nz-SELECT world FROM sessions WHERE session_id=?r1   r'   r%   rT   r   rX   rW   s      r   session_worldzSessionStore.session_world^   sP     	4jjll""#RUXTZ[[ddff",s7||,r   boolc                    |sdS |                                                      d|f                                          d uS )NFz)SELECT 1 FROM sessions WHERE session_id=?r[   )r   rX   s     r   session_existszSessionStore.session_existsf   sK     	5zz||##7#A AAISWX 	Xr   stepsnapshot_jsonc                    |                                  }|                    d||t          j                    |f           |                                 d S )NzHUPDATE sessions SET step=?, snapshot=?, last_active=? WHERE session_id=?r'   r%   r5   r-   )r   rX   ra   rb   r&   s        r   save_snapshotzSessionStore.save_snapshotl   sK    JJLL			\	S9	; 	; 	;	




r   tuple[int | None, str | None]c                    |                                                      d|f                                          }|r|d         |d         fndS )Nz6SELECT step, snapshot FROM sessions WHERE session_id=?ra   snapshot)NNr[   r\   s      r   load_snapshotzSessionStore.load_snapshotr   sQ    jjll""DsfN NNVhjj 	14FFS_--,Fr   c                    |                                  }|                    dt          j                    |f           |                                 d S )Nz4UPDATE sessions SET last_active=? WHERE session_id=?rd   )r   rX   r&   s      r   touchzSessionStore.touchw   sA    JJLL			H49;;X[J\]]]	




r   )r   r   r	   r
   )r	   r   )r	   r
   )r/   r0   r1   r   r	   r2   )N)r1   r@   r	   rA   )r>   r   r	   rN   )rX   r   r	   r@   )rX   r   r	   r^   )rX   r   ra   r0   rb   r   r	   r
   )rX   r   r	   rf   )rX   r   r	   r
   )__name__
__module____qualname__r   r'   r   r?   rM   rY   r]   r`   re   ri   rk   rC   r   r   r   r      s                     2   ' ' ' ' '   &- - - -X X X X   G G G G
     r   r   )
__doc__
__future__r   r7   r!   r   r5   pathlibr   r   rC   r   r   <module>rr      s     # " " " " "             i i i i i i i i i ir   