diff --git a/packages/geoip/index.ts b/packages/geoip/index.ts
new file mode 100644
index 000000000..165073318
--- /dev/null
+++ b/packages/geoip/index.ts
@@ -0,0 +1,34 @@
+import fs from 'fs';
+import { Reader } from 'maxmind';
+import { Context, findFileSync, Service } from 'hydrooj';
+
+const buffer = fs.readFileSync(findFileSync('@hydrooj/geoip/GeoLite2-City.mmdb'));
+const reader = new Reader(buffer);
+
+export interface Result {
+ location?: string,
+ continent?: string,
+ country?: string,
+ city?: string,
+ display: string
+}
+
+export function apply() {
+ Context.service('geoip', class GeoIPService extends Service {
+ provider = 'MaxMind';
+ lookup(ip: string, locale: string): Result {
+ const res: any = reader.get(ip);
+ if (!res) return { display: 'Unknown address'.translate(locale) };
+ const ret: Result = { display: '' };
+ if (res.location) ret.location = res.location;
+ if (res.continent) ret.continent = res.continent.names[locale] || res.continent.names.en;
+ if (res.country || res.registered_country) {
+ ret.country = (res.country || res.registered_country).names[locale]
+ || (res.country || res.registered_country).names.en;
+ }
+ if (res.city) ret.city = res.city.names[locale] || res.city.names.en;
+ ret.display = `${ret.continent} ${ret.country}${ret.city ? ` ${ret.city}` : ''}`;
+ return ret;
+ }
+ });
+}
diff --git a/packages/geoip/lib.ts b/packages/geoip/lib.ts
deleted file mode 100644
index dd6fe6118..000000000
--- a/packages/geoip/lib.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import 'hydrooj';
-
-import fs from 'fs';
-import { Reader } from 'maxmind';
-import { findFileSync } from '@hydrooj/utils/lib/utils';
-
-const buffer = fs.readFileSync(findFileSync('@hydrooj/geoip/GeoLite2-City.mmdb'));
-const reader = new Reader(buffer);
-
-export interface Result {
- location?: string,
- continent?: string,
- country?: string,
- city?: string,
- display: string
-}
-
-export function lookup(ip: string, locale: string): Result {
- const res: any = reader.get(ip);
- if (!res) return { display: 'Unknown address'.translate(locale) };
- const ret: Result = { display: '' };
- if (res.location) ret.location = res.location;
- if (res.continent) ret.continent = res.continent.names[locale] || res.continent.names.en;
- if (res.country || res.registered_country) {
- ret.country = (res.country || res.registered_country).names[locale]
- || (res.country || res.registered_country).names.en;
- }
- if (res.city) ret.city = res.city.names[locale] || res.city.names.en;
- ret.display = `${ret.continent} ${ret.country}${ret.city ? ` ${ret.city}` : ''}`;
- return ret;
-}
-
-export const provider = 'MaxMind';
-
-global.Hydro.lib.geoip = { provider, lookup };
diff --git a/packages/geoip/package.json b/packages/geoip/package.json
index 0eb7171f0..53e447854 100644
--- a/packages/geoip/package.json
+++ b/packages/geoip/package.json
@@ -1,7 +1,7 @@
{
"name": "@hydrooj/geoip",
"version": "1.2.3",
- "main": "package.json",
+ "main": "index.ts",
"repository": "git@github.com:hydro-dev/Hydro.git",
"author": "undefined ",
"license": "AGPL-3.0-or-later",
@@ -11,8 +11,5 @@
"preferUnplugged": true,
"scripts": {
"prepublish": "./download.sh"
- },
- "peerDependencies": {
- "hydrooj": "*"
}
}
diff --git a/packages/hydrooj/src/context.ts b/packages/hydrooj/src/context.ts
index e16f0f2c8..45420557d 100644
--- a/packages/hydrooj/src/context.ts
+++ b/packages/hydrooj/src/context.ts
@@ -1,6 +1,6 @@
import * as cordis from 'cordis';
import Schema from 'schemastery';
-import { ModuleInterfaces } from './interface';
+import { GeoIP, ModuleInterfaces } from './interface';
import { inject } from './lib/ui';
import { Loader } from './loader';
import { EventMap } from './service/bus';
@@ -33,6 +33,7 @@ export interface Context {
inject: typeof inject;
api: ApiMixin;
broadcast: Context['emit'];
+ geoip?: GeoIP;
}
export class Context extends cordis.Context {
diff --git a/packages/hydrooj/src/handler/home.ts b/packages/hydrooj/src/handler/home.ts
index 4ad8f2c23..d89923c9e 100644
--- a/packages/hydrooj/src/handler/home.ts
+++ b/packages/hydrooj/src/handler/home.ts
@@ -1,6 +1,7 @@
import yaml from 'js-yaml';
import { ObjectID } from 'mongodb';
import { camelCase } from '@hydrooj/utils/lib/utils';
+import { Context } from '../context';
import {
BlacklistedError, DomainAlreadyExistsError, InvalidTokenError,
NotFoundError, PermissionError, UserAlreadyExistError,
@@ -9,6 +10,7 @@ import {
import { DomainDoc, MessageDoc, Setting } from '../interface';
import avatar from '../lib/avatar';
import * as mail from '../lib/mail';
+import * as useragent from '../lib/useragent';
import { isDomainId, isEmail, isPassword } from '../lib/validator';
import BlackListModel from '../model/blacklist';
import { PERM, PRIV } from '../model/builtin';
@@ -28,8 +30,6 @@ import {
} from '../service/server';
import { md5 } from '../utils';
-const { geoip, useragent } = global.Hydro.lib;
-
export class HomeHandler extends Handler {
uids = new Set();
@@ -147,6 +147,7 @@ export class HomeHandler extends Handler {
}
}
+let geoip: Context['geoip'] = null;
class HomeSecurityHandler extends Handler {
async get() {
// TODO(iceboy): pagination? or limit session count for uid?
@@ -154,17 +155,18 @@ class HomeSecurityHandler extends Handler {
for (const session of sessions) {
session.isCurrent = session._id === this.session._id;
session._id = md5(session._id);
- if (useragent) session.updateUa = useragent.parse(session.updateUa || session.createUa || '');
- if (geoip) {
- session.updateGeoip = geoip.lookup(
- session.updateIp || session.createIp,
- this.translate('geoip_locale'),
- );
- }
+ session.updateUa = useragent.parse(session.updateUa || session.createUa || '');
+ session.updateGeoip = geoip?.lookup?.(
+ session.updateIp || session.createIp,
+ this.translate('geoip_locale'),
+ );
}
this.response.template = 'home_security.html';
- this.response.body = { sessions, geoipProvider: geoip?.provider };
- if (useragent) this.response.body.icon = useragent.icon;
+ this.response.body = {
+ sessions,
+ geoipProvider: geoip?.provider,
+ icon: useragent.icon,
+ };
}
@param('current', Types.String)
@@ -432,7 +434,10 @@ class HomeMessagesConnectionHandler extends ConnectionHandler {
}
}
-export async function apply(ctx) {
+export async function apply(ctx: Context) {
+ ctx.using(['geoip'], (g) => {
+ geoip = g.geoip;
+ });
ctx.Route('homepage', '/', HomeHandler);
ctx.Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
ctx.Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV.PRIV_USER_PROFILE);
diff --git a/packages/hydrooj/src/interface.ts b/packages/hydrooj/src/interface.ts
index f81f08872..26c2d739d 100644
--- a/packages/hydrooj/src/interface.ts
+++ b/packages/hydrooj/src/interface.ts
@@ -671,18 +671,17 @@ export interface ProblemSearchOptions {
export type ProblemSearch = (domainId: string, q: string, options?: ProblemSearchOptions) => Promise;
export interface Lib extends Record {
- difficulty: typeof import('./lib/difficulty'),
- buildContent: typeof import('./lib/content').buildContent,
- i18n: typeof import('./lib/i18n'),
- mail: typeof import('./lib/mail'),
- paginate: typeof import('./lib/paginate'),
- rank: typeof import('./lib/rank'),
- rating: typeof import('./lib/rating'),
- testdataConfig: typeof import('./lib/testdataConfig'),
- useragent: typeof import('./lib/useragent'),
- validator: typeof import('./lib/validator'),
- template?: any,
- geoip?: GeoIP,
+ difficulty: typeof import('./lib/difficulty');
+ buildContent: typeof import('./lib/content').buildContent;
+ i18n: typeof import('./lib/i18n');
+ mail: typeof import('./lib/mail');
+ paginate: typeof import('./lib/paginate');
+ rank: typeof import('./lib/rank');
+ rating: typeof import('./lib/rating');
+ testdataConfig: typeof import('./lib/testdataConfig');
+ useragent: typeof import('./lib/useragent');
+ validator: typeof import('./lib/validator');
+ template?: any;
problemSearch: ProblemSearch;
}