22using OurUmbraco . Forum . Extensions ;
33using OurUmbraco . Forum . Models ;
44using System ;
5- using System . Collections . Concurrent ;
65using System . Collections . Generic ;
76using System . Linq ;
87using System . Net . Http ;
9- using System . Runtime . Caching ;
10- using System . Threading ;
11- using System . Threading . Tasks ;
128
139namespace OurUmbraco . Forum . Services
1410{
1511 internal class DiscourseService
1612 {
17- internal async Task < DiscourseTopic > GetTopicByOldIdAsync ( int id )
13+ internal DiscourseTopic GetTopicByOldIdAsync ( int id )
1814 {
1915 var handler = new HttpClientHandler
2016 {
@@ -31,119 +27,71 @@ internal async Task<DiscourseTopic> GetTopicByOldIdAsync(int id)
3127 client . DefaultRequestHeaders . Add ( "Api-Key" , $ "{ System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiKey" ] } ") ;
3228 client . DefaultRequestHeaders . Add ( "Api-Username" , $ "{ System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiUsername" ] } ") ;
3329
34- var result = await client . GetAsync ( $ "t/external_id/{ id } .json") ;
30+ var result = client . GetAsync ( $ "t/external_id/{ id } .json") . Result ;
3531
3632 if ( result . IsSuccessStatusCode == false )
3733 {
3834 return null ;
3935 }
4036 else
4137 {
42- var resultContent = await result . Content . ReadAsStringAsync ( ) ;
38+ var resultContent = result . Content . ReadAsStringAsync ( ) . Result ;
4339 var discourseTopic = JsonConvert . DeserializeObject < DiscourseTopic > ( resultContent ) ;
4440 return discourseTopic ;
4541 }
4642 }
4743 }
4844
49- internal async Task < List < DiscourseTopic > > GetLatestTopicsAsync ( string categorySlug , int categoryId )
45+ internal List < DiscourseTopic > GetLatestTopics ( string categorySlug , int categoryId )
5046 {
51- var cacheKey = "LatestDiscourseTopics" + categorySlug + categoryId ;
5247
53- return await AsyncMemoryCache . GetOrAddAsync ( "myCacheKey" , async ( ) =>
54- {
55- var forumBaseUrl = System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiBaseUrl" ] ;
48+ var cacheKey = "LatestDiscourseTopics" + categorySlug + categoryId ;
5649
57- using ( var client = new HttpClient ( ) )
50+ return ( List < DiscourseTopic > ) Umbraco . Core . ApplicationContext . Current . ApplicationCache . RuntimeCache . GetCacheItem (
51+ cacheKey ,
52+ ( ) =>
5853 {
59- client . BaseAddress = new Uri ( forumBaseUrl ) ;
60- client . DefaultRequestHeaders . Add ( "Api-Key" , $ "{ System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiKey" ] } ") ;
61- client . DefaultRequestHeaders . Add ( "Api-Username" , $ "{ System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiUsername" ] } ") ;
54+ var forumBaseUrl = System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiBaseUrl" ] ;
6255
63- var endPoint = $ "c/{ categorySlug } /{ categoryId } .json?order=created";
64- var result = await client . GetAsync ( endPoint ) ;
65- if ( ! result . IsSuccessStatusCode )
56+ using ( var client = new HttpClient ( ) )
6657 {
67- var resultContent = await result . Content . ReadAsStringAsync ( ) ;
68- var errorModel = JsonConvert . DeserializeObject < ErrorModel > ( resultContent ) ;
69- string errors = string . Join ( ", ", errorModel . Errors ) ;
58+ client . BaseAddress = new Uri ( forumBaseUrl ) ;
59+ client . DefaultRequestHeaders . Add ( "Api-Key" , $ " { System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiKey" ] } " ) ;
60+ client . DefaultRequestHeaders . Add ( "Api-Username ", $ " { System . Configuration . ConfigurationManager . AppSettings [ "DiscourseApiUsername" ] } " ) ;
7061
71- // Logger.Debug(typeof(DiscourseController), $"Listing latest topics from {endPoint} didn't succeed: {errors}");
62+ var endPoint = $ "c/{ categorySlug } /{ categoryId } .json?order=created";
63+ var result = client . GetAsync ( endPoint ) . Result ;
64+ if ( result . IsSuccessStatusCode == false )
65+ {
66+ var resultContent = result . Content . ReadAsStringAsync ( ) . Result ;
67+ var errorModel = JsonConvert . DeserializeObject < ErrorModel > ( resultContent ) ;
68+ string errors = string . Join ( ", " , errorModel . Errors ) ;
7269
73- return null ;
74- }
75- else
76- {
77- var resultContent = await result . Content . ReadAsStringAsync ( ) ;
78- var latestTopics = JsonConvert . DeserializeObject < TopicListModel > ( resultContent ) ;
79- foreach ( var topic in latestTopics . TopicList . Topics )
70+ //Logger.Debug(typeof(DiscourseController), $"Listing lastest topic from {endPoint} didn't succeeed: {errors}");
71+
72+ return null ;
73+ }
74+ else
8075 {
81- var latestPostUser = topic . LastPosterUsername ;
82- var user = latestTopics . Users . FirstOrDefault ( x => x . Username == latestPostUser ) ;
83- if ( user != null )
76+ var resultContent = result . Content . ReadAsStringAsync ( ) . Result ;
77+ var lastestTopics = JsonConvert . DeserializeObject < TopicListModel > ( resultContent ) ;
78+ foreach ( var topic in lastestTopics . TopicList . Topics )
8479 {
85- topic . AuthorName = user . Name ;
86- topic . AuthorAvatar = $ "{ forumBaseUrl } { user . AvatarTemplate . Replace ( "{size}" , "112" ) } ";
80+ var latestPostUser = topic . LastPosterUsername ;
81+ var user = lastestTopics . Users . FirstOrDefault ( x => x . Username == latestPostUser ) ;
82+ if ( user != null )
83+ {
84+ topic . AuthorName = user . Name ;
85+ topic . AuthorAvatar = $ "{ forumBaseUrl } { user . AvatarTemplate . Replace ( "{size}" , "112" ) } ";
86+ }
87+ topic . LastUpdatedFriendly = topic . LastPostedAt . ConvertToRelativeTime ( ) ;
88+ topic . ForumCategory = "Umbraco questions" ;
8789 }
88- topic . LastUpdatedFriendly = topic . LastPostedAt . ConvertToRelativeTime ( ) ;
89- topic . ForumCategory = "Umbraco questions" ;
90- }
9190
92- return latestTopics . TopicList . Topics . OrderByDescending ( x => x . LastPostedAt ) . ToList ( ) ;
91+ return lastestTopics . TopicList . Topics . OrderByDescending ( x => x . LastPostedAt ) . ToList ( ) ;
92+ }
9393 }
94- }
95- } , TimeSpan . FromMinutes ( 5 ) ) ;
94+ } , TimeSpan . FromMinutes ( 5 ) ) ;
9695 }
9796 }
9897}
99-
100-
101- public static class AsyncMemoryCache
102- {
103- private static readonly MemoryCache _cache = MemoryCache . Default ;
104- private static readonly ConcurrentDictionary < string , SemaphoreSlim > _locks = new ConcurrentDictionary < string , SemaphoreSlim > ( ) ;
105-
106- public static async Task < T > GetOrAddAsync < T > ( string key , Func < Task < T > > valueFactory , TimeSpan absoluteExpiration )
107- {
108- if ( _cache . Contains ( key ) )
109- {
110- return ( T ) _cache . Get ( key ) ;
111- }
112-
113- var semaphore = _locks . GetOrAdd ( key , _ => new SemaphoreSlim ( 1 , 1 ) ) ;
114-
115- try
116- {
117- await semaphore . WaitAsync ( ) ;
118-
119- // Double-check if the value was added while waiting for the lock
120- if ( _cache . Contains ( key ) )
121- {
122- return ( T ) _cache . Get ( key ) ;
123- }
124-
125- T result ;
126- try
127- {
128- result = await valueFactory ( ) ;
129- }
130- catch ( Exception ex )
131- {
132- // Log the exception (optional)
133- throw ; // Re-throw or handle as needed
134- }
135-
136- if ( result != null )
137- {
138- _cache . Add ( key , result , DateTimeOffset . Now . Add ( absoluteExpiration ) ) ;
139- }
140-
141- return result ;
142- }
143- finally
144- {
145- semaphore . Release ( ) ;
146- _locks . TryRemove ( key , out _ ) ; // Clean up the lock
147- }
148- }
149- }
0 commit comments