methodMap;
16 | / **
17 | * Constructor for QQNotifyHandlerProxy.
18 | *
19 | * @param proxyObject a {@link java.lang.Object} object.
20 | * /
21 | public QQNotifyHandlerProxy(Object proxyObject){
22 | this.proxyObject = proxyObject;
23 | this.methodMap = new Dictionary();
24 | foreach (Method m in proxyObject.getClass().getDeclaredMethods()) {
25 | if(m.isAnnotationPresent(QQNotifyHandler.class)){
26 | QQNotifyHandler handler = m.getAnnotation(QQNotifyHandler.class);
27 | this.methodMap.Add(handler.value(), m);
28 | if(!m.isAccessible()){
29 | m.setAccessible(true);
30 | }
31 | }
32 | }
33 | }
34 |
35 | / ** {@inheritDoc} * /
36 |
37 | public void OnNotifyEvent(QQNotifyEvent Event) {
38 | Method m = methodMap[Event.Type];
39 | if(m != null){
40 | try {
41 | m.Invoke(proxyObject, Event);
42 | } catch (Exception e) {
43 | // LOG.warn("invoke QQNotifyHandler Error!!", e);
44 | }
45 | }else{
46 | // LOG.warn("Not found QQNotifyHandler for QQNotifyEvent = " + Event);
47 | }
48 | }
49 |
50 | }
51 | */
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Http/IHttpAction.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using iQQ.Net.WebQQCore.Im.Event;
3 |
4 | namespace iQQ.Net.WebQQCore.Im.Http
5 | {
6 | public interface IHttpAction : IQQHttpListener
7 | {
8 | QQHttpRequest BuildRequest();
9 |
10 | void CancelRequest();
11 |
12 | bool IsCancelable();
13 |
14 | void NotifyActionEvent(QQActionEventType type, object target);
15 |
16 | QQActionListener Listener { get; set; }
17 |
18 | IQQActionFuture ActionFuture { get; set; }
19 |
20 | Task ResponseFuture { set; }
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Http/IQQHttpListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace iQQ.Net.WebQQCore.Im.Http
4 | {
5 | public interface IQQHttpListener
6 | {
7 | void OnHttpFinish(QQHttpResponse response);
8 |
9 | void OnHttpError(Exception t);
10 |
11 | void OnHttpHeader(QQHttpResponse response);
12 |
13 | void OnHttpWrite(long current, long total);
14 |
15 | void OnHttpRead(long current, long total);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Log/EmptyQQLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using iQQ.Net.WebQQCore.Im.Core;
3 | using iQQ.Net.WebQQCore.Util;
4 | using Microsoft.Extensions.Logging;
5 |
6 | namespace iQQ.Net.WebQQCore.Im.Log
7 | {
8 | public class EmptyQQLogger : IQQLogger
9 | {
10 | public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
11 | {
12 | }
13 |
14 | public bool IsEnabled(LogLevel logLevel) => true;
15 |
16 | public IDisposable BeginScope(TState state) => Disposable.Empty;
17 |
18 | public IQQContext Context { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Log/IQQLogger.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Core;
2 | using Microsoft.Extensions.Logging;
3 |
4 | namespace iQQ.Net.WebQQCore.Im.Log
5 | {
6 | public interface IQQLogger : ILogger
7 | {
8 | IQQContext Context { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Log/QQConsoleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using iQQ.Net.WebQQCore.Im.Core;
3 | using iQQ.Net.WebQQCore.Util;
4 | using iQQ.Net.WebQQCore.Util.Extensions;
5 | using Microsoft.Extensions.Logging;
6 |
7 | namespace iQQ.Net.WebQQCore.Im.Log
8 | {
9 | public class QQConsoleLogger : SimpleConsoleLogger, IQQLogger
10 | {
11 | public QQConsoleLogger(string name) : base(name)
12 | {
13 | }
14 |
15 | public QQConsoleLogger() : this("iQQ.Net") { }
16 |
17 | public override string GetMessage(string message, Exception exception)
18 | {
19 | if (!message.IsNullOrEmpty() && Context?.Account != null)
20 | {
21 | var qqStr = Context.Account.QQ.IsDefault() ? string.Empty : $"[{Context.Account.QQ}] ";
22 | return $"{qqStr}{message}";
23 | }
24 | else return message;
25 | }
26 |
27 | public IQQContext Context { get; set; }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/AbstractModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Actor;
2 | using iQQ.Net.WebQQCore.Im.Core;
3 | using iQQ.Net.WebQQCore.Im.Event;
4 | using iQQ.Net.WebQQCore.Im.Event.Future;
5 | using iQQ.Net.WebQQCore.Im.Http;
6 |
7 | namespace iQQ.Net.WebQQCore.Im.Module
8 | {
9 | ///
10 | /// 基础模块
11 | /// @author solosky
12 | ///
13 | public abstract class AbstractModule : IQQModule
14 | {
15 | public IQQContext Context { get; private set; }
16 |
17 | public virtual void Init(IQQContext context)
18 | {
19 | Context = context;
20 | }
21 |
22 | public virtual void Destroy()
23 | {
24 | }
25 |
26 | public IQQActionFuture PushHttpAction(IHttpAction action)
27 | {
28 | var future = new HttpActionFuture(action); //替换掉原始的QQActionListener
29 | Context.PushActor(new HttpActor(HttpActorType.BuildRequest, Context, action));
30 | return future;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/BuddyModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Action;
2 | using iQQ.Net.WebQQCore.Im.Core;
3 | using iQQ.Net.WebQQCore.Im.Event;
4 |
5 | namespace iQQ.Net.WebQQCore.Im.Module
6 | {
7 | ///
8 | /// 好友信息处理模块
9 | /// @author solosky
10 | ///
11 | public class BuddyModule : AbstractModule
12 | {
13 | public IQQActionFuture GetOnlineBuddy(QQActionListener listener)
14 | {
15 | return PushHttpAction(new GetOnlineFriendAction(Context, listener));
16 | }
17 |
18 | public IQQActionFuture GetRecentList(QQActionListener listener)
19 | {
20 | return PushHttpAction(new GetRecentListAction(Context, listener));
21 | }
22 |
23 | public IQQActionFuture AddBuddy(QQActionListener listener, string account)
24 | {
25 | return PushHttpAction(new AcceptBuddyAddAction(Context, listener, account));
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/CategoryModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Action;
2 | using iQQ.Net.WebQQCore.Im.Core;
3 | using iQQ.Net.WebQQCore.Im.Event;
4 |
5 | namespace iQQ.Net.WebQQCore.Im.Module
6 | {
7 | ///
8 | /// 好友列表模块,处理好友的添加和删除
9 | /// @author solosky
10 | ///
11 | public class CategoryModule : AbstractModule
12 | {
13 | public IQQActionFuture GetBuddyList(QQActionListener listener = null)
14 | {
15 | return PushHttpAction(new GetBuddyListAction(Context, listener));
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/DiscuzModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Action;
2 | using iQQ.Net.WebQQCore.Im.Bean;
3 | using iQQ.Net.WebQQCore.Im.Core;
4 | using iQQ.Net.WebQQCore.Im.Event;
5 |
6 | namespace iQQ.Net.WebQQCore.Im.Module
7 | {
8 | ///
9 | /// 讨论组模块
10 | /// @author solosky
11 | ///
12 | public class DiscuzModule : AbstractModule
13 | {
14 | public IQQActionFuture GetDiscuzList(QQActionListener listener)
15 | {
16 | return PushHttpAction(new GetDiscuzListAction(this.Context, listener));
17 | }
18 |
19 | public IQQActionFuture GetDiscuzInfo(QQDiscuz discuz, QQActionListener listener)
20 | {
21 | return PushHttpAction(new GetDiscuzInfoAction(this.Context, listener, discuz));
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/GroupModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Action;
2 | using iQQ.Net.WebQQCore.Im.Bean;
3 | using iQQ.Net.WebQQCore.Im.Core;
4 | using iQQ.Net.WebQQCore.Im.Event;
5 |
6 | namespace iQQ.Net.WebQQCore.Im.Module
7 | {
8 | ///
9 | /// 群模块
10 | /// @author solosky
11 | ///
12 | public class GroupModule : AbstractModule
13 | {
14 | public IQQActionFuture GetGroupList(QQActionListener listener = null)
15 | {
16 | return PushHttpAction(new GetGroupListAction(Context, listener));
17 | }
18 |
19 | public IQQActionFuture UpdateGroupMessageFilter(QQActionListener listener = null)
20 | {
21 | return PushHttpAction(new UpdateGroupMessageFilterAction(Context, listener));
22 | }
23 |
24 | public IQQActionFuture GetGroupFace(QQGroup group, QQActionListener listener = null)
25 | {
26 | return PushHttpAction(new GetGroupFaceAction(Context, listener, group));
27 | }
28 |
29 | public IQQActionFuture GetGroupInfo(QQGroup group, QQActionListener listener = null)
30 | {
31 | return PushHttpAction(new GetGroupInfoAction(Context, listener, group));
32 | }
33 |
34 | public IQQActionFuture GetGroupGid(QQGroup group, QQActionListener listener = null)
35 | {
36 | return PushHttpAction(new GetGroupAccoutAction(Context, listener, group));
37 | }
38 |
39 | public IQQActionFuture GetMemberStatus(QQGroup group, QQActionListener listener = null)
40 | {
41 | return PushHttpAction(new GetGroupMemberStatusAction(Context, listener, group));
42 | }
43 |
44 | public IQQActionFuture SearchGroup(QQGroupSearchList resultList, QQActionListener listener = null)
45 | {
46 | return PushHttpAction(new SearchGroupInfoAction(Context, listener, resultList));
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Module/UserModule.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Action;
2 | using iQQ.Net.WebQQCore.Im.Bean;
3 | using iQQ.Net.WebQQCore.Im.Core;
4 | using iQQ.Net.WebQQCore.Im.Event;
5 |
6 | namespace iQQ.Net.WebQQCore.Im.Module
7 | {
8 | ///
9 | /// 个人信息模块
10 | ///
11 | public class UserModule : AbstractModule
12 | {
13 | public IQQActionFuture GetUserInfo(QQUser user, QQActionListener listener = null)
14 | {
15 | return PushHttpAction(new GetFriendInfoAction(Context, listener, user));
16 | }
17 |
18 | public IQQActionFuture GetUserFace(QQUser user, QQActionListener listener = null)
19 | {
20 | return PushHttpAction(new GetFriendFaceAction(Context, listener, user));
21 | }
22 |
23 | public IQQActionFuture GetUserAccount(QQUser user, QQActionListener listener = null)
24 | {
25 | return PushHttpAction(new GetFriendAccoutAction(Context, listener, user));
26 | }
27 |
28 | public IQQActionFuture GetUserSign(QQUser user, QQActionListener listener = null)
29 | {
30 | return PushHttpAction(new GetFriendSignAction(Context, listener, user));
31 | }
32 |
33 | public IQQActionFuture GetUserLevel(QQUser user, QQActionListener listener = null)
34 | {
35 | return PushHttpAction(new GetUserLevelAction(Context, listener, user));
36 | }
37 |
38 | public IQQActionFuture ChangeStatus(QQStatus status, QQActionListener listener = null)
39 | {
40 | return PushHttpAction(new ChangeStatusAction(Context, listener, status));
41 | }
42 |
43 | public IQQActionFuture GetStrangerInfo(QQUser user, QQActionListener listener = null)
44 | {
45 | return PushHttpAction(new GetStrangerInfoAction(Context, listener, user));
46 | }
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/QQActionListener.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Event;
2 | using System;
3 | using iQQ.Net.WebQQCore.Im.Http;
4 |
5 | namespace iQQ.Net.WebQQCore.Im
6 | {
7 | public delegate void QQActionListener(object sender, QQActionEvent e);
8 | }
9 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/QQNotifyListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using iQQ.Net.WebQQCore.Im.Event;
3 |
4 | namespace iQQ.Net.WebQQCore.Im
5 | {
6 | // 强类型的委托
7 | public delegate void QQNotifyListener(IQQClient sender, QQNotifyEvent e);
8 |
9 | /////
10 | ///// QQ通知事件监听器
11 | /////
12 | //public interface IQQNotifyListener
13 | //{
14 | // // event QQNotifyHandler OnNotifyEvent;
15 | // event EventHandler OnNotifyEvent;
16 | //}
17 | }
18 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Service/AbstractService.cs:
--------------------------------------------------------------------------------
1 | using iQQ.Net.WebQQCore.Im.Core;
2 |
3 | namespace iQQ.Net.WebQQCore.Im.Service
4 | {
5 | ///
6 | /// 抽象的服务类,实现了部分接口,方便子类实现
7 | ///
8 | public abstract class AbstractService : IQQService
9 | {
10 | public IQQContext Context { get; private set; }
11 |
12 | public virtual void Init(IQQContext context)
13 | {
14 | Context = context;
15 | }
16 |
17 | public abstract void Destroy();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/WebQQCore/Im/Service/IHttpService.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using iQQ.Net.WebQQCore.Im.Core;
4 | using iQQ.Net.WebQQCore.Im.Http;
5 |
6 | namespace iQQ.Net.WebQQCore.Im.Service
7 | {
8 | public enum ProxyType
9 | {
10 | HTTP,
11 | SOCK4,
12 | SOCK5
13 | }
14 |
15 | public interface IHttpService : IQQService
16 | {
17 | ///
18 | /// 设置HTTP代理
19 | ///
20 | /// 代理类型
21 | /// 代理主机
22 | /// 代理端口
23 | /// 认证用户名, 如果不需要认证,设置为null
24 | /// 认证密码,如果不需要认证,设置为null
25 | void SetHttpProxy(ProxyType proxyType, string proxyHost,
26 | int proxyPort, string proxyAuthUser, string proxyAuthPassword);
27 |
28 | string UserAgent { get; set; }
29 |
30 | ///
31 | /// 创建一个请求,这个方法会填充默认的HTTP头,比如User-Agent
32 | ///
33 | ///
34 | ///
35 | ///
36 | QQHttpRequest CreateHttpRequest(string method, string url);
37 |
38 | ///
39 | /// 执行一个HTTP请求
40 | ///
41 | ///
42 | ///
43 | ///
44 | QQHttpResponse ExecuteHttpRequest(QQHttpRequest qqRequest, IQQHttpListener listener);
45 | Task ExecuteHttpRequestAsync(QQHttpRequest request, IQQHttpListener listener, CancellationToken token);
46 |
47 | ///
48 | /// 获取一个cookie
49 | ///
50 | ///
51 | ///
52 | ///
53 | QQHttpCookie GetCookie(string name, string url);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/WebQQCore/Resources/hash.js:
--------------------------------------------------------------------------------
1 | hash = function (x, K) {
2 | x += "";
3 | for (var N = [], T = 0; T < K.length; T++)
4 | N[T % 4] ^= K.charCodeAt(T);
5 | var U = ["EC", "OK"], V = [];
6 | V[0] = x >> 24 & 255 ^ U[0].charCodeAt(0);
7 | V[1] = x >> 16 & 255 ^ U[0].charCodeAt(1);
8 | V[2] = x >> 8 & 255 ^ U[1].charCodeAt(0);
9 | V[3] = x & 255 ^ U[1].charCodeAt(1);
10 | U = [];
11 | for (T = 0; T < 8; T++)
12 | U[T] = T % 2 == 0 ? N[T >> 1] : V[T >> 1];
13 | N = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];
14 | V = "";
15 | for (T = 0; T < U.length; T++) {
16 | V += N[U[T] >> 4 & 15];
17 | V += N[U[T] & 15]
18 | }
19 | return V
20 | }
--------------------------------------------------------------------------------
/src/WebQQCore/Util/DateUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Newtonsoft.Json.Linq;
4 |
5 | namespace iQQ.Net.WebQQCore.Util
6 | {
7 | public class DateUtils
8 | {
9 | public static DateTime Parse(JObject jsonobj)
10 | {
11 | const string format = "yyyy-M-d";
12 | var dateString = jsonobj["year"] + "-" + jsonobj["month"] + "-" + jsonobj["day"];
13 | var dt = DateTime.ParseExact(dateString, format, CultureInfo.CurrentCulture);
14 | return dt;
15 | }
16 |
17 | ///
18 | /// 自1970年1月1日0时起的毫秒数
19 | ///
20 | ///
21 | public static long NowTimestamp()
22 | {
23 | return DateTime.Now.CurrentTimeMillis();
24 | }
25 | }
26 |
27 | public static class DateTimeExtensions
28 | {
29 | private static readonly DateTime _jan1St1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
30 |
31 | ///
32 | /// 自1970年1月1日0时起的毫秒数
33 | ///
34 | ///
35 | ///
36 | public static long CurrentTimeMillis(this DateTime d)
37 | {
38 | return (long)((DateTime.UtcNow - _jan1St1970).TotalMilliseconds);
39 | }
40 |
41 | public static long CurrentTimeSeconds(this DateTime d)
42 | {
43 | return CurrentTimeMillis(d) / 1000;
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/DefaultLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using iQQ.Net.WebQQCore.Im;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace iQQ.Net.WebQQCore.Util
10 | {
11 | internal static class DefaultLogger
12 | {
13 | public static ILogger Logger { get; }
14 |
15 | static DefaultLogger()
16 | {
17 | var loggerFactory = new LoggerFactory().AddSimpleConsole();
18 | Logger = loggerFactory.CreateLogger("iQQ.Net");
19 | }
20 |
21 | private static ILoggerFactory AddSimpleConsole(this ILoggerFactory factory)
22 | {
23 | factory.AddProvider(new SimpleConsoleLoggerProvider());
24 | return factory;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/EmptyDisposable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace iQQ.Net.WebQQCore.Util
7 | {
8 | public class Disposable : IDisposable
9 | {
10 | public static IDisposable Empty { get; } = new Disposable();
11 | public void Dispose()
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/ByteExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace iQQ.Net.WebQQCore.Util.Extensions
8 | {
9 | public static class ByteExtensions
10 | {
11 | public static string ToHexString(this byte[] bytes)
12 | {
13 | var builder = new StringBuilder();
14 | foreach (var @byte in bytes)
15 | {
16 | builder.Append(@byte.ToString("X2"));
17 | }
18 | return builder.ToString();
19 | }
20 |
21 | public static byte[] ToBytes(this bool num) => BitConverter.GetBytes(num);
22 |
23 | public static byte[] ToBytes(this char num) => BitConverter.GetBytes(num);
24 |
25 | public static byte[] ToBytes(this short num) => BitConverter.GetBytes(num);
26 |
27 | public static byte[] ToBytes(this int num) => BitConverter.GetBytes(num);
28 |
29 | public static byte[] ToBytes(this long num) => BitConverter.GetBytes(num);
30 |
31 | public static byte[] ToBytes(this ushort num) => BitConverter.GetBytes(num);
32 |
33 | public static byte[] ToBytes(this uint num) => BitConverter.GetBytes(num);
34 |
35 | public static byte[] ToBytes(this ulong num) => BitConverter.GetBytes(num);
36 |
37 | public static byte[] ToBytes(this float num) => BitConverter.GetBytes(num);
38 |
39 | public static byte[] ToBytes(this double num) => BitConverter.GetBytes(num);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/CollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace iQQ.Net.WebQQCore.Util.Extensions
9 | {
10 | public static class CollectionExtensions
11 | {
12 | public static bool IsNullOrEmpty(this ICollection col)
13 | {
14 | return col == null || col.Count == 0;
15 | }
16 |
17 | public static void AddWhenNotNull(this ICollection col, T item)
18 | {
19 | if(item != null) col.Add(item);
20 | }
21 |
22 | public static void AddRangeSafely(this ICollection col, IEnumerable items)
23 | {
24 | if(items == null) return;
25 |
26 | var list = col as List;
27 | if (list != null)
28 | {
29 | list.AddRange(items);
30 | }
31 | else
32 | {
33 | foreach (var item in items)
34 | {
35 | col.Add(item);
36 | }
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/LoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace iQQ.Net.WebQQCore.Util.Extensions
7 | {
8 | public static class LoggerExtensions
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/Md5Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace iQQ.Net.WebQQCore.Util.Extensions
9 | {
10 | public static class Md5Extensions
11 | {
12 | public static string ToMd5String(this byte[] input)
13 | {
14 | return input.ToMd5Bytes().ToHexString();
15 | }
16 |
17 | public static byte[] ToMd5Bytes(this byte[] input)
18 | {
19 | return MD5.Create().ComputeHash(input);
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/ObjectExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace iQQ.Net.WebQQCore.Util.Extensions
8 | {
9 | public static class ObjectExtensions
10 | {
11 | public static T GetOrDefault(this T obj, T defaultValue)
12 | {
13 | return obj == null ? defaultValue : obj;
14 | }
15 |
16 | public static bool IsDefault(this T obj)
17 | {
18 | return obj.Equals(default(T));
19 | }
20 |
21 | public static bool IsNull(this object obj)
22 | {
23 | return obj == null;
24 | }
25 |
26 | public static bool IsNullOrDefault(this T? obj) where T :struct
27 | {
28 | return obj == null || obj.Value.Equals(default(T));
29 | }
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/StreamExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace iQQ.Net.WebQQCore.Util.Extensions
9 | {
10 | public static class StreamExtensions
11 | {
12 | public static string ToString(this Stream stream, Encoding encoding = null)
13 | {
14 | using (var sr = new StreamReader(stream, encoding ?? Encoding.UTF8))
15 | {
16 | return sr.ReadToEnd();
17 | }
18 | }
19 |
20 | public static byte[] ToBytes(this Stream stream)
21 | {
22 | var bytes = new byte[stream.Length];
23 | stream.Read(bytes, 0, bytes.Length);
24 | // 设置当前流的位置为流的开始
25 | stream.Seek(0, SeekOrigin.Begin);
26 | return bytes;
27 | }
28 |
29 | public static Stream ToStream(this byte[] bytes)
30 | {
31 | return new MemoryStream(bytes);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/Extensions/StringBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace iQQ.Net.WebQQCore.Util.Extensions
8 | {
9 | public static class StringBuilderExtensions
10 | {
11 | public static StringBuilder AppendLineIf(this StringBuilder sb, string value, bool condition)
12 | {
13 | if (condition)
14 | {
15 | sb.AppendLine(value);
16 | }
17 | return sb;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/HttpConstants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace iQQ.Net.WebQQCore.Util
7 | {
8 | public enum HttpMethodType
9 | {
10 | Get,
11 | Post,
12 | Put,
13 | Delete,
14 | Head,
15 | Options,
16 | Trace
17 | }
18 |
19 | ///
20 | /// 返回类型
21 | ///
22 | public enum ResponseResultType
23 | {
24 | String,
25 | Byte,
26 | Stream,
27 | }
28 |
29 | public abstract class HttpConstants
30 | {
31 | public const string UserAgent = "User-Agent";
32 | public const string Referrer = "Referer";
33 | public const string Post = "POST";
34 | public const string Get = "GET";
35 | public const string ContentType = "Content-Type";
36 | public const string ContentLength = "Content-Length";
37 | public const string SetCookie = "Set-Cookie";
38 | public const string Origin = "Origin";
39 | public const string Cookie = "Cookie";
40 | public const string DefaultGetContentType = "application/json; charset=utf-8";
41 | public const string DefaultPostContentType = "application/x-www-form-urlencoded";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/RetryHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace iQQ.Net.WebQQCore.Util
8 | {
9 | public static class RetryHelper
10 | {
11 | public static T Retry(Func func, int retryTimes, TimeSpan ts)
12 | {
13 | var exceptions = new List();
14 | for (var i = 0; i < retryTimes; i++)
15 | {
16 | try
17 | {
18 | return func();
19 | }
20 | catch (Exception ex)
21 | {
22 | Thread.Sleep(ts);
23 | exceptions.Add(ex);
24 | }
25 | }
26 | throw new AggregateException(exceptions);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/RobotType.cs:
--------------------------------------------------------------------------------
1 | /************************************************************************************
2 | * 创建人: huoshan12345
3 | * 电子邮箱:89009143@qq.com
4 | * 创建时间:2015/2/26 18:24:01
5 | * 描述:
6 | /************************************************************************************/
7 |
8 | namespace iQQ.Net.WebQQCore.Util
9 | {
10 | public enum RobotType
11 | {
12 | Moli,
13 | Turing,
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/WebQQCore/Util/UrlUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace iQQ.Net.WebQQCore.Util
8 | {
9 | public class UrlUtils
10 | {
11 | public static string GetOrigin(string url)
12 | {
13 | return url.Substring(0, url.LastIndexOf("/"));
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/ActionResult/SyncCheckResult.cs:
--------------------------------------------------------------------------------
1 | namespace WebWeChat.Im.Actions.ActionResult
2 | {
3 | public enum SyncCheckResult
4 | {
5 | ///
6 | /// 什么都没有
7 | ///
8 | Nothing = 0,
9 |
10 | ///
11 | /// 新消息
12 | ///
13 | NewMsg = 2,
14 |
15 | ///
16 | /// 正在使用手机微信
17 | ///
18 | UsingPhone = 7,
19 |
20 | ///
21 | /// 红包
22 | ///
23 | RedEnvelope = 6,
24 |
25 | ///
26 | /// 已离线
27 | ///
28 | Offline = 1100,
29 |
30 | ///
31 | /// 被踢
32 | ///
33 | Kicked = 1101,
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/ActionResult/WatiForLoginResult.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace WebWeChat.Im.Actions.ActionResult
4 | {
5 | public enum WatiForLoginResult
6 | {
7 | ///
8 | /// 手机已允许登录
9 | ///
10 | [Description("手机已允许登录")]
11 | Success = 200,
12 |
13 | ///
14 | /// 二维码失效
15 | ///
16 | [Description("二维码失效")]
17 | QRCodeInvalid = 408,
18 |
19 | ///
20 | /// 手机已扫码
21 | ///
22 | [Description("手机已扫码")]
23 | ScanCode = 201,
24 |
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/GetQRCodeAction.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Threading.Tasks;
3 | using HttpAction.Core;
4 | using HttpAction.Event;
5 | using HttpAction;
6 | using WebWeChat.Im.Core;
7 |
8 | namespace WebWeChat.Im.Actions
9 | {
10 | ///
11 | /// 获取二维码
12 | ///
13 | [Description("获取二维码")]
14 | public class GetQRCodeAction : WebWeChatAction
15 | {
16 | public GetQRCodeAction(IWeChatContext context, ActionEventListener listener = null) : base(context, listener)
17 | {
18 | }
19 |
20 | protected override HttpRequestItem BuildRequest()
21 | {
22 | var req = new HttpRequestItem(HttpMethodType.Post, string.Format(ApiUrls.GetQRCode, Session.Uuid));
23 | req.AddData("t", "webwx");
24 | req.AddData("_", (Session.Seq++).ToString());
25 | req.ResultType = HttpResultType.Byte;
26 | return req;
27 | }
28 |
29 | protected override Task HandleResponse(HttpResponseItem responseItem)
30 | {
31 | // return NotifyOkEventAsync(Image.FromStream(responseItem.ResponseStream));
32 | return NotifyOkEventAsync(ImageSharp.Image.Load(responseItem.ResponseBytes));
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/GetUuidAction.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Text.RegularExpressions;
3 | using System.Threading.Tasks;
4 | using HttpAction.Core;
5 | using HttpAction.Event;
6 | using HttpAction;
7 | using WebWeChat.Im.Core;
8 |
9 | namespace WebWeChat.Im.Actions
10 | {
11 | ///
12 | /// 获取UUID
13 | ///
14 | [Description("获取UUID")]
15 | public class GetUuidAction : WebWeChatAction
16 | {
17 | private readonly Regex _reg = new Regex(@"window.QRLogin.code = (\d+); window.QRLogin.uuid = ""(\S+?)""");
18 |
19 | public GetUuidAction(IWeChatContext context, ActionEventListener listener = null) : base(context, listener)
20 | {
21 | Session.Seq = Timestamp;
22 | }
23 |
24 | protected override HttpRequestItem BuildRequest()
25 | {
26 | var req = new HttpRequestItem(HttpMethodType.Post, ApiUrls.GetUuid);
27 | req.AddQueryValue("appid", ApiUrls.Appid);
28 | req.AddQueryValue("fun", "new");
29 | req.AddQueryValue("lang", "zh_CN");
30 | req.AddQueryValue("_", Session.Seq++);
31 | return req;
32 | }
33 |
34 | protected override Task HandleResponse(HttpResponseItem responseItem)
35 | {
36 | var str = responseItem.ResponseString;
37 | var match = _reg.Match(str);
38 | if (match.Success && match.Groups.Count > 2 && match.Groups[1].Value == "200")
39 | {
40 | Session.Uuid = match.Groups[2].Value;
41 | return NotifyOkEventAsync();
42 | }
43 | return NotifyErrorEventAsync(WeChatErrorCode.ResponseError);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/SendMsgAction.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Threading.Tasks;
3 | using FclEx.Extensions;
4 | using HttpAction.Core;
5 | using HttpAction.Event;
6 | using WebWeChat.Im.Bean;
7 | using WebWeChat.Im.Core;
8 |
9 | namespace WebWeChat.Im.Actions
10 | {
11 | [Description("发送消息")]
12 | public class SendMsgAction : WebWeChatAction
13 | {
14 | private readonly MessageSent _msg;
15 |
16 | public SendMsgAction(IWeChatContext context, MessageSent msg, ActionEventListener listener = null) : base(context, listener)
17 | {
18 | _msg = msg;
19 | }
20 |
21 | protected override HttpRequestItem BuildRequest()
22 | {
23 | var url = string.Format(ApiUrls.SendMsg, Session.BaseUrl);
24 | var obj = new
25 | {
26 | Session.BaseRequest,
27 | Msg = _msg
28 | };
29 | var req = new HttpRequestItem(HttpMethodType.Post, url)
30 | {
31 | StringData = obj.ToJson(),
32 | ContentType = HttpConstants.JsonContentType
33 | };
34 | return req;
35 | }
36 |
37 | protected override Task HandleResponse(HttpResponseItem response)
38 | {
39 | var json = response.ResponseString.ToJToken();
40 | if (json["BaseResponse"]["Ret"].ToString() == "0")
41 | {
42 | return NotifyOkEventAsync();
43 | }
44 | else
45 | {
46 | throw new WeChatException(WeChatErrorCode.ResponseError, response.ResponseString);
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Actions/WebLoginAction.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Threading.Tasks;
3 | using System.Xml.Linq;
4 | using HttpAction.Core;
5 | using HttpAction.Event;
6 | using WebWeChat.Im.Core;
7 | using WebWeChat.Im.Module.Impl;
8 |
9 | namespace WebWeChat.Im.Actions
10 | {
11 | ///
12 | /// 获取登录参数
13 | ///
14 | [Description("获取登录参数")]
15 | public class WebLoginAction : WebWeChatAction
16 | {
17 | public WebLoginAction(IWeChatContext context, ActionEventListener listener = null)
18 | : base(context, listener)
19 | {
20 | }
21 |
22 | protected override HttpRequestItem BuildRequest()
23 | {
24 | return new HttpRequestItem(HttpMethodType.Get, Session.LoginUrl);
25 | }
26 |
27 | protected override Task HandleResponse(HttpResponseItem responseItem)
28 | {
29 | /*
30 |
31 | 0
32 |
33 | @crypt_c498484a_beffad67aa727e24f7c669c51d5c895f
34 | Lr2AUrW1+FSCmtHZ
35 | 463678295
36 | SSR%2BWEx6yJf8MTN2G2XjsWtRpXWQ0J6wBHc5BeHGL3gATmsW%2FMiFX0GBqWrmm7dN
37 | 1
38 |
39 | */
40 | var str = responseItem.ResponseString;
41 | var root = XDocument.Parse(str).Root;
42 | Session.Skey = root.Element("skey").Value;
43 | Session.Sid = root.Element("wxsid").Value;
44 | Session.Uin = root.Element("wxuin").Value;
45 | Session.PassTicket = root.Element("pass_ticket").Value;
46 |
47 | Session.State = SessionState.Online;
48 |
49 | return NotifyOkEventAsync();
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Bean/Appinfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace WebWeChat.Im.Bean
7 | {
8 | public class AppInfo
9 | {
10 | public string AppID { get; set; }
11 | public int Type { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Bean/GroupMember.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using FclEx.Extensions;
3 |
4 | namespace WebWeChat.Im.Bean
5 | {
6 | public class GroupMember
7 | {
8 | public int Uin { get; set; }
9 |
10 | ///
11 | /// 用户名称,一个"@"为好友,两个"@"为群组
12 | ///
13 | public string UserName { get; set; }
14 |
15 | ///
16 | /// 昵称
17 | ///
18 | public string NickName { get; set; }
19 |
20 | public long AttrStatus { get; set; }
21 |
22 | ///
23 | /// 用户名拼音缩写
24 | ///
25 | [JsonProperty(PropertyName = "PYInitial")]
26 | public string PyInitial { get; set; }
27 |
28 | ///
29 | /// 用户名拼音全拼
30 | ///
31 | [JsonProperty(PropertyName = "PYQuanPin")]
32 | public string PyQuanPin { get; set; }
33 |
34 | ///
35 | /// 备注拼音缩写
36 | ///
37 | [JsonProperty(PropertyName = "RemarkPYInitial")]
38 | public string RemarkPyInitial { get; set; }
39 |
40 | ///
41 | /// 备注拼音全拼
42 | ///
43 | [JsonProperty(PropertyName = "RemarkPYQuanPin")]
44 | public string RemarkPyQuanPin { get; set; }
45 |
46 | public int MemberStatus { get; set; }
47 |
48 | public string DisplayName { get; set; }
49 |
50 | public string KeyWord { get; set; }
51 |
52 | public virtual string ShowName => DisplayName.IsNullOrEmpty() ? (NickName.IsNullOrEmpty() ? UserName : DisplayName) : NickName;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Bean/MessageSent.cs:
--------------------------------------------------------------------------------
1 | using FclEx.Extensions;
2 | using System;
3 |
4 | namespace WebWeChat.Im.Bean
5 | {
6 | ///
7 | /// 要发送的消息
8 | ///
9 | public class MessageSent
10 | {
11 | public MessageType Type { get; }
12 | public string Content { get; }
13 | public string FromUserName { get; }
14 | public string ToUserName { get; }
15 | public string LocalID { get; }
16 | public string ClientMsgId { get; }
17 |
18 | private MessageSent()
19 | {
20 | var time = DateTime.Now.ToTimestampMilli();
21 | var random = new Random().Next(0, 9999).ToString("d4");
22 | LocalID = $"{time}{random}";
23 | ClientMsgId = LocalID;
24 | }
25 |
26 | public MessageSent(MessageType type, string content, string fromUserName, string toUserName)
27 | : this()
28 | {
29 | Type = type;
30 | Content = content;
31 | FromUserName = fromUserName;
32 | ToUserName = toUserName;
33 | }
34 |
35 | public static MessageSent CreateTextMsg(string content, string fromUserName, string toUserName)
36 | {
37 | return new MessageSent(MessageType.Text, content, fromUserName, toUserName);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Bean/RecommendInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace WebWeChat.Im.Bean
7 | {
8 | ///
9 | /// 名片信息
10 | ///
11 | public class RecommendInfo
12 | {
13 | public string UserName { get; set; }
14 | public string NickName { get; set; }
15 | public int QQNum { get; set; }
16 | public string Province { get; set; }
17 | public string City { get; set; }
18 | public string Content { get; set; }
19 | public string Signature { get; set; }
20 | public string Alias { get; set; }
21 | public int Scene { get; set; }
22 | public int VerifyFlag { get; set; }
23 | public long AttrStatus { get; set; }
24 | public int Sex { get; set; }
25 | public string Ticket { get; set; }
26 | public int OpCode { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Core/ApiUrls.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 |
6 | namespace WebWeChat.Im.Core
7 | {
8 | public static class ApiUrls
9 | {
10 | public const string Appid = "wx782c26e4c19acffb";
11 | public const string GetUuid = "https://login.weixin.qq.com/jslogin";
12 | public const string GetQRCode = "https://login.weixin.qq.com/qrcode/{0}";
13 | public const string CheckQRCode = "https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login";
14 | public const string WebwxInit = "{0}/webwxinit?pass_ticket={1}&skey={2}&r={3}";
15 | public const string StatusNotify = "{0}/webwxstatusnotify?lang=zh_CN&pass_ticket={1}";
16 | public const string GetContact = "{0}/webwxgetcontact?pass_ticket={1}&skey={2}&r={3}";
17 | public const string BatchGetContact = "{0}/webwxbatchgetcontact?type=ex&pass_ticket={1}&r={2}";
18 | // public const string SyncCheck = "{0}/synccheck";
19 | public const string WebwxSync = "{0}/webwxsync?sid={1}&skey={2}&lang=zh_CN&pass_ticket={3}";
20 | // public const string WebwxSync = "{0}/webwxsync";
21 | public const string SendMsg = "{0}/webwxsendmsg";
22 |
23 |
24 | public static readonly string[] SyncHosts =
25 | {
26 | "webpush.wx.qq.com",
27 | "webpush.wx2.qq.com",
28 | "webpush.wx8.qq.com",
29 | "webpush.web2.wechat.com",
30 | "webpush.web.wechat.com",
31 | //"webpush.wechat.com",
32 | //"webpush1.wechat.com",
33 | //"webpush2.wechat.com",
34 | //"webpush1.wechatapp.com",
35 | //"webpush.wechatapp.com",
36 | };
37 |
38 | public const string TulingRobot = "http://www.tuling123.com/openapi/api";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Core/IWeChatContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using Microsoft.Extensions.Logging;
4 | using WebWeChat.Im.Event;
5 | using WebWeChat.Im.Module;
6 | using WebWeChat.Im.Module.Interface;
7 | using WebWeChat.Im.Service.Interface;
8 |
9 | namespace WebWeChat.Im.Core
10 | {
11 | public interface IWeChatContext
12 | {
13 | Task FireNotifyAsync(WeChatNotifyEvent notifyEvent);
14 |
15 | T GetSerivce();
16 |
17 | T GetModule() where T : IWeChatModule;
18 |
19 | ILogger Logger { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Core/IWebWeChatClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using WebWeChat.Im.Module.Interface;
4 |
5 | namespace WebWeChat.Im.Core
6 | {
7 | public interface IWebWeChatClient : IDisposable, IWeChatContext, ILoginModule, IContactModule, IChatModule
8 | {
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Core/WeChatErrorCode.cs:
--------------------------------------------------------------------------------
1 | namespace WebWeChat.Im.Core
2 | {
3 | public enum WeChatErrorCode
4 | {
5 | ///
6 | /// 响应错误
7 | ///
8 | ResponseError,
9 |
10 | ///
11 | /// 网络错误
12 | ///
13 | IoError,
14 |
15 | ///
16 | /// 参数错误
17 | ///
18 | ParameterError,
19 |
20 | ///
21 | /// Cookie错误
22 | ///
23 | CookieError,
24 |
25 | Timeout, // 等待超时
26 |
27 | JsonError, // JSON解析出错
28 |
29 | ///
30 | /// 未知错误
31 | ///
32 | UnknownError,
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Event/WeChatNotifyEvent.cs:
--------------------------------------------------------------------------------
1 | using FclEx.Extensions;
2 | using System;
3 | using System.Collections.Concurrent;
4 |
5 | namespace WebWeChat.Im.Event
6 | {
7 |
8 | public class WeChatNotifyEvent : EventArgs
9 | {
10 | private static readonly ConcurrentDictionary EmptyEvents
11 | = new ConcurrentDictionary();
12 |
13 | public WeChatNotifyEventType Type { get; }
14 | public object Target { get; }
15 |
16 | private WeChatNotifyEvent(WeChatNotifyEventType type, object target = null)
17 | {
18 | Type = type;
19 | Target = target;
20 | }
21 |
22 | public override string ToString()
23 | {
24 | return $"{Type.GetFullDescription()}, target={Target ?? ""}]";
25 | }
26 |
27 | public static WeChatNotifyEvent CreateEvent(WeChatNotifyEventType type, object target = null)
28 | {
29 | return target == null ? EmptyEvents.GetOrAdd(type, key => new WeChatNotifyEvent(key)) : new WeChatNotifyEvent(type, target);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Event/WeChatNotifyEventListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WebWeChat.Im.Core;
6 |
7 | namespace WebWeChat.Im.Event
8 | {
9 | public delegate Task WeChatNotifyEventListener(IWebWeChatClient sender, WeChatNotifyEvent e);
10 | }
11 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Event/WeChatNotifyEventType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 |
7 | namespace WebWeChat.Im.Event
8 | {
9 | ///
10 | /// QQ通知事件类型
11 | ///
12 | [Description("微信通知事件类型")]
13 | public enum WeChatNotifyEventType
14 | {
15 | ///
16 | /// 二维码已就绪
17 | ///
18 | [Description("二维码已就绪")]
19 | QRCodeReady,
20 |
21 | ///
22 | /// 二维码失效
23 | ///
24 | [Description("二维码失效")]
25 | QRCodeInvalid,
26 |
27 | ///
28 | /// 二维码验证成功
29 | ///
30 | [Description("二维码验证成功")]
31 | QRCodeSuccess,
32 |
33 | ///
34 | /// 错误
35 | ///
36 | [Description("错误")]
37 | Error,
38 |
39 | ///
40 | /// 离线
41 | ///
42 | [Description("离线")]
43 | Offline,
44 |
45 | ///
46 | /// 登录成功
47 | ///
48 | [Description("登录成功")]
49 | LoginSuccess,
50 |
51 | ///
52 | /// 重新登录成功
53 | ///
54 | [Description("重新登录成功")]
55 | ReloginSuccess,
56 |
57 | ///
58 | /// 消息
59 | ///
60 | [Description("消息")]
61 | Message,
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Impl/ChatModule.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HttpAction.Event;
3 | using WebWeChat.Im.Bean;
4 | using WebWeChat.Im.Core;
5 | using WebWeChat.Im.Module.Interface;
6 | using HttpAction;
7 | using WebWeChat.Im.Actions;
8 |
9 | namespace WebWeChat.Im.Module.Impl
10 | {
11 | public class ChatModule : WeChatModule, IChatModule
12 | {
13 | public ChatModule(IWeChatContext context) : base(context)
14 | {
15 | }
16 |
17 | public Task SendMsg(MessageSent msg, ActionEventListener listener = null)
18 | {
19 | return new SendMsgAction(Context, msg, listener).ExecuteAsyncAuto();
20 | }
21 |
22 | public Task GetRobotReply(RobotType robotType, string input, ActionEventListener listener = null)
23 | {
24 | return new GetTuringRobotReplyAction(Context, input).ExecuteAsyncAuto();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Impl/ContactModule.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HttpAction.Event;
3 | using WebWeChat.Im.Core;
4 | using WebWeChat.Im.Module.Interface;
5 | using HttpAction;
6 | using WebWeChat.Im.Actions;
7 |
8 | namespace WebWeChat.Im.Module.Impl
9 | {
10 | public class ContactModule : WeChatModule, IContactModule
11 | {
12 | public Task GetContact(ActionEventListener listener = null)
13 | {
14 | // 如果直接new一个Action并执行的话也可以,但是不能自动重试
15 | return new WebWeChatActionFuture(Context, listener)
16 | .PushAction()
17 | .ExecuteAsync();
18 | }
19 |
20 | public Task GetGroupMember(ActionEventListener listener = null)
21 | {
22 | return new WebWeChatActionFuture(Context, listener)
23 | .PushAction()
24 | .ExecuteAsync();
25 | }
26 |
27 | public ContactModule(IWeChatContext context) : base(context)
28 | {
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Impl/LoginModule.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huoshan12345/WebQQWeChat/cecfd5deb7843ad5a9b0546ae4f073b9a7cd5413/src/WebWeChat/Im/Module/Impl/LoginModule.cs
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Impl/StoreModule.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using WebWeChat.Im.Bean;
5 | using WebWeChat.Im.Core;
6 | using WebWeChat.Util;
7 |
8 | namespace WebWeChat.Im.Module.Impl
9 | {
10 | public class StoreModule : WeChatModule
11 | {
12 | ///
13 | /// 联系人总数
14 | ///
15 | public int MemberCount { get; set; }
16 |
17 | ///
18 | /// 存放联系人
19 | /// 主键是member的username
20 | ///
21 | public ConcurrentDictionary ContactMemberDic { get; set; } = new ConcurrentDictionary();
22 |
23 | ///
24 | /// 特殊账号
25 | ///
26 | public IEnumerable SpecialUsers => ContactMemberDic.Values.Where(m => m.IsSpecialUser());
27 |
28 | public int SpecialUserCount => SpecialUsers.Count();
29 |
30 | ///
31 | /// 群
32 | ///
33 | public IEnumerable Groups => ContactMemberDic.Values.Where(m => m.IsGroup());
34 |
35 | public int GroupCount => Groups.Count();
36 |
37 | ///
38 | /// 好友
39 | ///
40 | public IEnumerable Friends => ContactMemberDic.Values.Where(m => !m.IsSpecialUser() && !m.IsGroup() && !m.IsPublicUsers());
41 |
42 | public int FriendCount => Friends.Count();
43 |
44 | ///
45 | /// 公众号/服务号
46 | ///
47 | public IEnumerable PublicUsers => ContactMemberDic.Values.Where(m => m.IsPublicUsers());
48 |
49 | public int PublicUserCount => PublicUsers.Count();
50 |
51 | public StoreModule(IWeChatContext context) : base(context)
52 | {
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Impl/WeChatModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Configuration;
3 | using Microsoft.Extensions.Logging;
4 | using WebWeChat.Im.Core;
5 | using WebWeChat.Im.Module.Interface;
6 |
7 | namespace WebWeChat.Im.Module.Impl
8 | {
9 | public abstract class WeChatModule : IWeChatModule
10 | {
11 | protected WeChatModule(IWeChatContext context)
12 | {
13 | Context = context ?? throw new ArgumentNullException(nameof(context));
14 | }
15 |
16 | public IWeChatContext Context { get; }
17 | protected ILogger Logger => Context.GetSerivce();
18 | protected IConfigurationRoot Config => Context.GetSerivce();
19 | protected SessionModule Session => Context.GetModule();
20 | protected StoreModule Store => Context.GetModule();
21 |
22 | public virtual void Dispose()
23 | {
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Interface/IChatModule.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HttpAction.Event;
6 | using WebWeChat.Im.Bean;
7 | using WebWeChat.Im.Module.Impl;
8 |
9 | namespace WebWeChat.Im.Module.Interface
10 | {
11 | public interface IChatModule : IWeChatModule
12 | {
13 | Task SendMsg(MessageSent msg, ActionEventListener listener = null);
14 |
15 | Task GetRobotReply(RobotType robotType, string input, ActionEventListener listener = null);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Interface/IContactModule.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HttpAction.Event;
3 |
4 | namespace WebWeChat.Im.Module.Interface
5 | {
6 | public interface IContactModule: IWeChatModule
7 | {
8 | Task GetContact(ActionEventListener listener = null);
9 |
10 | Task GetGroupMember(ActionEventListener listener = null);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Interface/ILoginModule.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using HttpAction.Event;
3 |
4 | namespace WebWeChat.Im.Module.Interface
5 | {
6 | public interface ILoginModule: IWeChatModule
7 | {
8 | ///
9 | /// 登录,扫码方式
10 | ///
11 | ///
12 | ///
13 | Task Login(ActionEventListener listener = null);
14 |
15 | ///
16 | /// 开始保持微信在线并检查新消息,即挂微信
17 | ///
18 | void BeginSyncCheck();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Module/Interface/IWeChatModule.cs:
--------------------------------------------------------------------------------
1 | using WebWeChat.Im.Core;
2 | using WebWeChat.Im.Service.Interface;
3 |
4 | namespace WebWeChat.Im.Module.Interface
5 | {
6 | ///
7 | /// 模块功能接口
8 | ///
9 | public interface IWeChatModule : IWeChatService
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/RobotType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace WebWeChat.Im
6 | {
7 | public enum RobotType
8 | {
9 | Tuling,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Service/Impl/WeChatActionFactory.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using HttpAction.Actions;
3 | using WebWeChat.Im.Actions;
4 | using WebWeChat.Im.Core;
5 | using WebWeChat.Im.Service.Interface;
6 |
7 | namespace WebWeChat.Im.Service.Impl
8 | {
9 | public class WeChatActionFactory : ActionFactory, IWeChatActionFactory
10 | {
11 | public IWeChatContext Context { get;}
12 |
13 | public WeChatActionFactory(IWeChatContext context)
14 | {
15 | Context = context;
16 | }
17 |
18 | public override IAction CreateAction(params object[] parameters)
19 | {
20 | var type = typeof(T);
21 | if (typeof(WebWeChatAction).GetTypeInfo().IsAssignableFrom(type))
22 | {
23 | var newArgs = new object[parameters.Length + 1];
24 | newArgs[0] = Context;
25 | parameters.CopyTo(newArgs, 1);
26 | parameters = newArgs;
27 | }
28 | return base.CreateAction(parameters);
29 | }
30 |
31 | public void Dispose()
32 | {
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Service/Impl/WeChatConsoleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Logging;
3 | using WebWeChat.Im.Core;
4 | using WebWeChat.Im.Module.Impl;
5 | using WebWeChat.Im.Service.Interface;
6 | using FclEx.Extensions;
7 | using FclEx.Logger;
8 |
9 | namespace WebWeChat.Im.Service.Impl
10 | {
11 | public class WeChatConsoleLogger : SimpleConsoleLogger, IWeChatService
12 | {
13 | public IWeChatContext Context { get; }
14 |
15 | public WeChatConsoleLogger(IWeChatContext context, LogLevel minLevel = LogLevel.Information) : base("WeChat", minLevel)
16 | {
17 | Context = context;
18 | }
19 |
20 | ///
21 | /// :warning:
22 | ///
23 | ///
24 | ///
25 | ///
26 | protected override string GetMessage(string message, Exception exception)
27 | {
28 | var userName = Context?.GetModule().User?.NickName;
29 | var prefix = userName.IsNullOrEmpty() ? string.Empty : $"[{userName}]";
30 | return $"{DateTime.Now:HH:mm:ss}> {prefix}{message}";
31 | }
32 |
33 | public void Dispose()
34 | {
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Service/Interface/IWeChatActionFactory.cs:
--------------------------------------------------------------------------------
1 | using HttpAction.Actions;
2 |
3 | namespace WebWeChat.Im.Service.Interface
4 | {
5 | public interface IWeChatActionFactory : IActionFactory, IWeChatService
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/WebWeChat/Im/Service/Interface/IWeChatService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using WebWeChat.Im.Core;
6 |
7 | namespace WebWeChat.Im.Service.Interface
8 | {
9 | ///
10 | /// 就是用来表示该服务是属于一个微信实例的
11 | /// 从而在微信实例销毁的时候服务也能一起销毁
12 | /// 如果是全局的服务(即多个实例共享的)请不要继承该接口
13 | ///
14 | public interface IWeChatService : IDisposable
15 | {
16 | IWeChatContext Context { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/WebWeChat/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 |
3 | namespace WebWeChat
4 | {
5 | public class Startup
6 | {
7 | public static IConfigurationRoot BuildConfig()
8 | {
9 | var builder = new ConfigurationBuilder()
10 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
11 |
12 | if (builder.GetFileProvider().GetFileInfo("project.json")?.Exists == true)
13 | {
14 | builder.AddUserSecrets();
15 | }
16 | return builder.Build();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/WebWeChat/WebWeChat.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | WebWeChat-20161027025319
6 | 2.0.0-beta1
7 | latest
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tools/gitlink/GitLink.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huoshan12345/WebQQWeChat/cecfd5deb7843ad5a9b0546ae4f073b9a7cd5413/tools/gitlink/GitLink.exe
--------------------------------------------------------------------------------
/tools/nuget/nuget.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huoshan12345/WebQQWeChat/cecfd5deb7843ad5a9b0546ae4f073b9a7cd5413/tools/nuget/nuget.exe
--------------------------------------------------------------------------------