利用AWS Lambda和iOS捷径实现手机一键开小区门禁

我住的小区使用了一个叫守望领域的智能门禁系统,可以通过手机 App 开小区门禁和单元门,但是用 App 开门需要经过四五步:打开 App→ 进入开门界面 → 找到需要开的门 → 点击开门。 加上戴口罩时候解锁手机需要输入密码,导致整个流程非常耗时,经常需要站在小区门口和单元门口操作半天,有一段时间我甚至养成了携带实体门禁卡的习惯,实体门禁卡开门要快很多。 最近又开始忘带门禁卡,苦恼之余发现 iOS 在锁屏界面右划可以免解锁直接进入 spotlight 界面,这个界面可以添加捷径,如果能写一个捷径去调用守望领域 App 的 API 开门,就可以实现手机免解锁一键开门。 查找 API 首先需要通过 Charles 之类的软件查找 App 调用的 API,配置 Charles 查看 App 请求的方式不再赘述,Google 一下可以看到很多教程。直接看结果 Charles 的结果,可以看到 api.lookdoor.cn 是这个软件所请求的 API 域名。 打开软件发的请求非常多,经过操作和请求的对比可以看到,发送开门指令调用的 API 是:/func/hjapp/house/v1/pushOpenDoorBySn.json?equipmentId=xxxxxx 这个路径。 详细查看这个请求可以发现,equipmentId 指的就是小区门的 Id,接口使用 cookie 做认证,只要将 cookie 带上就可以模拟开门指令。 第一次尝试 打开 iOS 捷径 App,创建一个新捷径,App 调用 API 使用了 POST 请求,搜索 Get contents of 这个动作来实现发送 POST 请求。 ...

十月 19, 2021 · 2 分钟 · Zhiya

规避 Go 中的常见并发 bug

