{"id":16367163,"url":"https://github.com/snower/slock","last_synced_at":"2025-05-09T03:01:09.455Z","repository":{"id":41269721,"uuid":"141275643","full_name":"snower/slock","owner":"snower","description":"High-performance distributed sync service and atomic DB","archived":false,"fork":false,"pushed_at":"2024-11-22T03:12:26.000Z","size":1554,"stargazers_count":56,"open_issues_count":0,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-24T22:33:18.029Z","etag":null,"topics":["cluster","distributed","raft","replication"],"latest_commit_sha":null,"homepage":"https://snower.github.io/slock/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/snower.png","metadata":{"files":{"readme":"README-zh-hans.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-17T10:48:17.000Z","updated_at":"2024-11-22T03:12:29.000Z","dependencies_parsed_at":"2024-04-20T14:44:02.853Z","dependency_job_id":"06291b93-ccb4-4e3c-988d-3727ce966f75","html_url":"https://github.com/snower/slock","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snower%2Fslock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snower%2Fslock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snower%2Fslock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/snower%2Fslock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/snower","download_url":"https://codeload.github.com/snower/slock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253181418,"owners_count":21866991,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cluster","distributed","raft","replication"],"created_at":"2024-10-11T02:48:46.441Z","updated_at":"2025-05-09T03:01:09.359Z","avatar_url":"https://github.com/snower.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# slock\n\n[![Tests](https://img.shields.io/github/actions/workflow/status/snower/slock/build-test.yml?label=tests)](https://github.com/snower/slock/actions/workflows/build-test.yml)\n[![GitHub Repo stars](https://img.shields.io/github/stars/snower/slock?style=social)](https://github.com/snower/slock/stargazers)\n\n高性能分布式状态同步与原子操作数据库。\n\n# 简介\n\n高性能分布式状态同步与原子操作数据库，提供服务级原子操作语义，通过锁队列、高性能异步二进制网络协议提供良好的多核支持。\n可用于削峰限流、加锁同步、事件通知、并发控制等。\n\n* [安装](#安装)\n* [快速启动服务器](#快速启动服务器)\n* [查看服务器信息](#查看服务器信息)\n* [可用的加锁类型](#可用的加锁类型)\n* [性能基准](#性能基准)\n* [主从模式](#主从模式)\n* [集群模式](#集群模式)\n* [通信协议](#通信协议)\n* [客户端库](#客户端库)\n* [Docker](#docker)\n\n# 安装\n\n```\ngo get github.com/snower/slock\n```\n\n# 快速启动服务器\n\n```bash\n./bin/slock -h\nUsage:\n  slock [info]\n        default start slock server\n        info command show db state\n\nApplication Options:\n      --conf=                                toml conf filename\n      --bind=                                bind address (default: 127.0.0.1)\n      --port=                                bind port (default: 5658)\n      --log=                                 log filename, default is output stdout (default: -)\n      --log_level=[DEBUG|INFO|Warning|ERROR] log level (default: INFO)\n      --log_rotating_size=                   log rotating byte size (default: 67108864)\n      --log_backup_count=                    log backup count (default: 5)\n      --log_buffer_size=                     log buffer byte size (default: 0)\n      --log_buffer_flush_time=               log buffer flush seconds time (default: 1)\n      --data_dir=                            data dir (default: ./data/)\n      --db_fast_key_count=                   db fast key count (default: 4194304)\n      --db_concurrent=                       db concurrent count (default: 8)\n      --db_lock_aof_time=                    db lock aof time (default: 1)\n      --db_lock_aof_parcent_time=            db lock aof parcent expried time (default: 0.3)\n      --aof_queue_size=                      aof channel queue size (default: 65536)\n      --aof_file_rewrite_size=               aof file rewrite size (default: 67174400)\n      --aof_file_buffer_size=                aof file buffer size (default: 4096)\n      --aof_ring_buffer_size=                slave sync ring buffer size (default: 1048576)\n      --aof_ring_buffer_max_size=            slave sync ring buffer max size (default: 268435456)\n      --slaveof=                             slave of to master sync\n      --replset=                             replset name, start replset mode when it set\n\nHelp Options:\n  -h, --help                                 Show this help message\n```\n\n```bash\n./bin/slock --bind=0.0.0.0 --port=5658 --log=/var/log/slock.log\n```\n\n# 查看服务器信息\n\n```bash\nredis-cli -h 127.0.0.1 -p 5658 info\n```\n\n# 可用的加锁类型\n\n- Lock - 非重入锁\n- Event - 分布式Event，可设置默认seted或默认unseted\n- RLock - 可重入锁，最大重入次数 0xff\n- Semaphore - Semaphore，最大次数 0xffff\n- RWLock - 读写锁， 最大并发读0xffff\n- MaxConcurrentFlow - 最大并发限流\n- TokenBucketFlow - 令牌桶限流\n\n# 性能基准\n\n```bash\ngo run tools/benchmark/main.go --mode=stream\n# Intel(R) Core(TM) i5-4590 CPU @ 3.30GHz 4 Processor\n# MemTotal: 8038144 kB\n\nRun 1 Client, 1 concurrentc, 2000000 Count Lock and Unlock\nClient Opened 1\n2000064 6.426136s 311238.965232r/s\n\nRun 16 Client, 16 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 16\n5001024 3.738898s 1337566.282457r/s\n\nRun 32 Client, 32 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 32\n5002048 3.375306s 1481953.845101r/s\n\nRun 64 Client, 64 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 64\n5004096 3.148570s 1589323.402086r/s\n\nRun 128 Client, 128 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 128\n5008192 3.713254s 1348734.158725r/s\n\nRun 256 Client, 256 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 256\n5016384 4.233933s 1184804.690796r/s\n\nRun 512 Client, 512 concurrentc, 5000000 Count Lock and Unlock\nClient Opened 512\n5032768 4.738539s 1062092.867154r/s\n\nSucced\n```\n\n# 主从模式\n\n非replset启动是默认为leader节点，可在启动参数中使用该参数指定leader节点连接参数信息启动为follower节点，follower节点会自动注册为代理转发lock和unlock指令到leader节点操作。\n\n```bash\n./bin/slock --bind=0.0.0.0 --port=5659 --log=/var/log/slock.log --slaveof=127.0.0.1:5658\n```\n\n# 集群模式\n\n使用replset参数指定集群名称即可启动为集群模式（集群模式会忽略slaveof参数），集群启动成功后自动投票选举leader节点，其余follower节点会启动代理转发lock和unlock命令模式，自动跟踪主节点变更，即集群启动后任意节点都可正常接受客户端连接，各节点完全一致。\n\n集群管理使用redis-cli，配置管理可在集群内任意节点完成。\n\nslock自身具备良好多核支持，集群模式自身不能起到提高性能的作用，但可完成高可用，单一节点失效不影响整体服务可用性，节点宕机时秒级恢复集群可用，节点网络超时可在数秒内恢复集群可用。\n\n！！！！注意：集群配置过程和MongoDB副本集初始化过程类似，添加的节点IP需要相互能访问，按以下配置示例自行配置时需要自行替换IP端口为节点间相互能访问的IP端口\n\n！！！！（特别提醒：Docker容器内127.0.0.1不互通，需使用容器外IP端口 ）。\n\n### 集群创建示例\n\n#### 第1步：启动集群节点\n\n```bash\n./bin/slock --data_dir=./data1 --bind=0.0.0.0 --port=5657 --log=/var/log/slock1.log --replset=s1\n\n./bin/slock --data_dir=./data2 --bind=0.0.0.0 --port=5658 --log=/var/log/slock2.log --replset=s1\n\n./bin/slock --data_dir=./data3 --bind=0.0.0.0 --port=5659 --log=/var/log/slock3.log --replset=s1\n```\n\n#### 第2步：使用redis-cli连接\n\n```bash\nredis-cli -h 127.0.0.1 -p 5657\n```\n\n#### 第3步：配置当前节点信息并初始化集群\n\n```bash\n# 在连接成功后的redis-cli中执行\n\nreplset config 127.0.0.1:5657 weight 1 arbiter 0\n```\n\nIP和端口必须为**当前节点**可被其它节点访问的外部IP和端口\n\n#### 第4步：添加其它节点信息\n\n```bash\n# 在连接成功后的redis-cli中执行\n\nreplset add 127.0.0.1:5658 weight 1 arbiter 0\n\nreplset add 127.0.0.1:5659 weight 1 arbiter 0\n```\n\nIP和端口必须为**其它节点**可被当前节点访问的外部IP和端口\n\n### 配置指令\n\n```\n# 添加节点\nreplset add \u003chost\u003e weight \u003cweight\u003e arbiter \u003carbiter\u003e\n\n# 更新节点参数\nreplset set \u003chost\u003e weight \u003cweight\u003e arbiter \u003carbiter\u003e\n\n# 移除节点\nreplset remove \u003chost\u003e\n\n# 查看节点信息\nreplset get \u003chost\u003e\n\n# 查询集群节点列表\nreplset members\n```\n\n### 参数说明\n\n#### host \nip:port或domain:port格式\n```\n注意：\n    集群内各节点需要相互连接，所以指定的host需要保证集群内的其它节点都要能正常连接到该地址。\n```\n\n#### weight\n数字，投票权重优先级，投票优先选择拥有最新数据节点，再选择weight最高节点，weight为0时永远不会被选为leader节点，即可通过设置weight为0使该节点单纯为数据节点。\n\n#### arbiter\n数字，非0即仅投票节点，此时依然启动集群代理，此时该节点也为集群agent节点。\n\n# 通信协议\n\n### 二进制异步协议\n\n```\n# 请求命令\n|     0     |      1    |     2     |     3     |     4     |     5     |     6     |     7     |\n|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|\n|   Magic   |  Version  |CommandType|                      RequestId                            |\n|-----------------------------------------------------------------------------------------------|\n|                                           RequestId                                           |\n|-----------------------------------------------------------------------------------------------|\n|           RequestId               |   FLAG    |   DBID    |               LockId              |\n|-----------------------------------------------------------------------------------------------|\n|                                           LockId                                              |\n|-----------------------------------------------------------------------------------------------|\n|                       LockId                              |               LockKey             |\n|-----------------------------------------------------------------------------------------------|\n|                                           LockKey                                             |\n|-----------------------------------------------------------------------------------------------|\n|                       LockKey                             |       Timeout         |TimeoutFlag|\n|-----------------------------------------------------------------------------------------------|\n|TimeoutFlag|         Expried       |     ExpriedFlag       |        Count         |   RCount   |\n|-----------------------------------------------------------------------------------------------|\n\n# 响应命令\n|     0     |      1    |     2     |     3     |     4     |     5     |     6     |     7     |\n|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|\n|   Magic   |  Version  |CommandType|                      RequestId                            |\n|-----------------------------------------------------------------------------------------------|\n|                                           RequestId                                           |\n|-----------------------------------------------------------------------------------------------|\n|           RequestId               |   Result  |   FLAG    |   DBID    |        LockId         |\n|-----------------------------------------------------------------------------------------------|\n|                                           LockId                                              |\n|-----------------------------------------------------------------------------------------------|\n|                             LockId                                    |        LockKey        |\n|-----------------------------------------------------------------------------------------------|\n|                                           LockKey                                             |\n|-----------------------------------------------------------------------------------------------|\n|                             LockKey                                   |        LCount         |\n|-----------------------------------------------------------------------------------------------|\n|        Count          |  LRCount  |   RCount  |                 PADDING                       |\n|-----------------------------------------------------------------------------------------------|\n\n# 请求及返回之类都是固定64字节，Magic值为0x56，Version当前为0x01\n# CommandType Lock调用值为1，UnLock调用值为2\n# 数字编码字节序为网络字节续，即低位在前，RequestId、LockId、LockKey三个为字节数组正常数组顺序\n# 协议为全双工异步协议，不保证顺序返回，以RequestId为准\n# RequestId连接级唯一，LockId相同LockKey下唯一即可\n# 二进制协议及redis文本协议都使用相同端口，首次收到数据会区分协议类型，后面需使用相同协议通信\n# Count为当个LockKey可锁定最大次数，RCoun为单个LockId可重入次数\n# 返回指令中LCount及LRCount分别为Count和RCount的当前以锁定次数\n```\n\n### Redis同步文本协议\n\n```\nLOCK lock_key [TIMEOUT seconds] [EXPRIED seconds] [LOCK_ID lock_id_string] [FLAG flag_uint8] [COUNT count_uint16] [RCOUNT rcount_uint8] [WILL will_uint8]\n\n对lock_key加锁。\n- LOCK_KEY 需要加锁的key值，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5\n- TIMEOUT 已锁定则等待时长，4字节无符号整型，高2字节是FLAG，低2字节是时间，可选\n- EXPRIED 锁定后超时时长，4字节无符号整型，高2字节是FLAG，低2字节是时间，可选\n- LOCK_ID 本次加锁ID，不指明lock_id则自动生成一个，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5，可选\n- FLAG 标识，可选\n- COUNT LOCK_KEY最大锁定次数，不超过两字节无符号整型，可选\n- RCOUNT LOCK_ID 重复锁定次数，不超过一字节无符号整型，可选\n- WILL 设置值1表示次命令遗言命令，在连接断开后被发送执行，可选\n\n返回 [RESULT_CODE, RESULG_MSG, 'LOCK_ID', lock_id, 'LCOUNT', lcount, 'COUNT', count, 'LRCOUNT', lrcoutn, 'RCOUNT', rcount]\n- RESULT_CODE 返回值，数字，0为成功\n- RESULG_MSG 放回值消息提示，OK为成功\n- LOCK_ID 本次加锁ID，解锁是需要\n- LCOUNT LOCK_KEY已锁定次数\n- COUNT LOCK_KEY最大锁定次数\n- LRCOUNT LOCK_ID已锁定次数\n- RCOUNT LOCK_ID最大锁定次数\n- WILL 设置值1表示次命令遗言命令，在连接断开后被发送执行，可选\n\nUNLOCK lock_key [LOCK_ID lock_id_string] [FLAG flag_uint8] [RCOUNT rcount_uint8] [WILL will_uint8]\n\n对lock_key解锁。\n- LOCK_KEY 需要加锁的key值，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5\n- LOCK_ID 本次加锁ID，不指明则自动使用上次锁定lock_id，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5，可选\n- FLAG 标识，可选\n- RCOUNT LOCK_ID 重复锁定次数，不超过一字节无符号整型，可选\n- WILL 设置值1表示次命令遗言命令，在连接断开后被发送执行，可选\n\n返回 [RESULT_CODE, RESULG_MSG, 'LOCK_ID', lock_id, 'LCOUNT', lcount, 'COUNT', count, 'LRCOUNT', lrcoutn, 'RCOUNT', rcount]\n- RESULT_CODE 返回值，数字，0为成功\n- RESULG_MSG 放回值消息提示，OK为成功\n- LOCK_ID 本次加锁ID，解锁是需要\n- LCOUNT LOCK_KEY已锁定次数\n- COUNT LOCK_KEY最大锁定次数\n- LRCOUNT LOCK_ID已锁定次数\n- RCOUNT LOCK_ID最大锁定次数\n\nPUSH lock_key [TIMEOUT seconds] [EXPRIED seconds] [LOCK_ID lock_id_string] [FLAG flag_uint8] [COUNT count_uint16] [RCOUNT rcount_uint8]\n\n推送对lock_key加锁命令，不等待结果返回。\n- LOCK_KEY 需要加锁的key值，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5\n- TIMEOUT 已锁定则等待时长，4字节无符号整型，高2字节是FLAG，低2字节是时间，可选\n- EXPRIED 锁定后超时时长，4字节无符号整型，高2字节是FLAG，低2字节是时间，可选\n- LOCK_ID 本次加锁ID，不指明lock_id则自动生成一个，长度16字节，不足16前面加0x00补足，32字节是尝试hex解码，超过16字节取MD5，可选\n- FLAG 标识，可选\n- COUNT LOCK_KEY最大锁定次数，不超过两字节无符号整型，可选\n- RCOUNT LOCK_ID 重复锁定次数，不超过一字节无符号整型，可选\n- WILL 设置值1表示次命令遗言命令，在连接断开后被发送执行，可选\n\n返回 [RESULT_CODE, RESULG_MSG, 'LOCK_ID', lock_id, 'LCOUNT', lcount, 'COUNT', count, 'LRCOUNT', lrcoutn, 'RCOUNT', rcount]\n- RESULT_CODE 返回值，数字，0为成功\n- RESULG_MSG 放回值消息提示，OK为成功\n- LOCK_ID 本次加锁ID，解锁是需要\n- LCOUNT LOCK_KEY已锁定次数\n- COUNT LOCK_KEY最大锁定次数\n- LRCOUNT LOCK_ID已锁定次数\n- RCOUNT LOCK_ID最大锁定次数\n```\n\n\n### Flags\n\n#### Lock命令FLAG\n```\n|7                    |           1           |         0           |\n|---------------------|-----------------------|---------------------|\n|                     |when_locked_update_lock|when_locked_show_lock|\n\n0x01 when_locked_show_lock 已锁定时返回锁定信息，过期实际设置为0可用于查询锁信息\n0x02 when_locked_update_lock 已锁定时更新锁定信息\n0x08 concurrent_check 超时时间为0时不加锁直接检查锁定次数已超过则返回超时错误\n0x10 lock_tree_lock 标识是数锁定\n```\n\n#### UnLock命令FLAG\n```\n|7                  |                4               |                  3            |            1            |               0               |\n|-------------------|--------------------------------|-------------------------------|-------------------------|-------------------------------|\n|                   |when_unloked_to_unlock_tree_lock|when_unloked_to_lock_wait_queue|when_unlocked_cancel_wait|when_unlocked_unlock_first_lock|\n\n0x01 when_unlocked_unlock_first_lock 未锁定时直接取消第一个已锁定的锁，并返回锁定信息\n0x02 when_unlocked_cancel_wait 等待锁定时取消等待\n0x08 when_unloked_to_lock_wait_queue 如果解锁成功则再次放入锁定等待队列\n0x10 when_unloked_to_unlock_tree_lock 如果解锁成功则执行树结构解锁\n0x20 contains_data 本次操作包含数据，如果执行成功则执行数据操作\n```\n\n#### Timeout参数FLAG\n\n```\n|    15  |                13                   |  12 |        11      |       10       |      9       |           8        |             7          |      6    |       5      |4           0|\n|--------|-------------------------------------|-----|----------------|----------------|--------------|--------------------|------------------------|-----------|--------------|-------------|\n|keeplive|update_no_reset_timeout_checked_count|acked|timeout_is_error|millisecond_time|unlock_to_wait|unrenew_expried_time|timeout_reverse_key_lock|minute_time|push_subscribe|             |\n\n0x0020 push_subscribe 超时时推送超时订阅信息\n0x0040 minute_time 超时时间是分钟单位\n0x0080 timeout_reverse_key_lock 超时时反转LockKey后调用锁定指令\n0x0100 unrenew_expried_time 锁定时不重计过期时间，即过期时间以接收到命令时计算\n0x0200 unlock_to_wait 该LockKey当前没有任何锁锁定则等待，否则执行正常锁定流程\n0x0400 millisecond_time 超时时间是毫秒单位\n0x0800 timeout_is_error 超时时以ERROR级别在日志中输出错误，可用于开发时调试死锁等异常\n0x1000 acked 需等待整个集群所有活动节点均锁定成功才返回成功，强一致锁定\n0x2000 update_no_reset_timeout_checked_count 用Lock命令更新Flag更新锁定信息是，不重置超时队列计数器\n0x4000 timeout_flag_less_lock_version_is_lock_succed 已加锁，但lock版本小于当前锁定版本则返回锁定成功（lock版本为lock_id低8字节）\n0x8000 keeplive 连接不断开则不超时，则此时设置的超时时间为检查连接存活状态的延时间隔\n0x20 contains_data 本次操作包含数据，如果执行成功则执行数据操作\n```\n\n#### Expried参数FLAG\n\n```\n|    15  |          14          |                13                   |                12         |        11      |       10       |         9        |        8    |            7           |     6     |    5         |4            0|\n|--------|----------------------|-------------------------------------|---------------------------|----------------|----------------|------------------|-------------|------------------------|-----------|--------------|--------------|\n|keeplive|unlimited_expried_time|update_no_reset_expried_checked_count|aof_time_of_expried_parcent|expried_is_error|millisecond_time|unlimited_aof_time|zeor_aof_time|expried_reverse_key_lock|minute_time|push_subscribe|              |\n\n0x0020 push_subscribe 过期时推送过期订阅信息\n0x0040 minute_time 过期时间是分钟单位\n0x0080 expried_reverse_key_lock 过期时反转LockKey后调用锁定指令\n0x0100 zeor_aof_time 立刻持久化该命令\n0x0200 unlimited_aof_time 不持久化该命令\n0x0400 millisecond_time 过期时间是毫秒单位\n0x0800 expried_is_error 过期时以ERROR级别在日志中输出错误，可用于开发时调试死锁等异常\n0x1000 aof_time_of_expried_parcent 持久化时间是过期时间的百分比，百分比值有启动参数db_lock_aof_parcent_time指定\n0x2000 update_no_reset_expried_checked_count 用Lock命令更新Flag更新锁定信息是，不重置过期队列计数器\n0x4000 unlimited_expried_time 永远不过期（谨慎使用）\n0x8000 keeplive 连接不断开则不过期，则此时设置的超时时间为检查连接存活状态的延时间隔\n```\n\n# 客户端库\n\nPHP Client [phslock](https://github.com/snower/phslock)\n\nPython Client [pyslock](https://github.com/snower/pyslock)\n\nJava Client [jaslock](https://github.com/snower/jaslock)\n\n.NET Core Client [jaslock](https://github.com/snower/slock4net)\n\nopenresty Client [slock-lua-nginx](https://github.com/snower/slock-lua-nginx)\n\n# docker\n\n[构建](docker/README.md)\n\n[https://hub.docker.com/repository/docker/sujin190/slock](https://hub.docker.com/repository/docker/sujin190/slock)\n\n```bash \ndocker pull sujin190/slock\n\ndocker run -d --name slock -p 5658:5658 slock\n```\n\n# License\n\nslock uses the MIT license, see LICENSE file for the details.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnower%2Fslock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnower%2Fslock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnower%2Fslock/lists"}