diff options
| author | 2024-07-20 17:22:25 +0300 | |
|---|---|---|
| committer | 2024-07-20 17:22:25 +0300 | |
| commit | c70ffd095a6de5cd5b872796a0d82a8c5afc1511 (patch) | |
| tree | 56183274b05a294e357bad4d06b523472a1c4a4a /src | |
| download | ukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.tar.gz ukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.tar.xz ukkobot-c70ffd095a6de5cd5b872796a0d82a8c5afc1511.zip | |
Initial commit
Diffstat (limited to 'src')
104 files changed, 1991 insertions, 0 deletions
diff --git a/src/Bot.zig b/src/Bot.zig new file mode 100644 index 0000000..d40a4a0 --- /dev/null +++ b/src/Bot.zig | |||
| @@ -0,0 +1,239 @@ | |||
| 1 | const types = @import("types.zig"); | ||
| 2 | const std = @import("std"); | ||
| 3 | |||
| 4 | const Allocator = std.mem.Allocator; | ||
| 5 | const ArrayList = std.ArrayList; | ||
| 6 | const Bot = @This(); | ||
| 7 | const Config = @import("Config.zig"); | ||
| 8 | const HttpClient = std.http.Client; | ||
| 9 | const HttpMethod = std.http.Method; | ||
| 10 | const Parsed = std.json.Parsed; | ||
| 11 | const Uri = std.Uri; | ||
| 12 | |||
| 13 | allocator: Allocator, | ||
| 14 | http_client: HttpClient, | ||
| 15 | config: Config, | ||
| 16 | base_uri: Uri = Uri.parse("https://api.telegram.org/") catch unreachable, | ||
| 17 | uri_path_data: ArrayList(u8), | ||
| 18 | poweron: bool = true, | ||
| 19 | server_header_buffer: [4096]u8 = undefined, | ||
| 20 | username: ?[]const u8 = null, | ||
| 21 | |||
| 22 | pub fn init(allocator: Allocator, config: Config) !Bot { | ||
| 23 | var uri_path_data = try ArrayList(u8).initCapacity(allocator, 5 + config.bot_token.len); | ||
| 24 | errdefer uri_path_data.deinit(); | ||
| 25 | |||
| 26 | uri_path_data.appendSliceAssumeCapacity("/bot"); | ||
| 27 | uri_path_data.appendSliceAssumeCapacity(config.bot_token); | ||
| 28 | uri_path_data.appendAssumeCapacity('/'); | ||
| 29 | |||
| 30 | return .{ | ||
| 31 | .allocator = allocator, | ||
| 32 | .http_client = .{ | ||
| 33 | .allocator = allocator, | ||
| 34 | }, | ||
| 35 | .config = config, | ||
| 36 | .uri_path_data = uri_path_data, | ||
| 37 | }; | ||
| 38 | } | ||
| 39 | |||
| 40 | pub fn deinit(self: *Bot) void { | ||
| 41 | self.http_client.deinit(); | ||
| 42 | self.uri_path_data.deinit(); | ||
| 43 | if (self.username) |username| self.allocator.free(username); | ||
| 44 | |||
| 45 | self.* = undefined; | ||
| 46 | } | ||
| 47 | |||
| 48 | pub inline fn editMessageText(self: *Bot, args: types.EditMessageTextParams) !Parsed(types.Message) { | ||
| 49 | return self.post(types.Message, "editMessageText", args); | ||
| 50 | } | ||
| 51 | |||
| 52 | pub inline fn editMessageText_(self: *Bot, args: types.EditMessageTextParams) !void { | ||
| 53 | (try self.editMessageText(args)).deinit(); | ||
| 54 | } | ||
| 55 | |||
| 56 | pub inline fn getMe(self: *Bot) !Parsed(types.User) { | ||
| 57 | return self.get(types.User, "getMe", null); | ||
| 58 | } | ||
| 59 | |||
| 60 | pub inline fn getMyName(self: *Bot, args: types.GetMyNameParams) !Parsed(types.BotName) { | ||
| 61 | return self.get(types.BotName, "getMyName", args); | ||
| 62 | } | ||
| 63 | |||
| 64 | pub inline fn getUpdates(self: *Bot, args: types.GetUpdatesParams) !Parsed([]types.Update) { | ||
| 65 | return self.get([]types.Update, "getUpdates", args); | ||
| 66 | } | ||
| 67 | |||
| 68 | pub inline fn getUsername(self: *Bot) ![]const u8 { | ||
| 69 | if (self.username) |username| return username; | ||
| 70 | const user = try self.getMe(); | ||
| 71 | defer user.deinit(); | ||
| 72 | self.username = user.value.username; | ||
| 73 | return self.username.?; | ||
| 74 | } | ||
| 75 | |||
| 76 | pub inline fn sendMessage(self: *Bot, args: types.SendMessageParams) !Parsed(types.Message) { | ||
| 77 | return self.post(types.Message, "sendMessage", args); | ||
| 78 | } | ||
| 79 | |||
| 80 | pub inline fn sendMessage_(self: *Bot, args: types.SendMessageParams) !void { | ||
| 81 | (try self.sendMessage(args)).deinit(); | ||
| 82 | } | ||
| 83 | |||
| 84 | pub inline fn setMyName(self: *Bot, args: types.SetMyNameParams) !void { | ||
| 85 | if (args.name) |new_name| { | ||
| 86 | // Check if the current name isn't the same as what we want to change to | ||
| 87 | const curr_name = try self.getMyName(.{ .language_code = args.language_code }); | ||
| 88 | defer curr_name.deinit(); | ||
| 89 | |||
| 90 | if (std.mem.eql(u8, curr_name.value.name, new_name)) { | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | const res = try self.post(bool, "setMyName", args); | ||
| 96 | defer res.deinit(); | ||
| 97 | if (!res.value) { | ||
| 98 | return error.FailedToSetName; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | fn Wrapper(comptime T: type) type { | ||
| 103 | return struct { | ||
| 104 | ok: bool, | ||
| 105 | description: ?[]const u8 = null, | ||
| 106 | result: ?T = null, | ||
| 107 | error_code: ?i64 = null, | ||
| 108 | parameters: ?types.ResponseParameters = null, | ||
| 109 | }; | ||
| 110 | } | ||
| 111 | |||
| 112 | fn call( | ||
| 113 | self: *Bot, | ||
| 114 | comptime T: type, | ||
| 115 | comptime method: HttpMethod, | ||
| 116 | uri: Uri, | ||
| 117 | data: ?[]const u8, | ||
| 118 | ) !Parsed(T) { | ||
| 119 | var request = try self.http_client.open(method, uri, .{ | ||
| 120 | .server_header_buffer = &self.server_header_buffer, | ||
| 121 | }); | ||
| 122 | defer request.deinit(); | ||
| 123 | |||
| 124 | if (data) |s| { | ||
| 125 | request.headers.content_type = .{ .override = "application/json" }; | ||
| 126 | request.transfer_encoding = .{ .content_length = s.len }; | ||
| 127 | } | ||
| 128 | try request.send(); | ||
| 129 | |||
| 130 | if (data) |s| { | ||
| 131 | try request.writeAll(s); | ||
| 132 | } | ||
| 133 | try request.finish(); | ||
| 134 | |||
| 135 | try request.wait(); | ||
| 136 | |||
| 137 | var reader = std.json.reader(self.allocator, request.reader()); | ||
| 138 | defer reader.deinit(); | ||
| 139 | |||
| 140 | const result = try std.json.parseFromTokenSource( | ||
| 141 | Wrapper(T), | ||
| 142 | self.allocator, | ||
| 143 | &reader, | ||
| 144 | .{ | ||
| 145 | .ignore_unknown_fields = true, | ||
| 146 | .allocate = .alloc_always, | ||
| 147 | }, | ||
| 148 | ); | ||
| 149 | errdefer result.deinit(); | ||
| 150 | |||
| 151 | if (!result.value.ok or result.value.result == null) { | ||
| 152 | std.log.err("Request failed: {any}", .{result.value}); | ||
| 153 | return error.RequestFailed; | ||
| 154 | } | ||
| 155 | |||
| 156 | return .{ | ||
| 157 | .arena = result.arena, | ||
| 158 | .value = result.value.result.?, | ||
| 159 | }; | ||
| 160 | } | ||
| 161 | |||
| 162 | inline fn isNull(value: anytype) bool { | ||
| 163 | return switch (@typeInfo(@TypeOf(value))) { | ||
| 164 | .Null => true, | ||
| 165 | .Optional => value == null, | ||
| 166 | else => false, | ||
| 167 | }; | ||
| 168 | } | ||
| 169 | |||
| 170 | fn intoQueryString(allocator: Allocator, data: anytype) !?[]u8 { | ||
| 171 | return switch (@typeInfo(@TypeOf(data))) { | ||
| 172 | .Null => null, | ||
| 173 | .Optional => if (data) |d| intoQueryString(allocator, d) else null, | ||
| 174 | .Struct => |s| { | ||
| 175 | var sb = ArrayList(u8).init(allocator); | ||
| 176 | defer sb.deinit(); | ||
| 177 | |||
| 178 | var counter: usize = 0; | ||
| 179 | |||
| 180 | inline for (s.fields) |field| { | ||
| 181 | if (!isNull(@field(data, field.name))) { | ||
| 182 | counter += 1; | ||
| 183 | |||
| 184 | try sb.ensureUnusedCapacity(field.name.len + 2); | ||
| 185 | if (counter != 1) { | ||
| 186 | sb.appendAssumeCapacity('&'); | ||
| 187 | } | ||
| 188 | |||
| 189 | sb.appendSliceAssumeCapacity(field.name); | ||
| 190 | sb.appendAssumeCapacity('='); | ||
| 191 | |||
| 192 | const value = try std.json.stringifyAlloc( | ||
| 193 | allocator, | ||
| 194 | @field(data, field.name), | ||
| 195 | .{ .emit_null_optional_fields = false }, | ||
| 196 | ); | ||
| 197 | defer allocator.free(value); | ||
| 198 | try sb.appendSlice(value); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | return try sb.toOwnedSlice(); | ||
| 203 | }, | ||
| 204 | else => @compileError(@typeName(@TypeOf(data)) ++ " not supported"), | ||
| 205 | }; | ||
| 206 | } | ||
| 207 | |||
| 208 | inline fn get(self: *Bot, Out: type, comptime path: []const u8, args: anytype) !Parsed(Out) { | ||
| 209 | const path_len = self.uri_path_data.items.len; | ||
| 210 | defer self.uri_path_data.shrinkRetainingCapacity(path_len); | ||
| 211 | |||
| 212 | try self.uri_path_data.appendSlice(path); | ||
| 213 | |||
| 214 | var uri = self.base_uri; | ||
| 215 | uri.path = .{ .raw = self.uri_path_data.items }; | ||
| 216 | |||
| 217 | const query = try intoQueryString(self.allocator, args); | ||
| 218 | defer if (query) |q| self.allocator.free(q); | ||
| 219 | if (query) |q| uri.query = .{ .raw = q }; | ||
| 220 | |||
| 221 | std.log.debug("GET {}", .{uri}); | ||
| 222 | return self.call(Out, .GET, uri, null); | ||
| 223 | } | ||
| 224 | |||
| 225 | inline fn post(self: *Bot, Out: type, comptime path: []const u8, args: anytype) !Parsed(Out) { | ||
| 226 | const str_data = try std.json.stringifyAlloc(self.allocator, args, .{ .emit_null_optional_fields = false }); | ||
| 227 | defer self.allocator.free(str_data); | ||
| 228 | |||
| 229 | const path_len = self.uri_path_data.items.len; | ||
| 230 | defer self.uri_path_data.shrinkRetainingCapacity(path_len); | ||
| 231 | |||
| 232 | try self.uri_path_data.appendSlice(path); | ||
| 233 | |||
| 234 | var uri = self.base_uri; | ||
| 235 | uri.path = .{ .raw = self.uri_path_data.items }; | ||
| 236 | |||
| 237 | std.log.debug("POST {}", .{uri}); | ||
| 238 | return self.call(Out, .POST, uri, str_data); | ||
| 239 | } | ||
diff --git a/src/Config.zig b/src/Config.zig new file mode 100644 index 0000000..4deebbc --- /dev/null +++ b/src/Config.zig | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Allocator = std.mem.Allocator; | ||
| 4 | const ArenaAllocator = std.heap.ArenaAllocator; | ||
| 5 | const Config = @This(); | ||
| 6 | |||
| 7 | pub const Wrapper = struct { | ||
| 8 | arena: ArenaAllocator, | ||
| 9 | config: Config, | ||
| 10 | |||
| 11 | pub fn deinit(self: Wrapper) void { | ||
| 12 | self.arena.deinit(); | ||
| 13 | } | ||
| 14 | |||
| 15 | pub fn merge(self: *Wrapper, filename: []const u8) !void { | ||
| 16 | const file = try std.fs.cwd().openFile(filename, .{}); | ||
| 17 | defer file.close(); | ||
| 18 | |||
| 19 | const allocator = self.arena.allocator(); | ||
| 20 | |||
| 21 | var reader = std.json.reader(allocator, file.reader()); | ||
| 22 | defer reader.deinit(); | ||
| 23 | |||
| 24 | const new_config = try std.json.parseFromTokenSourceLeaky( | ||
| 25 | Nullable, | ||
| 26 | allocator, | ||
| 27 | &reader, | ||
| 28 | .{ | ||
| 29 | .duplicate_field_behavior = .use_last, | ||
| 30 | .ignore_unknown_fields = true, | ||
| 31 | .allocate = .alloc_always, | ||
| 32 | }, | ||
| 33 | ); | ||
| 34 | |||
| 35 | inline for (std.meta.fields(Config)) |field| { | ||
| 36 | if (@field(new_config, field.name)) |value| { | ||
| 37 | @field(self.config, field.name) = value; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | }; | ||
| 42 | |||
| 43 | bot_token: []const u8, | ||
| 44 | dev_group: i64, | ||
| 45 | owner: i64, | ||
| 46 | |||
| 47 | pub fn load(parent_allocator: Allocator, filename: []const u8) !Wrapper { | ||
| 48 | const file = try std.fs.cwd().openFile(filename, .{}); | ||
| 49 | defer file.close(); | ||
| 50 | |||
| 51 | var arena = ArenaAllocator.init(parent_allocator); | ||
| 52 | errdefer arena.deinit(); | ||
| 53 | const allocator = arena.allocator(); | ||
| 54 | |||
| 55 | var reader = std.json.reader(allocator, file.reader()); | ||
| 56 | defer reader.deinit(); | ||
| 57 | |||
| 58 | const config = try std.json.parseFromTokenSourceLeaky( | ||
| 59 | Config, | ||
| 60 | allocator, | ||
| 61 | &reader, | ||
| 62 | .{ | ||
| 63 | .duplicate_field_behavior = .use_last, | ||
| 64 | .ignore_unknown_fields = true, | ||
| 65 | .allocate = .alloc_always, | ||
| 66 | }, | ||
| 67 | ); | ||
| 68 | |||
| 69 | return .{ .arena = arena, .config = config }; | ||
| 70 | } | ||
| 71 | |||
| 72 | const Nullable = blk: { | ||
| 73 | const template = @typeInfo(Config); | ||
| 74 | var fields: [template.Struct.fields.len]std.builtin.Type.StructField = undefined; | ||
| 75 | for (template.Struct.fields, 0..) |template_field, field_idx| { | ||
| 76 | fields[field_idx] = template_field; | ||
| 77 | fields[field_idx].type = ?template_field.type; | ||
| 78 | } | ||
| 79 | var new = template; | ||
| 80 | new.Struct.fields = &fields; | ||
| 81 | new.Struct.decls = &.{}; | ||
| 82 | break :blk @Type(new); | ||
| 83 | }; | ||
diff --git a/src/json.zig b/src/json.zig new file mode 100644 index 0000000..9252344 --- /dev/null +++ b/src/json.zig | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | // TODO: ALSO IMPLEMENT jsonStringify !!! | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | |||
| 5 | const Allocator = std.mem.Allocator; | ||
| 6 | const ParseError = std.json.ParseError; | ||
| 7 | const ParseFromValueError = std.json.ParseFromValueError; | ||
| 8 | const ParseOptions = std.json.ParseOptions; | ||
| 9 | const Value = std.json.Value; | ||
| 10 | |||
| 11 | pub fn JsonParse(T: type) type { | ||
| 12 | const f = struct { | ||
| 13 | pub fn f(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!T { | ||
| 14 | _ = allocator; | ||
| 15 | _ = options; | ||
| 16 | unreachable; | ||
| 17 | } | ||
| 18 | }.f; | ||
| 19 | return @TypeOf(f); | ||
| 20 | } | ||
| 21 | |||
| 22 | pub fn makeJsonParse(T: type) JsonParse(T) { | ||
| 23 | comptime if (!std.meta.hasFn(T, "jsonParseFromValue")) { | ||
| 24 | @compileError("Did you forget `pub const jsonParseFromValue = json.makeJsonParseFromValue(" ++ @typeName(T) ++ ") ?"); | ||
| 25 | }; | ||
| 26 | |||
| 27 | return struct { | ||
| 28 | pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!T { | ||
| 29 | const value = try std.json.innerParse(Value, allocator, source, options); | ||
| 30 | return try T.jsonParseFromValue(allocator, value, options); | ||
| 31 | } | ||
| 32 | }.jsonParse; | ||
| 33 | } | ||
| 34 | |||
| 35 | pub fn JsonParseFromValue(T: type) type { | ||
| 36 | const f = struct { | ||
| 37 | pub fn f(allocator: Allocator, source: Value, options: ParseOptions) ParseFromValueError!T { | ||
| 38 | _ = allocator; | ||
| 39 | _ = source; | ||
| 40 | _ = options; | ||
| 41 | unreachable; | ||
| 42 | } | ||
| 43 | }.f; | ||
| 44 | return @TypeOf(f); | ||
| 45 | } | ||
| 46 | |||
| 47 | pub fn makeJsonParseFromValue(T: type) JsonParseFromValue(T) { | ||
| 48 | return makeJsonParseFromValueWithTag(T, "type"); | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn makeJsonParseFromValueWithTag(T: type, comptime tag: [:0]const u8) JsonParseFromValue(T) { | ||
| 52 | const union_info = switch (@typeInfo(T)) { | ||
| 53 | .Union => |info| blk: { | ||
| 54 | if (info.tag_type == null) { | ||
| 55 | @compileError("Only tagged unions supported, got '" ++ @typeName(T) ++ "'"); | ||
| 56 | } | ||
| 57 | break :blk info; | ||
| 58 | }, | ||
| 59 | else => @compileError("Only unions supported, got '" ++ @typeName(T) ++ "'"), | ||
| 60 | }; | ||
| 61 | |||
| 62 | const TagType = union_info.tag_type.?; | ||
| 63 | |||
| 64 | const Base = blk: { | ||
| 65 | const info = std.builtin.Type{ .Struct = .{ | ||
| 66 | .layout = .auto, | ||
| 67 | .fields = &.{.{ | ||
| 68 | .name = tag, | ||
| 69 | .type = TagType, | ||
| 70 | .default_value = null, | ||
| 71 | .is_comptime = false, | ||
| 72 | .alignment = 0, | ||
| 73 | }}, | ||
| 74 | .decls = &.{}, | ||
| 75 | .is_tuple = false, | ||
| 76 | } }; | ||
| 77 | break :blk @Type(info); | ||
| 78 | }; | ||
| 79 | |||
| 80 | return struct { | ||
| 81 | pub fn jsonParseFromValue( | ||
| 82 | allocator: Allocator, | ||
| 83 | source: Value, | ||
| 84 | options: ParseOptions, | ||
| 85 | ) ParseFromValueError!T { | ||
| 86 | const new_options = blk: { | ||
| 87 | var opt = options; | ||
| 88 | opt.ignore_unknown_fields = true; | ||
| 89 | break :blk opt; | ||
| 90 | }; | ||
| 91 | |||
| 92 | const base = try std.json.innerParseFromValue(Base, allocator, source, new_options); | ||
| 93 | const typeName = @tagName(@field(base, tag)); | ||
| 94 | // TODO: Upgrade to StaticStringMap | ||
| 95 | inline for (union_info.fields) |field_info| { | ||
| 96 | if (std.mem.eql(u8, typeName, field_info.name)) { | ||
| 97 | return @unionInit( | ||
| 98 | T, | ||
| 99 | field_info.name, | ||
| 100 | try std.json.innerParseFromValue(field_info.type, allocator, source, new_options), | ||
| 101 | ); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | unreachable; | ||
| 106 | } | ||
| 107 | }.jsonParseFromValue; | ||
| 108 | } | ||
diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..0c524a7 --- /dev/null +++ b/src/main.zig | |||
| @@ -0,0 +1,353 @@ | |||
| 1 | const types = @import("types.zig"); | ||
| 2 | const std = @import("std"); | ||
| 3 | |||
| 4 | const Allocator = std.mem.Allocator; | ||
| 5 | const ArrayList = std.ArrayList; | ||
| 6 | const Bot = @import("Bot.zig"); | ||
| 7 | const Config = @import("Config.zig"); | ||
| 8 | const GPA = std.heap.GeneralPurposeAllocator(.{}); | ||
| 9 | |||
| 10 | pub fn main() !void { | ||
| 11 | defer std.log.info("We're done", .{}); | ||
| 12 | |||
| 13 | var gpa = GPA{}; | ||
| 14 | const allocator = gpa.allocator(); | ||
| 15 | defer _ = gpa.deinit(); | ||
| 16 | |||
| 17 | // Load config | ||
| 18 | var config = try Config.load(allocator, "config.default.json"); | ||
| 19 | defer config.deinit(); | ||
| 20 | try config.merge("config.json"); | ||
| 21 | |||
| 22 | var bot = try Bot.init(allocator, config.config); | ||
| 23 | defer bot.deinit(); | ||
| 24 | |||
| 25 | // TODO: Catch fatal errors, report them | ||
| 26 | try wrappedMain(&bot); | ||
| 27 | } | ||
| 28 | |||
| 29 | fn loadConfig(allocator: Allocator, filename: []const u8) !std.json.Parsed(Config) { | ||
| 30 | const file = try std.fs.cwd().openFile(filename, .{}); | ||
| 31 | defer file.close(); | ||
| 32 | |||
| 33 | var reader = std.json.reader(allocator, file.reader()); | ||
| 34 | defer reader.deinit(); | ||
| 35 | |||
| 36 | return try std.json.parseFromTokenSource( | ||
| 37 | Config, | ||
| 38 | allocator, | ||
| 39 | &reader, | ||
| 40 | .{ | ||
| 41 | .duplicate_field_behavior = .use_last, | ||
| 42 | .ignore_unknown_fields = true, | ||
| 43 | .allocate = .alloc_always, | ||
| 44 | }, | ||
| 45 | ); | ||
| 46 | } | ||
| 47 | |||
| 48 | fn wrappedMain(bot: *Bot) !void { | ||
| 49 | try bot.sendMessage_(.{ | ||
| 50 | .chat_id = bot.config.dev_group, | ||
| 51 | .text = "Initializing...", | ||
| 52 | }); | ||
| 53 | |||
| 54 | try bot.setMyName(.{ .name = "Ukko's bot" }); | ||
| 55 | |||
| 56 | var gup = types.GetUpdatesParams{ .timeout = 60 }; | ||
| 57 | while (bot.poweron) { | ||
| 58 | // TODO: Catch major errors, report them (and crash after 5 of them or so) | ||
| 59 | const updates = try bot.getUpdates(gup); | ||
| 60 | defer updates.deinit(); | ||
| 61 | for (updates.value) |update| { | ||
| 62 | defer gup.offset = update.update_id + 1; | ||
| 63 | |||
| 64 | if (update.message) |message| { | ||
| 65 | // TODO: Catch minor errors, report them | ||
| 66 | try onMessage(bot, message); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | // one last getUpdates to make sure offset is saved | ||
| 72 | gup.timeout = 0; | ||
| 73 | gup.limit = 1; | ||
| 74 | (try bot.getUpdates(gup)).deinit(); | ||
| 75 | |||
| 76 | try bot.sendMessage_(.{ | ||
| 77 | .chat_id = bot.config.dev_group, | ||
| 78 | .text = "Shutting down...", | ||
| 79 | }); | ||
| 80 | } | ||
| 81 | |||
| 82 | fn onMessage(bot: *Bot, msg: types.Message) !void { | ||
| 83 | if (msg.text) |text| { | ||
| 84 | try onTextMessage(bot, msg, text); | ||
| 85 | } | ||
| 86 | |||
| 87 | if (msg.new_chat_members) |new_chat_members| { | ||
| 88 | for (new_chat_members) |new_chat_member| { | ||
| 89 | try onNewMember(bot, msg, new_chat_member); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | fn onNewMember(bot: *Bot, msg: types.Message, new_member: types.User) !void { | ||
| 95 | var sb = ArrayList(u8).init(bot.allocator); | ||
| 96 | defer sb.deinit(); | ||
| 97 | |||
| 98 | const w = sb.writer(); | ||
| 99 | |||
| 100 | try w.writeAll("Hello there, "); | ||
| 101 | try new_member.writeFormattedName(w); | ||
| 102 | try w.writeAll("! Be on your bestest behaviour now!!"); | ||
| 103 | |||
| 104 | try bot.sendMessage_(.{ | ||
| 105 | .chat_id = msg.chat.id, | ||
| 106 | .text = sb.items, | ||
| 107 | .parse_mode = .html, | ||
| 108 | .reply_parameters = .{ | ||
| 109 | .allow_sending_without_reply = true, | ||
| 110 | .message_id = msg.message_id, | ||
| 111 | .chat_id = msg.chat.id, | ||
| 112 | }, | ||
| 113 | }); | ||
| 114 | } | ||
| 115 | |||
| 116 | fn isBadText(text: []const u8) bool { | ||
| 117 | _ = text; | ||
| 118 | return false; | ||
| 119 | } | ||
| 120 | |||
| 121 | fn onTextMessage(bot: *Bot, msg: types.Message, text: []const u8) !void { | ||
| 122 | if (isBadText(text)) { | ||
| 123 | // TODO: Delete message, mute & warn user | ||
| 124 | // 0 current warns: 5 minute mute, +1 warn | ||
| 125 | // 1 current warn : 10 minute mute, +1 warn | ||
| 126 | // 2 current warns: 30 minute mute, +1 warn | ||
| 127 | // 3 current warns: 1 hour mute, +1 warn | ||
| 128 | // 4 current warns: 1 day mute, +1 warn | ||
| 129 | // 5 current warns: Ban | ||
| 130 | // | ||
| 131 | // warn gets removed after a month of no warns | ||
| 132 | // | ||
| 133 | // Lines to say in response: | ||
| 134 | // Your head will be my new trophy! | ||
| 135 | // Your cursed bloodline ends here! | ||
| 136 | // This is the end of you, s'wit! | ||
| 137 | // Your life's end is approaching. | ||
| 138 | // Surrender your life to me and I will end your pain! | ||
| 139 | // Your pain is nearing an end. | ||
| 140 | // May our Lords be merciful! | ||
| 141 | // You have sealed your fate! | ||
| 142 | // You cannot escape the righteous! | ||
| 143 | // You will pay with your blood! | ||
| 144 | // You will die. | ||
| 145 | // There is no escape. | ||
| 146 | // Die, fetcher. | ||
| 147 | // I shall enjoy watching you take your last breath. | ||
| 148 | // You'll soon be nothing more than a bad memory! | ||
| 149 | // You will die in disgrace. | ||
| 150 | // I'll see you dead. | ||
| 151 | // One of us will die here and it won't be me. | ||
| 152 | // You don't deserve to live. | ||
| 153 | // Surrender now and I might let you live! | ||
| 154 | // I will bathe in your blood. | ||
| 155 | // Your bones will be my dinner. | ||
| 156 | // So small and tasty. I will enjoy eating you. | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | if (msg.entities) |entities| { | ||
| 161 | for (entities) |entity| { | ||
| 162 | if (entity.type == .bot_command and entity.offset == 0) { | ||
| 163 | const cmd = try entity.extract(text); | ||
| 164 | try onTextCommand(bot, msg, text, cmd); | ||
| 165 | } | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | if (std.mem.eql(u8, text, ":3")) { | ||
| 170 | try bot.sendMessage_(.{ | ||
| 171 | .chat_id = msg.chat.id, | ||
| 172 | .text = ">:3", | ||
| 173 | .reply_parameters = .{ | ||
| 174 | .message_id = msg.message_id, | ||
| 175 | .chat_id = msg.chat.id, | ||
| 176 | }, | ||
| 177 | }); | ||
| 178 | } else if (std.mem.eql(u8, text, ">:3")) { | ||
| 179 | try bot.sendMessage_(.{ | ||
| 180 | .chat_id = msg.chat.id, | ||
| 181 | .text = "<b>>:3</b>", | ||
| 182 | .parse_mode = .html, | ||
| 183 | .reply_parameters = .{ | ||
| 184 | .message_id = msg.message_id, | ||
| 185 | .chat_id = msg.chat.id, | ||
| 186 | }, | ||
| 187 | }); | ||
| 188 | } else if (std.ascii.startsWithIgnoreCase(text, "big ")) { | ||
| 189 | var output = try bot.allocator.alloc(u8, text.len + 3); | ||
| 190 | defer bot.allocator.free(output); | ||
| 191 | |||
| 192 | std.mem.copyForwards(u8, output, "<b>"); | ||
| 193 | _ = std.ascii.upperString(output[3..], text[4..]); | ||
| 194 | std.mem.copyForwards(u8, output[output.len - 4 ..], "</b>"); | ||
| 195 | |||
| 196 | try bot.sendMessage_(.{ | ||
| 197 | .chat_id = msg.chat.id, | ||
| 198 | .text = output, | ||
| 199 | .parse_mode = .html, | ||
| 200 | .reply_parameters = .{ | ||
| 201 | .message_id = msg.message_id, | ||
| 202 | .chat_id = msg.chat.id, | ||
| 203 | }, | ||
| 204 | }); | ||
| 205 | } else if (std.mem.eql(u8, text, "H")) { | ||
| 206 | try bot.sendMessage_(.{ | ||
| 207 | .chat_id = msg.chat.id, | ||
| 208 | .text = "<code>Randomly selected reminder that h > H.</code>", | ||
| 209 | .parse_mode = .html, | ||
| 210 | .reply_parameters = .{ | ||
| 211 | .message_id = msg.message_id, | ||
| 212 | .chat_id = msg.chat.id, | ||
| 213 | }, | ||
| 214 | }); | ||
| 215 | } else if (std.ascii.startsWithIgnoreCase(text, "say ")) { | ||
| 216 | try bot.sendMessage_(.{ | ||
| 217 | .chat_id = msg.chat.id, | ||
| 218 | .text = text[4..], | ||
| 219 | .reply_parameters = .{ | ||
| 220 | .message_id = msg.message_id, | ||
| 221 | .chat_id = msg.chat.id, | ||
| 222 | }, | ||
| 223 | }); | ||
| 224 | } else if (std.ascii.eqlIgnoreCase(text, "uwu")) { | ||
| 225 | try bot.sendMessage_(.{ | ||
| 226 | .chat_id = msg.chat.id, | ||
| 227 | .text = "OwO", | ||
| 228 | .reply_parameters = .{ | ||
| 229 | .message_id = msg.message_id, | ||
| 230 | .chat_id = msg.chat.id, | ||
| 231 | }, | ||
| 232 | }); | ||
| 233 | } else if (std.ascii.eqlIgnoreCase(text, "waow")) { | ||
| 234 | const reply_to = if (msg.reply_to_message) |r| | ||
| 235 | r.message_id | ||
| 236 | else | ||
| 237 | msg.message_id; | ||
| 238 | |||
| 239 | try bot.sendMessage_(.{ | ||
| 240 | .chat_id = msg.chat.id, | ||
| 241 | .text = "BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED BASED", | ||
| 242 | .reply_parameters = .{ | ||
| 243 | .message_id = reply_to, | ||
| 244 | .chat_id = msg.chat.id, | ||
| 245 | }, | ||
| 246 | }); | ||
| 247 | } else if (std.ascii.eqlIgnoreCase(text, "what")) { | ||
| 248 | var sb = try ArrayList(u8).initCapacity(bot.allocator, 9); | ||
| 249 | defer sb.deinit(); | ||
| 250 | |||
| 251 | if (text[0] == 'w') { | ||
| 252 | sb.appendSliceAssumeCapacity("g"); | ||
| 253 | } else { | ||
| 254 | sb.appendSliceAssumeCapacity("G"); | ||
| 255 | } | ||
| 256 | if (text[1] == 'h') { | ||
| 257 | sb.appendSliceAssumeCapacity("ood "); | ||
| 258 | } else { | ||
| 259 | sb.appendSliceAssumeCapacity("OOD "); | ||
| 260 | } | ||
| 261 | if (text[2] == 'a') { | ||
| 262 | sb.appendSliceAssumeCapacity("gir"); | ||
| 263 | } else { | ||
| 264 | sb.appendSliceAssumeCapacity("GIR"); | ||
| 265 | } | ||
| 266 | if (text[3] == 't') { | ||
| 267 | sb.appendSliceAssumeCapacity("l"); | ||
| 268 | } else { | ||
| 269 | sb.appendSliceAssumeCapacity("L"); | ||
| 270 | } | ||
| 271 | |||
| 272 | try bot.sendMessage_(.{ | ||
| 273 | .chat_id = msg.chat.id, | ||
| 274 | .text = sb.items, | ||
| 275 | .reply_parameters = .{ | ||
| 276 | .message_id = msg.message_id, | ||
| 277 | .chat_id = msg.chat.id, | ||
| 278 | }, | ||
| 279 | }); | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | fn onTextCommand(bot: *Bot, msg: types.Message, text: []const u8, cmd: []const u8) !void { | ||
| 284 | _ = text; | ||
| 285 | |||
| 286 | const simple_cmd = if (std.mem.indexOfScalar(u8, cmd, '@')) |idx| blk: { | ||
| 287 | const cmd_username = cmd[idx + 1 ..]; | ||
| 288 | if (!std.mem.eql(u8, cmd_username, try bot.getUsername())) { | ||
| 289 | return; | ||
| 290 | } | ||
| 291 | break :blk cmd[1..idx]; | ||
| 292 | } else cmd[1..]; | ||
| 293 | |||
| 294 | // TODO: StaticStringMap :) | ||
| 295 | if (std.mem.eql(u8, simple_cmd, "chatid")) { | ||
| 296 | var sb = ArrayList(u8).init(bot.allocator); | ||
| 297 | defer sb.deinit(); | ||
| 298 | try sb.writer().print("<code>{}</code>", .{msg.chat.id}); | ||
| 299 | |||
| 300 | try bot.sendMessage_(.{ | ||
| 301 | .chat_id = msg.chat.id, | ||
| 302 | .text = sb.items, | ||
| 303 | .parse_mode = .html, | ||
| 304 | .reply_parameters = .{ | ||
| 305 | .message_id = msg.message_id, | ||
| 306 | .chat_id = msg.chat.id, | ||
| 307 | }, | ||
| 308 | }); | ||
| 309 | } else if (std.mem.eql(u8, simple_cmd, "ping")) { | ||
| 310 | var timer = try std.time.Timer.start(); | ||
| 311 | |||
| 312 | const recv = msg.date - @as(u64, @intCast(std.time.timestamp())); | ||
| 313 | |||
| 314 | var sb = ArrayList(u8).init(bot.allocator); | ||
| 315 | defer sb.deinit(); | ||
| 316 | try sb.writer().print("Pong!\nReceive time: {}s\nSend time: ...", .{recv}); | ||
| 317 | |||
| 318 | const reply = try bot.sendMessage(.{ | ||
| 319 | .chat_id = msg.chat.id, | ||
| 320 | .text = sb.items, | ||
| 321 | .reply_parameters = .{ | ||
| 322 | .message_id = msg.message_id, | ||
| 323 | .chat_id = msg.chat.id, | ||
| 324 | }, | ||
| 325 | }); | ||
| 326 | defer reply.deinit(); | ||
| 327 | |||
| 328 | const send = @as(f64, @floatFromInt(timer.read())) / std.time.ns_per_ms; | ||
| 329 | sb.clearRetainingCapacity(); | ||
| 330 | try sb.writer().print("Pong!\nReceive time: {}s\nSend time: {d}ms", .{ recv, send }); | ||
| 331 | |||
| 332 | try bot.editMessageText_(.{ | ||
| 333 | .chat_id = reply.value.chat.id, | ||
| 334 | .message_id = reply.value.message_id, | ||
| 335 | .text = sb.items, | ||
| 336 | }); | ||
| 337 | } else if (std.mem.eql(u8, simple_cmd, "shutdown")) blk: { | ||
| 338 | if (msg.from == null or msg.from.?.id != bot.config.owner) { | ||
| 339 | break :blk; | ||
| 340 | } | ||
| 341 | |||
| 342 | bot.poweron = false; | ||
| 343 | try bot.sendMessage_(.{ | ||
| 344 | .chat_id = msg.chat.id, | ||
| 345 | .text = "Initialising shutdown...", | ||
| 346 | .reply_parameters = .{ | ||
| 347 | .allow_sending_without_reply = true, | ||
| 348 | .message_id = msg.message_id, | ||
| 349 | .chat_id = msg.chat.id, | ||
| 350 | }, | ||
| 351 | }); | ||
| 352 | } | ||
| 353 | } | ||
diff --git a/src/textutils.zig b/src/textutils.zig new file mode 100644 index 0000000..41dd5f5 --- /dev/null +++ b/src/textutils.zig | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Allocator = std.mem.Allocator; | ||
| 4 | const ArrayList = std.ArrayList; | ||
| 5 | |||
| 6 | pub fn escapeXml(writer: anytype, text: []const u8) !void { | ||
| 7 | for (text) |ch| { | ||
| 8 | try switch (ch) { | ||
| 9 | '<' => writer.writeAll("<"), | ||
| 10 | '>' => writer.writeAll(">"), | ||
| 11 | '&' => writer.writeAll("&"), | ||
| 12 | '"' => writer.writeAll("""), | ||
| 13 | else => writer.writeByte(ch), | ||
| 14 | }; | ||
| 15 | } | ||
| 16 | } | ||
diff --git a/src/types.zig b/src/types.zig new file mode 100644 index 0000000..ab1ab20 --- /dev/null +++ b/src/types.zig | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | pub const Animation = @import("types/Animation.zig"); | ||
| 2 | pub const Audio = @import("types/Audio.zig"); | ||
| 3 | pub const BackgroundFill = @import("types/background_fill.zig").BackgroundFill; | ||
| 4 | pub const BackgroundType = @import("types/background_type.zig").BackgroundType; | ||
| 5 | pub const BotName = @import("types/BotName.zig"); | ||
| 6 | pub const BusinessConnection = @import("types/BusinessConnection.zig"); | ||
| 7 | pub const BusinessMessagesDeleted = @import("types/BusinessMessagesDeleted.zig"); | ||
| 8 | pub const CallbackGame = @import("types/CallbackGame.zig"); | ||
| 9 | pub const CallbackQuery = @import("types/CallbackQuery.zig"); | ||
| 10 | pub const Chat = @import("types/Chat.zig"); | ||
| 11 | pub const ChatBackground = @import("types/ChatBackground.zig"); | ||
| 12 | pub const ChatBoost = @import("types/ChatBoost.zig"); | ||
| 13 | pub const ChatBoostAdded = @import("types/ChatBoostAdded.zig"); | ||
| 14 | pub const ChatBoostRemoved = @import("types/ChatBoostRemoved.zig"); | ||
| 15 | pub const ChatBoostSource = @import("types/chat_boost_source.zig").ChatBoostSource; | ||
| 16 | pub const ChatBoostUpdated = @import("types/ChatBoostUpdated.zig"); | ||
| 17 | pub const ChatInviteLink = @import("types/ChatInviteLink.zig"); | ||
| 18 | pub const ChatJoinRequest = @import("types/ChatJoinRequest.zig"); | ||
| 19 | pub const ChatMember = @import("types/chat_member.zig").ChatMember; | ||
| 20 | pub const ChatMemberUpdated = @import("types/ChatMemberUpdated.zig"); | ||
| 21 | pub const ChatShared = @import("types/ChatShared.zig"); | ||
| 22 | pub const ChosenInlineResult = @import("types/ChosenInlineResult.zig"); | ||
| 23 | pub const Contact = @import("types/Contact.zig"); | ||
| 24 | pub const Dice = @import("types/Dice.zig"); | ||
| 25 | pub const Document = @import("types/Document.zig"); | ||
| 26 | pub const EncryptedCredentials = @import("types/EncryptedCredentials.zig"); | ||
| 27 | pub const EncryptedPassportElement = @import("types/EncryptedPassportElement.zig"); | ||
| 28 | pub const ExternalReplyInfo = @import("types/ExternalReplyInfo.zig"); | ||
| 29 | pub const File = @import("types/File.zig"); | ||
| 30 | pub const ForumTopicClosed = @import("types/ForumTopicClosed.zig"); | ||
| 31 | pub const ForumTopicCreated = @import("types/ForumTopicCreated.zig"); | ||
| 32 | pub const ForumTopicEdited = @import("types/ForumTopicEdited.zig"); | ||
| 33 | pub const ForumTopicReopened = @import("types/ForumTopicReopened.zig"); | ||
| 34 | pub const Game = @import("types/Game.zig"); | ||
| 35 | pub const GeneralForumTopicHidden = @import("types/GeneralForumTopicHidden.zig"); | ||
| 36 | pub const GeneralForumTopicUnhidden = @import("types/GeneralForumTopicUnhidden.zig"); | ||
| 37 | pub const Giveaway = @import("types/Giveaway.zig"); | ||
| 38 | pub const GiveawayCompleted = @import("types/GiveawayCompleted.zig"); | ||
| 39 | pub const GiveawayCreated = @import("types/GiveawayCreated.zig"); | ||
| 40 | pub const GiveawayWinners = @import("types/GiveawayWinners.zig"); | ||
| 41 | pub const InlineKeyboardButton = @import("types/InlineKeyboardButton.zig"); | ||
| 42 | pub const InlineKeyboardMarkup = @import("types/InlineKeyboardMarkup.zig"); | ||
| 43 | pub const InlineQuery = @import("types/InlineQuery.zig"); | ||
| 44 | pub const Invoice = @import("types/Invoice.zig"); | ||
| 45 | pub const LinkPreviewOptions = @import("types/LinkPreviewOptions.zig"); | ||
| 46 | pub const Location = @import("types/Location.zig"); | ||
| 47 | pub const LoginUrl = @import("types/LoginUrl.zig"); | ||
| 48 | pub const MaskPosition = @import("types/MaskPosition.zig"); | ||
| 49 | pub const MaybeInaccessibleMessage = Message; | ||
| 50 | pub const Message = @import("types/Message.zig"); | ||
| 51 | pub const MessageAutoDeleteTimerChanged = @import("types/MessageAutoDeleteTimerChanged.zig"); | ||
| 52 | pub const MessageEntity = @import("types/MessageEntity.zig"); | ||
| 53 | pub const MessageOrigin = @import("types/message_origin.zig").MessageOrigin; | ||
| 54 | pub const MessageReactionCountUpdated = @import("types/MessageReactionCountUpdated.zig"); | ||
| 55 | pub const MessageReactionUpdated = @import("types/MessageReactionUpdated.zig"); | ||
| 56 | pub const OrderInfo = @import("types/OrderInfo.zig"); | ||
| 57 | pub const PaidMedia = @import("types/paid_media.zig").PaidMedia; | ||
| 58 | pub const PaidMediaInfo = @import("types/PaidMediaInfo.zig"); | ||
| 59 | pub const PassportData = @import("types/PassportData.zig"); | ||
| 60 | pub const PassportFile = @import("types/PassportFile.zig"); | ||
| 61 | pub const PhotoSize = @import("types/PhotoSize.zig"); | ||
| 62 | pub const Poll = @import("types/Poll.zig"); | ||
| 63 | pub const PollAnswer = @import("types/PollAnswer.zig"); | ||
| 64 | pub const PollOption = @import("types/PollOption.zig"); | ||
| 65 | pub const PreCheckoutQuery = @import("types/PreCheckoutQuery.zig"); | ||
| 66 | pub const ProximityAlertTriggered = @import("types/ProximityAlertTriggered.zig"); | ||
| 67 | pub const ReactionCount = @import("types/ReactionCount.zig"); | ||
| 68 | pub const ReactionType = @import("types/reaction_type.zig").ReactionType; | ||
| 69 | pub const RefundedPayment = @import("types/RefundedPayment.zig"); | ||
| 70 | pub const ReplyParameters = @import("types/ReplyParameters.zig"); | ||
| 71 | pub const ResponseParameters = @import("types/ResponseParameters.zig"); | ||
| 72 | pub const SharedUser = @import("types/SharedUser.zig"); | ||
| 73 | pub const ShippingAddress = @import("types/ShippingAddress.zig"); | ||
| 74 | pub const ShippingQuery = @import("types/ShippingQuery.zig"); | ||
| 75 | pub const Sticker = @import("types/Sticker.zig"); | ||
| 76 | pub const Story = @import("types/Story.zig"); | ||
| 77 | pub const SuccessfulPayment = @import("types/SuccessfulPayment.zig"); | ||
| 78 | pub const SwitchInlineQueryChosenChat = @import("types/SwitchInlineQueryChosenChat.zig"); | ||
| 79 | pub const TextQuote = @import("types/TextQuote.zig"); | ||
| 80 | pub const Update = @import("types/Update.zig"); | ||
| 81 | pub const User = @import("types/User.zig"); | ||
| 82 | pub const UsersShared = @import("types/UsersShared.zig"); | ||
| 83 | pub const Venue = @import("types/Venue.zig"); | ||
| 84 | pub const Video = @import("types/Video.zig"); | ||
| 85 | pub const VideoChatEnded = @import("types/VideoChatEnded.zig"); | ||
| 86 | pub const VideoChatParticipantsInvited = @import("types/VideoChatParticipantsInvited.zig"); | ||
| 87 | pub const VideoChatScheduled = @import("types/VideoChatScheduled.zig"); | ||
| 88 | pub const VideoChatStarted = @import("types/VideoChatStarted.zig"); | ||
| 89 | pub const VideoNote = @import("types/VideoNote.zig"); | ||
| 90 | pub const Voice = @import("types/Voice.zig"); | ||
| 91 | pub const WebAppData = @import("types/WebAppData.zig"); | ||
| 92 | pub const WebAppInfo = @import("types/WebAppInfo.zig"); | ||
| 93 | pub const WriteAccessAllowed = @import("types/WriteAccessAllowed.zig"); | ||
| 94 | |||
| 95 | pub const EditMessageTextParams = @import("types/EditMessageTextParams.zig"); | ||
| 96 | pub const GetMyNameParams = @import("types/GetMyNameParams.zig"); | ||
| 97 | pub const GetUpdatesParams = @import("types/GetUpdatesParams.zig"); | ||
| 98 | pub const SendMessageParams = @import("types/SendMessageParams.zig"); | ||
| 99 | pub const SetMyNameParams = @import("types/SetMyNameParams.zig"); | ||
diff --git a/src/types/Animation.zig b/src/types/Animation.zig new file mode 100644 index 0000000..f5d6efc --- /dev/null +++ b/src/types/Animation.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | file_id: []const u8, | ||
| 4 | file_unique_id: []const u8, | ||
| 5 | width: u64, | ||
| 6 | height: u64, | ||
| 7 | duration: u64, | ||
| 8 | thumbnail: ?[]PhotoSize = null, | ||
| 9 | file_name: ?[]const u8 = null, | ||
| 10 | mime_type: ?[]const u8 = null, | ||
| 11 | file_size: ?u64 = null, | ||
diff --git a/src/types/Audio.zig b/src/types/Audio.zig new file mode 100644 index 0000000..1914088 --- /dev/null +++ b/src/types/Audio.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | file_id: []const u8, | ||
| 4 | file_unique_id: []const u8, | ||
| 5 | duration: u64, | ||
| 6 | performer: ?[]const u8 = null, | ||
| 7 | title: ?[]const u8 = null, | ||
| 8 | file_name: ?[]const u8 = null, | ||
| 9 | mime_type: ?[]const u8 = null, | ||
| 10 | file_size: ?u64 = null, | ||
| 11 | thumbnail: ?PhotoSize = null, | ||
diff --git a/src/types/BotName.zig b/src/types/BotName.zig new file mode 100644 index 0000000..61a2cb6 --- /dev/null +++ b/src/types/BotName.zig | |||
| @@ -0,0 +1 @@ | |||
| name: []const u8, | |||
diff --git a/src/types/BusinessConnection.zig b/src/types/BusinessConnection.zig new file mode 100644 index 0000000..0801235 --- /dev/null +++ b/src/types/BusinessConnection.zig | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | const User = @import("User.zig"); | ||
| 2 | |||
| 3 | id: []const u8, | ||
| 4 | user: User, | ||
| 5 | user_chat_id: i64, | ||
| 6 | date: u64, | ||
| 7 | can_reply: bool, | ||
| 8 | is_enabled: bool, | ||
diff --git a/src/types/BusinessMessagesDeleted.zig b/src/types/BusinessMessagesDeleted.zig new file mode 100644 index 0000000..ef55793 --- /dev/null +++ b/src/types/BusinessMessagesDeleted.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | |||
| 3 | business_connection_id: []const u8, | ||
| 4 | chat: Chat, | ||
| 5 | message_ids: []u64, | ||
diff --git a/src/types/CallbackGame.zig b/src/types/CallbackGame.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/CallbackGame.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/CallbackQuery.zig b/src/types/CallbackQuery.zig new file mode 100644 index 0000000..8fb96c3 --- /dev/null +++ b/src/types/CallbackQuery.zig | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | const MaybeInaccessibleMessage = @import("Message.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | id: []const u8, | ||
| 5 | from: User, | ||
| 6 | message: ?MaybeInaccessibleMessage = null, | ||
| 7 | inline_message_id: ?[]const u8 = null, | ||
| 8 | chat_instance: []const u8, | ||
| 9 | data: ?[]const u8 = null, | ||
| 10 | game_short_name: ?[]const u8 = null, | ||
diff --git a/src/types/Chat.zig b/src/types/Chat.zig new file mode 100644 index 0000000..f44e480 --- /dev/null +++ b/src/types/Chat.zig | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | pub const Type = enum { | ||
| 2 | private, | ||
| 3 | group, | ||
| 4 | supergroup, | ||
| 5 | channel, | ||
| 6 | }; | ||
| 7 | |||
| 8 | id: i64, | ||
| 9 | type: Type, | ||
| 10 | title: ?[]const u8 = null, | ||
| 11 | username: ?[]const u8 = null, | ||
| 12 | first_name: ?[]const u8 = null, | ||
| 13 | last_name: ?[]const u8 = null, | ||
| 14 | is_forum: bool = false, | ||
diff --git a/src/types/ChatBackground.zig b/src/types/ChatBackground.zig new file mode 100644 index 0000000..34d2e15 --- /dev/null +++ b/src/types/ChatBackground.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | const BackgroundType = @import("background_type.zig").BackgroundType; | ||
| 2 | |||
| 3 | type: BackgroundType, | ||
diff --git a/src/types/ChatBoost.zig b/src/types/ChatBoost.zig new file mode 100644 index 0000000..353805b --- /dev/null +++ b/src/types/ChatBoost.zig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | const ChatBoostSource = @import("chat_boost_source.zig").ChatBoostSource; | ||
| 2 | |||
| 3 | boost_id: []const u8, | ||
| 4 | add_date: u64, | ||
| 5 | expiration_date: u64, | ||
| 6 | source: ChatBoostSource, | ||
diff --git a/src/types/ChatBoostAdded.zig b/src/types/ChatBoostAdded.zig new file mode 100644 index 0000000..487ae70 --- /dev/null +++ b/src/types/ChatBoostAdded.zig | |||
| @@ -0,0 +1 @@ | |||
| boost_count: u64, | |||
diff --git a/src/types/ChatBoostRemoved.zig b/src/types/ChatBoostRemoved.zig new file mode 100644 index 0000000..0d61bc5 --- /dev/null +++ b/src/types/ChatBoostRemoved.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ChatBoostSource = @import("chat_boost_source.zig").ChatBoostSource; | ||
| 3 | |||
| 4 | chat: Chat, | ||
| 5 | boost_id: []const u8, | ||
| 6 | remove_date: u64, | ||
| 7 | source: ChatBoostSource, | ||
diff --git a/src/types/ChatBoostUpdated.zig b/src/types/ChatBoostUpdated.zig new file mode 100644 index 0000000..e7ad33c --- /dev/null +++ b/src/types/ChatBoostUpdated.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ChatBoost = @import("ChatBoost.zig"); | ||
| 3 | |||
| 4 | chat: Chat, | ||
| 5 | boost: ChatBoost, | ||
diff --git a/src/types/ChatInviteLink.zig b/src/types/ChatInviteLink.zig new file mode 100644 index 0000000..41a1f44 --- /dev/null +++ b/src/types/ChatInviteLink.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | const User = @import("User.zig"); | ||
| 2 | |||
| 3 | invite_link: []const u8, | ||
| 4 | creator: User, | ||
| 5 | creates_join_request: bool, | ||
| 6 | is_primary: bool, | ||
| 7 | is_revoked: bool, | ||
| 8 | name: ?[]const u8, | ||
| 9 | expire_date: ?u64, | ||
| 10 | member_limit: ?u64, | ||
| 11 | pending_join_request_count: ?u64, | ||
diff --git a/src/types/ChatJoinRequest.zig b/src/types/ChatJoinRequest.zig new file mode 100644 index 0000000..f08e070 --- /dev/null +++ b/src/types/ChatJoinRequest.zig | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ChatInviteLink = @import("ChatInviteLink.zig"); | ||
| 3 | const User = @import("User.zig"); | ||
| 4 | |||
| 5 | chat: Chat, | ||
| 6 | from: User, | ||
| 7 | user_chat_id: i64, | ||
| 8 | date: u64, | ||
| 9 | bio: ?[]const u8, | ||
| 10 | invite_link: ?ChatInviteLink, | ||
diff --git a/src/types/ChatMemberUpdated.zig b/src/types/ChatMemberUpdated.zig new file mode 100644 index 0000000..8df56ec --- /dev/null +++ b/src/types/ChatMemberUpdated.zig | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ChatInviteLink = @import("ChatInviteLink.zig"); | ||
| 3 | const ChatMember = @import("chat_member.zig").ChatMember; | ||
| 4 | const User = @import("User.zig"); | ||
| 5 | |||
| 6 | chat: Chat, | ||
| 7 | from: User, | ||
| 8 | date: u64, | ||
| 9 | old_chat_member: ChatMember, | ||
| 10 | new_chat_member: ChatMember, | ||
| 11 | invite_link: ?ChatInviteLink = null, | ||
| 12 | via_join_request: bool = false, | ||
| 13 | via_chat_folder_invite_link: bool = false, | ||
diff --git a/src/types/ChatShared.zig b/src/types/ChatShared.zig new file mode 100644 index 0000000..7b49f02 --- /dev/null +++ b/src/types/ChatShared.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | request_id: u64, | ||
| 4 | chat_id: i64, | ||
| 5 | title: ?[]const u8 = null, | ||
| 6 | username: ?[]const u8 = null, | ||
| 7 | photo: ?[]PhotoSize = null, | ||
diff --git a/src/types/ChosenInlineResult.zig b/src/types/ChosenInlineResult.zig new file mode 100644 index 0000000..e0528cd --- /dev/null +++ b/src/types/ChosenInlineResult.zig | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | const Location = @import("Location.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | result_id: []const u8, | ||
| 5 | from: User, | ||
| 6 | location: ?Location = null, | ||
| 7 | inline_message_id: ?[]const u8, | ||
| 8 | query: []const u8, | ||
diff --git a/src/types/Contact.zig b/src/types/Contact.zig new file mode 100644 index 0000000..e3000fa --- /dev/null +++ b/src/types/Contact.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | phone_number: []const u8, | ||
| 2 | first_name: []const u8, | ||
| 3 | last_name: ?[]const u8 = null, | ||
| 4 | user_id: ?[]u64 = null, | ||
| 5 | vcard: ?[]const u8 = null, | ||
diff --git a/src/types/Dice.zig b/src/types/Dice.zig new file mode 100644 index 0000000..9aa6b06 --- /dev/null +++ b/src/types/Dice.zig | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | emoji: []const u8, | ||
| 2 | value: u8, | ||
diff --git a/src/types/Document.zig b/src/types/Document.zig new file mode 100644 index 0000000..811273d --- /dev/null +++ b/src/types/Document.zig | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | file_id: []const u8, | ||
| 4 | file_unique_id: []const u8, | ||
| 5 | thumbnail: ?PhotoSize = null, | ||
| 6 | file_name: ?[]const u8, | ||
| 7 | mime_type: ?[]const u8, | ||
| 8 | file_size: ?u64 = null, | ||
diff --git a/src/types/EditMessageTextParams.zig b/src/types/EditMessageTextParams.zig new file mode 100644 index 0000000..3e7701f --- /dev/null +++ b/src/types/EditMessageTextParams.zig | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | const InlineKeyboardMarkup = @import("InlineKeyboardMarkup.zig"); | ||
| 2 | const LinkPreviewOptions = @import("LinkPreviewOptions.zig"); | ||
| 3 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 4 | const ParseMode = @import("parse_mode.zig").ParseMode; | ||
| 5 | |||
| 6 | business_connection_id: ?[]const u8 = null, | ||
| 7 | // TODO: Integer or String | ||
| 8 | chat_id: i64, | ||
| 9 | message_id: u64, | ||
| 10 | // TODO: Make a different call for this bcs it returns just true :D | ||
| 11 | // inline_message_id: ?u64 = null, | ||
| 12 | text: []const u8, | ||
| 13 | parse_mode: ?ParseMode = null, | ||
| 14 | entities: ?[]MessageEntity = null, | ||
| 15 | link_preview_options: ?LinkPreviewOptions = null, | ||
| 16 | reply_markup: ?InlineKeyboardMarkup = null, | ||
diff --git a/src/types/EncryptedCredentials.zig b/src/types/EncryptedCredentials.zig new file mode 100644 index 0000000..6c87689 --- /dev/null +++ b/src/types/EncryptedCredentials.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | data: []const u8, | ||
| 2 | hash: []const u8, | ||
| 3 | secret: []const u8, | ||
diff --git a/src/types/EncryptedPassportElement.zig b/src/types/EncryptedPassportElement.zig new file mode 100644 index 0000000..ca0e2ed --- /dev/null +++ b/src/types/EncryptedPassportElement.zig | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // TODO: Turn this into a tagged union | ||
| 2 | |||
| 3 | const PassportFile = @import("PassportFile.zig"); | ||
| 4 | |||
| 5 | pub const Type = enum { | ||
| 6 | personal_details, | ||
| 7 | passport, | ||
| 8 | driver_license, | ||
| 9 | identity_card, | ||
| 10 | internal_passport, | ||
| 11 | address, | ||
| 12 | utility_bill, | ||
| 13 | bank_statement, | ||
| 14 | rental_agreement, | ||
| 15 | passport_registration, | ||
| 16 | temporary_registration, | ||
| 17 | phone_number, | ||
| 18 | email, | ||
| 19 | }; | ||
| 20 | |||
| 21 | type: Type, | ||
| 22 | data: ?[]const u8, | ||
| 23 | phone_number: ?[]const u8, | ||
| 24 | email: ?[]const u8, | ||
| 25 | files: ?[]PassportFile, | ||
| 26 | front_side: ?PassportFile, | ||
| 27 | reverse_side: ?PassportFile, | ||
| 28 | selfie: ?PassportFile, | ||
| 29 | translation: ?[]PassportFile, | ||
| 30 | hash: []const u8, | ||
diff --git a/src/types/ExternalReplyInfo.zig b/src/types/ExternalReplyInfo.zig new file mode 100644 index 0000000..89aa004 --- /dev/null +++ b/src/types/ExternalReplyInfo.zig | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | const Animation = @import("Animation.zig"); | ||
| 2 | const Audio = @import("Audio.zig"); | ||
| 3 | const Chat = @import("Chat.zig"); | ||
| 4 | const Contact = @import("Contact.zig"); | ||
| 5 | const Dice = @import("Dice.zig"); | ||
| 6 | const Document = @import("Document.zig"); | ||
| 7 | const Game = @import("Game.zig"); | ||
| 8 | const Giveaway = @import("Giveaway.zig"); | ||
| 9 | const GiveawayWinners = @import("GiveawayWinners.zig"); | ||
| 10 | const Invoice = @import("Invoice.zig"); | ||
| 11 | const LinkPreviewOptions = @import("LinkPreviewOptions.zig"); | ||
| 12 | const Location = @import("Location.zig"); | ||
| 13 | const MessageOrigin = @import("message_origin.zig").MessageOrigin; | ||
| 14 | const PaidMediaInfo = @import("PaidMediaInfo.zig"); | ||
| 15 | const Poll = @import("Poll.zig"); | ||
| 16 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 17 | const Sticker = @import("Sticker.zig"); | ||
| 18 | const Story = @import("Story.zig"); | ||
| 19 | const Venue = @import("Venue.zig"); | ||
| 20 | const Video = @import("Video.zig"); | ||
| 21 | const VideoNote = @import("VideoNote.zig"); | ||
| 22 | const Voice = @import("Voice.zig"); | ||
| 23 | |||
| 24 | origin: MessageOrigin, | ||
| 25 | chat: ?Chat = null, | ||
| 26 | message_id: ?u64 = null, | ||
| 27 | link_preview_options: ?LinkPreviewOptions = null, | ||
| 28 | animation: ?Animation = null, | ||
| 29 | audio: ?Audio = null, | ||
| 30 | document: ?Document = null, | ||
| 31 | paid_media: ?PaidMediaInfo = null, | ||
| 32 | photo: ?[]PhotoSize = null, | ||
| 33 | sticker: ?Sticker = null, | ||
| 34 | story: ?Story = null, | ||
| 35 | video: ?Video = null, | ||
| 36 | video_note: ?VideoNote = null, | ||
| 37 | voice: ?Voice = null, | ||
| 38 | has_media_spoiler: bool = false, | ||
| 39 | contact: ?Contact = null, | ||
| 40 | dice: ?Dice = null, | ||
| 41 | game: ?Game = null, | ||
| 42 | giveaway: ?Giveaway = null, | ||
| 43 | giveaway_winners: ?GiveawayWinners = null, | ||
| 44 | invoice: ?Invoice = null, | ||
| 45 | location: ?Location = null, | ||
| 46 | poll: ?Poll = null, | ||
| 47 | venue: ?Venue = null, | ||
diff --git a/src/types/File.zig b/src/types/File.zig new file mode 100644 index 0000000..3555bc9 --- /dev/null +++ b/src/types/File.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | file_id: []const u8, | ||
| 2 | file_unique_id: []const u8, | ||
| 3 | file_size: ?u64 = null, | ||
| 4 | file_path: ?[]const u8 = null, | ||
diff --git a/src/types/ForumTopicClosed.zig b/src/types/ForumTopicClosed.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/ForumTopicClosed.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/ForumTopicCreated.zig b/src/types/ForumTopicCreated.zig new file mode 100644 index 0000000..2429de7 --- /dev/null +++ b/src/types/ForumTopicCreated.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | name: []const u8, | ||
| 2 | icon_color: u24, | ||
| 3 | icon_custom_emoji_id: ?[]const u8 = null, | ||
diff --git a/src/types/ForumTopicEdited.zig b/src/types/ForumTopicEdited.zig new file mode 100644 index 0000000..097acb3 --- /dev/null +++ b/src/types/ForumTopicEdited.zig | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | name: ?[]const u8 = null, | ||
| 2 | icon_custom_emoji_id: ?[]const u8 = null, | ||
diff --git a/src/types/ForumTopicReopened.zig b/src/types/ForumTopicReopened.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/ForumTopicReopened.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/Game.zig b/src/types/Game.zig new file mode 100644 index 0000000..3738284 --- /dev/null +++ b/src/types/Game.zig | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | const Animation = @import("Animation.zig"); | ||
| 2 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 3 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 4 | |||
| 5 | title: []const u8, | ||
| 6 | description: []const u8, | ||
| 7 | photo: []PhotoSize, | ||
| 8 | text: ?[]const u8 = null, | ||
| 9 | text_entities: ?[]MessageEntity = null, | ||
| 10 | animation: ?Animation = null, | ||
diff --git a/src/types/GeneralForumTopicHidden.zig b/src/types/GeneralForumTopicHidden.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/GeneralForumTopicHidden.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/GeneralForumTopicUnhidden.zig b/src/types/GeneralForumTopicUnhidden.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/GeneralForumTopicUnhidden.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/GetMyNameParams.zig b/src/types/GetMyNameParams.zig new file mode 100644 index 0000000..2cb38fa --- /dev/null +++ b/src/types/GetMyNameParams.zig | |||
| @@ -0,0 +1 @@ | |||
| language_code: ?[]const u8 = null | |||
diff --git a/src/types/GetUpdatesParams.zig b/src/types/GetUpdatesParams.zig new file mode 100644 index 0000000..0a4e333 --- /dev/null +++ b/src/types/GetUpdatesParams.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | offset: ?u64 = null, | ||
| 2 | limit: ?u64 = null, | ||
| 3 | timeout: ?u64 = null, | ||
| 4 | allowed_updates: ?[]const u8 = null, | ||
diff --git a/src/types/Giveaway.zig b/src/types/Giveaway.zig new file mode 100644 index 0000000..d1cfa7e --- /dev/null +++ b/src/types/Giveaway.zig | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | |||
| 3 | chats: []Chat, | ||
| 4 | winners_selection_date: u64, | ||
| 5 | winner_count: u64, | ||
| 6 | only_new_members: bool = false, | ||
| 7 | has_public_winners: bool = false, | ||
| 8 | prize_description: ?[]const u8 = null, | ||
| 9 | country_codes: ?[]const u8 = null, | ||
| 10 | premium_subscription_month_count: ?u64 = null, | ||
diff --git a/src/types/GiveawayCompleted.zig b/src/types/GiveawayCompleted.zig new file mode 100644 index 0000000..9e07ad9 --- /dev/null +++ b/src/types/GiveawayCompleted.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const Message = @import("Message.zig"); | ||
| 2 | |||
| 3 | winner_count: u64, | ||
| 4 | unclaimed_prize_count: ?u64 = null, | ||
| 5 | giveaway_message: ?Message = null, | ||
diff --git a/src/types/GiveawayCreated.zig b/src/types/GiveawayCreated.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/GiveawayCreated.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/GiveawayWinners.zig b/src/types/GiveawayWinners.zig new file mode 100644 index 0000000..b99a7d2 --- /dev/null +++ b/src/types/GiveawayWinners.zig | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | chat: Chat, | ||
| 5 | giveaway_message_id: u64, | ||
| 6 | winners_selection_date: u64, | ||
| 7 | winner_count: u64, | ||
| 8 | winners: []User, | ||
| 9 | additional_chat_count: ?u64 = null, | ||
| 10 | premium_subscription_month_count: ?u64 = null, | ||
| 11 | unclaimed_prize_count: ?u64 = null, | ||
| 12 | only_new_members: bool = false, | ||
| 13 | was_refunded: bool = false, | ||
| 14 | prize_description: ?[]const u8 = null, | ||
diff --git a/src/types/InlineKeyboardButton.zig b/src/types/InlineKeyboardButton.zig new file mode 100644 index 0000000..be156b4 --- /dev/null +++ b/src/types/InlineKeyboardButton.zig | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | const CallbackGame = @import("CallbackGame.zig"); | ||
| 2 | const LoginUrl = @import("LoginUrl.zig"); | ||
| 3 | const SwitchInlineQueryChosenChat = @import("SwitchInlineQueryChosenChat.zig"); | ||
| 4 | const WebAppInfo = @import("WebAppInfo.zig"); | ||
| 5 | |||
| 6 | text: []const u8, | ||
| 7 | url: ?[]const u8 = null, | ||
| 8 | callback_data: ?[]const u8 = null, | ||
| 9 | web_app: ?WebAppInfo = null, | ||
| 10 | login_url: ?LoginUrl = null, | ||
| 11 | switch_inline_query: ?[]const u8 = null, | ||
| 12 | switch_inline_query_current_chat: ?[]const u8 = null, | ||
| 13 | switch_inline_query_chosen_chat: ?SwitchInlineQueryChosenChat = null, | ||
| 14 | callback_game: ?CallbackGame = null, | ||
| 15 | pay: bool = false, | ||
diff --git a/src/types/InlineKeyboardMarkup.zig b/src/types/InlineKeyboardMarkup.zig new file mode 100644 index 0000000..388d4fc --- /dev/null +++ b/src/types/InlineKeyboardMarkup.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | const InlineKeyboardButton = @import("InlineKeyboardButton.zig"); | ||
| 2 | |||
| 3 | inline_keyboard: [][]InlineKeyboardButton, | ||
diff --git a/src/types/InlineQuery.zig b/src/types/InlineQuery.zig new file mode 100644 index 0000000..7cbbe20 --- /dev/null +++ b/src/types/InlineQuery.zig | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | const Location = @import("Location.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | pub const ChatType = enum { | ||
| 5 | sender, | ||
| 6 | private, | ||
| 7 | group, | ||
| 8 | supergroup, | ||
| 9 | channel, | ||
| 10 | }; | ||
| 11 | |||
| 12 | id: []const u8, | ||
| 13 | from: User, | ||
| 14 | query: []const u8, | ||
| 15 | offset: []const u8, | ||
| 16 | chat_type: ?ChatType, | ||
| 17 | location: ?Location, | ||
diff --git a/src/types/Invoice.zig b/src/types/Invoice.zig new file mode 100644 index 0000000..5ff6bfd --- /dev/null +++ b/src/types/Invoice.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | title: []const u8, | ||
| 2 | description: []const u8, | ||
| 3 | start_parameter: []const u8, | ||
| 4 | currency: []const u8, | ||
| 5 | total_amount: u64, | ||
diff --git a/src/types/LinkPreviewOptions.zig b/src/types/LinkPreviewOptions.zig new file mode 100644 index 0000000..c8258e7 --- /dev/null +++ b/src/types/LinkPreviewOptions.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | is_disabled: ?bool = null, | ||
| 2 | url: ?[]const u8 = null, | ||
| 3 | prefer_small_media: ?bool = null, | ||
| 4 | prefer_large_media: ?bool = null, | ||
| 5 | show_above_text: ?bool = null, | ||
diff --git a/src/types/Location.zig b/src/types/Location.zig new file mode 100644 index 0000000..1fef4e3 --- /dev/null +++ b/src/types/Location.zig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | latitude: f32, | ||
| 2 | longitude: f32, | ||
| 3 | horizontal_accuracy: ?f32 = null, | ||
| 4 | live_period: ?u64 = null, | ||
| 5 | heading: ?u64 = null, | ||
| 6 | proximity_alert_radius: ?u64 = null, | ||
diff --git a/src/types/LoginUrl.zig b/src/types/LoginUrl.zig new file mode 100644 index 0000000..37b89f6 --- /dev/null +++ b/src/types/LoginUrl.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | url: []const u8, | ||
| 2 | forward_text: ?[]const u8 = null, | ||
| 3 | bot_username: ?[]const u8 = null, | ||
| 4 | request_write_access: ?[]const u8 = null, | ||
diff --git a/src/types/MaskPosition.zig b/src/types/MaskPosition.zig new file mode 100644 index 0000000..ba668c4 --- /dev/null +++ b/src/types/MaskPosition.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | pub const Point = enum { | ||
| 2 | forehead, | ||
| 3 | eyes, | ||
| 4 | mouth, | ||
| 5 | chin, | ||
| 6 | }; | ||
| 7 | |||
| 8 | point: Point, | ||
| 9 | x_shift: f32, | ||
| 10 | y_shift: f32, | ||
| 11 | scale: f32, | ||
diff --git a/src/types/Message.zig b/src/types/Message.zig new file mode 100644 index 0000000..448ca86 --- /dev/null +++ b/src/types/Message.zig | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | const Animation = @import("Animation.zig"); | ||
| 2 | const Audio = @import("Audio.zig"); | ||
| 3 | const Chat = @import("Chat.zig"); | ||
| 4 | const ChatBackground = @import("ChatBackground.zig"); | ||
| 5 | const ChatBoostAdded = @import("ChatBoostAdded.zig"); | ||
| 6 | const ChatShared = @import("ChatShared.zig"); | ||
| 7 | const Contact = @import("Contact.zig"); | ||
| 8 | const Dice = @import("Dice.zig"); | ||
| 9 | const Document = @import("Document.zig"); | ||
| 10 | const ExternalReplyInfo = @import("ExternalReplyInfo.zig"); | ||
| 11 | const ForumTopicClosed = @import("ForumTopicClosed.zig"); | ||
| 12 | const ForumTopicCreated = @import("ForumTopicCreated.zig"); | ||
| 13 | const ForumTopicEdited = @import("ForumTopicEdited.zig"); | ||
| 14 | const ForumTopicReopened = @import("ForumTopicReopened.zig"); | ||
| 15 | const Game = @import("Game.zig"); | ||
| 16 | const GeneralForumTopicHidden = @import("GeneralForumTopicHidden.zig"); | ||
| 17 | const GeneralForumTopicUnhidden = @import("GeneralForumTopicUnhidden.zig"); | ||
| 18 | const Giveaway = @import("Giveaway.zig"); | ||
| 19 | const GiveawayCompleted = @import("GiveawayCompleted.zig"); | ||
| 20 | const GiveawayCreated = @import("GiveawayCreated.zig"); | ||
| 21 | const GiveawayWinners = @import("GiveawayWinners.zig"); | ||
| 22 | const InlineKeyboardMarkup = @import("InlineKeyboardMarkup.zig"); | ||
| 23 | const Invoice = @import("Invoice.zig"); | ||
| 24 | const LinkPreviewOptions = @import("LinkPreviewOptions.zig"); | ||
| 25 | const Location = @import("Location.zig"); | ||
| 26 | const MaybeInaccessibleMessage = @This(); | ||
| 27 | const Message = @This(); | ||
| 28 | const MessageAutoDeleteTimerChanged = @import("MessageAutoDeleteTimerChanged.zig"); | ||
| 29 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 30 | const MessageOrigin = @import("message_origin.zig").MessageOrigin; | ||
| 31 | const PaidMediaInfo = @import("PaidMediaInfo.zig"); | ||
| 32 | const PassportData = @import("PassportData.zig"); | ||
| 33 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 34 | const Poll = @import("Poll.zig"); | ||
| 35 | const ProximityAlertTriggered = @import("ProximityAlertTriggered.zig"); | ||
| 36 | const RefundedPayment = @import("RefundedPayment.zig"); | ||
| 37 | const Sticker = @import("Sticker.zig"); | ||
| 38 | const Story = @import("Story.zig"); | ||
| 39 | const SuccessfulPayment = @import("SuccessfulPayment.zig"); | ||
| 40 | const TextQuote = @import("TextQuote.zig"); | ||
| 41 | const User = @import("User.zig"); | ||
| 42 | const UsersShared = @import("UsersShared.zig"); | ||
| 43 | const Venue = @import("Venue.zig"); | ||
| 44 | const Video = @import("Video.zig"); | ||
| 45 | const VideoChatEnded = @import("VideoChatEnded.zig"); | ||
| 46 | const VideoChatParticipantsInvited = @import("VideoChatParticipantsInvited.zig"); | ||
| 47 | const VideoChatScheduled = @import("VideoChatScheduled.zig"); | ||
| 48 | const VideoChatStarted = @import("VideoChatStarted.zig"); | ||
| 49 | const VideoNote = @import("VideoNote.zig"); | ||
| 50 | const Voice = @import("Voice.zig"); | ||
| 51 | const WebAppData = @import("WebAppData.zig"); | ||
| 52 | const WriteAccessAllowed = @import("WriteAccessAllowed.zig"); | ||
| 53 | |||
| 54 | message_id: u64, | ||
| 55 | message_thread_id: ?u64 = null, | ||
| 56 | from: ?User = null, | ||
| 57 | sender_chat: ?Chat = null, | ||
| 58 | sender_boost_count: ?u64 = null, | ||
| 59 | sender_business_bot: ?User = null, | ||
| 60 | // If this is a MaybeInaccessibleMessage this will be 0 if this is inaccessible | ||
| 61 | date: u64, | ||
| 62 | business_connection_id: ?[]const u8 = null, | ||
| 63 | chat: Chat, | ||
| 64 | forward_origin: ?MessageOrigin = null, | ||
| 65 | is_topic_message: bool = false, | ||
| 66 | is_automatic_forward: bool = false, | ||
| 67 | reply_to_message: ?*Message = null, | ||
| 68 | external_reply: ?ExternalReplyInfo = null, | ||
| 69 | quote: ?TextQuote = null, | ||
| 70 | reply_to_story: ?Story = null, | ||
| 71 | via_bot: ?User = null, | ||
| 72 | edit_date: ?u64 = null, | ||
| 73 | has_protected_content: bool = false, | ||
| 74 | is_from_offline: bool = false, | ||
| 75 | media_group_id: ?[]const u8 = null, | ||
| 76 | author_signature: ?[]const u8 = null, | ||
| 77 | text: ?[]const u8 = null, | ||
| 78 | entities: ?[]MessageEntity = null, | ||
| 79 | link_preview_options: ?LinkPreviewOptions = null, | ||
| 80 | effect_id: ?[]const u8 = null, | ||
| 81 | animation: ?Animation = null, | ||
| 82 | audio: ?Audio = null, | ||
| 83 | document: ?Document = null, | ||
| 84 | paid_media: ?PaidMediaInfo = null, | ||
| 85 | photo: ?[]PhotoSize = null, | ||
| 86 | sticker: ?Sticker = null, | ||
| 87 | story: ?Story = null, | ||
| 88 | video: ?Video = null, | ||
| 89 | video_note: ?VideoNote = null, | ||
| 90 | voice: ?Voice = null, | ||
| 91 | caption: ?[]const u8 = null, | ||
| 92 | caption_entities: ?[]MessageEntity = null, | ||
| 93 | show_caption_above_media: bool = false, | ||
| 94 | has_media_spoiler: bool = false, | ||
| 95 | contact: ?Contact = null, | ||
| 96 | dice: ?Dice = null, | ||
| 97 | game: ?Game = null, | ||
| 98 | poll: ?Poll = null, | ||
| 99 | venue: ?Venue = null, | ||
| 100 | location: ?Location = null, | ||
| 101 | new_chat_members: ?[]User = null, | ||
| 102 | left_chat_member: ?User = null, | ||
| 103 | new_chat_title: ?[]const u8 = null, | ||
| 104 | new_chat_photo: ?[]PhotoSize = null, | ||
| 105 | delete_chat_photo: bool = false, | ||
| 106 | group_chat_created: bool = false, | ||
| 107 | supergroup_chat_created: bool = false, | ||
| 108 | channel_chat_created: bool = false, | ||
| 109 | message_auto_delete_timer_changed: ?MessageAutoDeleteTimerChanged = null, | ||
| 110 | migrate_to_chat_id: ?i64 = null, | ||
| 111 | migrate_from_chat_id: ?i64 = null, | ||
| 112 | pinned_message: ?*MaybeInaccessibleMessage = null, | ||
| 113 | invoice: ?Invoice = null, | ||
| 114 | successful_payment: ?SuccessfulPayment = null, | ||
| 115 | refunded_payment: ?RefundedPayment = null, | ||
| 116 | users_shared: ?UsersShared = null, | ||
| 117 | chat_shared: ?ChatShared = null, | ||
| 118 | connected_website: ?[]const u8 = null, | ||
| 119 | write_access_allowed: ?WriteAccessAllowed = null, | ||
| 120 | passport_data: ?PassportData = null, | ||
| 121 | proximity_alert_triggered: ?ProximityAlertTriggered = null, | ||
| 122 | boost_added: ?ChatBoostAdded = null, | ||
| 123 | chat_background_set: ?ChatBackground = null, | ||
| 124 | forum_topic_created: ?ForumTopicCreated = null, | ||
| 125 | forum_topic_edited: ?ForumTopicEdited = null, | ||
| 126 | forum_topic_closed: ?ForumTopicClosed = null, | ||
| 127 | forum_topic_reopened: ?ForumTopicReopened = null, | ||
| 128 | general_forum_topic_hidden: ?GeneralForumTopicHidden = null, | ||
| 129 | general_forum_topic_unhidden: ?GeneralForumTopicUnhidden = null, | ||
| 130 | giveaway_created: ?GiveawayCreated = null, | ||
| 131 | giveaway: ?Giveaway = null, | ||
| 132 | giveaway_winners: ?GiveawayWinners = null, | ||
| 133 | giveaway_completed: ?*GiveawayCompleted = null, | ||
| 134 | video_chat_scheduled: ?VideoChatScheduled = null, | ||
| 135 | video_chat_started: ?VideoChatStarted = null, | ||
| 136 | video_chat_ended: ?VideoChatEnded = null, | ||
| 137 | video_chat_participants_invited: ?VideoChatParticipantsInvited = null, | ||
| 138 | web_app_data: ?WebAppData = null, | ||
| 139 | reply_markup: ?InlineKeyboardMarkup = null, | ||
diff --git a/src/types/MessageAutoDeleteTimerChanged.zig b/src/types/MessageAutoDeleteTimerChanged.zig new file mode 100644 index 0000000..c73e682 --- /dev/null +++ b/src/types/MessageAutoDeleteTimerChanged.zig | |||
| @@ -0,0 +1 @@ | |||
| message_auto_delete_time: u64, | |||
diff --git a/src/types/MessageEntity.zig b/src/types/MessageEntity.zig new file mode 100644 index 0000000..1c44d20 --- /dev/null +++ b/src/types/MessageEntity.zig | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const MessageEntity = @This(); | ||
| 4 | const User = @import("User.zig"); | ||
| 5 | const Utf8View = std.unicode.Utf8View; | ||
| 6 | |||
| 7 | pub const Type = enum { | ||
| 8 | mention, | ||
| 9 | hashtag, | ||
| 10 | cashtag, | ||
| 11 | bot_command, | ||
| 12 | url, | ||
| 13 | email, | ||
| 14 | phone_number, | ||
| 15 | bold, | ||
| 16 | italic, | ||
| 17 | underline, | ||
| 18 | strikethrough, | ||
| 19 | spoiler, | ||
| 20 | blockquote, | ||
| 21 | expandable_blockquote, | ||
| 22 | code, | ||
| 23 | pre, | ||
| 24 | text_link, | ||
| 25 | text_mention, | ||
| 26 | custom_emoji, | ||
| 27 | }; | ||
| 28 | |||
| 29 | type: Type, | ||
| 30 | offset: u64, | ||
| 31 | length: u64, | ||
| 32 | url: ?[]const u8 = null, | ||
| 33 | user: ?User = null, | ||
| 34 | language: ?[]const u8 = null, | ||
| 35 | custom_emoji_id: ?[]const u8 = null, | ||
| 36 | |||
| 37 | pub fn extract(self: MessageEntity, src: []const u8) ![]const u8 { | ||
| 38 | if (self.length == 0) { | ||
| 39 | return ""; | ||
| 40 | } | ||
| 41 | |||
| 42 | var utf8 = (try Utf8View.init(src)).iterator(); | ||
| 43 | var i: usize = 0; | ||
| 44 | |||
| 45 | const start = if (i >= self.offset) | ||
| 46 | utf8.i | ||
| 47 | else blk: { | ||
| 48 | while (utf8.nextCodepoint()) |cp| { | ||
| 49 | i += std.unicode.utf16CodepointSequenceLength(cp) catch unreachable; | ||
| 50 | if (i >= self.offset) { | ||
| 51 | break :blk utf8.i; | ||
| 52 | } | ||
| 53 | } | ||
| 54 | return ""; | ||
| 55 | }; | ||
| 56 | |||
| 57 | i = 0; | ||
| 58 | while (utf8.nextCodepoint()) |cp| { | ||
| 59 | i += std.unicode.utf16CodepointSequenceLength(cp) catch unreachable; | ||
| 60 | if (i >= self.length) { | ||
| 61 | return src[start..utf8.i]; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | return src[start..]; | ||
| 66 | } | ||
diff --git a/src/types/MessageReactionCountUpdated.zig b/src/types/MessageReactionCountUpdated.zig new file mode 100644 index 0000000..48a9f24 --- /dev/null +++ b/src/types/MessageReactionCountUpdated.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ReactionCount = @import("ReactionCount.zig"); | ||
| 3 | |||
| 4 | chat: Chat, | ||
| 5 | message_id: u64, | ||
| 6 | date: u64, | ||
| 7 | reactions: []ReactionCount, | ||
diff --git a/src/types/MessageReactionUpdated.zig b/src/types/MessageReactionUpdated.zig new file mode 100644 index 0000000..7da679b --- /dev/null +++ b/src/types/MessageReactionUpdated.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const ReactionType = @import("reaction_type.zig").ReactionType; | ||
| 3 | const User = @import("User.zig"); | ||
| 4 | |||
| 5 | chat: Chat, | ||
| 6 | message_id: u64, | ||
| 7 | user: ?User = null, | ||
| 8 | actor_chat: ?Chat = null, | ||
| 9 | date: u64, | ||
| 10 | old_reaction: []ReactionType, | ||
| 11 | new_reaction: []ReactionType, | ||
diff --git a/src/types/OrderInfo.zig b/src/types/OrderInfo.zig new file mode 100644 index 0000000..3f94376 --- /dev/null +++ b/src/types/OrderInfo.zig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | const ShippingAddress = @import("ShippingAddress.zig"); | ||
| 2 | |||
| 3 | name: ?[]const u8 = null, | ||
| 4 | phone_number: ?[]const u8 = null, | ||
| 5 | email: ?[]const u8 = null, | ||
| 6 | shipping_address: ?ShippingAddress = null, | ||
diff --git a/src/types/PaidMediaInfo.zig b/src/types/PaidMediaInfo.zig new file mode 100644 index 0000000..6de7447 --- /dev/null +++ b/src/types/PaidMediaInfo.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | const PaidMedia = @import("paid_media.zig").PaidMedia; | ||
| 2 | |||
| 3 | star_count: u64, | ||
| 4 | paid_media: []PaidMedia, | ||
diff --git a/src/types/PassportData.zig b/src/types/PassportData.zig new file mode 100644 index 0000000..679534c --- /dev/null +++ b/src/types/PassportData.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const EncryptedCredentials = @import("EncryptedCredentials.zig"); | ||
| 2 | const EncryptedPassportElement = @import("EncryptedPassportElement.zig"); | ||
| 3 | |||
| 4 | data: []EncryptedPassportElement, | ||
| 5 | credentials: EncryptedCredentials, | ||
diff --git a/src/types/PassportFile.zig b/src/types/PassportFile.zig new file mode 100644 index 0000000..2b208fa --- /dev/null +++ b/src/types/PassportFile.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | file_id: []const u8, | ||
| 2 | file_unique_id: []const u8, | ||
| 3 | file_size: u64, | ||
| 4 | file_date: u64, | ||
diff --git a/src/types/PhotoSize.zig b/src/types/PhotoSize.zig new file mode 100644 index 0000000..887b530 --- /dev/null +++ b/src/types/PhotoSize.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | file_id: []const u8, | ||
| 2 | file_unique_id: []const u8, | ||
| 3 | width: u64, | ||
| 4 | height: u64, | ||
| 5 | file_size: ?u64 = null, | ||
diff --git a/src/types/Poll.zig b/src/types/Poll.zig new file mode 100644 index 0000000..ccc3b68 --- /dev/null +++ b/src/types/Poll.zig | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 2 | const PollOption = @import("PollOption.zig"); | ||
| 3 | |||
| 4 | pub const Type = enum { | ||
| 5 | regular, | ||
| 6 | quiz, | ||
| 7 | }; | ||
| 8 | |||
| 9 | id: []const u8, | ||
| 10 | question: []const u8, | ||
| 11 | question_entities: ?[]MessageEntity = null, | ||
| 12 | options: []PollOption, | ||
| 13 | total_voter_count: u64, | ||
| 14 | is_closed: bool, | ||
| 15 | is_anonymous: bool, | ||
| 16 | type: Type, | ||
| 17 | allows_multiple_answers: bool, | ||
| 18 | correct_option_id: ?u64 = null, | ||
| 19 | explanation: ?[]const u8 = null, | ||
| 20 | explanation_entities: ?[]MessageEntity = null, | ||
| 21 | open_period: ?u64 = null, | ||
| 22 | close_date: ?u64 = null, | ||
diff --git a/src/types/PollAnswer.zig b/src/types/PollAnswer.zig new file mode 100644 index 0000000..7d4985c --- /dev/null +++ b/src/types/PollAnswer.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | poll_id: []const u8, | ||
| 5 | voter_chat: ?Chat, | ||
| 6 | user: ?User, | ||
| 7 | option_ids: []u64, | ||
diff --git a/src/types/PollOption.zig b/src/types/PollOption.zig new file mode 100644 index 0000000..870bfee --- /dev/null +++ b/src/types/PollOption.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 2 | |||
| 3 | text: []const u8, | ||
| 4 | text_entities: ?[]MessageEntity = null, | ||
| 5 | voter_count: u64, | ||
diff --git a/src/types/PreCheckoutQuery.zig b/src/types/PreCheckoutQuery.zig new file mode 100644 index 0000000..48e013f --- /dev/null +++ b/src/types/PreCheckoutQuery.zig | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | const OrderInfo = @import("OrderInfo.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | id: []const u8, | ||
| 5 | from: User, | ||
| 6 | currency: []const u8, | ||
| 7 | total_amount: u64, | ||
| 8 | invoice_payload: []const u8, | ||
| 9 | shipping_option_id: ?[]const u8, | ||
| 10 | order_info: ?OrderInfo, | ||
diff --git a/src/types/ProximityAlertTriggered.zig b/src/types/ProximityAlertTriggered.zig new file mode 100644 index 0000000..db5159d --- /dev/null +++ b/src/types/ProximityAlertTriggered.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | const User = @import("User.zig"); | ||
| 2 | |||
| 3 | traveler: User, | ||
| 4 | watcher: User, | ||
| 5 | distance: u64, | ||
diff --git a/src/types/ReactionCount.zig b/src/types/ReactionCount.zig new file mode 100644 index 0000000..7c6a0bc --- /dev/null +++ b/src/types/ReactionCount.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | const ReactionType = @import("reaction_type.zig").ReactionType; | ||
| 2 | |||
| 3 | type: ReactionType, | ||
| 4 | total_count: u64, | ||
diff --git a/src/types/RefundedPayment.zig b/src/types/RefundedPayment.zig new file mode 100644 index 0000000..31f04c0 --- /dev/null +++ b/src/types/RefundedPayment.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | currency: []const u8, | ||
| 2 | total_amount: u64, | ||
| 3 | invoice_payload: []const u8, | ||
| 4 | telegram_payment_charge_id: []const u8, | ||
| 5 | provider_payment_charge_id: []const u8, | ||
diff --git a/src/types/ReplyParameters.zig b/src/types/ReplyParameters.zig new file mode 100644 index 0000000..57d75c2 --- /dev/null +++ b/src/types/ReplyParameters.zig | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | message_id: u64, | ||
| 2 | // TODO: Integer OR String | ||
| 3 | chat_id: ?i64 = null, | ||
| 4 | allow_sending_without_reply: ?bool = null, | ||
| 5 | quote: ?[]const u8 = null, | ||
| 6 | // one of quote_parse_mode or quote_entities | ||
| 7 | quote_parse_mode: ?[]const u8 = null, | ||
| 8 | quote_entities: ?[]const u8 = null, | ||
| 9 | quote_position: ?u64 = null, | ||
diff --git a/src/types/ResponseParameters.zig b/src/types/ResponseParameters.zig new file mode 100644 index 0000000..655c4f9 --- /dev/null +++ b/src/types/ResponseParameters.zig | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | migrate_to_chat_id: ?i64 = null, | ||
| 2 | retry_after: ?i64 = null, | ||
diff --git a/src/types/SendMessageParams.zig b/src/types/SendMessageParams.zig new file mode 100644 index 0000000..8c84940 --- /dev/null +++ b/src/types/SendMessageParams.zig | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | const LinkPreviewOptions = @import("LinkPreviewOptions.zig"); | ||
| 2 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 3 | const ParseMode = @import("parse_mode.zig").ParseMode; | ||
| 4 | const ReplyParameters = @import("ReplyParameters.zig"); | ||
| 5 | |||
| 6 | business_connection_id: ?[]const u8 = null, | ||
| 7 | // TODO: Integer or String | ||
| 8 | chat_id: i64, | ||
| 9 | message_thread_id: ?u64 = null, | ||
| 10 | text: []const u8, | ||
| 11 | parse_mode: ?ParseMode = null, | ||
| 12 | entities: ?[]MessageEntity = null, | ||
| 13 | link_preview_options: ?LinkPreviewOptions = null, | ||
| 14 | disable_notification: ?bool = null, | ||
| 15 | protect_content: ?bool = null, | ||
| 16 | message_effect_id: ?[]const u8 = null, | ||
| 17 | reply_parameters: ?ReplyParameters = null, | ||
| 18 | // TODO: reply_markup: InlineKeyboardMarkup OR ReplyKeyboardMarkup OR ReplyKeyboardRemove OR ForceReply | ||
diff --git a/src/types/SetMyNameParams.zig b/src/types/SetMyNameParams.zig new file mode 100644 index 0000000..0bd2f06 --- /dev/null +++ b/src/types/SetMyNameParams.zig | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | name: ?[]const u8 = null, | ||
| 2 | language_code: ?[]const u8 = null, | ||
diff --git a/src/types/SharedUser.zig b/src/types/SharedUser.zig new file mode 100644 index 0000000..4afe053 --- /dev/null +++ b/src/types/SharedUser.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | user_id: u64, | ||
| 4 | first_name: ?[]const u8 = null, | ||
| 5 | last_name: ?[]const u8 = null, | ||
| 6 | username: ?[]const u8 = null, | ||
| 7 | photo: ?[]PhotoSize = null, | ||
diff --git a/src/types/ShippingAddress.zig b/src/types/ShippingAddress.zig new file mode 100644 index 0000000..f4203fe --- /dev/null +++ b/src/types/ShippingAddress.zig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | country_code: []const u8, | ||
| 2 | state: []const u8, | ||
| 3 | city: []const u8, | ||
| 4 | street_line1: []const u8, | ||
| 5 | street_line2: []const u8, | ||
| 6 | post_code: []const u8, | ||
diff --git a/src/types/ShippingQuery.zig b/src/types/ShippingQuery.zig new file mode 100644 index 0000000..15abcda --- /dev/null +++ b/src/types/ShippingQuery.zig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | const ShippingAddress = @import("ShippingAddress.zig"); | ||
| 2 | const User = @import("User.zig"); | ||
| 3 | |||
| 4 | id: []const u8, | ||
| 5 | from: User, | ||
| 6 | invoice_payload: []const u8, | ||
| 7 | shipping_address: ShippingAddress, | ||
diff --git a/src/types/Sticker.zig b/src/types/Sticker.zig new file mode 100644 index 0000000..e28df69 --- /dev/null +++ b/src/types/Sticker.zig | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | const File = @import("File.zig"); | ||
| 2 | const MaskPosition = @import("MaskPosition.zig"); | ||
| 3 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 4 | |||
| 5 | pub const Type = enum { | ||
| 6 | regular, | ||
| 7 | mask, | ||
| 8 | custom_emoji, | ||
| 9 | }; | ||
| 10 | |||
| 11 | file_id: []const u8, | ||
| 12 | file_unique_id: []const u8, | ||
| 13 | type: Type, | ||
| 14 | width: u64, | ||
| 15 | height: u64, | ||
| 16 | is_animated: bool = false, | ||
| 17 | is_video: bool = false, | ||
| 18 | thumbnail: ?PhotoSize = null, | ||
| 19 | emoji: ?[]const u8 = null, | ||
| 20 | set_name: ?[]const u8 = null, | ||
| 21 | premium_animation: ?File = null, | ||
| 22 | mask_position: ?MaskPosition = null, | ||
| 23 | custom_emoji_id: ?[]const u8 = null, | ||
| 24 | needs_repainting: bool = false, | ||
| 25 | file_size: ?u64 = null, | ||
diff --git a/src/types/Story.zig b/src/types/Story.zig new file mode 100644 index 0000000..479b7a9 --- /dev/null +++ b/src/types/Story.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | const Chat = @import("Chat.zig"); | ||
| 2 | |||
| 3 | chat: Chat, | ||
| 4 | id: u64, | ||
diff --git a/src/types/SuccessfulPayment.zig b/src/types/SuccessfulPayment.zig new file mode 100644 index 0000000..c508f48 --- /dev/null +++ b/src/types/SuccessfulPayment.zig | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | const OrderInfo = @import("OrderInfo.zig"); | ||
| 2 | |||
| 3 | currency: []const u8, | ||
| 4 | total_amount: u64, | ||
| 5 | invoice_payload: []const u8, | ||
| 6 | shipping_option_id: ?[]const u8 = null, | ||
| 7 | order_info: ?OrderInfo = null, | ||
| 8 | telegram_payment_charge_id: []const u8, | ||
| 9 | provider_payment_charge_id: []const u8, | ||
diff --git a/src/types/SwitchInlineQueryChosenChat.zig b/src/types/SwitchInlineQueryChosenChat.zig new file mode 100644 index 0000000..860f2d9 --- /dev/null +++ b/src/types/SwitchInlineQueryChosenChat.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | query: ?[]const u8, | ||
| 2 | allow_user_chats: ?bool = null, | ||
| 3 | allow_bot_chats: ?bool = null, | ||
| 4 | allow_group_chats: ?bool = null, | ||
| 5 | allow_channel_chats: ?bool = null, | ||
diff --git a/src/types/TextQuote.zig b/src/types/TextQuote.zig new file mode 100644 index 0000000..6dc6be2 --- /dev/null +++ b/src/types/TextQuote.zig | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | const MessageEntity = @import("MessageEntity.zig"); | ||
| 2 | |||
| 3 | text: []const u8, | ||
| 4 | entities: ?[]MessageEntity = null, | ||
| 5 | position: u64, | ||
| 6 | is_manual: bool = false, | ||
diff --git a/src/types/Update.zig b/src/types/Update.zig new file mode 100644 index 0000000..0491110 --- /dev/null +++ b/src/types/Update.zig | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | const BusinessConnection = @import("BusinessConnection.zig"); | ||
| 2 | const BusinessMessagesDeleted = @import("BusinessMessagesDeleted.zig"); | ||
| 3 | const CallbackQuery = @import("CallbackQuery.zig"); | ||
| 4 | const ChatBoostRemoved = @import("ChatBoostRemoved.zig"); | ||
| 5 | const ChatBoostUpdated = @import("ChatBoostUpdated.zig"); | ||
| 6 | const ChatJoinRequest = @import("ChatJoinRequest.zig"); | ||
| 7 | const ChatMemberUpdated = @import("ChatMemberUpdated.zig"); | ||
| 8 | const ChosenInlineResult = @import("ChosenInlineResult.zig"); | ||
| 9 | const InlineQuery = @import("InlineQuery.zig"); | ||
| 10 | const Message = @import("Message.zig"); | ||
| 11 | const MessageReactionCountUpdated = @import("MessageReactionCountUpdated.zig"); | ||
| 12 | const MessageReactionUpdated = @import("MessageReactionUpdated.zig"); | ||
| 13 | const Poll = @import("Poll.zig"); | ||
| 14 | const PollAnswer = @import("PollAnswer.zig"); | ||
| 15 | const PreCheckoutQuery = @import("PreCheckoutQuery.zig"); | ||
| 16 | const ShippingQuery = @import("ShippingQuery.zig"); | ||
| 17 | |||
| 18 | // TODO: Make this into a tagged union | ||
| 19 | update_id: u64, | ||
| 20 | message: ?Message = null, | ||
| 21 | edited_message: ?Message = null, | ||
| 22 | channel_post: ?Message = null, | ||
| 23 | edited_channel_post: ?Message = null, | ||
| 24 | business_connection: ?BusinessConnection = null, | ||
| 25 | business_message: ?Message = null, | ||
| 26 | edited_business_message: ?Message = null, | ||
| 27 | deleted_business_messages: ?BusinessMessagesDeleted = null, | ||
| 28 | message_reaction: ?MessageReactionUpdated = null, | ||
| 29 | message_reaction_count: ?MessageReactionCountUpdated = null, | ||
| 30 | inline_query: ?InlineQuery = null, | ||
| 31 | chosen_inline_result: ?ChosenInlineResult = null, | ||
| 32 | callback_query: ?CallbackQuery = null, | ||
| 33 | shipping_query: ?ShippingQuery = null, | ||
| 34 | pre_checkout_query: ?PreCheckoutQuery = null, | ||
| 35 | poll: ?Poll = null, | ||
| 36 | poll_answer: ?PollAnswer = null, | ||
| 37 | my_chat_member: ?ChatMemberUpdated = null, | ||
| 38 | chat_member: ?ChatMemberUpdated = null, | ||
| 39 | chat_join_request: ?ChatJoinRequest = null, | ||
| 40 | chat_boost: ?ChatBoostUpdated = null, | ||
| 41 | removed_chat_boost: ?ChatBoostRemoved = null, | ||
diff --git a/src/types/User.zig b/src/types/User.zig new file mode 100644 index 0000000..dc06097 --- /dev/null +++ b/src/types/User.zig | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | const textutils = @import("../textutils.zig"); | ||
| 2 | |||
| 3 | const User = @This(); | ||
| 4 | |||
| 5 | id: i64, | ||
| 6 | is_bot: bool, | ||
| 7 | first_name: []const u8, | ||
| 8 | last_name: ?[]const u8 = null, | ||
| 9 | username: ?[]const u8 = null, | ||
| 10 | language_code: ?[]const u8 = null, | ||
| 11 | is_premium: bool = false, | ||
| 12 | added_to_attachment_menu: bool = false, | ||
| 13 | can_join_groups: bool = false, | ||
| 14 | can_read_all_group_messages: bool = false, | ||
| 15 | supports_inline_queries: bool = false, | ||
| 16 | can_connect_to_business: bool = false, | ||
| 17 | |||
| 18 | pub fn writeFormattedName(self: User, w: anytype) !void { | ||
| 19 | try w.print("<a href=\"tg://user?id={}\"><i>", .{self.id}); | ||
| 20 | try textutils.escapeXml(w, self.first_name); | ||
| 21 | if (self.last_name) |last_name| { | ||
| 22 | try w.writeByte(' '); | ||
| 23 | try textutils.escapeXml(w, last_name); | ||
| 24 | } | ||
| 25 | try w.writeAll("</i>"); | ||
| 26 | |||
| 27 | if (self.username) |username| { | ||
| 28 | try w.writeAll(" @"); | ||
| 29 | try textutils.escapeXml(w, username); | ||
| 30 | } | ||
| 31 | try w.print("</a> [<code>{}</code>]", .{self.id}); | ||
| 32 | } | ||
diff --git a/src/types/UsersShared.zig b/src/types/UsersShared.zig new file mode 100644 index 0000000..0fff785 --- /dev/null +++ b/src/types/UsersShared.zig | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | const SharedUser = @import("SharedUser.zig"); | ||
| 2 | |||
| 3 | request_id: u64, | ||
| 4 | users: []SharedUser, | ||
diff --git a/src/types/Venue.zig b/src/types/Venue.zig new file mode 100644 index 0000000..6ae61f3 --- /dev/null +++ b/src/types/Venue.zig | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | const Location = @import("Location.zig"); | ||
| 2 | |||
| 3 | location: Location, | ||
| 4 | title: []const u8, | ||
| 5 | address: []const u8, | ||
| 6 | foursquare_id: ?[]const u8 = null, | ||
| 7 | foursquare_type: ?[]const u8 = null, | ||
| 8 | google_place_id: ?[]const u8 = null, | ||
| 9 | google_place_type: ?[]const u8 = null, | ||
diff --git a/src/types/Video.zig b/src/types/Video.zig new file mode 100644 index 0000000..8330637 --- /dev/null +++ b/src/types/Video.zig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | file_id: []const u8, | ||
| 4 | file_unique_id: []const u8, | ||
| 5 | width: u64, | ||
| 6 | height: u64, | ||
| 7 | duration: u64, | ||
| 8 | thumbnail: ?PhotoSize = null, | ||
| 9 | file_name: ?[]const u8 = null, | ||
| 10 | mime_type: ?[]const u8 = null, | ||
| 11 | file_size: ?u64 = null, | ||
diff --git a/src/types/VideoChatEnded.zig b/src/types/VideoChatEnded.zig new file mode 100644 index 0000000..748bf44 --- /dev/null +++ b/src/types/VideoChatEnded.zig | |||
| @@ -0,0 +1 @@ | |||
| duration: u64, | |||
diff --git a/src/types/VideoChatParticipantsInvited.zig b/src/types/VideoChatParticipantsInvited.zig new file mode 100644 index 0000000..22a46f7 --- /dev/null +++ b/src/types/VideoChatParticipantsInvited.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | const User = @import("User.zig"); | ||
| 2 | |||
| 3 | users: []User, | ||
diff --git a/src/types/VideoChatScheduled.zig b/src/types/VideoChatScheduled.zig new file mode 100644 index 0000000..a55dfe3 --- /dev/null +++ b/src/types/VideoChatScheduled.zig | |||
| @@ -0,0 +1 @@ | |||
| start_date: u64, | |||
diff --git a/src/types/VideoChatStarted.zig b/src/types/VideoChatStarted.zig new file mode 100644 index 0000000..2f72c10 --- /dev/null +++ b/src/types/VideoChatStarted.zig | |||
| @@ -0,0 +1 @@ | |||
| // meant to be empty | |||
diff --git a/src/types/VideoNote.zig b/src/types/VideoNote.zig new file mode 100644 index 0000000..aadb318 --- /dev/null +++ b/src/types/VideoNote.zig | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 2 | |||
| 3 | file_id: []const u8, | ||
| 4 | file_unique_id: []const u8, | ||
| 5 | length: u64, | ||
| 6 | duration: u64, | ||
| 7 | thumbnail: ?PhotoSize = null, | ||
| 8 | file_size: ?u64 = null, | ||
diff --git a/src/types/Voice.zig b/src/types/Voice.zig new file mode 100644 index 0000000..609ee0b --- /dev/null +++ b/src/types/Voice.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | file_id: []const u8, | ||
| 2 | file_unique_id: []const u8, | ||
| 3 | duration: u64, | ||
| 4 | mime_type: ?[]const u8 = null, | ||
| 5 | file_size: ?u64 = null, | ||
diff --git a/src/types/WebAppData.zig b/src/types/WebAppData.zig new file mode 100644 index 0000000..e853fdc --- /dev/null +++ b/src/types/WebAppData.zig | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | data: []const u8, | ||
| 2 | button_text: []const u8, | ||
diff --git a/src/types/WebAppInfo.zig b/src/types/WebAppInfo.zig new file mode 100644 index 0000000..02fcc5e --- /dev/null +++ b/src/types/WebAppInfo.zig | |||
| @@ -0,0 +1 @@ | |||
| url: []const u8, | |||
diff --git a/src/types/WriteAccessAllowed.zig b/src/types/WriteAccessAllowed.zig new file mode 100644 index 0000000..2ff3259 --- /dev/null +++ b/src/types/WriteAccessAllowed.zig | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | from_request: ?bool = null, | ||
| 2 | web_app_name: ?[]const u8 = null, | ||
| 3 | from_attachment_menu: ?bool = null, | ||
diff --git a/src/types/background_fill.zig b/src/types/background_fill.zig new file mode 100644 index 0000000..86aaa59 --- /dev/null +++ b/src/types/background_fill.zig | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | pub const BackgroundFill = union(enum) { | ||
| 4 | solid: struct { | ||
| 5 | color: u24, | ||
| 6 | }, | ||
| 7 | gradient: struct { | ||
| 8 | top_color: u24, | ||
| 9 | bottom_color: u24, | ||
| 10 | rotation_angle: u16, | ||
| 11 | }, | ||
| 12 | freeform_gradient: struct { | ||
| 13 | colors: []const u24, | ||
| 14 | }, | ||
| 15 | |||
| 16 | pub const jsonParse = json.makeJsonParse(BackgroundFill); | ||
| 17 | }; | ||
diff --git a/src/types/background_type.zig b/src/types/background_type.zig new file mode 100644 index 0000000..220465a --- /dev/null +++ b/src/types/background_type.zig | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | const BackgroundFill = @import("background_fill.zig").BackgroundFill; | ||
| 4 | const Document = @import("Document.zig"); | ||
| 5 | |||
| 6 | pub const BackgroundType = union(enum) { | ||
| 7 | fill: struct { | ||
| 8 | fill: BackgroundFill, | ||
| 9 | dark_theme_dimming: u8, | ||
| 10 | }, | ||
| 11 | wallpaper: struct { | ||
| 12 | document: Document, | ||
| 13 | dark_theme_dimming: u8, | ||
| 14 | is_blurred: bool = false, | ||
| 15 | is_moving: bool = false, | ||
| 16 | }, | ||
| 17 | pattern: struct { | ||
| 18 | document: Document, | ||
| 19 | fill: BackgroundFill, | ||
| 20 | intensity: u8, | ||
| 21 | is_inverted: bool = false, | ||
| 22 | is_moving: bool = false, | ||
| 23 | }, | ||
| 24 | chat_theme: struct { | ||
| 25 | theme_name: []const u8, | ||
| 26 | }, | ||
| 27 | |||
| 28 | pub const jsonParse = json.makeJsonParse(BackgroundType); | ||
| 29 | pub const jsonParseFromValue = json.makeJsonParseFromValue(BackgroundType); | ||
| 30 | }; | ||
diff --git a/src/types/chat_boost_source.zig b/src/types/chat_boost_source.zig new file mode 100644 index 0000000..ead19a0 --- /dev/null +++ b/src/types/chat_boost_source.zig | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | const User = @import("User.zig"); | ||
| 4 | |||
| 5 | pub const ChatBoostSource = union(enum) { | ||
| 6 | premium: struct { | ||
| 7 | user: User, | ||
| 8 | }, | ||
| 9 | gift_code: struct { | ||
| 10 | user: User, | ||
| 11 | }, | ||
| 12 | giveaway: struct { | ||
| 13 | giveaway_message_id: u64, | ||
| 14 | user: ?User = null, | ||
| 15 | is_unclaimed: bool = false, | ||
| 16 | }, | ||
| 17 | |||
| 18 | pub const jsonParse = json.makeJsonParse(ChatBoostSource); | ||
| 19 | pub const jsonParseFromValue = json.makeJsonParseFromValue(ChatBoostSource); | ||
| 20 | }; | ||
diff --git a/src/types/chat_member.zig b/src/types/chat_member.zig new file mode 100644 index 0000000..7650299 --- /dev/null +++ b/src/types/chat_member.zig | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | const User = @import("User.zig"); | ||
| 4 | |||
| 5 | pub const ChatMember = union(enum) { | ||
| 6 | creator: struct { | ||
| 7 | user: User, | ||
| 8 | is_anonymous: bool, | ||
| 9 | custom_title: ?[]const u8 = null, | ||
| 10 | }, | ||
| 11 | administrator: struct { | ||
| 12 | user: User, | ||
| 13 | can_be_edited: bool, | ||
| 14 | is_anonymous: bool, | ||
| 15 | can_manage_chat: bool, | ||
| 16 | can_delete_messages: bool, | ||
| 17 | can_manage_video_chats: bool, | ||
| 18 | can_restrict_members: bool, | ||
| 19 | can_promote_members: bool, | ||
| 20 | can_change_info: bool, | ||
| 21 | can_invite_users: bool, | ||
| 22 | can_post_stories: bool, | ||
| 23 | can_edit_stories: bool, | ||
| 24 | can_delete_stories: bool, | ||
| 25 | can_post_messages: ?bool = null, | ||
| 26 | can_edit_messages: ?bool = null, | ||
| 27 | can_pin_messages: ?bool = null, | ||
| 28 | can_manage_topics: ?bool = null, | ||
| 29 | custom_title: ?[]const u8 = null, | ||
| 30 | }, | ||
| 31 | member: struct { | ||
| 32 | user: User, | ||
| 33 | }, | ||
| 34 | restricted: struct { | ||
| 35 | user: User, | ||
| 36 | is_member: bool, | ||
| 37 | can_send_messages: bool, | ||
| 38 | can_send_audios: bool, | ||
| 39 | can_send_documents: bool, | ||
| 40 | can_send_photos: bool, | ||
| 41 | can_send_videos: bool, | ||
| 42 | can_send_video_notes: bool, | ||
| 43 | can_send_voice_notes: bool, | ||
| 44 | can_send_polls: bool, | ||
| 45 | can_send_other_messages: bool, | ||
| 46 | can_add_web_page_previews: bool, | ||
| 47 | can_change_info: bool, | ||
| 48 | can_invite_users: bool, | ||
| 49 | can_pin_messages: bool, | ||
| 50 | can_manage_topics: bool, | ||
| 51 | until_date: u64, | ||
| 52 | }, | ||
| 53 | left: struct { | ||
| 54 | user: User, | ||
| 55 | }, | ||
| 56 | banned: struct { | ||
| 57 | user: User, | ||
| 58 | until_date: u64, | ||
| 59 | }, | ||
| 60 | |||
| 61 | pub const jsonParse = json.makeJsonParse(ChatMember); | ||
| 62 | pub const jsonParseFromValue = json.makeJsonParseFromValueWithTag(ChatMember, "status"); | ||
| 63 | }; | ||
diff --git a/src/types/message_origin.zig b/src/types/message_origin.zig new file mode 100644 index 0000000..5ca1f9f --- /dev/null +++ b/src/types/message_origin.zig | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | const Chat = @import("Chat.zig"); | ||
| 4 | const User = @import("User.zig"); | ||
| 5 | |||
| 6 | pub const MessageOrigin = union(enum) { | ||
| 7 | user: struct { | ||
| 8 | date: u64, | ||
| 9 | sender_user: User, | ||
| 10 | }, | ||
| 11 | hidden_user: struct { | ||
| 12 | date: u64, | ||
| 13 | sender_user_name: []const u8, | ||
| 14 | }, | ||
| 15 | chat: struct { | ||
| 16 | date: u64, | ||
| 17 | sender_chat: Chat, | ||
| 18 | author_signature: ?[]const u8, | ||
| 19 | }, | ||
| 20 | channel: struct { | ||
| 21 | date: u64, | ||
| 22 | chat: Chat, | ||
| 23 | message_id: u64, | ||
| 24 | author_signature: ?[]const u8, | ||
| 25 | }, | ||
| 26 | |||
| 27 | pub const jsonParse = json.makeJsonParse(MessageOrigin); | ||
| 28 | pub const jsonParseFromValue = json.makeJsonParseFromValue(MessageOrigin); | ||
| 29 | }; | ||
diff --git a/src/types/paid_media.zig b/src/types/paid_media.zig new file mode 100644 index 0000000..3b50250 --- /dev/null +++ b/src/types/paid_media.zig | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | const PhotoSize = @import("PhotoSize.zig"); | ||
| 4 | const Video = @import("Video.zig"); | ||
| 5 | |||
| 6 | pub const PaidMedia = union(enum) { | ||
| 7 | preview: struct { | ||
| 8 | width: ?u64 = null, | ||
| 9 | height: ?u64 = null, | ||
| 10 | duration: ?u64 = null, | ||
| 11 | }, | ||
| 12 | photo: struct { | ||
| 13 | photo: []PhotoSize, | ||
| 14 | }, | ||
| 15 | video: struct { | ||
| 16 | video: Video, | ||
| 17 | }, | ||
| 18 | |||
| 19 | pub const jsonParse = json.makeJsonParse(PaidMedia); | ||
| 20 | pub const jsonParseFromValue = json.makeJsonParseFromValue(PaidMedia); | ||
| 21 | }; | ||
diff --git a/src/types/parse_mode.zig b/src/types/parse_mode.zig new file mode 100644 index 0000000..7285c64 --- /dev/null +++ b/src/types/parse_mode.zig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | pub const ParseMode = enum { | ||
| 2 | markdownv2, | ||
| 3 | html, | ||
| 4 | markdown, | ||
| 5 | }; | ||
diff --git a/src/types/reaction_type.zig b/src/types/reaction_type.zig new file mode 100644 index 0000000..416def9 --- /dev/null +++ b/src/types/reaction_type.zig | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | const json = @import("../json.zig"); | ||
| 2 | |||
| 3 | pub const ReactionType = union(enum) { | ||
| 4 | emoji: struct { | ||
| 5 | emoji: []const u8, | ||
| 6 | }, | ||
| 7 | custom_emoji: struct { | ||
| 8 | custom_emoji_id: []const u8, | ||
| 9 | }, | ||
| 10 | |||
| 11 | pub const jsonParse = json.makeJsonParse(ReactionType); | ||
| 12 | pub const jsonParseFromValue = json.makeJsonParseFromValue(ReactionType); | ||
| 13 | }; | ||