Skip to content

Commit

Permalink
feat: show engine and CLI versions in engine dropdown widget (#202)
Browse files Browse the repository at this point in the history
* feat: add version fetching for Java and Go Casbin engines

* fix: update engine GitHub links to use version-specific tags for Java and Go

* feat: extract engine version logic into custom hook useEngineVersions

* feat: handle unknown versions and refactor GitHub link generation in useEngineVersions hook

* refactor: make getVersion method optional in ICasbinEngine interface and simplify version fetching in useEngineVersions hook

* feat: enhance version handling to include both engine and library versions

* fix: ensure consistent version formatting in editor component

* refactor: simplify and generalize engine version handling in useEngineVersions hook

* refactor: simplify version handling and improve type safety

* style: update formatting in editor dropdown options for Java and Go versions
  • Loading branch information
HashCookie authored Jan 13, 2025
1 parent 39a8df9 commit c4e29ca
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 30 deletions.
26 changes: 5 additions & 21 deletions app/components/editor/CasbinEngine.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { newEnforcer, newModel, StringAdapter } from 'casbin';
import { remoteEnforcer } from './hooks/useRemoteEnforcer';
import { remoteEnforcer, getRemoteVersion, VersionInfo } from './hooks/useRemoteEnforcer';
import { setupRoleManager, setupCustomConfig, processRequests } from '@/app/utils/casbinEnforcer';

interface EnforceResult {
Expand All @@ -17,18 +17,14 @@ export interface ICasbinEngine {
enforceContextData?: Map<string, string>;
}): Promise<EnforceResult>;

getVersion(): string;
getType(): 'node' | 'java' | 'go';
getVersion?(): Promise<VersionInfo>;
}

// Node.js
export class NodeCasbinEngine implements ICasbinEngine {
async enforce(params) {
try {
const e = await newEnforcer(
newModel(params.model),
params.policy ? new StringAdapter(params.policy) : undefined
);
const e = await newEnforcer(newModel(params.model), params.policy ? new StringAdapter(params.policy) : undefined);

setupRoleManager(e);

Expand All @@ -47,14 +43,6 @@ export class NodeCasbinEngine implements ICasbinEngine {
throw error;
}
}

getVersion(): string {
return process.env.CASBIN_VERSION || '';
}

getType(): 'node' {
return 'node';
}
}

// RemoteCasbinEngine
Expand Down Expand Up @@ -84,12 +72,8 @@ export class RemoteCasbinEngine implements ICasbinEngine {
}
}

getVersion(): string {
return '';
}

getType(): 'java' | 'go' {
return this.engine;
async getVersion(): Promise<VersionInfo> {
return getRemoteVersion(this.engine);
}
}

Expand Down
96 changes: 96 additions & 0 deletions app/components/editor/hooks/useEngineVersions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { useState, useEffect } from 'react';
import { createCasbinEngine } from '../CasbinEngine';
import { VersionInfo } from './useRemoteEnforcer';

type EngineType = 'java' | 'go' | 'node';

export interface EngineVersionsReturn {
javaVersion: VersionInfo;
goVersion: VersionInfo;
casbinVersion: string | undefined;
engineGithubLinks: Record<EngineType, string>;
}

interface EngineConfig {
githubRepo: string;
createEngine: () => ReturnType<typeof createCasbinEngine>;
}

const ENGINE_CONFIGS: Record<EngineType, EngineConfig> = {
java: {
githubRepo: 'casbin/jcasbin',
createEngine: () => {
return createCasbinEngine('java');
},
},
go: {
githubRepo: 'casbin/casbin',
createEngine: () => {
return createCasbinEngine('go');
},
},
node: {
githubRepo: 'casbin/node-casbin',
createEngine: () => {
return createCasbinEngine('node');
},
},
};