在Understanding Real-World Concurrency Bugs in Go这篇论文中,几名研究人员分析了常见的Go并发bug,并在最流行的几个Go开源项目中进行了验证。本文梳理了论文中提到的常见的bug并给出解决方法的分析。 论文中对bugs进行了分类,分为阻塞式和非阻塞式两种: 阻塞式:goroutine发生阻塞无法继续执行(例如死锁) 非阻塞式:不会阻塞执行,但存在潜在的数据冲突(例如并发写) 阻塞式bug 阻塞式bug发生的根因有两种,一种是共享内存(例如卡在了意图保护共享内存的锁操作上),一种是消息传递(比如等待chan)。同时研究发现共享内存和消息传递导致的bug数量不想上下,但是共享这种方法的使用量比消息传递使用的更频繁,所以也得出了共享内存方式更不容易导致bug的结论。 读写锁优先级导致的死锁 在Go中的写锁优先级高于读锁优先级,假设一个goroutine(goroutine A)连续获取两次读锁,而另一个goroutine(goroutine B)在gouroutine A两次获取读锁中间获取了写锁,就会导致死锁的发生。论文中没有针对这个bug给出示例代码,我写了一个简单的代码示意一下。 func gouroutine1() { m.RLock() m.RLock() } func gouroutine2() { m.WLock() } f1和f2都在goroutine中执行,当f1执行完第一个l.RLock()语句后,假设这时f2的m.WLock执行,由于写锁是排它的,WLock本身被f1的第一个m.RLock()阻塞,写锁操作本身又会阻塞f1中的第二个m.RLock WaitGroup误用导致的死锁 这种情况就是比较典型的WaitGroup的误用了,提前执行group.Wait()会导致部分group.Done()无法执行到,进而导致程序被阻塞。 var group sync.WaitGroup group.Add(len(pm.plugins)) for _, p := range pm.plugins { go func(p *plugin) { defer group.Done() } group.Wait() // blocked } // group.Wait() should be here for循环内的group.Wait()执行到的时候,循环内的部分goroutine还没有被创建出来,其中的group.Done()也就永远没法执行到,所以会导致永远阻塞在这一句,正确的写法是将group.Wait()移到for循环外。 Channel的误用 Channel是go支持并发的一个非常重要的特性,Channel虽然在很多场景下非常解决问题,但是误用也是不容易发现的。 func goroutine1() { m.Lock() ch <- request // blocked m.Unlock() } func goroutine2() { for { m.Lock() // 阻塞 m.Unlock() request <- ch } } 这段代码的业务语义是goroutine1会通过ch接收goroutine2发送的消息,但是当goroutine1执行到ch <- request时候会阻塞并等待ch,此时由于goroutine1没有释放锁,goroutine2的m.Lock()也会阻塞,形成死锁。 ...

八月 17, 2021 · 2 分钟 · Zhiya

MySQL 子查询中order by不生效问题

一个偶然的机会,发现一条 SQL 语句在不同的 MySQL 实例上执行得到了不同的结果。 问题描述 创建商品表 product_tbl 和商品操作记录表 product_operation_tbl 两个表,来模拟下业务场景,结构和数据如下: 接下来需要查询所有商品最新的修改时间,使用如下语句: select t1.id, t1.name, t2.product_id, t2.created_at from product_tbl t1 left join (select * from product_operation_log_tbl order by created_at desc) t2 on t1.id = t2.product_id group by t1.id; 通过结果可以看到,子查询先将 product_operation_log_tbl 里的所有记录按创建时间(created_at)逆序,然后和 product_tbl 进行 join 操作,进而查询出的商品的最新修改时间。 在区域 A 的 MySQL 实例上,查询商品最新修改时间可以得到正确结果,但是在区域 B 的 MySQL 实例上,得到的修改时间并不是最新的,而是最老的。通过对语句进行简化,发现是子查询中的 order by created_at desc 语句在区域 B 的实例上没有生效。 排查过程 难道区域会影响 MySQL 的行为?经过 DBA 排查,区域 A 的 MySQL 是 5.6 版,区域 B 的 MySQL 是 5.7 版,并且找到了这篇文章: ...

七月 29, 2021 · 2 分钟 · Zhiya

为 WSL2 一键设置代理

在 WSL2 环境中 clone 一个很大的 git 项目,不走代理速度很慢,所以研究了一下怎么让 WSL2 走 Windows 的代理客户端。 WSL1 和 WSL2 网络的区别 在 WSL1 时代,由于 Linux 子系统和 Windows 共享了网络端口,所以访问 Windows 的代理非常简单。例如 Windows 的代理客户端监听了 8000 端口,那么只需要在 Linux 子系统中执行如下命令,就可以让当前 session 中的请求通过代理访问互联网。 export ALL_PROXY="http://127.0.0.1:8000" 但是 WSL2 基于 Hyper-V 运行,导致 Linux 子系统和 Windows 在网络上是两台各自独立的机器,从 Linux 子系统访问 Windows 首先需要找到 Windows 的 IP。 配置 WSL2 访问 Windows 上的代理 有两个关键步骤: WSL2 中配置的代理要指向 Windows 的 IP; Windows 上的代理客户端需要允许来自本地局域网的请求; 由于 Linux 子系统也是通过 Windows 访问网络,所以 Linux 子系统中的网关指向的是 Windows,DNS 服务器指向的也是 Windows,基于这两个特性,我们可以将 Windows 的 IP 读取出来。 ...

六月 30, 2020 · 1 分钟 · Zhiya

面向开发者的 WSL2 安装指南

为什么要使用 Windows 做开发 一直以来 macOS 以类 unix 的特性,获得了程序员的青睐,但是近几年 Apple 在硬件领域少有让人耳目一新的产品,加上取消 Esc、使用蝶式键盘、基本为 0 的硬件可升级性、系统权限的收紧等骚操作,让 Mac 从软件到硬件都不如以前适合编程。另一方面,PC 阵营在软件层面保持开放的基础上,硬件体验也逐步赶上甚至超越 Mac,我也不想在用 Mac 做开发,用 PC 玩游戏,希望用一台电脑兼顾游戏和开发,所以选择回到了 PC 阵营。 随着微软拥抱开源领域,Windows 也开始变得程序员友好。Windows 10 2004 发布后,WSL2 也可以在正式版 Windows 10 中使用,相比于 macOS,WSL2 是一个原生 Linux 环境而非类 unix 环境,甚至可以在 App 商店中选择所需要的发行版。而相比于 WSL1,WSL2 采用了 HyperV 虚拟机的方式,解决了 WSL1 不能安装 Docker 等问题。 WSL1 和 WSL2 相比于 WSL1,WSL2 通过虚拟机的方式带来了更完整的 Linux 内核,但这种方式也引入了一些问题,微软给出了下面的图表来展示这些不同: WSL2 不能和 VMWarework Station、VirtualBox 同时运行这一条已经过时了,VirtualBox 和 VMWare Workstation 都发布了支持 WSL2 和 Hyper-V 的新版。 ...

六月 1, 2020 · 2 分钟 · Zhiya