s13 文件邮箱。 发送消息就是追加一行 JSONL;读取 inbox 后删除文件,表示消息已消费。 教学版用 synchronized 覆盖同进程并发,不处理跨进程文件锁。
| 15 | * 教学版用 synchronized 覆盖同进程并发,不处理跨进程文件锁。 |
| 16 | */ |
| 17 | public class MessageBus { |
| 18 | |
| 19 | private final File mailboxDir; |
| 20 | |
| 21 | public MessageBus(File workdir) { |
| 22 | this.mailboxDir = new File(workdir, ".mailboxes"); |
| 23 | FileUtil.mkdir(mailboxDir); |
| 24 | } |
| 25 | |
| 26 | public synchronized void send(String from, String to, String content) { |
| 27 | send(from, to, content, "message"); |
| 28 | } |
| 29 | |
| 30 | public synchronized void send(String from, String to, String content, String type) { |
| 31 | send(from, to, content, type, new JSONObject()); |
| 32 | } |
| 33 | |
| 34 | public synchronized void send(String from, String to, String content, |
| 35 | String type, JSONObject metadata) { |
| 36 | TeamMessage message = new TeamMessage(from, to, type, content, |
| 37 | System.currentTimeMillis(), metadata); |
| 38 | FileUtil.appendUtf8String(JSON.toJSONString(message) + "\n", inboxFile(to)); |
| 39 | System.out.println(" [bus] " + from + " -> " + to |
| 40 | + ": (" + type + ") " + preview(content)); |
| 41 | } |
| 42 | |
| 43 | public synchronized List<TeamMessage> readInbox(String agent) { |
| 44 | File inbox = inboxFile(agent); |
| 45 | if (!inbox.exists()) { |
| 46 | return new ArrayList<>(); |
| 47 | } |
| 48 | List<TeamMessage> messages = new ArrayList<>(); |
| 49 | String text = FileUtil.readUtf8String(inbox); |
| 50 | for (String line : text.split("\\R")) { |
| 51 | if (!line.isBlank()) { |
| 52 | messages.add(JSON.parseObject(line, TeamMessage.class)); |
| 53 | } |
| 54 | } |
| 55 | FileUtil.del(inbox); |
| 56 | return messages; |
| 57 | } |
| 58 | |
| 59 | public String formatInbox(List<TeamMessage> messages) { |
| 60 | StringBuilder sb = new StringBuilder(); |
| 61 | for (TeamMessage message : messages) { |
| 62 | JSONObject metadata = message.getMetadata(); |
| 63 | String requestId = metadata == null ? "" : metadata.getString("request_id"); |
| 64 | sb.append("From ").append(message.getFrom()) |
| 65 | .append(" [").append(message.getType()); |
| 66 | if (requestId != null && !requestId.isBlank()) { |
| 67 | sb.append(" req:").append(requestId); |
| 68 | } |
| 69 | sb.append("]: ") |
| 70 | .append(message.getContent()) |
| 71 | .append("\n"); |
| 72 | } |
| 73 | return sb.toString().trim(); |
| 74 | } |
nothing calls this directly
no outgoing calls
no test coverage detected