export default function useEngineVersions(isEngineLoading: boolean): EngineVersionsReturn {
const [versions, setVersions] = useState<Record<EngineType, VersionInfo>>(() => {
return Object.fromEntries(
Object.keys(ENGINE_CONFIGS).map((key) => {
return [key, { engineVersion: '', libVersion: '' }];
}),
) as Record<EngineType, VersionInfo>;
});

const casbinVersion = process.env.CASBIN_VERSION;

useEffect(() => {
const fetchVersions = async () => {
if (isEngineLoading) return;

try {
const versionEntries = await Promise.all(
Object.entries(ENGINE_CONFIGS).map(async ([type, config]) => {
const engine = config.createEngine();
const version = await engine.getVersion?.();
return [type, version || { engineVersion: 'unknown', libVersion: 'unknown' }] as const;
}),
);

setVersions(Object.fromEntries(versionEntries) as Record<EngineType, VersionInfo>);
} catch (error) {
const defaultVersions = Object.fromEntries(
Object.keys(ENGINE_CONFIGS).map((key) => {
return [key, { engineVersion: 'unknown', libVersion: 'unknown' }];
}),
);
setVersions(defaultVersions as Record<EngineType, VersionInfo>);
}
};

fetchVersions();
}, [isEngineLoading]);

const getVersionedLink = (repo: string, version?: string | null) => {
return version && version !== 'unknown'
? `https://github.com/${repo}/releases/tag/v${version.startsWith('v') ? version.slice(1) : version}`
: `https://github.com/${repo}/releases/`;
};

const engineGithubLinks = Object.fromEntries(
Object.entries(ENGINE_CONFIGS).map(([type, config]) => {
return [type, getVersionedLink(config.githubRepo, type === 'node' ? casbinVersion : versions[type as EngineType]?.libVersion)];
}),
) as Record<EngineType, string>;

return {
javaVersion: versions.java,
goVersion: versions.go,
casbinVersion,
engineGithubLinks,
};
}
36 changes: 36 additions & 0 deletions app/components/editor/hooks/useRemoteEnforcer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ interface RemoteEnforcerProps {
engine: 'java' | 'go';
}

export interface VersionInfo {
engineVersion: string;
libVersion: string;
}

export async function remoteEnforcer(props: RemoteEnforcerProps) {
try {
const baseUrl = 'https://door.casdoor.com/api/run-casbin-command';
Expand Down Expand Up @@ -76,3 +81,34 @@ export async function remoteEnforcer(props: RemoteEnforcerProps) {
};
}
}

export async function getRemoteVersion(language: 'java' | 'go'): Promise<VersionInfo> {
try {
const baseUrl = 'https://door.casdoor.com/api/run-casbin-command';
const url = new URL(baseUrl);
url.searchParams.set('language', language);
url.searchParams.set('args', JSON.stringify(['-v']));

const response = await fetch(url.toString());
const result = await response.json();
const versionInfo = result.data as string;

const [cliLine, libLine] = versionInfo.split('\n');

const getVersionNumber = (line: string) => {
const match = line.match(/(?:v|[\s])([\d.]+)/);
return match ? `v${match[1]}` : 'unknown';
};

return {
engineVersion: getVersionNumber(cliLine),
libVersion: getVersionNumber(libLine),
};
} catch (error) {
console.error(`Error getting ${language} version:`, error);
return {
engineVersion: 'unknown',
libVersion: 'unknown',
};
}
}
18 changes: 9 additions & 9 deletions app/components/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { casbinLinter } from '@/app/utils/casbinLinter';
import { toast, Toaster } from 'react-hot-toast';
import { CustomConfigPanel } from './CustomConfigPanel';
import { loadingOverlay } from './LoadingOverlayExtension';
import useEngineVersions from './hooks/useEngineVersions';

export const EditorScreen = () => {
const {
Expand Down Expand Up @@ -70,12 +71,7 @@ export const EditorScreen = () => {
const [isContentLoaded, setIsContentLoaded] = useState(false);
const [isEngineLoading, setIsEngineLoading] = useState(false);
const skipNextEffectRef = useRef(false);
const casbinVersion = process.env.CASBIN_VERSION;
const engineGithubLinks = {
node: `https://github.com/casbin/node-casbin/releases/tag/v${casbinVersion}`,
java: 'https://github.com/casbin/jcasbin/releases',
go: 'https://github.com/casbin/casbin/releases',
};
const { javaVersion, goVersion, casbinVersion, engineGithubLinks } = useEngineVersions(isEngineLoading);

useEffect(() => {
if (modelKind && modelText) {
Expand Down Expand Up @@ -305,9 +301,13 @@ export const EditorScreen = () => {
});
}}
>
<option value="node">Node-Casbin(NodeJs) v{casbinVersion}</option>
<option value="java">jCasbin(Java)</option>
<option value="go">Casbin(Go)</option>
<option value="node">Node-Casbin (NodeJs) {casbinVersion}</option>
<option value="java">
jCasbin (Java) {javaVersion.libVersion} | (CLI {javaVersion.engineVersion})
</option>
<option value="go">
Casbin (Go) {goVersion.libVersion} | (CLI {goVersion.engineVersion})
</option>
</select>
<a href={engineGithubLinks[selectedEngine]} target="_blank" rel="noopener noreferrer" className="text-[#e13c3c] hover:text-[#ff4d4d]">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
Expand Down

0 comments on commit c4e29ca

Please sign in to comment.