mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Refactor Server into generic type
We need to have routes available within the server if we are going to do any kind of dynamic dispatch for Channel Actions.
This commit is contained in:
parent
d3b3ae63cf
commit
8c2d6806b5
@ -16,7 +16,7 @@ pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
}
|
||||
|
||||
pub fn edit(id: []const u8, request: *jetzig.Request) !jetzig.View {
|
||||
try request.server.logger.INFO("id: {s}", .{id});
|
||||
try request.logger.INFO("id: {s}", .{id});
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,7 @@
|
||||
const std = @import("std");
|
||||
const jetzig = @import("jetzig");
|
||||
|
||||
pub fn index(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
pub fn get(id: []const u8, request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
_ = id;
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
pub fn post(request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
return request.render(.created);
|
||||
}
|
||||
|
||||
pub fn put(id: []const u8, request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
_ = id;
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
pub fn patch(id: []const u8, request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
_ = id;
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
pub fn delete(id: []const u8, request: *jetzig.Request, data: *jetzig.Data) !jetzig.View {
|
||||
_ = data;
|
||||
_ = id;
|
||||
pub fn index(request: *jetzig.Request) !jetzig.View {
|
||||
return request.render(.ok);
|
||||
}
|
||||
|
||||
@ -90,6 +60,13 @@ pub const Channel = struct {
|
||||
try message.channel.sync();
|
||||
}
|
||||
|
||||
pub const Actions = struct {
|
||||
pub fn reset(channel: jetzig.channels.Channel) !void {
|
||||
_ = channel;
|
||||
std.debug.print("here\n", .{});
|
||||
}
|
||||
};
|
||||
|
||||
fn resetGame(channel: jetzig.channels.Channel) !void {
|
||||
try channel.put("winner", null);
|
||||
var cells = try channel.put("cells", .array);
|
||||
@ -172,51 +149,3 @@ const Game = struct {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test "index" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.GET, "/websockets", .{});
|
||||
try response.expectStatus(.ok);
|
||||
}
|
||||
|
||||
test "get" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.GET, "/websockets/example-id", .{});
|
||||
try response.expectStatus(.ok);
|
||||
}
|
||||
|
||||
test "post" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.POST, "/websockets", .{});
|
||||
try response.expectStatus(.created);
|
||||
}
|
||||
|
||||
test "put" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.PUT, "/websockets/example-id", .{});
|
||||
try response.expectStatus(.ok);
|
||||
}
|
||||
|
||||
test "patch" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.PATCH, "/websockets/example-id", .{});
|
||||
try response.expectStatus(.ok);
|
||||
}
|
||||
|
||||
test "delete" {
|
||||
var app = try jetzig.testing.app(std.testing.allocator, @import("routes"));
|
||||
defer app.deinit();
|
||||
|
||||
const response = try app.request(.DELETE, "/websockets/example-id", .{});
|
||||
try response.expectStatus(.ok);
|
||||
}
|
||||
|
@ -57,15 +57,15 @@
|
||||
<div id="party-container"></div>
|
||||
|
||||
<div class="board" id="board">
|
||||
<div class="cell" id="tic-tac-toe-cell-0" data-cell="0"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-1" data-cell="1"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-2" data-cell="2"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-3" data-cell="3"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-4" data-cell="4"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-5" data-cell="5"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-6" data-cell="6"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-7" data-cell="7"></div>
|
||||
<div class="cell" id="tic-tac-toe-cell-8" data-cell="8"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.0" id="tic-tac-toe-cell-0" data-cell="0"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.1" id="tic-tac-toe-cell-1" data-cell="1"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.2" id="tic-tac-toe-cell-2" data-cell="2"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.3" id="tic-tac-toe-cell-3" data-cell="3"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.4" id="tic-tac-toe-cell-4" data-cell="4"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.5" id="tic-tac-toe-cell-5" data-cell="5"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.6" id="tic-tac-toe-cell-6" data-cell="6"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.7" id="tic-tac-toe-cell-7" data-cell="7"></div>
|
||||
<div class="cell" jetzig-connect="$.cells.8" id="tic-tac-toe-cell-8" data-cell="8"></div>
|
||||
</div>
|
||||
|
||||
<button id="reset-button">Reset Game</button>
|
||||
@ -86,7 +86,7 @@
|
||||
|
||||
Object.entries(state.cells).forEach(([cell, state]) => {
|
||||
const element = document.querySelector(`#tic-tac-toe-cell-${cell}`);
|
||||
element.innerHTML = { player: "✈", cpu: "🦎" }[state] || "";
|
||||
element.innerHTML = { player: "✈️", cpu: "🦎" }[state] || "";
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ buffer: std.ArrayList(u8),
|
||||
dynamic_routes: std.ArrayList(Function),
|
||||
static_routes: std.ArrayList(Function),
|
||||
channel_routes: std.ArrayList([]const u8),
|
||||
module_paths: std.ArrayList([]const u8),
|
||||
module_paths: std.StringHashMap(void),
|
||||
data: *jetzig.data.Data,
|
||||
|
||||
const receive_message = "receiveMessage";
|
||||
@ -124,7 +124,7 @@ pub fn init(
|
||||
.static_routes = std.ArrayList(Function).init(allocator),
|
||||
.dynamic_routes = std.ArrayList(Function).init(allocator),
|
||||
.channel_routes = std.ArrayList([]const u8).init(allocator),
|
||||
.module_paths = std.ArrayList([]const u8).init(allocator),
|
||||
.module_paths = std.StringHashMap(void).init(allocator),
|
||||
.data = data,
|
||||
};
|
||||
}
|
||||
@ -186,16 +186,29 @@ pub fn generateRoutes(self: *Routes) ![]const u8 {
|
||||
\\
|
||||
);
|
||||
|
||||
try writer.writeAll(
|
||||
\\
|
||||
\\pub const View = struct { name: []const u8, module: type };
|
||||
\\pub const views = [_]View{
|
||||
\\
|
||||
);
|
||||
try self.writeViewsArray(writer);
|
||||
try writer.writeAll(
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
|
||||
try writer.writeAll(
|
||||
\\test {
|
||||
\\
|
||||
);
|
||||
|
||||
for (self.module_paths.items) |module_path| {
|
||||
var it = self.module_paths.keyIterator();
|
||||
while (it.next()) |module_path| {
|
||||
try writer.print(
|
||||
\\ _ = @import("{s}");
|
||||
\\
|
||||
, .{module_path});
|
||||
, .{module_path.*});
|
||||
}
|
||||
|
||||
try writer.writeAll(
|
||||
@ -362,7 +375,7 @@ fn writeRoute(self: *Routes, writer: std.ArrayList(u8).Writer, route: Function)
|
||||
unreachable;
|
||||
|
||||
std.mem.replaceScalar(u8, module_path, '\\', '/');
|
||||
try self.module_paths.append(try self.allocator.dupe(u8, module_path));
|
||||
try self.module_paths.put(try self.allocator.dupe(u8, module_path), {});
|
||||
|
||||
var buf: [32]u8 = undefined;
|
||||
const id = jetzig.util.generateVariableName(&buf);
|
||||
@ -879,3 +892,15 @@ fn writeJobs(self: Routes, writer: anytype) !void {
|
||||
|
||||
std.debug.print("[jetzig] Imported {} job(s)\n", .{count});
|
||||
}
|
||||
|
||||
fn writeViewsArray(self: Routes, writer: anytype) !void {
|
||||
var it = self.module_paths.keyIterator();
|
||||
while (it.next()) |path| {
|
||||
try writer.print(
|
||||
\\.{{ .name = "{s}", .module = @import("{s}") }},
|
||||
\\
|
||||
,
|
||||
.{ chompExtension(try self.relativePathFrom(.views, path.*, .posix)), path.* },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ env: jetzig.Environment,
|
||||
allocator: std.mem.Allocator,
|
||||
custom_routes: std.ArrayList(jetzig.views.Route),
|
||||
initHook: ?*const fn (*App) anyerror!void,
|
||||
server: *jetzig.http.Server = undefined,
|
||||
server: *anyopaque = undefined,
|
||||
|
||||
pub fn deinit(self: *const App) void {
|
||||
@constCast(self).custom_routes.deinit();
|
||||
@ -28,6 +28,10 @@ const AppOptions = struct {
|
||||
pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
defer self.env.deinit();
|
||||
|
||||
const action_router = comptime jetzig.channels.ActionRouter.initComptime(routes_module);
|
||||
_ = action_router;
|
||||
// inline for (action_router.actions) |action| std.debug.print("{s}\n", .{@typeName(action.params[0].type.?)});
|
||||
|
||||
if (self.initHook) |hook| try hook(@constCast(self));
|
||||
|
||||
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||
@ -93,7 +97,7 @@ pub fn start(self: *const App, routes_module: type, options: AppOptions) !void {
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
var server = jetzig.http.Server.init(
|
||||
var server = jetzig.http.Server.RoutedServer(routes_module).init(
|
||||
self.allocator,
|
||||
self.env,
|
||||
routes,
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub const Channel = @import("channels/Channel.zig");
|
||||
pub const Message = @import("channels/Message.zig");
|
||||
pub const Route = @import("channels/Route.zig");
|
||||
pub const ActionRouter = @import("channels/ActionRouter.zig");
|
||||
|
45
src/jetzig/channels/ActionRouter.zig
Normal file
45
src/jetzig/channels/ActionRouter.zig
Normal file
@ -0,0 +1,45 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn initComptime(T: type) ActionRouter {
|
||||
comptime {
|
||||
var len: usize = 0;
|
||||
for (T.views) |view| {
|
||||
if (!@hasDecl(view.module, "Channel")) continue;
|
||||
if (!@hasDecl(view.module.Channel, "Actions")) continue;
|
||||
|
||||
const actions = view.module.Channel.Actions;
|
||||
for (std.meta.declarations(actions)) |_| {
|
||||
len += 1;
|
||||
}
|
||||
}
|
||||
var actions: [len]Action = undefined;
|
||||
var index: usize = 0;
|
||||
for (T.views) |view| {
|
||||
if (!@hasDecl(view.module, "Channel")) continue;
|
||||
if (!@hasDecl(view.module.Channel, "Actions")) continue;
|
||||
|
||||
const channel_actions = view.module.Channel.Actions;
|
||||
for (std.meta.declarations(channel_actions)) |decl| {
|
||||
actions[index] = .{
|
||||
.view = view.name,
|
||||
.name = decl.name,
|
||||
.params = &.{}, //@typeInfo(@TypeOf(@field(view.module.Channel.Actions, decl.name))).@"fn".params,
|
||||
};
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const result = actions;
|
||||
return .{ .actions = &result };
|
||||
}
|
||||
}
|
||||
|
||||
pub const Action = struct {
|
||||
view: []const u8,
|
||||
name: []const u8,
|
||||
params: []const u8,
|
||||
};
|
||||
|
||||
pub const ActionRouter = struct {
|
||||
actions: []const Action,
|
||||
};
|
@ -30,7 +30,12 @@ pub fn value(message: Message) !*jetzig.data.Value {
|
||||
test "message with payload" {
|
||||
const message = Message.init(
|
||||
std.testing.allocator,
|
||||
Channel{ .websocket = undefined, .state = undefined },
|
||||
Channel{
|
||||
.websocket = undefined,
|
||||
.state = undefined,
|
||||
.allocator = undefined,
|
||||
.data = undefined,
|
||||
},
|
||||
"foo",
|
||||
);
|
||||
try std.testing.expectEqualStrings(message.payload, "foo");
|
||||
|
@ -39,9 +39,10 @@ pub fn repo(allocator: std.mem.Allocator, app: anytype) !Repo {
|
||||
}
|
||||
|
||||
fn eventCallback(event: jetzig.jetquery.events.Event, app: anytype) !void {
|
||||
try app.server.logger.logSql(event);
|
||||
var server: *jetzig.http.Server.RoutedServer(@import("root").routes) = @ptrCast(@alignCast(app.server));
|
||||
try server.logger.logSql(event);
|
||||
if (event.err) |err| {
|
||||
try app.server.logger.ERROR("[database] {?s}", .{err.message});
|
||||
try server.logger.ERROR("[database] {?s}", .{err.message});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ path: jetzig.http.Path,
|
||||
method: Method,
|
||||
headers: jetzig.http.Headers,
|
||||
host: []const u8,
|
||||
server: *jetzig.http.Server,
|
||||
httpz_request: *httpz.Request,
|
||||
httpz_response: *httpz.Response,
|
||||
response: *jetzig.http.Response,
|
||||
@ -53,8 +52,14 @@ rendered_view: ?jetzig.views.View = null,
|
||||
start_time: i128,
|
||||
store: RequestStore(jetzig.kv.Store.GeneralStore),
|
||||
cache: RequestStore(jetzig.kv.Store.CacheStore),
|
||||
job_queue: RequestStore(jetzig.kv.Store.JobQueueStore),
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
mailer_definitions: []const jetzig.MailerDefinition,
|
||||
repo: *jetzig.database.Repo,
|
||||
global: *jetzig.Global,
|
||||
env: jetzig.Environment,
|
||||
routes: []const *const jetzig.views.Route,
|
||||
logger: jetzig.loggers.Logger,
|
||||
|
||||
/// Wrapper for KV store that uses the request's arena allocator for fetching values.
|
||||
pub fn RequestStore(T: type) type {
|
||||
@ -123,12 +128,20 @@ pub fn RequestStore(T: type) type {
|
||||
|
||||
pub fn init(
|
||||
allocator: std.mem.Allocator,
|
||||
server: *jetzig.http.Server,
|
||||
start_time: i128,
|
||||
httpz_request: *httpz.Request,
|
||||
httpz_response: *httpz.Response,
|
||||
response: *jetzig.http.Response,
|
||||
repo: *jetzig.database.Repo,
|
||||
env: jetzig.Environment,
|
||||
routes: []const *const jetzig.views.Route,
|
||||
logger: jetzig.loggers.Logger,
|
||||
store: *jetzig.kv.Store.GeneralStore,
|
||||
cache: *jetzig.kv.Store.CacheStore,
|
||||
job_queue: *jetzig.kv.Store.JobQueueStore,
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
mailer_definitions: []const jetzig.MailerDefinition,
|
||||
global: *anyopaque,
|
||||
) !Request {
|
||||
const path = jetzig.http.Path.init(httpz_request.url.raw);
|
||||
|
||||
@ -156,19 +169,24 @@ pub fn init(
|
||||
.method = method,
|
||||
.headers = headers,
|
||||
.host = host,
|
||||
.server = server,
|
||||
.response = response,
|
||||
.response_data = response_data,
|
||||
.httpz_request = httpz_request,
|
||||
.httpz_response = httpz_response,
|
||||
.start_time = start_time,
|
||||
.store = .{ .store = server.store, .allocator = allocator },
|
||||
.cache = .{ .store = server.cache, .allocator = allocator },
|
||||
.store = .{ .store = store, .allocator = allocator },
|
||||
.cache = .{ .store = cache, .allocator = allocator },
|
||||
.job_queue = .{ .store = job_queue, .allocator = allocator },
|
||||
.job_definitions = job_definitions,
|
||||
.mailer_definitions = mailer_definitions,
|
||||
.env = env,
|
||||
.routes = routes,
|
||||
.logger = logger,
|
||||
.repo = repo,
|
||||
.global = if (@hasField(jetzig.Global, "__jetzig_default"))
|
||||
undefined
|
||||
else
|
||||
@ptrCast(@alignCast(server.global)),
|
||||
@ptrCast(@alignCast(global)),
|
||||
};
|
||||
}
|
||||
|
||||
@ -501,19 +519,19 @@ pub fn cookies(self: *Request) !*jetzig.http.Cookies {
|
||||
/// `jetzig.http.Session`.
|
||||
pub fn session(self: *Request) !*jetzig.http.Session {
|
||||
if (self._session) |capture| return capture;
|
||||
const cookie_name = self.server.env.vars.get("JETZIG_SESSION_COOKIE") orelse
|
||||
const cookie_name = self.env.vars.get("JETZIG_SESSION_COOKIE") orelse
|
||||
jetzig.http.Session.default_cookie_name;
|
||||
const local_session = try self.allocator.create(jetzig.http.Session);
|
||||
local_session.* = jetzig.http.Session.init(
|
||||
self.allocator,
|
||||
try self.cookies(),
|
||||
self.server.env.secret,
|
||||
self.env.secret,
|
||||
.{ .cookie_name = cookie_name },
|
||||
);
|
||||
local_session.parse() catch |err| {
|
||||
switch (err) {
|
||||
error.JetzigInvalidSessionCookie => {
|
||||
try self.server.logger.DEBUG("Invalid session cookie detected. Resetting session.", .{});
|
||||
try self.logger.DEBUG("Invalid session cookie detected. Resetting session.", .{});
|
||||
try local_session.reset();
|
||||
},
|
||||
else => return err,
|
||||
@ -565,11 +583,11 @@ pub fn job(self: *Request, job_name: []const u8) !*jetzig.Job {
|
||||
const background_job = try self.allocator.create(jetzig.Job);
|
||||
background_job.* = jetzig.Job.init(
|
||||
self.allocator,
|
||||
self.server.store,
|
||||
self.server.job_queue,
|
||||
self.server.cache,
|
||||
self.server.logger,
|
||||
self.server.job_definitions,
|
||||
self.store.store,
|
||||
self.job_queue.store,
|
||||
self.cache.store,
|
||||
self.logger,
|
||||
self.job_definitions,
|
||||
job_name,
|
||||
);
|
||||
return background_job;
|
||||
@ -611,14 +629,14 @@ const RequestMail = struct {
|
||||
self.request.allocator,
|
||||
mail_job.params,
|
||||
jetzig.jobs.JobEnv{
|
||||
.vars = self.request.server.env.vars,
|
||||
.environment = self.request.server.env.environment,
|
||||
.logger = self.request.server.logger,
|
||||
.routes = self.request.server.routes,
|
||||
.mailers = self.request.server.mailer_definitions,
|
||||
.jobs = self.request.server.job_definitions,
|
||||
.store = self.request.server.store,
|
||||
.cache = self.request.server.cache,
|
||||
.vars = self.request.env.vars,
|
||||
.environment = self.request.env.environment,
|
||||
.logger = self.request.logger,
|
||||
.routes = self.request.routes,
|
||||
.mailers = self.request.mailer_definitions,
|
||||
.jobs = self.request.job_definitions,
|
||||
.store = self.request.store.store,
|
||||
.cache = self.request.cache.store,
|
||||
.mutex = undefined,
|
||||
.repo = self.request.repo,
|
||||
},
|
||||
|
@ -6,28 +6,33 @@ const zmpl = @import("zmpl");
|
||||
const zmd = @import("zmd");
|
||||
const httpz = @import("httpz");
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
logger: jetzig.loggers.Logger,
|
||||
env: jetzig.Environment,
|
||||
routes: []const *const jetzig.views.Route,
|
||||
channel_routes: std.StaticStringMap(jetzig.channels.Route),
|
||||
custom_routes: []const jetzig.views.Route,
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
mailer_definitions: []const jetzig.MailerDefinition,
|
||||
mime_map: *jetzig.http.mime.MimeMap,
|
||||
initialized: bool = false,
|
||||
store: *jetzig.kv.Store.GeneralStore,
|
||||
job_queue: *jetzig.kv.Store.JobQueueStore,
|
||||
cache: *jetzig.kv.Store.CacheStore,
|
||||
channels: *jetzig.kv.Store.ChannelStore,
|
||||
repo: *jetzig.database.Repo,
|
||||
global: *anyopaque,
|
||||
decoded_static_route_params: []const *jetzig.data.Value = &.{},
|
||||
debug_mutex: std.Thread.Mutex = .{},
|
||||
pub const RenderedView = struct { view: jetzig.views.View, content: []const u8 };
|
||||
|
||||
const Server = @This();
|
||||
pub fn RoutedServer(Routes: type) type {
|
||||
_ = Routes;
|
||||
return struct {
|
||||
allocator: std.mem.Allocator,
|
||||
logger: jetzig.loggers.Logger,
|
||||
env: jetzig.Environment,
|
||||
routes: []const *const jetzig.views.Route,
|
||||
channel_routes: std.StaticStringMap(jetzig.channels.Route),
|
||||
custom_routes: []const jetzig.views.Route,
|
||||
job_definitions: []const jetzig.JobDefinition,
|
||||
mailer_definitions: []const jetzig.MailerDefinition,
|
||||
mime_map: *jetzig.http.mime.MimeMap,
|
||||
initialized: bool = false,
|
||||
store: *jetzig.kv.Store.GeneralStore,
|
||||
job_queue: *jetzig.kv.Store.JobQueueStore,
|
||||
cache: *jetzig.kv.Store.CacheStore,
|
||||
channels: *jetzig.kv.Store.ChannelStore,
|
||||
repo: *jetzig.database.Repo,
|
||||
global: *anyopaque,
|
||||
decoded_static_route_params: []const *jetzig.data.Value = &.{},
|
||||
debug_mutex: std.Thread.Mutex = .{},
|
||||
|
||||
pub fn init(
|
||||
const Server = @This();
|
||||
|
||||
pub fn init(
|
||||
allocator: std.mem.Allocator,
|
||||
env: jetzig.Environment,
|
||||
routes: []const *const jetzig.views.Route,
|
||||
@ -42,7 +47,7 @@ pub fn init(
|
||||
channels: *jetzig.kv.Store.ChannelStore,
|
||||
repo: *jetzig.database.Repo,
|
||||
global: *anyopaque,
|
||||
) Server {
|
||||
) Server {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.logger = env.logger,
|
||||
@ -60,14 +65,14 @@ pub fn init(
|
||||
.repo = repo,
|
||||
.global = global,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Server) void {
|
||||
pub fn deinit(self: *Server) void {
|
||||
self.allocator.free(self.env.secret);
|
||||
self.allocator.free(self.env.bind);
|
||||
}
|
||||
}
|
||||
|
||||
const HttpzHandler = struct {
|
||||
const HttpzHandler = struct {
|
||||
server: *Server,
|
||||
|
||||
pub const WebsocketHandler = jetzig.http.Websocket;
|
||||
@ -77,9 +82,9 @@ const HttpzHandler = struct {
|
||||
self.server.errorHandlerFn(request, response, err) catch {};
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub fn listen(self: *Server) !void {
|
||||
pub fn listen(self: *Server) !void {
|
||||
try self.decodeStaticParams();
|
||||
|
||||
const worker_count = jetzig.config.get(u16, "worker_count");
|
||||
@ -121,9 +126,9 @@ pub fn listen(self: *Server) !void {
|
||||
try jetzig.http.middleware.afterLaunch(self);
|
||||
|
||||
return try httpz_server.listen();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.Response, err: anyerror) !void {
|
||||
pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.Response, err: anyerror) !void {
|
||||
if (isBadHttpError(err)) return;
|
||||
|
||||
self.logger.ERROR("Encountered error: {s} {s}", .{ @errorName(err), request.url.raw }) catch {};
|
||||
@ -135,13 +140,13 @@ pub fn errorHandlerFn(self: *Server, request: *httpz.Request, response: *httpz.R
|
||||
}
|
||||
|
||||
response.body = "500 Internal Server Error";
|
||||
}
|
||||
}
|
||||
|
||||
pub fn processNextRequest(
|
||||
pub fn processNextRequest(
|
||||
self: *Server,
|
||||
httpz_request: *httpz.Request,
|
||||
httpz_response: *httpz.Response,
|
||||
) !void {
|
||||
) !void {
|
||||
const start_time = std.time.nanoTimestamp();
|
||||
|
||||
var repo = try self.repo.bindConnect(.{ .allocator = httpz_response.arena });
|
||||
@ -150,12 +155,20 @@ pub fn processNextRequest(
|
||||
var response = try jetzig.http.Response.init(httpz_response.arena, httpz_response);
|
||||
var request = try jetzig.http.Request.init(
|
||||
httpz_response.arena,
|
||||
self,
|
||||
start_time,
|
||||
httpz_request,
|
||||
httpz_response,
|
||||
&response,
|
||||
&repo,
|
||||
self.env,
|
||||
self.routes,
|
||||
self.logger,
|
||||
self.store,
|
||||
self.cache,
|
||||
self.job_queue,
|
||||
self.job_definitions,
|
||||
self.mailer_definitions,
|
||||
self.global,
|
||||
);
|
||||
|
||||
if (try self.upgradeWebsocket(httpz_request, httpz_response, &request)) {
|
||||
@ -180,19 +193,20 @@ pub fn processNextRequest(
|
||||
jetzig.http.middleware.deinit(&middleware_data, &request);
|
||||
|
||||
try self.logger.logRequest(&request);
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to match a channel name to a view with a Channel implementation.
|
||||
pub fn matchChannelRoute(self: *const Server, channel_name: []const u8) ?jetzig.channels.Route {
|
||||
/// Attempt to match a channel name to a view with a Channel implementation.
|
||||
pub fn matchChannelRoute(self: *const Server, channel_name: []const u8) ?jetzig.channels.Route {
|
||||
// TODO: Detect root path correctly.
|
||||
return self.channel_routes.get(channel_name);
|
||||
}
|
||||
}
|
||||
|
||||
fn upgradeWebsocket(
|
||||
fn upgradeWebsocket(
|
||||
self: *const Server,
|
||||
httpz_request: *httpz.Request,
|
||||
httpz_response: *httpz.Response,
|
||||
request: *jetzig.http.Request,
|
||||
) !bool {
|
||||
) !bool {
|
||||
const route = self.matchChannelRoute(request.path.view_name) orelse return false;
|
||||
const session = try request.session();
|
||||
const session_id = session.getT(.string, "_id") orelse {
|
||||
@ -208,12 +222,12 @@ fn upgradeWebsocket(
|
||||
.allocator = self.allocator,
|
||||
.route = route,
|
||||
.session_id = session_id,
|
||||
.server = self,
|
||||
.channels = self.channels,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn maybeMiddlewareRender(request: *jetzig.http.Request, response: *const jetzig.http.Response) !bool {
|
||||
fn maybeMiddlewareRender(request: *jetzig.http.Request, response: *const jetzig.http.Response) !bool {
|
||||
if (request.middleware_rendered) |_| {
|
||||
// Request processing ends when a middleware renders or redirects.
|
||||
if (request.redirect_state) |state| {
|
||||
@ -226,9 +240,9 @@ fn maybeMiddlewareRender(request: *jetzig.http.Request, response: *const jetzig.
|
||||
try request.respond();
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
||||
fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
||||
const static_resource = self.matchStaticResource(request) catch |err| {
|
||||
if (isUnhandledError(err)) return err;
|
||||
|
||||
@ -295,20 +309,20 @@ fn renderResponse(self: *Server, request: *jetzig.http.Request) !void {
|
||||
}
|
||||
|
||||
if (request.redirect_state) |state| try request.renderRedirect(state);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderStatic(resource: StaticResource, request: *jetzig.http.Request) !void {
|
||||
fn renderStatic(resource: StaticResource, request: *jetzig.http.Request) !void {
|
||||
request.setResponse(
|
||||
.{ .view = .{ .data = request.response_data }, .content = resource.content },
|
||||
.{ .content_type = resource.mime_type },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderHTML(
|
||||
fn renderHTML(
|
||||
self: *Server,
|
||||
request: *jetzig.http.Request,
|
||||
route: ?jetzig.views.Route,
|
||||
) !void {
|
||||
) !void {
|
||||
if (route) |matched_route| {
|
||||
if (zmpl.findPrefixed("views", matched_route.template)) |template| {
|
||||
const rendered = self.renderView(matched_route, request, template) catch |err| {
|
||||
@ -345,13 +359,13 @@ fn renderHTML(
|
||||
return request.setResponse(try self.renderNotFound(request), .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn renderJSON(
|
||||
fn renderJSON(
|
||||
self: *Server,
|
||||
request: *jetzig.http.Request,
|
||||
route: ?jetzig.views.Route,
|
||||
) !void {
|
||||
) !void {
|
||||
if (route) |matched_route| {
|
||||
var rendered = try self.renderView(matched_route, request, null);
|
||||
var data = rendered.view.data;
|
||||
@ -367,9 +381,9 @@ fn renderJSON(
|
||||
} else {
|
||||
request.setResponse(try self.renderNotFound(request), .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn renderMarkdown(self: *Server, request: *jetzig.http.Request) !?RenderedView {
|
||||
fn renderMarkdown(self: *Server, request: *jetzig.http.Request) !?RenderedView {
|
||||
_ = self;
|
||||
// No route recognized, but we can still render a static markdown file if it matches the URI:
|
||||
if (request.method != .GET) return null;
|
||||
@ -381,16 +395,14 @@ fn renderMarkdown(self: *Server, request: *jetzig.http.Request) !?RenderedView {
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const RenderedView = struct { view: jetzig.views.View, content: []const u8 };
|
||||
|
||||
fn renderView(
|
||||
fn renderView(
|
||||
self: *Server,
|
||||
route: jetzig.views.Route,
|
||||
request: *jetzig.http.Request,
|
||||
maybe_template: ?zmpl.Template,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
// View functions return a `View` to encourage users to return from a view function with
|
||||
// `return request.render(.ok)`, but the actual rendered view is stored in
|
||||
// `request.rendered_view`.
|
||||
@ -448,15 +460,15 @@ fn renderView(
|
||||
.content = "",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn renderTemplateWithLayout(
|
||||
fn renderTemplateWithLayout(
|
||||
self: *Server,
|
||||
request: *jetzig.http.Request,
|
||||
template: zmpl.Template,
|
||||
view: jetzig.views.View,
|
||||
route: jetzig.views.Route,
|
||||
) ![]const u8 {
|
||||
) ![]const u8 {
|
||||
try addTemplateConstants(view, route);
|
||||
|
||||
const template_context = jetzig.TemplateContext{ .request = request };
|
||||
@ -492,9 +504,9 @@ fn renderTemplateWithLayout(
|
||||
template_context,
|
||||
.{},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn addTemplateConstants(view: jetzig.views.View, route: jetzig.views.Route) !void {
|
||||
fn addTemplateConstants(view: jetzig.views.View, route: jetzig.views.Route) !void {
|
||||
const action = switch (route.action) {
|
||||
.custom => route.name,
|
||||
else => |tag| @tagName(tag),
|
||||
@ -502,23 +514,23 @@ fn addTemplateConstants(view: jetzig.views.View, route: jetzig.views.Route) !voi
|
||||
|
||||
try view.data.addConst("jetzig_action", view.data.string(action));
|
||||
try view.data.addConst("jetzig_view", view.data.string(route.view_name));
|
||||
}
|
||||
}
|
||||
|
||||
fn isBadRequest(err: anyerror) bool {
|
||||
fn isBadRequest(err: anyerror) bool {
|
||||
return switch (err) {
|
||||
error.JetzigBodyParseError, error.JetzigQueryParseError => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn isUnhandledError(err: anyerror) bool {
|
||||
fn isUnhandledError(err: anyerror) bool {
|
||||
return switch (err) {
|
||||
error.OutOfMemory => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn isBadHttpError(err: anyerror) bool {
|
||||
fn isBadHttpError(err: anyerror) bool {
|
||||
return switch (err) {
|
||||
error.JetzigParseHeadError,
|
||||
error.UnknownHttpMethod,
|
||||
@ -535,63 +547,63 @@ fn isBadHttpError(err: anyerror) bool {
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn renderInternalServerError(
|
||||
fn renderInternalServerError(
|
||||
self: *Server,
|
||||
request: *jetzig.http.Request,
|
||||
stack_trace: ?*std.builtin.StackTrace,
|
||||
err: anyerror,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
try self.logger.logError(stack_trace, err);
|
||||
|
||||
const status = jetzig.http.StatusCode.internal_server_error;
|
||||
|
||||
return try self.renderError(request, status, .{ .stack_trace = stack_trace, .err = err });
|
||||
}
|
||||
}
|
||||
|
||||
fn renderNotFound(self: *Server, request: *jetzig.http.Request) !RenderedView {
|
||||
fn renderNotFound(self: *Server, request: *jetzig.http.Request) !RenderedView {
|
||||
request.response_data.reset();
|
||||
|
||||
const status: jetzig.http.StatusCode = .not_found;
|
||||
return try self.renderError(request, status, .{});
|
||||
}
|
||||
}
|
||||
|
||||
fn renderBadRequest(self: *Server, request: *jetzig.http.Request) !RenderedView {
|
||||
fn renderBadRequest(self: *Server, request: *jetzig.http.Request) !RenderedView {
|
||||
request.response_data.reset();
|
||||
|
||||
const status: jetzig.http.StatusCode = .bad_request;
|
||||
return try self.renderError(request, status, .{});
|
||||
}
|
||||
}
|
||||
|
||||
fn renderError(
|
||||
fn renderError(
|
||||
self: Server,
|
||||
request: *jetzig.http.Request,
|
||||
status_code: jetzig.http.StatusCode,
|
||||
error_info: jetzig.debug.ErrorInfo,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
if (comptime jetzig.build_options.debug_console) {
|
||||
return try self.renderDebugConsole(request, status_code, error_info);
|
||||
} else return try self.renderGeneralError(request, status_code);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderGeneralError(
|
||||
fn renderGeneralError(
|
||||
self: Server,
|
||||
request: *jetzig.http.Request,
|
||||
status_code: jetzig.http.StatusCode,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
if (try self.renderErrorView(request, status_code)) |view| return view;
|
||||
if (try renderStaticErrorPage(request, status_code)) |view| return view;
|
||||
|
||||
return try renderDefaultError(request, status_code);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderDebugConsole(
|
||||
fn renderDebugConsole(
|
||||
self: Server,
|
||||
request: *jetzig.http.Request,
|
||||
status_code: jetzig.http.StatusCode,
|
||||
error_info: jetzig.debug.ErrorInfo,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
if (comptime jetzig.build_options.debug_console) {
|
||||
var buf = std.ArrayList(u8).init(request.allocator);
|
||||
const writer = buf.writer();
|
||||
@ -620,13 +632,13 @@ fn renderDebugConsole(
|
||||
.content = if (content.len == 0) "" else content,
|
||||
};
|
||||
} else unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn renderErrorView(
|
||||
fn renderErrorView(
|
||||
self: Server,
|
||||
request: *jetzig.http.Request,
|
||||
status_code: jetzig.http.StatusCode,
|
||||
) !?RenderedView {
|
||||
) !?RenderedView {
|
||||
for (self.routes) |route| {
|
||||
if (std.mem.eql(u8, route.view_name, "errors") and route.action == .index) {
|
||||
request.response_data.reset();
|
||||
@ -665,9 +677,9 @@ fn renderErrorView(
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn renderStaticErrorPage(request: *jetzig.http.Request, status_code: jetzig.http.StatusCode) !?RenderedView {
|
||||
fn renderStaticErrorPage(request: *jetzig.http.Request, status_code: jetzig.http.StatusCode) !?RenderedView {
|
||||
if (request.requestFormat() == .JSON) return null;
|
||||
|
||||
var dir = std.fs.cwd().openDir(
|
||||
@ -697,40 +709,40 @@ fn renderStaticErrorPage(request: *jetzig.http.Request, status_code: jetzig.http
|
||||
.view = jetzig.views.View{ .data = request.response_data, .status_code = status_code },
|
||||
.content = content,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn renderDefaultError(
|
||||
fn renderDefaultError(
|
||||
request: *const jetzig.http.Request,
|
||||
status_code: jetzig.http.StatusCode,
|
||||
) !RenderedView {
|
||||
) !RenderedView {
|
||||
const content = try request.formatStatus(status_code);
|
||||
return .{
|
||||
.view = jetzig.views.View{ .data = request.response_data, .status_code = status_code },
|
||||
.content = content,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn logStackTrace(
|
||||
fn logStackTrace(
|
||||
self: Server,
|
||||
stack: *std.builtin.StackTrace,
|
||||
allocator: std.mem.Allocator,
|
||||
) !void {
|
||||
) !void {
|
||||
var buf = std.ArrayList(u8).init(allocator);
|
||||
defer buf.deinit();
|
||||
const writer = buf.writer();
|
||||
try stack.format("", .{}, writer);
|
||||
if (buf.items.len > 0) try self.logger.ERROR("{s}\n", .{buf.items});
|
||||
}
|
||||
}
|
||||
|
||||
fn matchCustomRoute(self: Server, request: *const jetzig.http.Request) ?jetzig.views.Route {
|
||||
fn matchCustomRoute(self: Server, request: *const jetzig.http.Request) ?jetzig.views.Route {
|
||||
for (self.custom_routes) |custom_route| {
|
||||
if (custom_route.match(request)) return custom_route;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn matchMiddlewareRoute(request: *const jetzig.http.Request) ?jetzig.middleware.MiddlewareRoute {
|
||||
fn matchMiddlewareRoute(request: *const jetzig.http.Request) ?jetzig.middleware.MiddlewareRoute {
|
||||
const middlewares = jetzig.config.get([]const type, "middleware");
|
||||
|
||||
inline for (middlewares) |middleware| {
|
||||
@ -742,9 +754,9 @@ fn matchMiddlewareRoute(request: *const jetzig.http.Request) ?jetzig.middleware.
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn matchRoute(self: *Server, request: *jetzig.http.Request, static: bool) !?jetzig.views.Route {
|
||||
fn matchRoute(self: *Server, request: *jetzig.http.Request, static: bool) !?jetzig.views.Route {
|
||||
for (self.routes) |route| {
|
||||
// .index routes always take precedence.
|
||||
if (route.action == .index and try request.match(route.*)) {
|
||||
@ -761,14 +773,14 @@ fn matchRoute(self: *Server, request: *jetzig.http.Request, static: bool) !?jetz
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const StaticResource = struct {
|
||||
const StaticResource = struct {
|
||||
content: []const u8,
|
||||
mime_type: []const u8 = "application/octet-stream",
|
||||
};
|
||||
};
|
||||
|
||||
fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
||||
fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
||||
if (comptime jetzig.build_options.debug_console) {
|
||||
if (std.mem.eql(u8, request.path.path, "/_jetzig_debug.js")) return .{
|
||||
.content = @embedFile("../../assets/debug.js"),
|
||||
@ -791,9 +803,9 @@ fn matchStaticResource(self: *Server, request: *jetzig.http.Request) !?StaticRes
|
||||
};
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
||||
fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticResource {
|
||||
if (request.path.file_path.len <= 1) return null;
|
||||
if (request.method != .GET) return null;
|
||||
|
||||
@ -833,9 +845,9 @@ fn matchPublicContent(self: *Server, request: *jetzig.http.Request) !?StaticReso
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn matchStaticContent(self: *Server, request: *jetzig.http.Request) !?[]const u8 {
|
||||
fn matchStaticContent(self: *Server, request: *jetzig.http.Request) !?[]const u8 {
|
||||
const request_format = request.requestFormat();
|
||||
const matched_route = try self.matchRoute(request, true);
|
||||
|
||||
@ -867,9 +879,9 @@ fn matchStaticContent(self: *Server, request: *jetzig.http.Request) !?[]const u8
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decodeStaticParams(self: *Server) !void {
|
||||
pub fn decodeStaticParams(self: *Server) !void {
|
||||
if (comptime !@hasDecl(jetzig.root, "static")) return;
|
||||
|
||||
// Store decoded static params (i.e. declared in views) for faster comparison at request time.
|
||||
@ -882,15 +894,15 @@ pub fn decodeStaticParams(self: *Server) !void {
|
||||
}
|
||||
|
||||
self.decoded_static_route_params = try decoded.toOwnedSlice();
|
||||
}
|
||||
}
|
||||
|
||||
fn matchStaticOutput(
|
||||
fn matchStaticOutput(
|
||||
maybe_expected_id: ?[]const u8,
|
||||
maybe_expected_params: ?*jetzig.data.Value,
|
||||
route: jetzig.views.Route,
|
||||
request: *const jetzig.http.Request,
|
||||
params: jetzig.data.Value,
|
||||
) bool {
|
||||
) bool {
|
||||
return if (maybe_expected_params) |expected_params| blk: {
|
||||
const params_match = expected_params.count() == 0 or expected_params.eql(params);
|
||||
break :blk switch (route.action) {
|
||||
@ -904,4 +916,6 @@ fn matchStaticOutput(
|
||||
std.mem.eql(u8, id, request.path.resource_id)
|
||||
else
|
||||
true; // We reached a params filter (possibly the default catch-all) with no params set.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -8,14 +8,14 @@ pub const Context = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
route: jetzig.channels.Route,
|
||||
session_id: []const u8,
|
||||
server: *const jetzig.http.Server,
|
||||
channels: *jetzig.kv.Store.ChannelStore,
|
||||
};
|
||||
|
||||
const Websocket = @This();
|
||||
|
||||
allocator: std.mem.Allocator,
|
||||
connection: *httpz.websocket.Conn,
|
||||
server: *const jetzig.http.Server,
|
||||
channels: *jetzig.kv.Store.ChannelStore,
|
||||
route: jetzig.channels.Route,
|
||||
data: *jetzig.Data,
|
||||
session_id: []const u8,
|
||||
@ -29,7 +29,7 @@ pub fn init(connection: *httpz.websocket.Conn, context: Context) !Websocket {
|
||||
.connection = connection,
|
||||
.route = context.route,
|
||||
.session_id = context.session_id,
|
||||
.server = context.server,
|
||||
.channels = context.channels,
|
||||
.data = data,
|
||||
};
|
||||
}
|
||||
@ -70,15 +70,15 @@ pub fn syncState(websocket: *Websocket, channel: jetzig.channels.Channel) !void
|
||||
const writer = write_buffer.writer();
|
||||
|
||||
// TODO: Make this really fast.
|
||||
try websocket.server.channels.put(websocket.session_id, channel.state);
|
||||
try websocket.channels.put(websocket.session_id, channel.state);
|
||||
try writer.print("__jetzig_channel_state__:{s}", .{try websocket.data.toJson()});
|
||||
try write_buffer.flush();
|
||||
}
|
||||
|
||||
pub fn getState(websocket: *Websocket) !*jetzig.data.Value {
|
||||
return try websocket.server.channels.get(websocket.data, websocket.session_id) orelse blk: {
|
||||
return try websocket.channels.get(websocket.data, websocket.session_id) orelse blk: {
|
||||
const root = try websocket.data.root(.object);
|
||||
try websocket.server.channels.put(websocket.session_id, root);
|
||||
break :blk try websocket.server.channels.get(websocket.data, websocket.session_id) orelse error.JetzigInvalidChannel;
|
||||
try websocket.channels.put(websocket.session_id, root);
|
||||
break :blk try websocket.channels.get(websocket.data, websocket.session_id) orelse error.JetzigInvalidChannel;
|
||||
};
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ pub fn Type(comptime name: MiddlewareEnum()) type {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn afterLaunch(server: *jetzig.http.Server) !void {
|
||||
pub fn afterLaunch(server: *jetzig.http.Server.RoutedServer(@import("root").routes)) !void {
|
||||
inline for (middlewares) |middleware| {
|
||||
if (comptime @hasDecl(middleware, "afterLaunch")) {
|
||||
try middleware.afterLaunch(server);
|
||||
|
@ -29,7 +29,7 @@ pub fn beforeRender(request: *jetzig.http.Request, route: jetzig.views.Route) !v
|
||||
|
||||
fn logFailure(request: *jetzig.http.Request) !void {
|
||||
_ = request.fail(.forbidden);
|
||||
try request.server.logger.DEBUG("Anti-CSRF token validation failed. Request aborted.", .{});
|
||||
try request.logger.DEBUG("Anti-CSRF token validation failed. Request aborted.", .{});
|
||||
}
|
||||
|
||||
fn verifyCsrfToken(request: *jetzig.http.Request) !void {
|
||||
|
@ -15,7 +15,7 @@ channels: *MemoryStore,
|
||||
job_queue: *MemoryStore,
|
||||
multipart_boundary: ?[]const u8 = null,
|
||||
logger: jetzig.loggers.Logger,
|
||||
server: Server,
|
||||
server: *jetzig.http.Server.RoutedServer(@import("root").routes),
|
||||
repo: *jetzig.database.Repo,
|
||||
cookies: *jetzig.http.Cookies,
|
||||
session: *jetzig.http.Session,
|
||||
@ -58,6 +58,28 @@ pub fn init(allocator: std.mem.Allocator, routes_module: type) !App {
|
||||
const session = try alloc.create(jetzig.http.Session);
|
||||
session.* = jetzig.http.Session.init(alloc, cookies, jetzig.testing.secret, .{});
|
||||
|
||||
const server = try alloc.create(jetzig.http.Server.RoutedServer(@import("root").routes));
|
||||
// This server is only used by database logging - we create a more lifelike server when we
|
||||
// process the actual test request.
|
||||
server.* = .{
|
||||
.logger = logger,
|
||||
.allocator = undefined,
|
||||
.env = undefined,
|
||||
.routes = undefined,
|
||||
.channel_routes = undefined,
|
||||
.custom_routes = undefined,
|
||||
.job_definitions = undefined,
|
||||
.mailer_definitions = undefined,
|
||||
.mime_map = undefined,
|
||||
.initialized = undefined,
|
||||
.store = undefined,
|
||||
.job_queue = undefined,
|
||||
.cache = undefined,
|
||||
.channels = undefined,
|
||||
.repo = undefined,
|
||||
.global = undefined,
|
||||
};
|
||||
|
||||
app.* = App{
|
||||
.arena = arena,
|
||||
.allocator = allocator,
|
||||
@ -67,7 +89,7 @@ pub fn init(allocator: std.mem.Allocator, routes_module: type) !App {
|
||||
.channels = try createStore(arena.allocator(), logger, .channels),
|
||||
.job_queue = try createStore(arena.allocator(), logger, .jobs),
|
||||
.logger = logger,
|
||||
.server = .{ .logger = logger },
|
||||
.server = server,
|
||||
.repo = repo,
|
||||
.cookies = cookies,
|
||||
.session = session,
|
||||
@ -133,7 +155,7 @@ pub fn request(
|
||||
.env_map = std.process.EnvMap.init(allocator),
|
||||
.env_file = null,
|
||||
};
|
||||
var server = jetzig.http.Server{
|
||||
var server = jetzig.http.Server.RoutedServer(@import("root").routes){
|
||||
.allocator = allocator,
|
||||
.logger = self.logger,
|
||||
.env = .{
|
||||
@ -150,6 +172,7 @@ pub fn request(
|
||||
.secret = jetzig.testing.secret,
|
||||
},
|
||||
.routes = routes,
|
||||
.channel_routes = std.StaticStringMap(jetzig.channels.Route).initComptime(.{}),
|
||||
.custom_routes = &.{},
|
||||
.mailer_definitions = &.{},
|
||||
.job_definitions = &.{},
|
||||
|
@ -8,6 +8,7 @@ pub const std_options = std.Options{
|
||||
};
|
||||
|
||||
pub const jetzig_options = @import("main").jetzig_options;
|
||||
pub const routes = @import("main").routes;
|
||||
|
||||
pub fn log(
|
||||
comptime message_level: std.log.Level,
|
||||
|
Loading…
x
Reference in New Issue
Block a user